diff --git a/.gitignore b/.gitignore index a4368367..08aabe92 100755 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ build/ !default.mode2v3 *.perspectivev3 !default.perspectivev3 -*.xcworkspace +*.xccheckout !default.xcworkspace xcuserdata profile @@ -17,3 +17,4 @@ profile DerivedData .idea/ .svn* +*.pyc diff --git a/JavaScriptCore-iOS-Static.xcconfig b/JavaScriptCore-iOS-Static.xcconfig new file mode 100644 index 00000000..2b0ef2de --- /dev/null +++ b/JavaScriptCore-iOS-Static.xcconfig @@ -0,0 +1,34 @@ +// +// JavaScriptCore-iOS-Static.xcconfig +// JavaScriptCore +// +// Created by Martijn The on 1/17/14. +// +// + +#include "JavaScriptCore/Configurations/JavaScriptCore.xcconfig" + +ARCHS = armv7 armv7s arm64; +ONLY_ACTIVE_ARCH = NO; +SDKROOT = iphoneos; +VALID_ARCHS = arm64 armv7 i386; +BUILD_VARIANTS = normal; +IPHONEOS_DEPLOYMENT_TARGET = 5.1; +STRIP_INSTALLED_PRODUCT = YES; +OTHER_LDFLAGS = ; +PRODUCT_NAME = JavaScriptCore; +HEADER_SEARCH_PATHS = "${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore" "${SOURCE_ROOT}/../WTF/" $(HEADER_SEARCH_PATHS); +LIBRARY_SEARCH_PATHS = "${SOURCE_ROOT}/../Build/"; + +SECTORDER_FLAGS = ; +SECTORDER_FLAGS_iphoneos = ; + +GCC_GENERATE_DEBUGGING_SYMBOLS = NO; +GCC_OPTIMIZATION_LEVEL = 3; +GCC_PREPROCESSOR_DEFINITIONS = $(DEBUG_DEFINES) HAVE_DTRACE=$(HAVE_DTRACE) WEBKIT_VERSION_MIN_REQUIRED=WEBKIT_VERSION_LATEST HAVE_HEADER_DETECTION_H JSC_OBJC_API_ENABLED=0 JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 $(FEATURE_DEFINES) $(GCC_PREPROCESSOR_DEFINITIONS) __MAC_OS_X_VERSION_MIN_REQUIRED=0 ENABLE_YARR_JIT=0; + +ENABLE_REMOTE_INSPECTOR = ENABLE_REMOTE_INSPECTOR=0; // Requires XPC + +PRIVATE_HEADERS_FOLDER_PATH = /dev/null; +PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; + diff --git a/JavaScriptCore-iOS.xcworkspace/contents.xcworkspacedata b/JavaScriptCore-iOS.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..7028adad --- /dev/null +++ b/JavaScriptCore-iOS.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/JavaScriptCore/API/APICallbackFunction.h b/JavaScriptCore/API/APICallbackFunction.h new file mode 100644 index 00000000..65c519b7 --- /dev/null +++ b/JavaScriptCore/API/APICallbackFunction.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2013 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 APICallbackFunction_h +#define APICallbackFunction_h + +#include "APICast.h" +#include "APIShims.h" +#include "Error.h" +#include "JSCallbackConstructor.h" +#include + +namespace JSC { + +struct APICallbackFunction { + +template static EncodedJSValue JSC_HOST_CALL call(ExecState*); +template static EncodedJSValue JSC_HOST_CALL construct(ExecState*); + +}; + +template +EncodedJSValue JSC_HOST_CALL APICallbackFunction::call(ExecState* exec) +{ + JSContextRef execRef = toRef(exec); + JSObjectRef functionRef = toRef(exec->callee()); + JSObjectRef thisObjRef = toRef(jsCast(exec->hostThisValue().toThis(exec, NotStrictMode))); + + int argumentCount = static_cast(exec->argumentCount()); + Vector arguments; + arguments.reserveInitialCapacity(argumentCount); + for (int i = 0; i < argumentCount; i++) + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); + + JSValueRef exception = 0; + JSValueRef result; + { + APICallbackShim callbackShim(exec); + result = jsCast(toJS(functionRef))->functionCallback()(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception); + } + if (exception) + exec->vm().throwException(exec, toJS(exec, exception)); + + // result must be a valid JSValue. + if (!result) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(toJS(exec, result)); +} + +template +EncodedJSValue JSC_HOST_CALL APICallbackFunction::construct(ExecState* exec) +{ + JSObject* constructor = exec->callee(); + JSContextRef ctx = toRef(exec); + JSObjectRef constructorRef = toRef(constructor); + + JSObjectCallAsConstructorCallback callback = jsCast(constructor)->constructCallback(); + if (callback) { + size_t argumentCount = exec->argumentCount(); + Vector arguments; + arguments.reserveInitialCapacity(argumentCount); + for (size_t i = 0; i < argumentCount; ++i) + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); + + JSValueRef exception = 0; + JSObjectRef result; + { + APICallbackShim callbackShim(exec); + result = callback(ctx, constructorRef, argumentCount, arguments.data(), &exception); + } + if (exception) { + exec->vm().throwException(exec, toJS(exec, exception)); + return JSValue::encode(toJS(exec, exception)); + } + // result must be a valid JSValue. + if (!result) + return throwVMTypeError(exec); + return JSValue::encode(toJS(result)); + } + + return JSValue::encode(toJS(JSObjectMake(ctx, jsCast(constructor)->classRef(), 0))); +} + +} // namespace JSC + +#endif // APICallbackFunction_h diff --git a/JavaScriptCore/API/APICast.h b/JavaScriptCore/API/APICast.h index f019a7a4..6526d890 100644 --- a/JavaScriptCore/API/APICast.h +++ b/JavaScriptCore/API/APICast.h @@ -27,14 +27,14 @@ #define APICast_h #include "JSAPIValueWrapper.h" +#include "JSCJSValue.h" +#include "JSCJSValueInlines.h" #include "JSGlobalObject.h" -#include "JSValue.h" -#include namespace JSC { class ExecState; class PropertyNameArray; - class JSGlobalData; + class VM; class JSObject; class JSValue; } @@ -63,46 +63,63 @@ inline JSC::ExecState* toJS(JSGlobalContextRef c) inline JSC::JSValue toJS(JSC::ExecState* exec, JSValueRef v) { ASSERT_UNUSED(exec, exec); - ASSERT(v); #if USE(JSVALUE32_64) JSC::JSCell* jsCell = reinterpret_cast(const_cast(v)); if (!jsCell) - return JSC::JSValue(); + return JSC::jsNull(); + JSC::JSValue result; if (jsCell->isAPIValueWrapper()) - return JSC::jsCast(jsCell)->value(); - return jsCell; + result = JSC::jsCast(jsCell)->value(); + else + result = jsCell; #else - return JSC::JSValue::decode(reinterpret_cast(const_cast(v))); + JSC::JSValue result = JSC::JSValue::decode(reinterpret_cast(const_cast(v))); #endif + if (!result) + return JSC::jsNull(); + if (result.isCell()) + RELEASE_ASSERT(result.asCell()->methodTable()); + return result; } inline JSC::JSValue toJSForGC(JSC::ExecState* exec, JSValueRef v) { ASSERT_UNUSED(exec, exec); - ASSERT(v); #if USE(JSVALUE32_64) JSC::JSCell* jsCell = reinterpret_cast(const_cast(v)); if (!jsCell) return JSC::JSValue(); - return jsCell; + JSC::JSValue result = jsCell; #else - return JSC::JSValue::decode(reinterpret_cast(const_cast(v))); + JSC::JSValue result = JSC::JSValue::decode(reinterpret_cast(const_cast(v))); #endif + if (result && result.isCell()) + RELEASE_ASSERT(result.asCell()->methodTable()); + return result; } -inline JSC::JSObject* toJS(JSObjectRef o) +// Used in JSObjectGetPrivate as that may be called during finalization +inline JSC::JSObject* uncheckedToJS(JSObjectRef o) { return reinterpret_cast(o); } +inline JSC::JSObject* toJS(JSObjectRef o) +{ + JSC::JSObject* object = uncheckedToJS(o); + if (object) + RELEASE_ASSERT(object->methodTable()); + return object; +} + inline JSC::PropertyNameArray* toJS(JSPropertyNameAccumulatorRef a) { return reinterpret_cast(a); } -inline JSC::JSGlobalData* toJS(JSContextGroupRef g) +inline JSC::VM* toJS(JSContextGroupRef g) { - return reinterpret_cast(const_cast(g)); + return reinterpret_cast(const_cast(g)); } inline JSValueRef toRef(JSC::ExecState* exec, JSC::JSValue v) @@ -145,7 +162,7 @@ inline JSPropertyNameAccumulatorRef toRef(JSC::PropertyNameArray* l) return reinterpret_cast(l); } -inline JSContextGroupRef toRef(JSC::JSGlobalData* g) +inline JSContextGroupRef toRef(JSC::VM* g) { return reinterpret_cast(g); } diff --git a/JavaScriptCore/API/APIShims.h b/JavaScriptCore/API/APIShims.h index e1589f6a..a133b8ed 100644 --- a/JavaScriptCore/API/APIShims.h +++ b/JavaScriptCore/API/APIShims.h @@ -28,39 +28,29 @@ #include "CallFrame.h" #include "GCActivityCallback.h" +#include "IncrementalSweeper.h" #include "JSLock.h" #include namespace JSC { class APIEntryShimWithoutLock { -public: - enum RefGlobalDataTag { DontRefGlobalData = 0, RefGlobalData }; - protected: - APIEntryShimWithoutLock(JSGlobalData* globalData, bool registerThread, RefGlobalDataTag shouldRefGlobalData) - : m_shouldRefGlobalData(shouldRefGlobalData) - , m_globalData(globalData) - , m_entryIdentifierTable(wtfThreadData().setCurrentIdentifierTable(globalData->identifierTable)) + APIEntryShimWithoutLock(VM* vm, bool registerThread) + : m_vm(vm) + , m_entryIdentifierTable(wtfThreadData().setCurrentIdentifierTable(vm->identifierTable)) { - if (shouldRefGlobalData) - m_globalData->ref(); - UNUSED_PARAM(registerThread); if (registerThread) - globalData->heap.machineThreads().addCurrentThread(); - m_globalData->heap.activityCallback()->synchronize(); + vm->heap.machineThreads().addCurrentThread(); } ~APIEntryShimWithoutLock() { wtfThreadData().setCurrentIdentifierTable(m_entryIdentifierTable); - if (m_shouldRefGlobalData) - m_globalData->deref(); } protected: - RefGlobalDataTag m_shouldRefGlobalData; - JSGlobalData* m_globalData; + RefPtr m_vm; IdentifierTable* m_entryIdentifierTable; }; @@ -68,57 +58,66 @@ class APIEntryShim : public APIEntryShimWithoutLock { public: // Normal API entry APIEntryShim(ExecState* exec, bool registerThread = true) - : APIEntryShimWithoutLock(&exec->globalData(), registerThread, RefGlobalData) - { - init(); - } - - // This constructor is necessary for HeapTimer to prevent it from accidentally resurrecting - // the ref count of a "dead" JSGlobalData. - APIEntryShim(JSGlobalData* globalData, RefGlobalDataTag refGlobalData, bool registerThread = true) - : APIEntryShimWithoutLock(globalData, registerThread, refGlobalData) + : APIEntryShimWithoutLock(&exec->vm(), registerThread) + , m_lockHolder(exec->vm().exclusiveThread ? 0 : exec) { - init(); } - // JSPropertyNameAccumulator only has a globalData. - APIEntryShim(JSGlobalData* globalData, bool registerThread = true) - : APIEntryShimWithoutLock(globalData, registerThread, RefGlobalData) + // JSPropertyNameAccumulator only has a vm. + APIEntryShim(VM* vm, bool registerThread = true) + : APIEntryShimWithoutLock(vm, registerThread) + , m_lockHolder(vm->exclusiveThread ? 0 : vm) { - init(); } ~APIEntryShim() { - m_globalData->timeoutChecker.stop(); - m_globalData->apiLock().unlock(); + // Destroying our JSLockHolder should also destroy the VM. + m_vm.clear(); } private: - void init() - { - m_globalData->apiLock().lock(); - m_globalData->timeoutChecker.start(); - } + JSLockHolder m_lockHolder; }; class APICallbackShim { public: APICallbackShim(ExecState* exec) - : m_dropAllLocks(exec) - , m_globalData(&exec->globalData()) + : m_dropAllLocks(shouldDropAllLocks(exec->vm()) ? exec : nullptr) + , m_vm(&exec->vm()) + { + wtfThreadData().resetCurrentIdentifierTable(); + } + + APICallbackShim(VM& vm) + : m_dropAllLocks(shouldDropAllLocks(vm) ? &vm : nullptr) + , m_vm(&vm) { wtfThreadData().resetCurrentIdentifierTable(); } ~APICallbackShim() { - wtfThreadData().setCurrentIdentifierTable(m_globalData->identifierTable); + wtfThreadData().setCurrentIdentifierTable(m_vm->identifierTable); } private: + static bool shouldDropAllLocks(VM& vm) + { + if (vm.exclusiveThread) + return false; + + // If the VM is in the middle of being destroyed then we don't want to resurrect it + // by allowing DropAllLocks to ref it. By this point the APILock has already been + // released anyways, so it doesn't matter that DropAllLocks is a no-op. + if (!vm.refCount()) + return false; + + return true; + } + JSLock::DropAllLocks m_dropAllLocks; - JSGlobalData* m_globalData; + VM* m_vm; }; } diff --git a/JavaScriptCore/API/JSAPIWrapperObject.h b/JavaScriptCore/API/JSAPIWrapperObject.h new file mode 100644 index 00000000..90903977 --- /dev/null +++ b/JavaScriptCore/API/JSAPIWrapperObject.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSAPIWrapperObject_h +#define JSAPIWrapperObject_h + +#include "JSBase.h" +#include "JSDestructibleObject.h" +#include "WeakReferenceHarvester.h" + +#if JSC_OBJC_API_ENABLED + +namespace JSC { + +class JSAPIWrapperObject : public JSDestructibleObject { +public: + typedef JSDestructibleObject Base; + + void finishCreation(VM&); + static void visitChildren(JSCell*, JSC::SlotVisitor&); + + void* wrappedObject() { return m_wrappedObject; } + void setWrappedObject(void*); + +protected: + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + + JSAPIWrapperObject(VM&, Structure*); + +private: + void* m_wrappedObject; +}; + +} // namespace JSC + +#endif // JSC_OBJC_API_ENABLED + +#endif // JSAPIWrapperObject_h diff --git a/JavaScriptCore/API/JSAPIWrapperObject.mm b/JavaScriptCore/API/JSAPIWrapperObject.mm new file mode 100644 index 00000000..dd3af39f --- /dev/null +++ b/JavaScriptCore/API/JSAPIWrapperObject.mm @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSAPIWrapperObject.h" + +#include "DelayedReleaseScope.h" +#include "JSCJSValueInlines.h" +#include "JSCallbackObject.h" +#include "JSCellInlines.h" +#include "JSVirtualMachineInternal.h" +#include "SlotVisitorInlines.h" +#include "Structure.h" +#include "StructureInlines.h" + +#if JSC_OBJC_API_ENABLED + +class JSAPIWrapperObjectHandleOwner : public JSC::WeakHandleOwner { +public: + virtual void finalize(JSC::Handle, void*) OVERRIDE; + virtual bool isReachableFromOpaqueRoots(JSC::Handle, void* context, JSC::SlotVisitor&) OVERRIDE; +}; + +static JSAPIWrapperObjectHandleOwner* jsAPIWrapperObjectHandleOwner() +{ + DEFINE_STATIC_LOCAL(JSAPIWrapperObjectHandleOwner, jsWrapperObjectHandleOwner, ()); + return &jsWrapperObjectHandleOwner; +} + +void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle handle, void*) +{ + JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast(handle.get().asCell()); + if (!wrapperObject->wrappedObject()) + return; + + JSC::Heap::heap(wrapperObject)->releaseSoon(adoptNS(static_cast(wrapperObject->wrappedObject()))); + JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot())); +} + +bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle handle, void*, JSC::SlotVisitor& visitor) +{ + JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast(handle.get().asCell()); + // We use the JSGlobalObject when processing weak handles to prevent the situation where using + // the same Objective-C object in multiple global objects keeps all of the global objects alive. + if (!wrapperObject->wrappedObject()) + return false; + return JSC::Heap::isMarked(wrapperObject->structure()->globalObject()) && visitor.containsOpaqueRoot(wrapperObject->wrappedObject()); +} + +namespace JSC { + +template <> const ClassInfo JSCallbackObject::s_info = { "JSAPIWrapperObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; + +template<> const bool JSCallbackObject::needsDestruction = true; + +template <> +Structure* JSCallbackObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) +{ + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); +} + +JSAPIWrapperObject::JSAPIWrapperObject(VM& vm, Structure* structure) + : Base(vm, structure) + , m_wrappedObject(0) +{ +} + +void JSAPIWrapperObject::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + WeakSet::allocate(this, jsAPIWrapperObjectHandleOwner(), 0); // Balanced in JSAPIWrapperObjectHandleOwner::finalize. +} + +void JSAPIWrapperObject::setWrappedObject(void* wrappedObject) +{ + ASSERT(!m_wrappedObject); + m_wrappedObject = [static_cast(wrappedObject) retain]; +} + +void JSAPIWrapperObject::visitChildren(JSCell* cell, JSC::SlotVisitor& visitor) +{ + JSAPIWrapperObject* thisObject = JSC::jsCast(cell); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + Base::visitChildren(cell, visitor); + + if (thisObject->wrappedObject()) + scanExternalObjectGraph(cell->structure()->globalObject()->vm(), visitor, thisObject->wrappedObject()); +} + +} // namespace JSC + +#endif // JSC_OBJC_API_ENABLED diff --git a/JavaScriptCore/API/JSBase.cpp b/JavaScriptCore/API/JSBase.cpp index d0ffa311..c0930a49 100644 --- a/JavaScriptCore/API/JSBase.cpp +++ b/JavaScriptCore/API/JSBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,31 +29,36 @@ #include "APICast.h" #include "APIShims.h" +#include "CallFrame.h" +#include "Completion.h" +#include "InitializeThreading.h" +#include "JSGlobalObject.h" +#include "JSLock.h" +#include "JSObject.h" #include "OpaqueJSString.h" +#include "Operations.h" #include "SourceCode.h" -#include -#include -#include -#include -#include -#include #include using namespace JSC; JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsThisObject = toJS(thisObject); // evaluate sets "this" to the global object if it is NULL - JSGlobalObject* globalObject = exec->dynamicGlobalObject(); - SourceCode source = makeSource(script->ustring(), sourceURL->ustring(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + JSGlobalObject* globalObject = exec->vmEntryGlobalObject(); + SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); JSValue evaluationException; - JSValue returnValue = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), source, jsThisObject, &evaluationException); + JSValue returnValue = evaluate(globalObject->globalExec(), source, jsThisObject, &evaluationException); if (evaluationException) { if (exception) @@ -70,13 +75,17 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - SourceCode source = makeSource(script->ustring(), sourceURL->ustring(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); JSValue syntaxException; - bool isValidSyntax = checkSyntax(exec->dynamicGlobalObject()->globalExec(), source, &syntaxException); + bool isValidSyntax = checkSyntax(exec->vmEntryGlobalObject()->globalExec(), source, &syntaxException); if (!isValidSyntax) { if (exception) @@ -100,12 +109,50 @@ void JSGarbageCollect(JSContextRef ctx) ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec, false); - exec->globalData().heap.reportAbandonedObjectGraph(); + exec->vm().heap.reportAbandonedObjectGraph(); } void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - exec->globalData().heap.reportExtraMemoryCost(size); + exec->vm().heap.reportExtraMemoryCost(size); } + +extern "C" JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef); + +void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx) +{ + if (!ctx) + return; + + ExecState* exec = toJS(ctx); + APIEntryShim entryShim(exec); + exec->vm().heap.collectAllGarbage(); +} + +void JSDisableGCTimer(void) +{ + GCActivityCallback::s_shouldCreateGCTimer = false; +} + +#if PLATFORM(IOS) +// FIXME: Expose symbols to tell dyld where to find JavaScriptCore on older versions of +// iOS (< 7.0). We should remove these symbols once we no longer need to support such +// versions of iOS. See for more details. +JS_EXPORT extern const char iosInstallName43 __asm("$ld$install_name$os4.3$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore"); +JS_EXPORT extern const char iosInstallName50 __asm("$ld$install_name$os5.0$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore"); +JS_EXPORT extern const char iosInstallName51 __asm("$ld$install_name$os5.1$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore"); +JS_EXPORT extern const char iosInstallName60 __asm("$ld$install_name$os6.0$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore"); +JS_EXPORT extern const char iosInstallName61 __asm("$ld$install_name$os6.1$/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore"); + +const char iosInstallName43 = 0; +const char iosInstallName50 = 0; +const char iosInstallName51 = 0; +const char iosInstallName60 = 0; +const char iosInstallName61 = 0; +#endif diff --git a/JavaScriptCore/API/JSBase.h b/JavaScriptCore/API/JSBase.h index fed54fe2..def4ea07 100644 --- a/JavaScriptCore/API/JSBase.h +++ b/JavaScriptCore/API/JSBase.h @@ -30,6 +30,10 @@ #include #endif +#ifdef __OBJC__ +#import +#endif + /* JavaScript engine interface */ /*! @typedef JSContextGroupRef A group that associates JavaScript contexts with one another. Contexts in the same group may share and exchange JavaScript objects. */ @@ -71,7 +75,7 @@ typedef struct OpaqueJSValue* JSObjectRef; #elif defined(__GNUC__) && !defined(__CC_ARM) && !defined(__ARMCC__) #define JS_EXPORT __attribute__((visibility("default"))) #elif defined(WIN32) || defined(_WIN32) || defined(_WIN32_WCE) || defined(__CC_ARM) || defined(__ARMCC__) -#if defined(BUILDING_JavaScriptCore) || defined(BUILDING_WTF) +#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore) #define JS_EXPORT __declspec(dllexport) #else #define JS_EXPORT __declspec(dllimport) @@ -135,4 +139,13 @@ JS_EXPORT void JSGarbageCollect(JSContextRef ctx); } #endif +/* Enable the Objective-C API for platforms with a modern runtime. */ +#if !defined(JSC_OBJC_API_ENABLED) +#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 +#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 && !defined(__i386__)) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE))) +#else +#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 && !defined(__i386__)) +#endif +#endif + #endif /* JSBase_h */ diff --git a/JavaScriptCore/API/JSBasePrivate.h b/JavaScriptCore/API/JSBasePrivate.h index befa3164..133176e1 100644 --- a/JavaScriptCore/API/JSBasePrivate.h +++ b/JavaScriptCore/API/JSBasePrivate.h @@ -43,7 +43,9 @@ owns a large non-GC memory region. Calling this function will encourage the garbage collector to collect soon, hoping to reclaim that large non-GC memory region. */ -JS_EXPORT void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) CF_AVAILABLE(10_6, 7_0); + +JS_EXPORT void JSDisableGCTimer(void); #ifdef __cplusplus } diff --git a/JavaScriptCore/API/JSCTestRunnerUtils.cpp b/JavaScriptCore/API/JSCTestRunnerUtils.cpp new file mode 100644 index 00000000..2e93ac11 --- /dev/null +++ b/JavaScriptCore/API/JSCTestRunnerUtils.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 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 "JSCTestRunnerUtils.h" + +#include "APICast.h" +#include "Operations.h" +#include "TestRunnerUtils.h" + +namespace JSC { + +JSValueRef numberOfDFGCompiles(JSContextRef context, JSValueRef theFunctionValueRef) +{ + ExecState* exec= toJS(context); + return toRef(exec, numberOfDFGCompiles(toJS(exec, theFunctionValueRef))); +} + +JSValueRef setNeverInline(JSContextRef context, JSValueRef theFunctionValueRef) +{ + ExecState* exec= toJS(context); + return toRef(exec, setNeverInline(toJS(exec, theFunctionValueRef))); +} + +} // namespace JSC + diff --git a/JavaScriptCore/API/JSCTestRunnerUtils.h b/JavaScriptCore/API/JSCTestRunnerUtils.h new file mode 100644 index 00000000..aaecdd5c --- /dev/null +++ b/JavaScriptCore/API/JSCTestRunnerUtils.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 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 JSCTestRunnerUtils_h +#define JSCTestRunnerUtils_h + +#include +#include + +namespace JSC { + +JS_EXPORT_PRIVATE JSValueRef numberOfDFGCompiles(JSContextRef, JSValueRef theFunction); +JS_EXPORT_PRIVATE JSValueRef setNeverInline(JSContextRef, JSValueRef theFunction); + +} // namespace JSC + +#endif // JSCTestRunnerUtils_h diff --git a/JavaScriptCore/API/JSCallbackConstructor.cpp b/JavaScriptCore/API/JSCallbackConstructor.cpp index c8b4c065..8ea97a44 100644 --- a/JavaScriptCore/API/JSCallbackConstructor.cpp +++ b/JavaScriptCore/API/JSCallbackConstructor.cpp @@ -26,20 +26,22 @@ #include "config.h" #include "JSCallbackConstructor.h" -#include "APIShims.h" +#include "APICallbackFunction.h" #include "APICast.h" -#include -#include -#include -#include +#include "APIShims.h" +#include "Error.h" +#include "JSGlobalObject.h" +#include "JSLock.h" +#include "ObjectPrototype.h" +#include "Operations.h" #include namespace JSC { -const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) }; +const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) }; JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback) - : JSNonFinalObject(globalObject->globalData(), structure) + : JSDestructibleObject(globalObject->vm(), structure) , m_class(jsClass) , m_callback(callback) { @@ -47,8 +49,8 @@ JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Struc void JSCallbackConstructor::finishCreation(JSGlobalObject* globalObject, JSClassRef jsClass) { - Base::finishCreation(globalObject->globalData()); - ASSERT(inherits(&s_info)); + Base::finishCreation(globalObject->vm()); + ASSERT(inherits(info())); if (m_class) JSClassRetain(jsClass); } @@ -61,42 +63,12 @@ JSCallbackConstructor::~JSCallbackConstructor() void JSCallbackConstructor::destroy(JSCell* cell) { - jsCast(cell)->JSCallbackConstructor::~JSCallbackConstructor(); -} - -static EncodedJSValue JSC_HOST_CALL constructJSCallback(ExecState* exec) -{ - JSObject* constructor = exec->callee(); - JSContextRef ctx = toRef(exec); - JSObjectRef constructorRef = toRef(constructor); - - JSObjectCallAsConstructorCallback callback = jsCast(constructor)->callback(); - if (callback) { - int argumentCount = static_cast(exec->argumentCount()); - Vector arguments(argumentCount); - for (int i = 0; i < argumentCount; i++) - arguments[i] = toRef(exec, exec->argument(i)); - - JSValueRef exception = 0; - JSObjectRef result; - { - APICallbackShim callbackShim(exec); - result = callback(ctx, constructorRef, argumentCount, arguments.data(), &exception); - } - if (exception) - throwError(exec, toJS(exec, exception)); - // result must be a valid JSValue. - if (!result) - return throwVMTypeError(exec); - return JSValue::encode(toJS(result)); - } - - return JSValue::encode(toJS(JSObjectMake(ctx, jsCast(constructor)->classRef(), 0))); + static_cast(cell)->JSCallbackConstructor::~JSCallbackConstructor(); } ConstructType JSCallbackConstructor::getConstructData(JSCell*, ConstructData& constructData) { - constructData.native.function = constructJSCallback; + constructData.native.function = APICallbackFunction::construct; return ConstructTypeHost; } diff --git a/JavaScriptCore/API/JSCallbackConstructor.h b/JavaScriptCore/API/JSCallbackConstructor.h index 25fde132..7eedb52e 100644 --- a/JavaScriptCore/API/JSCallbackConstructor.h +++ b/JavaScriptCore/API/JSCallbackConstructor.h @@ -27,13 +27,13 @@ #define JSCallbackConstructor_h #include "JSObjectRef.h" -#include +#include "runtime/JSDestructibleObject.h" namespace JSC { -class JSCallbackConstructor : public JSNonFinalObject { +class JSCallbackConstructor : public JSDestructibleObject { public: - typedef JSNonFinalObject Base; + typedef JSDestructibleObject Base; static JSCallbackConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, JSObjectCallAsConstructorCallback callback) { @@ -46,11 +46,11 @@ class JSCallbackConstructor : public JSNonFinalObject { static void destroy(JSCell*); JSClassRef classRef() const { return m_class; } JSObjectCallAsConstructorCallback callback() const { return m_callback; } - static const ClassInfo s_info; + DECLARE_INFO; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); } protected: @@ -59,8 +59,12 @@ class JSCallbackConstructor : public JSNonFinalObject { static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; private: + friend struct APICallbackFunction; + static ConstructType getConstructData(JSCell*, ConstructData&); + JSObjectCallAsConstructorCallback constructCallback() { return m_callback; } + JSClassRef m_class; JSObjectCallAsConstructorCallback m_callback; }; diff --git a/JavaScriptCore/API/JSCallbackFunction.cpp b/JavaScriptCore/API/JSCallbackFunction.cpp index d287ab77..1996991f 100644 --- a/JavaScriptCore/API/JSCallbackFunction.cpp +++ b/JavaScriptCore/API/JSCallbackFunction.cpp @@ -26,65 +26,47 @@ #include "config.h" #include "JSCallbackFunction.h" -#include "APIShims.h" +#include "APICallbackFunction.h" #include "APICast.h" +#include "APIShims.h" #include "CodeBlock.h" +#include "Error.h" #include "ExceptionHelpers.h" -#include "JSFunction.h" #include "FunctionPrototype.h" -#include -#include +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "JSLock.h" +#include "Operations.h" #include namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSCallbackFunction); -ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSCallbackFunction); +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSCallbackFunction); const ClassInfo JSCallbackFunction::s_info = { "CallbackFunction", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackFunction) }; -JSCallbackFunction::JSCallbackFunction(JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback callback) - : InternalFunction(globalObject, globalObject->callbackFunctionStructure()) +JSCallbackFunction::JSCallbackFunction(VM& vm, Structure* structure, JSObjectCallAsFunctionCallback callback) + : InternalFunction(vm, structure) , m_callback(callback) { } -void JSCallbackFunction::finishCreation(JSGlobalData& globalData, const Identifier& name) +void JSCallbackFunction::finishCreation(VM& vm, const String& name) { - Base::finishCreation(globalData, name); - ASSERT(inherits(&s_info)); + Base::finishCreation(vm, name); + ASSERT(inherits(info())); } -EncodedJSValue JSCallbackFunction::call(ExecState* exec) +JSCallbackFunction* JSCallbackFunction::create(VM& vm, JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback callback, const String& name) { - JSContextRef execRef = toRef(exec); - JSObjectRef functionRef = toRef(exec->callee()); - JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec)); - - int argumentCount = static_cast(exec->argumentCount()); - Vector arguments(argumentCount); - for (int i = 0; i < argumentCount; i++) - arguments[i] = toRef(exec, exec->argument(i)); - - JSValueRef exception = 0; - JSValueRef result; - { - APICallbackShim callbackShim(exec); - result = jsCast(toJS(functionRef))->m_callback(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception); - } - if (exception) - throwError(exec, toJS(exec, exception)); - - // result must be a valid JSValue. - if (!result) - return JSValue::encode(jsUndefined()); - - return JSValue::encode(toJS(exec, result)); + JSCallbackFunction* function = new (NotNull, allocateCell(vm.heap)) JSCallbackFunction(vm, globalObject->callbackFunctionStructure(), callback); + function->finishCreation(vm, name); + return function; } CallType JSCallbackFunction::getCallData(JSCell*, CallData& callData) { - callData.native.function = call; + callData.native.function = APICallbackFunction::call; return CallTypeHost; } diff --git a/JavaScriptCore/API/JSCallbackFunction.h b/JavaScriptCore/API/JSCallbackFunction.h index fec4136f..dff18de5 100644 --- a/JavaScriptCore/API/JSCallbackFunction.h +++ b/JavaScriptCore/API/JSCallbackFunction.h @@ -32,33 +32,28 @@ namespace JSC { class JSCallbackFunction : public InternalFunction { -protected: - JSCallbackFunction(JSGlobalObject*, JSObjectCallAsFunctionCallback); - void finishCreation(JSGlobalData&, const Identifier& name); - + friend struct APICallbackFunction; public: typedef InternalFunction Base; - static JSCallbackFunction* create(ExecState* exec, JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback callback, const Identifier& name) - { - JSCallbackFunction* function = new (NotNull, allocateCell(*exec->heap())) JSCallbackFunction(globalObject, callback); - function->finishCreation(exec->globalData(), name); - return function; - } + static JSCallbackFunction* create(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, const String& name); - static const ClassInfo s_info; + DECLARE_INFO; // InternalFunction mish-mashes constructor and function behavior -- we should // refactor the code so this override isn't necessary - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); } private: + JSCallbackFunction(VM&, Structure*, JSObjectCallAsFunctionCallback); + void finishCreation(VM&, const String& name); + static CallType getCallData(JSCell*, CallData&); - static EncodedJSValue JSC_HOST_CALL call(ExecState*); + JSObjectCallAsFunctionCallback functionCallback() { return m_callback; } JSObjectCallAsFunctionCallback m_callback; }; diff --git a/JavaScriptCore/API/JSCallbackObject.cpp b/JavaScriptCore/API/JSCallbackObject.cpp index 68c26824..94713da3 100644 --- a/JavaScriptCore/API/JSCallbackObject.cpp +++ b/JavaScriptCore/API/JSCallbackObject.cpp @@ -28,39 +28,43 @@ #include "JSCallbackObject.h" #include "Heap.h" +#include "Operations.h" #include namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject); -ASSERT_CLASS_FITS_IN_CELL(JSCallbackObject); - // Define the two types of JSCallbackObjects we support. -template <> const ClassInfo JSCallbackObject::s_info = { "CallbackObject", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; -template <> const ClassInfo JSCallbackObject::s_info = { "CallbackGlobalObject", &JSGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; +template <> const ClassInfo JSCallbackObject::s_info = { "CallbackObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; +template <> const ClassInfo JSCallbackObject::s_info = { "CallbackGlobalObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; + +template<> const bool JSCallbackObject::needsDestruction = true; +template<> const bool JSCallbackObject::needsDestruction = false; + +template<> +JSCallbackObject* JSCallbackObject::create(VM& vm, JSClassRef classRef, Structure* structure) +{ + JSCallbackObject* callbackObject = new (NotNull, allocateCell>(vm.heap)) JSCallbackObject(vm, classRef, structure); + callbackObject->finishCreation(vm); + vm.heap.addFinalizer(callbackObject, destroy); + return callbackObject; +} template <> -Structure* JSCallbackObject::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) +Structure* JSCallbackObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); } template <> -Structure* JSCallbackObject::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) +Structure* JSCallbackObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(globalData, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), &s_info); -} - -template -void JSCallbackObject::destroy(JSCell* cell) -{ - jsCast(cell)->JSCallbackObject::~JSCallbackObject(); + return Structure::create(vm, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), info()); } void JSCallbackObjectData::finalize(Handle handle, void* context) { JSClassRef jsClass = static_cast(context); - JSObjectRef thisRef = toRef(asObject(handle.get())); + JSObjectRef thisRef = toRef(static_cast(handle.get().asCell())); for (; jsClass; jsClass = jsClass->parentClass) if (JSObjectFinalizeCallback finalize = jsClass->finalize) diff --git a/JavaScriptCore/API/JSCallbackObject.h b/JavaScriptCore/API/JSCallbackObject.h index 9aca0c7e..7ad16080 100644 --- a/JavaScriptCore/API/JSCallbackObject.h +++ b/JavaScriptCore/API/JSCallbackObject.h @@ -42,7 +42,7 @@ struct JSCallbackObjectData : WeakHandleOwner { JSClassRetain(jsClass); } - ~JSCallbackObjectData() + virtual ~JSCallbackObjectData() { JSClassRelease(jsClass); } @@ -54,11 +54,11 @@ struct JSCallbackObjectData : WeakHandleOwner { return m_privateProperties->getPrivateProperty(propertyName); } - void setPrivateProperty(JSGlobalData& globalData, JSCell* owner, const Identifier& propertyName, JSValue value) + void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value) { if (!m_privateProperties) m_privateProperties = adoptPtr(new JSPrivatePropertyMap); - m_privateProperties->setPrivateProperty(globalData, owner, propertyName, value); + m_privateProperties->setPrivateProperty(vm, owner, propertyName, value); } void deletePrivateProperty(const Identifier& propertyName) @@ -83,13 +83,13 @@ struct JSCallbackObjectData : WeakHandleOwner { PrivatePropertyMap::const_iterator location = m_propertyMap.find(propertyName.impl()); if (location == m_propertyMap.end()) return JSValue(); - return location->second.get(); + return location->value.get(); } - void setPrivateProperty(JSGlobalData& globalData, JSCell* owner, const Identifier& propertyName, JSValue value) + void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value) { WriteBarrier empty; - m_propertyMap.add(propertyName.impl(), empty).iterator->second.set(globalData, owner, value); + m_propertyMap.add(propertyName.impl(), empty).iterator->value.set(vm, owner, value); } void deletePrivateProperty(const Identifier& propertyName) @@ -100,8 +100,8 @@ struct JSCallbackObjectData : WeakHandleOwner { void visitChildren(SlotVisitor& visitor) { for (PrivatePropertyMap::iterator ptr = m_propertyMap.begin(); ptr != m_propertyMap.end(); ++ptr) { - if (ptr->second) - visitor.append(&ptr->second); + if (ptr->value) + visitor.append(&ptr->value); } } @@ -110,7 +110,7 @@ struct JSCallbackObjectData : WeakHandleOwner { PrivatePropertyMap m_propertyMap; }; OwnPtr m_privateProperties; - virtual void finalize(Handle, void*); + virtual void finalize(Handle, void*) OVERRIDE; }; @@ -118,10 +118,10 @@ template class JSCallbackObject : public Parent { protected: JSCallbackObject(ExecState*, Structure*, JSClassRef, void* data); - JSCallbackObject(JSGlobalData&, JSClassRef, Structure*); + JSCallbackObject(VM&, JSClassRef, Structure*); void finishCreation(ExecState*); - void finishCreation(JSGlobalData&); + void finishCreation(VM&); public: typedef Parent Base; @@ -133,31 +133,32 @@ class JSCallbackObject : public Parent { callbackObject->finishCreation(exec); return callbackObject; } - static JSCallbackObject* create(JSGlobalData& globalData, JSClassRef classRef, Structure* structure) + static JSCallbackObject* create(VM&, JSClassRef, Structure*); + + static const bool needsDestruction; + static void destroy(JSCell* cell) { - JSCallbackObject* callbackObject = new (NotNull, allocateCell(globalData.heap)) JSCallbackObject(globalData, classRef, structure); - callbackObject->finishCreation(globalData); - return callbackObject; + static_cast(cell)->JSCallbackObject::~JSCallbackObject(); } void setPrivate(void* data); void* getPrivate(); - static const ClassInfo s_info; + DECLARE_INFO; JSClassRef classRef() const { return m_callbackObjectData->jsClass; } bool inherits(JSClassRef) const; - static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue); + static Structure* createStructure(VM&, JSGlobalObject*, JSValue); JSValue getPrivateProperty(const Identifier& propertyName) const { return m_callbackObjectData->getPrivateProperty(propertyName); } - void setPrivateProperty(JSGlobalData& globalData, const Identifier& propertyName, JSValue value) + void setPrivateProperty(VM& vm, const Identifier& propertyName, JSValue value) { - m_callbackObjectData->setPrivateProperty(globalData, this, propertyName, value); + m_callbackObjectData->setPrivateProperty(vm, this, propertyName, value); } void deletePrivateProperty(const Identifier& propertyName) @@ -168,26 +169,25 @@ class JSCallbackObject : public Parent { using Parent::methodTable; protected: - static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Parent::StructureFlags; + static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Parent::StructureFlags; private: - static UString className(const JSObject*); - - static void destroy(JSCell*); + static String className(const JSObject*); static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); - static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&); + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static void putByIndex(JSCell*, ExecState*, unsigned, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, const Identifier&); + static bool deleteProperty(JSCell*, ExecState*, PropertyName); static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned); - static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue proto); + static bool customHasInstance(JSObject*, ExecState*, JSValue); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); static ConstructType getConstructData(JSCell*, ConstructData&); static CallType getCallData(JSCell*, CallData&); @@ -195,7 +195,7 @@ class JSCallbackObject : public Parent { static void visitChildren(JSCell* cell, SlotVisitor& visitor) { JSCallbackObject* thisObject = jsCast(cell); - ASSERT_GC_OBJECT_INHERITS((static_cast(thisObject)), &JSCallbackObject::s_info); + ASSERT_GC_OBJECT_INHERITS((static_cast(thisObject)), JSCallbackObject::info()); COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->Parent::structure()->typeInfo().overridesVisitChildren()); Parent::visitChildren(thisObject, visitor); @@ -205,13 +205,14 @@ class JSCallbackObject : public Parent { void init(ExecState*); static JSCallbackObject* asCallbackObject(JSValue); + static JSCallbackObject* asCallbackObject(EncodedJSValue); static EncodedJSValue JSC_HOST_CALL call(ExecState*); static EncodedJSValue JSC_HOST_CALL construct(ExecState*); - JSValue getStaticValue(ExecState*, const Identifier&); - static JSValue staticFunctionGetter(ExecState*, JSValue, const Identifier&); - static JSValue callbackGetter(ExecState*, JSValue, const Identifier&); + JSValue getStaticValue(ExecState*, PropertyName); + static EncodedJSValue staticFunctionGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); + static EncodedJSValue callbackGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); OwnPtr m_callbackObjectData; }; diff --git a/JavaScriptCore/API/JSCallbackObjectFunctions.h b/JavaScriptCore/API/JSCallbackObjectFunctions.h index b909dde7..5be053f1 100644 --- a/JavaScriptCore/API/JSCallbackObjectFunctions.h +++ b/JavaScriptCore/API/JSCallbackObjectFunctions.h @@ -45,13 +45,20 @@ namespace JSC { template inline JSCallbackObject* JSCallbackObject::asCallbackObject(JSValue value) { - ASSERT(asObject(value)->inherits(&s_info)); + ASSERT(asObject(value)->inherits(info())); return jsCast(asObject(value)); } +template +inline JSCallbackObject* JSCallbackObject::asCallbackObject(EncodedJSValue value) +{ + ASSERT(asObject(JSValue::decode(value))->inherits(info())); + return jsCast(asObject(JSValue::decode(value))); +} + template JSCallbackObject::JSCallbackObject(ExecState* exec, Structure* structure, JSClassRef jsClass, void* data) - : Parent(exec->globalData(), structure) + : Parent(exec->vm(), structure) , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass))) { } @@ -59,8 +66,8 @@ JSCallbackObject::JSCallbackObject(ExecState* exec, Structure* structure // Global object constructor. // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. template -JSCallbackObject::JSCallbackObject(JSGlobalData& globalData, JSClassRef jsClass, Structure* structure) - : Parent(globalData, structure) +JSCallbackObject::JSCallbackObject(VM& vm, JSClassRef jsClass, Structure* structure) + : Parent(vm, structure) , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass))) { } @@ -68,18 +75,18 @@ JSCallbackObject::JSCallbackObject(JSGlobalData& globalData, JSClassRef template void JSCallbackObject::finishCreation(ExecState* exec) { - Base::finishCreation(exec->globalData()); - ASSERT(Parent::inherits(&s_info)); + Base::finishCreation(exec->vm()); + ASSERT(Parent::inherits(info())); init(exec); } // This is just for Global object, so we can assume that Base::finishCreation is JSGlobalObject::finishCreation. template -void JSCallbackObject::finishCreation(JSGlobalData& globalData) +void JSCallbackObject::finishCreation(VM& vm) { - ASSERT(Parent::inherits(&s_info)); + ASSERT(Parent::inherits(info())); ASSERT(Parent::isGlobalObject()); - Base::finishCreation(globalData); + Base::finishCreation(vm); init(jsCast(this)->globalExec()); } @@ -111,10 +118,10 @@ void JSCallbackObject::init(ExecState* exec) } template -UString JSCallbackObject::className(const JSObject* object) +String JSCallbackObject::className(const JSObject* object) { const JSCallbackObject* thisObject = jsCast(object); - UString thisClassName = thisObject->classRef()->className(); + String thisClassName = thisObject->classRef()->className(); if (!thisClassName.isEmpty()) return thisClassName; @@ -122,64 +129,72 @@ UString JSCallbackObject::className(const JSObject* object) } template -bool JSCallbackObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot) +bool JSCallbackObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - JSCallbackObject* thisObject = jsCast(cell); + JSCallbackObject* thisObject = jsCast(object); JSContextRef ctx = toRef(exec); JSObjectRef thisRef = toRef(thisObject); RefPtr propertyNameRef; - for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { - // optional optimization to bypass getProperty in cases when we only need to know if the property exists - if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.ustring()); - APICallbackShim callbackShim(exec); - if (hasProperty(ctx, thisRef, propertyNameRef.get())) { - slot.setCustom(thisObject, callbackGetter); - return true; - } - } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.ustring()); - JSValueRef exception = 0; - JSValueRef value; - { + if (StringImpl* name = propertyName.publicName()) { + for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { + // optional optimization to bypass getProperty in cases when we only need to know if the property exists + if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { + if (!propertyNameRef) + propertyNameRef = OpaqueJSString::create(name); APICallbackShim callbackShim(exec); - value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); - } - if (exception) { - throwError(exec, toJS(exec, exception)); - slot.setValue(jsUndefined()); - return true; - } - if (value) { - slot.setValue(toJS(exec, value)); - return true; - } - } - - if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { - if (staticValues->contains(propertyName.impl())) { - JSValue value = thisObject->getStaticValue(exec, propertyName); + if (hasProperty(ctx, thisRef, propertyNameRef.get())) { + slot.setCustom(thisObject, ReadOnly | DontEnum, callbackGetter); + return true; + } + } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { + if (!propertyNameRef) + propertyNameRef = OpaqueJSString::create(name); + JSValueRef exception = 0; + JSValueRef value; + { + APICallbackShim callbackShim(exec); + value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); + } + if (exception) { + exec->vm().throwException(exec, toJS(exec, exception)); + slot.setValue(thisObject, ReadOnly | DontEnum, jsUndefined()); + return true; + } if (value) { - slot.setValue(value); + slot.setValue(thisObject, ReadOnly | DontEnum, toJS(exec, value)); return true; } } - } - - if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { - if (staticFunctions->contains(propertyName.impl())) { - slot.setCustom(thisObject, staticFunctionGetter); - return true; + + if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { + if (staticValues->contains(name)) { + JSValue value = thisObject->getStaticValue(exec, propertyName); + if (value) { + slot.setValue(thisObject, ReadOnly | DontEnum, value); + return true; + } + } + } + + if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { + if (staticFunctions->contains(name)) { + slot.setCustom(thisObject, ReadOnly | DontEnum, staticFunctionGetter); + return true; + } } } } - + return Parent::getOwnPropertySlot(thisObject, exec, propertyName, slot); } +template +bool JSCallbackObject::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + return object->methodTable()->getOwnPropertySlot(object, exec, Identifier::from(exec, propertyName), slot); +} + template JSValue JSCallbackObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint) { @@ -193,7 +208,7 @@ JSValue JSCallbackObject::defaultValue(const JSObject* object, ExecState JSValueRef exception = 0; JSValueRef result = convertToType(ctx, thisRef, jsHint, &exception); if (exception) { - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); return jsUndefined(); } if (result) @@ -205,38 +220,78 @@ JSValue JSCallbackObject::defaultValue(const JSObject* object, ExecState } template -bool JSCallbackObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +void JSCallbackObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { - JSCallbackObject* thisObject = jsCast(object); - PropertySlot slot; - if (thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot)) { - // Ideally we should return an access descriptor, but returning a value descriptor is better than nothing. - JSValue value = slot.getValue(exec, propertyName); - if (!exec->hadException()) - descriptor.setValue(value); - // We don't know whether the property is configurable, but assume it is. - descriptor.setConfigurable(true); - // We don't know whether the property is enumerable (we could call getOwnPropertyNames() to find out), but assume it isn't. - descriptor.setEnumerable(false); - return true; + JSCallbackObject* thisObject = jsCast(cell); + JSContextRef ctx = toRef(exec); + JSObjectRef thisRef = toRef(thisObject); + RefPtr propertyNameRef; + JSValueRef valueRef = toRef(exec, value); + + if (StringImpl* name = propertyName.publicName()) { + for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { + if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { + if (!propertyNameRef) + propertyNameRef = OpaqueJSString::create(name); + JSValueRef exception = 0; + bool result; + { + APICallbackShim callbackShim(exec); + result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); + } + if (exception) + exec->vm().throwException(exec, toJS(exec, exception)); + if (result || exception) + return; + } + + if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { + if (StaticValueEntry* entry = staticValues->get(name)) { + if (entry->attributes & kJSPropertyAttributeReadOnly) + return; + if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { + JSValueRef exception = 0; + bool result; + { + APICallbackShim callbackShim(exec); + result = setProperty(ctx, thisRef, entry->propertyNameRef.get(), valueRef, &exception); + } + if (exception) + exec->vm().throwException(exec, toJS(exec, exception)); + if (result || exception) + return; + } + } + } + + if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { + if (StaticFunctionEntry* entry = staticFunctions->get(name)) { + if (entry->attributes & kJSPropertyAttributeReadOnly) + return; + thisObject->JSCallbackObject::putDirect(exec->vm(), propertyName, value); // put as override property + return; + } + } + } } - return Parent::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); + return Parent::put(thisObject, exec, propertyName, value, slot); } template -void JSCallbackObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +void JSCallbackObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyIndex, JSValue value, bool shouldThrow) { JSCallbackObject* thisObject = jsCast(cell); JSContextRef ctx = toRef(exec); JSObjectRef thisRef = toRef(thisObject); RefPtr propertyNameRef; JSValueRef valueRef = toRef(exec, value); - + Identifier propertyName = Identifier::from(exec, propertyIndex); + for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.ustring()); + propertyNameRef = OpaqueJSString::create(propertyName.impl()); JSValueRef exception = 0; bool result; { @@ -244,86 +299,85 @@ void JSCallbackObject::put(JSCell* cell, ExecState* exec, const Identifi result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); } if (exception) - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); if (result || exception) return; } - + if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { if (entry->attributes & kJSPropertyAttributeReadOnly) return; if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.ustring()); JSValueRef exception = 0; bool result; { APICallbackShim callbackShim(exec); - result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); + result = setProperty(ctx, thisRef, entry->propertyNameRef.get(), valueRef, &exception); } if (exception) - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); if (result || exception) return; } } } - + if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { if (entry->attributes & kJSPropertyAttributeReadOnly) return; - thisObject->JSCallbackObject::putDirect(exec->globalData(), propertyName, value); // put as override property - return; + break; } } } - - return Parent::put(thisObject, exec, propertyName, value, slot); + + return Parent::putByIndex(thisObject, exec, propertyIndex, value, shouldThrow); } template -bool JSCallbackObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName) +bool JSCallbackObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) { JSCallbackObject* thisObject = jsCast(cell); JSContextRef ctx = toRef(exec); JSObjectRef thisRef = toRef(thisObject); RefPtr propertyNameRef; - for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { - if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.ustring()); - JSValueRef exception = 0; - bool result; - { - APICallbackShim callbackShim(exec); - result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); + if (StringImpl* name = propertyName.publicName()) { + for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { + if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { + if (!propertyNameRef) + propertyNameRef = OpaqueJSString::create(name); + JSValueRef exception = 0; + bool result; + { + APICallbackShim callbackShim(exec); + result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); + } + if (exception) + exec->vm().throwException(exec, toJS(exec, exception)); + if (result || exception) + return true; } - if (exception) - throwError(exec, toJS(exec, exception)); - if (result || exception) - return true; - } - - if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { - if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) { - if (entry->attributes & kJSPropertyAttributeDontDelete) - return false; - return true; + + if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { + if (StaticValueEntry* entry = staticValues->get(name)) { + if (entry->attributes & kJSPropertyAttributeDontDelete) + return false; + return true; + } } - } - - if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { - if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { - if (entry->attributes & kJSPropertyAttributeDontDelete) - return false; - return true; + + if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { + if (StaticFunctionEntry* entry = staticFunctions->get(name)) { + if (entry->attributes & kJSPropertyAttributeDontDelete) + return false; + return true; + } } } } - + return Parent::deleteProperty(thisObject, exec, propertyName); } @@ -356,10 +410,11 @@ EncodedJSValue JSCallbackObject::construct(ExecState* exec) for (JSClassRef jsClass = jsCast*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) { - int argumentCount = static_cast(exec->argumentCount()); - Vector arguments(argumentCount); - for (int i = 0; i < argumentCount; i++) - arguments[i] = toRef(exec, exec->argument(i)); + size_t argumentCount = exec->argumentCount(); + Vector arguments; + arguments.reserveInitialCapacity(argumentCount); + for (size_t i = 0; i < argumentCount; ++i) + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); JSValueRef exception = 0; JSObject* result; { @@ -367,17 +422,17 @@ EncodedJSValue JSCallbackObject::construct(ExecState* exec) result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); } if (exception) - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); return JSValue::encode(result); } } - ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here + RELEASE_ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here return JSValue::encode(JSValue()); } template -bool JSCallbackObject::hasInstance(JSObject* object, ExecState* exec, JSValue value, JSValue) +bool JSCallbackObject::customHasInstance(JSObject* object, ExecState* exec, JSValue value) { JSCallbackObject* thisObject = jsCast(object); JSContextRef execRef = toRef(exec); @@ -393,7 +448,7 @@ bool JSCallbackObject::hasInstance(JSObject* object, ExecState* exec, JS result = hasInstance(execRef, thisRef, valueRef, &exception); } if (exception) - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); return result; } } @@ -418,14 +473,15 @@ EncodedJSValue JSCallbackObject::call(ExecState* exec) { JSContextRef execRef = toRef(exec); JSObjectRef functionRef = toRef(exec->callee()); - JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec)); + JSObjectRef thisObjRef = toRef(jsCast(exec->hostThisValue().toThis(exec, NotStrictMode))); for (JSClassRef jsClass = jsCast*>(toJS(functionRef))->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { - int argumentCount = static_cast(exec->argumentCount()); - Vector arguments(argumentCount); - for (int i = 0; i < argumentCount; i++) - arguments[i] = toRef(exec, exec->argument(i)); + size_t argumentCount = exec->argumentCount(); + Vector arguments; + arguments.reserveInitialCapacity(argumentCount); + for (size_t i = 0; i < argumentCount; ++i) + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); JSValueRef exception = 0; JSValue result; { @@ -433,17 +489,17 @@ EncodedJSValue JSCallbackObject::call(ExecState* exec) result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); } if (exception) - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); return JSValue::encode(result); } } - ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here + RELEASE_ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here return JSValue::encode(JSValue()); } template -void JSCallbackObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +void JSCallbackObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { JSCallbackObject* thisObject = jsCast(object); JSContextRef execRef = toRef(exec); @@ -459,8 +515,8 @@ void JSCallbackObject::getOwnPropertyNames(JSObject* object, ExecState* typedef OpaqueJSClassStaticValuesTable::const_iterator iterator; iterator end = staticValues->end(); for (iterator it = staticValues->begin(); it != end; ++it) { - StringImpl* name = it->first.get(); - StaticValueEntry* entry = it->second.get(); + StringImpl* name = it->key.get(); + StaticValueEntry* entry = it->value.get(); if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) propertyNames.add(Identifier(exec, name)); } @@ -470,15 +526,15 @@ void JSCallbackObject::getOwnPropertyNames(JSObject* object, ExecState* typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator; iterator end = staticFunctions->end(); for (iterator it = staticFunctions->begin(); it != end; ++it) { - StringImpl* name = it->first.get(); - StaticFunctionEntry* entry = it->second.get(); + StringImpl* name = it->key.get(); + StaticFunctionEntry* entry = it->value.get(); if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) propertyNames.add(Identifier(exec, name)); } } } - Parent::getOwnPropertyNames(thisObject, exec, propertyNames, mode); + Parent::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); } template @@ -496,95 +552,102 @@ void* JSCallbackObject::getPrivate() template bool JSCallbackObject::inherits(JSClassRef c) const { - for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) + for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { if (jsClass == c) return true; - + } return false; } template -JSValue JSCallbackObject::getStaticValue(ExecState* exec, const Identifier& propertyName) +JSValue JSCallbackObject::getStaticValue(ExecState* exec, PropertyName propertyName) { JSObjectRef thisRef = toRef(this); - RefPtr propertyNameRef; - for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) - if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) - if (StaticValueEntry* entry = staticValues->get(propertyName.impl())) - if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.ustring()); - JSValueRef exception = 0; - JSValueRef value; - { - APICallbackShim callbackShim(exec); - value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); - } - if (exception) { - throwError(exec, toJS(exec, exception)); - return jsUndefined(); + if (StringImpl* name = propertyName.publicName()) { + for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { + if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { + if (StaticValueEntry* entry = staticValues->get(name)) { + if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { + JSValueRef exception = 0; + JSValueRef value; + { + APICallbackShim callbackShim(exec); + value = getProperty(toRef(exec), thisRef, entry->propertyNameRef.get(), &exception); + } + if (exception) { + exec->vm().throwException(exec, toJS(exec, exception)); + return jsUndefined(); + } + if (value) + return toJS(exec, value); } - if (value) - return toJS(exec, value); } + } + } + } return JSValue(); } template -JSValue JSCallbackObject::staticFunctionGetter(ExecState* exec, JSValue slotParent, const Identifier& propertyName) +EncodedJSValue JSCallbackObject::staticFunctionGetter(ExecState* exec, EncodedJSValue slotParent, EncodedJSValue, PropertyName propertyName) { JSCallbackObject* thisObj = asCallbackObject(slotParent); // Check for cached or override property. PropertySlot slot2(thisObj); if (Parent::getOwnPropertySlot(thisObj, exec, propertyName, slot2)) - return slot2.getValue(exec, propertyName); - - for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { - if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { - if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.impl())) { - if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { - - JSObject* o = JSCallbackFunction::create(exec, thisObj->globalObject(), callAsFunction, propertyName); - thisObj->putDirect(exec->globalData(), propertyName, o, entry->attributes); - return o; + return JSValue::encode(slot2.getValue(exec, propertyName)); + + if (StringImpl* name = propertyName.publicName()) { + for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { + if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { + if (StaticFunctionEntry* entry = staticFunctions->get(name)) { + if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { + VM& vm = exec->vm(); + JSObject* o = JSCallbackFunction::create(vm, thisObj->globalObject(), callAsFunction, name); + thisObj->putDirect(vm, propertyName, o, entry->attributes); + return JSValue::encode(o); + } } } } } - - return throwError(exec, createReferenceError(exec, "Static function property defined with NULL callAsFunction callback.")); + + return JSValue::encode(exec->vm().throwException(exec, createReferenceError(exec, ASCIILiteral("Static function property defined with NULL callAsFunction callback.")))); } template -JSValue JSCallbackObject::callbackGetter(ExecState* exec, JSValue slotParent, const Identifier& propertyName) +EncodedJSValue JSCallbackObject::callbackGetter(ExecState* exec, EncodedJSValue slotParent, EncodedJSValue, PropertyName propertyName) { JSCallbackObject* thisObj = asCallbackObject(slotParent); JSObjectRef thisRef = toRef(thisObj); RefPtr propertyNameRef; - for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) - if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.ustring()); - JSValueRef exception = 0; - JSValueRef value; - { - APICallbackShim callbackShim(exec); - value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); - } - if (exception) { - throwError(exec, toJS(exec, exception)); - return jsUndefined(); + if (StringImpl* name = propertyName.publicName()) { + for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { + if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { + if (!propertyNameRef) + propertyNameRef = OpaqueJSString::create(name); + JSValueRef exception = 0; + JSValueRef value; + { + APICallbackShim callbackShim(exec); + value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); + } + if (exception) { + exec->vm().throwException(exec, toJS(exec, exception)); + return JSValue::encode(jsUndefined()); + } + if (value) + return JSValue::encode(toJS(exec, value)); } - if (value) - return toJS(exec, value); } - - return throwError(exec, createReferenceError(exec, "hasProperty callback returned true for a property that doesn't exist.")); + } + + return JSValue::encode(exec->vm().throwException(exec, createReferenceError(exec, ASCIILiteral("hasProperty callback returned true for a property that doesn't exist.")))); } } // namespace JSC diff --git a/JavaScriptCore/API/JSClassRef.cpp b/JavaScriptCore/API/JSClassRef.cpp index 08fa5c5e..544c359b 100644 --- a/JavaScriptCore/API/JSClassRef.cpp +++ b/JavaScriptCore/API/JSClassRef.cpp @@ -27,12 +27,13 @@ #include "JSClassRef.h" #include "APICast.h" +#include "Identifier.h" +#include "InitializeThreading.h" #include "JSCallbackObject.h" +#include "JSGlobalObject.h" #include "JSObjectRef.h" -#include -#include -#include -#include +#include "ObjectPrototype.h" +#include "Operations.h" #include #include @@ -42,20 +43,6 @@ using namespace WTF::Unicode; const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static inline UString tryCreateStringFromUTF8(const char* string) -{ - if (!string) - return UString(); - - size_t length = strlen(string); - Vector buffer(length); - UChar* p = buffer.data(); - if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length)) - return UString(); - - return UString(buffer.data(), p - buffer.data()); -} - OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass) : parentClass(definition->parentClass) , prototypeClass(0) @@ -70,16 +57,16 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* , callAsConstructor(definition->callAsConstructor) , hasInstance(definition->hasInstance) , convertToType(definition->convertToType) - , m_className(tryCreateStringFromUTF8(definition->className)) + , m_className(String::fromUTF8(definition->className)) { initializeThreading(); if (const JSStaticValue* staticValue = definition->staticValues) { m_staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable); while (staticValue->name) { - UString valueName = tryCreateStringFromUTF8(staticValue->name); + String valueName = String::fromUTF8(staticValue->name); if (!valueName.isNull()) - m_staticValues->set(valueName.impl(), adoptPtr(new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes))); + m_staticValues->set(valueName.impl(), std::make_unique(staticValue->getProperty, staticValue->setProperty, staticValue->attributes, valueName)); ++staticValue; } } @@ -87,9 +74,9 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* if (const JSStaticFunction* staticFunction = definition->staticFunctions) { m_staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable); while (staticFunction->name) { - UString functionName = tryCreateStringFromUTF8(staticFunction->name); + String functionName = String::fromUTF8(staticFunction->name); if (!functionName.isNull()) - m_staticFunctions->set(functionName.impl(), adoptPtr(new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes))); + m_staticFunctions->set(functionName.impl(), std::make_unique(staticFunction->callAsFunction, staticFunction->attributes)); ++staticFunction; } } @@ -107,13 +94,13 @@ OpaqueJSClass::~OpaqueJSClass() if (m_staticValues) { OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end(); for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it) - ASSERT(!it->first->isIdentifier()); + ASSERT(!it->key->isIdentifier()); } if (m_staticFunctions) { OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end(); for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it) - ASSERT(!it->first->isIdentifier()); + ASSERT(!it->key->isIdentifier()); } #endif @@ -140,40 +127,41 @@ PassRefPtr OpaqueJSClass::create(const JSClassDefinition* clientD return adoptRef(new OpaqueJSClass(&definition, protoClass.get())); } -OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSClass* jsClass) +OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsClass) : m_class(jsClass) { if (jsClass->m_staticValues) { - staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable); + staticValues = std::make_unique(); OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end(); for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) { - ASSERT(!it->first->isIdentifier()); - staticValues->add(StringImpl::create(it->first->characters(), it->first->length()), adoptPtr(new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes))); + ASSERT(!it->key->isIdentifier()); + String valueName = it->key->isolatedCopy(); + staticValues->add(valueName.impl(), std::make_unique(it->value->getProperty, it->value->setProperty, it->value->attributes, valueName)); } } if (jsClass->m_staticFunctions) { - staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable); + staticFunctions = std::make_unique(); OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end(); for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) { - ASSERT(!it->first->isIdentifier()); - staticFunctions->add(StringImpl::create(it->first->characters(), it->first->length()), adoptPtr(new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes))); + ASSERT(!it->key->isIdentifier()); + staticFunctions->add(it->key->isolatedCopy(), std::make_unique(it->value->callAsFunction, it->value->attributes)); } } } OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec) { - OwnPtr& contextData = exec->globalData().opaqueJSClassData.add(this, nullptr).iterator->second; + std::unique_ptr& contextData = exec->lexicalGlobalObject()->opaqueJSClassData().add(this, nullptr).iterator->value; if (!contextData) - contextData = adoptPtr(new OpaqueJSClassContextData(exec->globalData(), this)); + contextData = std::make_unique(exec->vm(), this); return *contextData; } -UString OpaqueJSClass::className() +String OpaqueJSClass::className() { // Make a deep copy, so that the caller has no chance to put the original into IdentifierTable. - return UString(m_className.characters(), m_className.length()); + return m_className.isolatedCopy(); } OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec) @@ -209,13 +197,16 @@ JSObject* OpaqueJSClass::prototype(ExecState* exec) OpaqueJSClassContextData& jsClassData = contextData(exec); - if (!jsClassData.cachedPrototype) { - // Recursive, but should be good enough for our purposes - jsClassData.cachedPrototype = PassWeak(JSCallbackObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData), 0); // set jsClassData as the object's private data, so it can clear our reference on destruction - if (parentClass) { - if (JSObject* prototype = parentClass->prototype(exec)) - jsClassData.cachedPrototype->setPrototype(exec->globalData(), prototype); - } + if (JSObject* prototype = jsClassData.cachedPrototype.get()) + return prototype; + + // Recursive, but should be good enough for our purposes + JSObject* prototype = JSCallbackObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction + if (parentClass) { + if (JSObject* parentPrototype = parentClass->prototype(exec)) + prototype->setPrototype(exec->vm(), parentPrototype); } - return jsClassData.cachedPrototype.get(); + + jsClassData.cachedPrototype = Weak(prototype); + return prototype; } diff --git a/JavaScriptCore/API/JSClassRef.h b/JavaScriptCore/API/JSClassRef.h index 82c7ab3f..f979f3b2 100644 --- a/JavaScriptCore/API/JSClassRef.h +++ b/JavaScriptCore/API/JSClassRef.h @@ -26,25 +26,25 @@ #ifndef JSClassRef_h #define JSClassRef_h -#include "JSObjectRef.h" - -#include "Weak.h" -#include "JSObject.h" +#include "OpaqueJSString.h" #include "Protect.h" -#include "UString.h" +#include "Weak.h" +#include #include +#include struct StaticValueEntry { WTF_MAKE_FAST_ALLOCATED; public: - StaticValueEntry(JSObjectGetPropertyCallback _getProperty, JSObjectSetPropertyCallback _setProperty, JSPropertyAttributes _attributes) - : getProperty(_getProperty), setProperty(_setProperty), attributes(_attributes) + StaticValueEntry(JSObjectGetPropertyCallback _getProperty, JSObjectSetPropertyCallback _setProperty, JSPropertyAttributes _attributes, String& propertyName) + : getProperty(_getProperty), setProperty(_setProperty), attributes(_attributes), propertyNameRef(OpaqueJSString::create(propertyName)) { } JSObjectGetPropertyCallback getProperty; JSObjectSetPropertyCallback setProperty; JSPropertyAttributes attributes; + RefPtr propertyNameRef; }; struct StaticFunctionEntry { @@ -59,8 +59,8 @@ struct StaticFunctionEntry { JSPropertyAttributes attributes; }; -typedef HashMap, OwnPtr > OpaqueJSClassStaticValuesTable; -typedef HashMap, OwnPtr > OpaqueJSClassStaticFunctionsTable; +typedef HashMap, std::unique_ptr> OpaqueJSClassStaticValuesTable; +typedef HashMap, std::unique_ptr> OpaqueJSClassStaticFunctionsTable; struct OpaqueJSClass; @@ -69,27 +69,27 @@ struct OpaqueJSClass; struct OpaqueJSClassContextData { WTF_MAKE_NONCOPYABLE(OpaqueJSClassContextData); WTF_MAKE_FAST_ALLOCATED; public: - OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSClass*); + OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass*); // It is necessary to keep OpaqueJSClass alive because of the following rare scenario: - // 1. A class is created and used, so its context data is stored in JSGlobalData hash map. + // 1. A class is created and used, so its context data is stored in VM hash map. // 2. The class is released, and when all JS objects that use it are collected, OpaqueJSClass // is deleted (that's the part prevented by this RefPtr). // 3. Another class is created at the same address. - // 4. When it is used, the old context data is found in JSGlobalData and used. + // 4. When it is used, the old context data is found in VM and used. RefPtr m_class; - OwnPtr staticValues; - OwnPtr staticFunctions; + std::unique_ptr staticValues; + std::unique_ptr staticFunctions; JSC::Weak cachedPrototype; }; struct OpaqueJSClass : public ThreadSafeRefCounted { static PassRefPtr create(const JSClassDefinition*); static PassRefPtr createNoAutomaticPrototype(const JSClassDefinition*); - ~OpaqueJSClass(); + JS_EXPORT_PRIVATE ~OpaqueJSClass(); - JSC::UString className(); + String className(); OpaqueJSClassStaticValuesTable* staticValues(JSC::ExecState*); OpaqueJSClassStaticFunctionsTable* staticFunctions(JSC::ExecState*); JSC::JSObject* prototype(JSC::ExecState*); @@ -118,8 +118,8 @@ struct OpaqueJSClass : public ThreadSafeRefCounted { OpaqueJSClassContextData& contextData(JSC::ExecState*); - // UStrings in these data members should not be put into any IdentifierTable. - JSC::UString m_className; + // Strings in these data members should not be put into any IdentifierTable. + String m_className; OwnPtr m_staticValues; OwnPtr m_staticFunctions; }; diff --git a/JavaScriptCore/API/JSContext.h b/JavaScriptCore/API/JSContext.h new file mode 100644 index 00000000..6f780977 --- /dev/null +++ b/JavaScriptCore/API/JSContext.h @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2013 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 JSContext_h +#define JSContext_h + +#include + +#if JSC_OBJC_API_ENABLED + +@class JSVirtualMachine, JSValue; + +/*! +@interface +@discussion An instance of JSContext represents a JavaScript execution environment. All + JavaScript execution takes place within a context. + JSContext is also used to manage the life-cycle of objects within the + JavaScript virtual machine. Every instance of JSValue is associated with a + JSContext via a strong reference. The JSValue will keep the JSContext it + references alive so long as the JSValue remains alive. When all of the JSValues + that reference a particular JSContext have been deallocated the JSContext + will be deallocated unless it has been previously retained. +*/ +#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 +NS_CLASS_AVAILABLE(10_9, 7_0) +#else +OBJC_VISIBLE +#endif +@interface JSContext : NSObject + +/*! +@methodgroup Creating New JSContexts +*/ +/*! +@method +@abstract Create a JSContext. +@result The new context. +*/ +- (instancetype)init; + +/*! +@method +@abstract Create a JSContext in the specified virtual machine. +@param virtualMachine The JSVirtualMachine in which the context will be created. +@result The new context. +*/ +- (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine; + +/*! +@methodgroup Evaluating Scripts +*/ +/*! +@method +@abstract Evaluate a string of JavaScript code. +@param script A string containing the JavaScript code to evaluate. +@result The last value generated by the script. +*/ +- (JSValue *)evaluateScript:(NSString *)script; + +/*! +@methodgroup Callback Accessors +*/ +/*! +@method +@abstract Get the JSContext that is currently executing. +@discussion This method may be called from within an Objective-C block or method invoked + as a callback from JavaScript to retrieve the callback's context. Outside of + a callback from JavaScript this method will return nil. +@result The currently executing JSContext or nil if there isn't one. +*/ ++ (JSContext *)currentContext; + +/*! +@method +@abstract Get the this value of the currently executing method. +@discussion This method may be called from within an Objective-C block or method invoked + as a callback from JavaScript to retrieve the callback's this value. Outside + of a callback from JavaScript this method will return nil. +@result The current this value or nil if there isn't one. +*/ ++ (JSValue *)currentThis; + +/*! +@method +@abstract Get the arguments to the current callback. +@discussion This method may be called from within an Objective-C block or method invoked + as a callback from JavaScript to retrieve the callback's arguments, objects + in the returned array are instances of JSValue. Outside of a callback from + JavaScript this method will return nil. +@result An NSArray of the arguments nil if there is no current callback. +*/ ++ (NSArray *)currentArguments; + +/*! +@methodgroup Global Properties +*/ +/*! +@property +@abstract Get the global object of the context. +@discussion This method retrieves the global object of the JavaScript execution context. + Instances of JSContext originating from WebKit will return a reference to the + WindowProxy object. +@result The global object. +*/ +@property (readonly, strong) JSValue *globalObject; + +/*! +@property +@discussion The exception property may be used to throw an exception to JavaScript. + + Before a callback is made from JavaScript to an Objective-C block or method, + the prior value of the exception property will be preserved and the property + will be set to nil. After the callback has completed the new value of the + exception property will be read, and prior value restored. If the new value + of exception is not nil, the callback will result in that value being thrown. + + This property may also be used to check for uncaught exceptions arising from + API function calls (since the default behaviour of exceptionHandler is to + assign an uncaught exception to this property). + + If a JSValue originating from a different JSVirtualMachine than this context + is assigned to this property, an Objective-C exception will be raised. +*/ +@property (strong) JSValue *exception; + +/*! +@property +@discussion If a call to an API function results in an uncaught JavaScript exception, the + exceptionHandler block will be invoked. The default implementation for the + exception handler will store the exception to the exception property on + context. As a consequence the default behaviour is for unhandled exceptions + occurring within a callback from JavaScript to be rethrown upon return. + Setting this value to nil will result in all uncaught exceptions thrown from + the API being silently consumed. +*/ +@property (copy) void(^exceptionHandler)(JSContext *context, JSValue *exception); + +/*! +@property +@discussion All instances of JSContext are associated with a single JSVirtualMachine. The + virtual machine provides an "object space" or set of execution resources. +*/ +@property (readonly, strong) JSVirtualMachine *virtualMachine; + +/*! +@property +@discussion Name of the JSContext. Exposed when remote debugging the context. +*/ +@property (copy) NSString *name; + +@end + +/*! +@category +@discussion Instances of JSContext implement the following methods in order to enable + support for subscript access by key and index, for example: + +@textblock + JSContext *context; + JSValue *v = context[@"X"]; // Get value for "X" from the global object. + context[@"Y"] = v; // Assign 'v' to "Y" on the global object. +@/textblock + + An object key passed as a subscript will be converted to a JavaScript value, + and then the value converted to a string used to resolve a property of the + global object. +*/ +@interface JSContext (SubscriptSupport) + +/*! +method +@abstract Get a particular property on the global object. +@param key +@result The JSValue for the global object's property. +*/ +- (JSValue *)objectForKeyedSubscript:(id)key; + +/*! +method +@abstract Set a particular property on the global object. +@param object +@param key +*/ +- (void)setObject:(id)object forKeyedSubscript:(NSObject *)key; + +@end + +/*! +@category +@discussion These functions are for bridging between the C API and the Objective-C API. +*/ +@interface JSContext (JSContextRefSupport) + +/*! +@method +@abstract Create a JSContext, wrapping its C API counterpart. +@param jsGlobalContextRef +@result The JSContext equivalent of the provided JSGlobalContextRef. +*/ ++ (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)jsGlobalContextRef; + +/*! +@property +@abstract Get the C API counterpart wrapped by a JSContext. +@result The C API equivalent of this JSContext. +*/ +@property (readonly) JSGlobalContextRef JSGlobalContextRef; +@end + +#endif + +#endif // JSContext_h diff --git a/JavaScriptCore/API/JSContext.mm b/JavaScriptCore/API/JSContext.mm new file mode 100644 index 00000000..cdce9662 --- /dev/null +++ b/JavaScriptCore/API/JSContext.mm @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2013 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" + +#import "APICast.h" +#import "APIShims.h" +#import "JSContextInternal.h" +#import "JSGlobalObject.h" +#import "JSValueInternal.h" +#import "JSVirtualMachineInternal.h" +#import "JSWrapperMap.h" +#import "JavaScriptCore.h" +#import "ObjcRuntimeExtras.h" +#import "Operations.h" +#import "StrongInlines.h" +#import + +#if JSC_OBJC_API_ENABLED + +@implementation JSContext { + JSVirtualMachine *m_virtualMachine; + JSGlobalContextRef m_context; + JSWrapperMap *m_wrapperMap; + JSC::Strong m_exception; +} + +@synthesize exceptionHandler; + +- (JSGlobalContextRef)JSGlobalContextRef +{ + return m_context; +} + +- (instancetype)init +{ + return [self initWithVirtualMachine:[[[JSVirtualMachine alloc] init] autorelease]]; +} + +- (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine +{ + self = [super init]; + if (!self) + return nil; + + m_virtualMachine = [virtualMachine retain]; + m_context = JSGlobalContextCreateInGroup(getGroupFromVirtualMachine(virtualMachine), 0); + m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self]; + + self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { + context.exception = exceptionValue; + }; + + [m_virtualMachine addContext:self forGlobalContextRef:m_context]; + + return self; +} + +- (void)dealloc +{ + [m_wrapperMap release]; + JSGlobalContextRelease(m_context); + [m_virtualMachine release]; + [self.exceptionHandler release]; + [super dealloc]; +} + +- (JSValue *)evaluateScript:(NSString *)script +{ + JSValueRef exceptionValue = 0; + JSStringRef scriptJS = JSStringCreateWithCFString((CFStringRef)script); + JSValueRef result = JSEvaluateScript(m_context, scriptJS, 0, 0, 0, &exceptionValue); + JSStringRelease(scriptJS); + + if (exceptionValue) + return [self valueFromNotifyException:exceptionValue]; + + return [JSValue valueWithJSValueRef:result inContext:self]; +} + +- (void)setException:(JSValue *)value +{ + if (value) + m_exception.set(toJS(m_context)->vm(), toJS(JSValueToObject(m_context, valueInternalValue(value), 0))); + else + m_exception.clear(); +} + +- (JSValue *)exception +{ + if (!m_exception) + return nil; + return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self]; +} + +- (JSWrapperMap *)wrapperMap +{ + return m_wrapperMap; +} + +- (JSValue *)globalObject +{ + return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self]; +} + ++ (JSContext *)currentContext +{ + WTFThreadData& threadData = wtfThreadData(); + CallbackData *entry = (CallbackData *)threadData.m_apiData; + return entry ? entry->context : nil; +} + ++ (JSValue *)currentThis +{ + WTFThreadData& threadData = wtfThreadData(); + CallbackData *entry = (CallbackData *)threadData.m_apiData; + if (!entry) + return nil; + return [JSValue valueWithJSValueRef:entry->thisValue inContext:[JSContext currentContext]]; +} + ++ (NSArray *)currentArguments +{ + WTFThreadData& threadData = wtfThreadData(); + CallbackData *entry = (CallbackData *)threadData.m_apiData; + + if (!entry) + return nil; + + if (!entry->currentArguments) { + JSContext *context = [JSContext currentContext]; + size_t count = entry->argumentCount; + JSValue * argumentArray[count]; + for (size_t i =0; i < count; ++i) + argumentArray[i] = [JSValue valueWithJSValueRef:entry->arguments[i] inContext:context]; + entry->currentArguments = [[NSArray alloc] initWithObjects:argumentArray count:count]; + } + + return entry->currentArguments; +} + +- (JSVirtualMachine *)virtualMachine +{ + return m_virtualMachine; +} + +- (NSString *)name +{ + JSStringRef name = JSGlobalContextCopyName(m_context); + if (!name) + return nil; + + return [(NSString *)JSStringCopyCFString(kCFAllocatorDefault, name) autorelease]; +} + +- (void)setName:(NSString *)name +{ + JSStringRef nameJS = JSStringCreateWithCFString((CFStringRef)[name copy]); + JSGlobalContextSetName(m_context, nameJS); + JSStringRelease(nameJS); +} + +@end + +@implementation JSContext(SubscriptSupport) + +- (JSValue *)objectForKeyedSubscript:(id)key +{ + return [self globalObject][key]; +} + +- (void)setObject:(id)object forKeyedSubscript:(NSObject *)key +{ + [self globalObject][key] = object; +} + +@end + +@implementation JSContext (Internal) + +- (instancetype)initWithGlobalContextRef:(JSGlobalContextRef)context +{ + self = [super init]; + if (!self) + return nil; + + JSC::JSGlobalObject* globalObject = toJS(context)->lexicalGlobalObject(); + m_virtualMachine = [[JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&globalObject->vm())] retain]; + ASSERT(m_virtualMachine); + m_context = JSGlobalContextRetain(context); + m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self]; + + self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { + context.exception = exceptionValue; + }; + + [m_virtualMachine addContext:self forGlobalContextRef:m_context]; + + return self; +} + +- (void)notifyException:(JSValueRef)exceptionValue +{ + self.exceptionHandler(self, [JSValue valueWithJSValueRef:exceptionValue inContext:self]); +} + +- (JSValue *)valueFromNotifyException:(JSValueRef)exceptionValue +{ + [self notifyException:exceptionValue]; + return [JSValue valueWithUndefinedInContext:self]; +} + +- (BOOL)boolFromNotifyException:(JSValueRef)exceptionValue +{ + [self notifyException:exceptionValue]; + return NO; +} + +- (void)beginCallbackWithData:(CallbackData *)callbackData thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments +{ + WTFThreadData& threadData = wtfThreadData(); + [self retain]; + CallbackData *prevStack = (CallbackData *)threadData.m_apiData; + *callbackData = (CallbackData){ prevStack, self, [self.exception retain], thisValue, argumentCount, arguments, nil }; + threadData.m_apiData = callbackData; + self.exception = nil; +} + +- (void)endCallbackWithData:(CallbackData *)callbackData +{ + WTFThreadData& threadData = wtfThreadData(); + self.exception = callbackData->preservedException; + [callbackData->preservedException release]; + [callbackData->currentArguments release]; + threadData.m_apiData = callbackData->next; + [self release]; +} + +- (JSValue *)wrapperForObjCObject:(id)object +{ + // Lock access to m_wrapperMap + JSC::JSLockHolder lock(toJS(m_context)); + return [m_wrapperMap jsWrapperForObject:object]; +} + +- (JSValue *)wrapperForJSObject:(JSValueRef)value +{ + JSC::JSLockHolder lock(toJS(m_context)); + return [m_wrapperMap objcWrapperForJSValueRef:value]; +} + ++ (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)globalContext +{ + JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->vm())]; + JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext]; + if (!context) + context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease]; + return context; +} + +@end + +WeakContextRef::WeakContextRef(JSContext *context) +{ + objc_initWeak(&m_weakContext, context); +} + +WeakContextRef::~WeakContextRef() +{ + objc_destroyWeak(&m_weakContext); +} + +JSContext * WeakContextRef::get() +{ + return objc_loadWeak(&m_weakContext); +} + +void WeakContextRef::set(JSContext *context) +{ + objc_storeWeak(&m_weakContext, context); +} + +#endif diff --git a/JavaScriptCore/API/JSContextInternal.h b/JavaScriptCore/API/JSContextInternal.h new file mode 100644 index 00000000..d7300f54 --- /dev/null +++ b/JavaScriptCore/API/JSContextInternal.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 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 JSContextInternal_h +#define JSContextInternal_h + +#import + +#if JSC_OBJC_API_ENABLED + +#import + +struct CallbackData { + CallbackData *next; + JSContext *context; + JSValue *preservedException; + JSValueRef thisValue; + size_t argumentCount; + const JSValueRef *arguments; + NSArray *currentArguments; +}; + +class WeakContextRef { +public: + WeakContextRef(JSContext * = nil); + ~WeakContextRef(); + + JSContext * get(); + void set(JSContext *); + +private: + JSContext *m_weakContext; +}; + +@class JSWrapperMap; + +@interface JSContext(Internal) + +- (id)initWithGlobalContextRef:(JSGlobalContextRef)context; + +- (void)notifyException:(JSValueRef)exception; +- (JSValue *)valueFromNotifyException:(JSValueRef)exception; +- (BOOL)boolFromNotifyException:(JSValueRef)exception; + +- (void)beginCallbackWithData:(CallbackData *)callbackData thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments; +- (void)endCallbackWithData:(CallbackData *)callbackData; + +- (JSValue *)wrapperForObjCObject:(id)object; +- (JSValue *)wrapperForJSObject:(JSValueRef)value; + +@property (readonly, retain) JSWrapperMap *wrapperMap; + +@end + +#endif + +#endif // JSContextInternal_h diff --git a/JavaScriptCore/API/JSContextRef.cpp b/JavaScriptCore/API/JSContextRef.cpp index 7a57287d..81b61cf4 100644 --- a/JavaScriptCore/API/JSContextRef.cpp +++ b/JavaScriptCore/API/JSContextRef.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2013 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,14 +28,17 @@ #include "JSContextRefPrivate.h" #include "APICast.h" +#include "CallFrame.h" +#include "CallFrameInlines.h" #include "InitializeThreading.h" -#include -#include #include "JSCallbackObject.h" #include "JSClassRef.h" #include "JSGlobalObject.h" #include "JSObject.h" -#include "UStringBuilder.h" +#include "Operations.h" +#include "SourceProvider.h" +#include "StackVisitor.h" +#include #include #if OS(DARWIN) @@ -54,7 +57,7 @@ using namespace JSC; JSContextGroupRef JSContextGroupCreate() { initializeThreading(); - return toRef(JSGlobalData::createContextGroup(ThreadStackTypeSmall).leakRef()); + return toRef(VM::createContextGroup().leakRef()); } JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) @@ -65,7 +68,44 @@ JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) void JSContextGroupRelease(JSContextGroupRef group) { - toJS(group)->deref(); + IdentifierTable* savedIdentifierTable; + VM& vm = *toJS(group); + + { + JSLockHolder lock(vm); + savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable); + vm.deref(); + } + + wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable); +} + +static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData) +{ + JSShouldTerminateCallback callback = reinterpret_cast(callbackPtr); + JSContextRef contextRef = toRef(exec); + ASSERT(callback); + return callback(contextRef, callbackData); +} + +void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData) +{ + VM& vm = *toJS(group); + APIEntryShim entryShim(&vm); + Watchdog& watchdog = vm.watchdog; + if (callback) { + void* callbackPtr = reinterpret_cast(callback); + watchdog.setTimeLimit(vm, limit, internalScriptTimeoutCallback, callbackPtr, callbackData); + } else + watchdog.setTimeLimit(vm, limit); +} + +void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) +{ + VM& vm = *toJS(group); + APIEntryShim entryShim(&vm); + Watchdog& watchdog = vm.watchdog; + watchdog.setTimeLimit(vm, std::numeric_limits::infinity()); } // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained. @@ -75,10 +115,10 @@ JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) initializeThreading(); #if OS(DARWIN) - // If the application was linked before JSGlobalContextCreate was changed to use a unique JSGlobalData, + // If the application was linked before JSGlobalContextCreate was changed to use a unique VM, // we use a shared one for backwards compatibility. if (NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitFirstVersionWithConcurrentGlobalContexts) { - return JSGlobalContextCreateInGroup(toRef(&JSGlobalData::sharedInstance()), globalObjectClass); + return JSGlobalContextCreateInGroup(toRef(&VM::sharedInstance()), globalObjectClass); } #endif // OS(DARWIN) @@ -89,22 +129,23 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass { initializeThreading(); - RefPtr globalData = group ? PassRefPtr(toJS(group)) : JSGlobalData::createContextGroup(ThreadStackTypeSmall); + RefPtr vm = group ? PassRefPtr(toJS(group)) : VM::createContextGroup(); - APIEntryShim entryShim(globalData.get(), false); - globalData->makeUsableFromMultipleThreads(); + APIEntryShim entryShim(vm.get(), false); + vm->makeUsableFromMultipleThreads(); if (!globalObjectClass) { - JSGlobalObject* globalObject = JSGlobalObject::create(*globalData, JSGlobalObject::createStructure(*globalData, jsNull())); + JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull())); + globalObject->setGlobalThis(*vm, JSProxy::create(*vm, JSProxy::createStructure(*vm, globalObject, globalObject->prototype()), globalObject)); return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec())); } - JSGlobalObject* globalObject = JSCallbackObject::create(*globalData, globalObjectClass, JSCallbackObject::createStructure(*globalData, 0, jsNull())); + JSGlobalObject* globalObject = JSCallbackObject::create(*vm, globalObjectClass, JSCallbackObject::createStructure(*vm, 0, jsNull())); ExecState* exec = globalObject->globalExec(); JSValue prototype = globalObjectClass->prototype(exec); if (!prototype) prototype = jsNull(); - globalObject->resetPrototype(*globalData, prototype); + globalObject->resetPrototype(*vm, prototype); return JSGlobalContextRetain(toGlobalRef(exec)); } @@ -113,9 +154,9 @@ JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx) ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - JSGlobalData& globalData = exec->globalData(); - gcProtect(exec->dynamicGlobalObject()); - globalData.ref(); + VM& vm = exec->vm(); + gcProtect(exec->vmEntryGlobalObject()); + vm.ref(); return ctx; } @@ -126,13 +167,13 @@ void JSGlobalContextRelease(JSGlobalContextRef ctx) { JSLockHolder lock(exec); - JSGlobalData& globalData = exec->globalData(); - savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(globalData.identifierTable); + VM& vm = exec->vm(); + savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable); - bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject()); + bool protectCountIsZero = Heap::heap(exec->vmEntryGlobalObject())->unprotect(exec->vmEntryGlobalObject()); if (protectCountIsZero) - globalData.heap.reportAbandonedObjectGraph(); - globalData.deref(); + vm.heap.reportAbandonedObjectGraph(); + vm.deref(); } wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable); @@ -140,80 +181,133 @@ void JSGlobalContextRelease(JSGlobalContextRef ctx) JSObjectRef JSContextGetGlobalObject(JSContextRef ctx) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - // It is necessary to call toThisObject to get the wrapper object when used with WebCore. - return toRef(exec->lexicalGlobalObject()->methodTable()->toThisObject(exec->lexicalGlobalObject(), exec)); + return toRef(jsCast(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode))); } JSContextGroupRef JSContextGetGroup(JSContextRef ctx) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); - return toRef(&exec->globalData()); + return toRef(&exec->vm()); } JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); return toGlobalRef(exec->lexicalGlobalObject()->globalExec()); } - -JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) + +JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + ExecState* exec = toJS(ctx); - JSLockHolder lock(exec); + APIEntryShim entryShim(exec); - unsigned count = 0; - UStringBuilder builder; - CallFrame* callFrame = exec; - UString functionName; - if (exec->callee()) { - if (asObject(exec->callee())->inherits(&InternalFunction::s_info)) { - functionName = asInternalFunction(exec->callee())->name(exec); - builder.append("#0 "); - builder.append(functionName); - builder.append("() "); - count++; - } + String name = exec->vmEntryGlobalObject()->name(); + if (name.isNull()) + return 0; + + return OpaqueJSString::create(name).leakRef(); +} + +void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } + + ExecState* exec = toJS(ctx); + APIEntryShim entryShim(exec); + + exec->vmEntryGlobalObject()->setName(name ? name->string() : String()); +} + + +class BacktraceFunctor { +public: + BacktraceFunctor(StringBuilder& builder, unsigned remainingCapacityForFrameCapture) + : m_builder(builder) + , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture) + { } - while (true) { - ASSERT(callFrame); - int signedLineNumber; - intptr_t sourceID; - UString urlString; - JSValue function; - - UString levelStr = UString::number(count); - - exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function); - - if (function) - functionName = jsCast(function)->name(exec); - else { - // Caller is unknown, but if frame is empty we should still add the frame, because - // something called us, and gave us arguments. - if (count) - break; + + StackVisitor::Status operator()(StackVisitor& visitor) + { + if (m_remainingCapacityForFrameCapture) { + // If callee is unknown, but we've not added any frame yet, we should + // still add the frame, because something called us, and gave us arguments. + JSObject* callee = visitor->callee(); + if (!callee && visitor->index()) + return StackVisitor::Done; + + StringBuilder& builder = m_builder; + if (!builder.isEmpty()) + builder.append('\n'); + builder.append('#'); + builder.appendNumber(visitor->index()); + builder.append(' '); + builder.append(visitor->functionName()); + builder.appendLiteral("() at "); + builder.append(visitor->sourceURL()); + if (visitor->isJSFrame()) { + builder.append(':'); + unsigned lineNumber; + unsigned unusedColumn; + visitor->computeLineAndColumn(lineNumber, unusedColumn); + builder.appendNumber(lineNumber); + } + + if (!callee) + return StackVisitor::Done; + + m_remainingCapacityForFrameCapture--; + return StackVisitor::Continue; } - unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0; - if (!builder.isEmpty()) - builder.append("\n"); - builder.append("#"); - builder.append(levelStr); - builder.append(" "); - builder.append(functionName); - builder.append("() at "); - builder.append(urlString); - builder.append(":"); - builder.append(UString::number(lineNumber)); - if (!function || ++count == maxStackSize) - break; - callFrame = callFrame->callerFrame(); + return StackVisitor::Done; + } + +private: + StringBuilder& m_builder; + unsigned m_remainingCapacityForFrameCapture; +}; + +JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; } - return OpaqueJSString::create(builder.toUString()).leakRef(); + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + StringBuilder builder; + CallFrame* frame = exec->vm().topCallFrame; + + ASSERT(maxStackSize); + BacktraceFunctor functor(builder, maxStackSize); + frame->iterate(functor); + + return OpaqueJSString::create(builder.toString()).leakRef(); } diff --git a/JavaScriptCore/API/JSContextRef.h b/JavaScriptCore/API/JSContextRef.h index c5c8a71e..c8db1e56 100644 --- a/JavaScriptCore/API/JSContextRef.h +++ b/JavaScriptCore/API/JSContextRef.h @@ -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. */ #ifndef JSContextRef_h @@ -48,7 +48,7 @@ extern "C" { synchronization is required. @result The created JSContextGroup. */ -JS_EXPORT JSContextGroupRef JSContextGroupCreate() AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSContextGroupRef JSContextGroupCreate() CF_AVAILABLE(10_6, 7_0); /*! @function @@ -56,14 +56,14 @@ JS_EXPORT JSContextGroupRef JSContextGroupCreate() AVAILABLE_IN_WEBKIT_VERSION_4 @param group The JSContextGroup to retain. @result A JSContextGroup that is the same as group. */ -JS_EXPORT JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0); /*! @function @abstract Releases a JavaScript context group. @param group The JSContextGroup to release. */ -JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0); /*! @function @@ -78,7 +78,7 @@ JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) AVAILABLE_IN_WEBKI NULL to use the default object class. @result A JSGlobalContext with a global object of class globalObjectClass. */ -JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER; +JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) CF_AVAILABLE(10_5, 7_0); /*! @function @@ -92,7 +92,7 @@ JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) @result A JSGlobalContext with a global object of class globalObjectClass and a context group equal to group. */ -JS_EXPORT JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) CF_AVAILABLE(10_6, 7_0); /*! @function @@ -123,7 +123,33 @@ JS_EXPORT JSObjectRef JSContextGetGlobalObject(JSContextRef ctx); @param ctx The JSContext whose group you want to get. @result ctx's group. */ -JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) CF_AVAILABLE(10_6, 7_0); + +/*! +@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) CF_AVAILABLE(10_7, 7_0); + +/*! +@function +@abstract Gets a copy of the name of a context. +@param ctx The JSGlobalContext whose name you want to get. +@result The name for ctx. +@discussion A JSGlobalContext's name is exposed for remote debugging to make it +easier to identify the context you would like to attach to. +*/ +JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx); + +/*! +@function +@abstract Sets the remote debugging name for a context. +@param ctx The JSGlobalContext that you want to name. +@param name The remote debugging name to set on ctx. +*/ +JS_EXPORT void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name); #ifdef __cplusplus } diff --git a/JavaScriptCore/API/JSContextRefPrivate.h b/JavaScriptCore/API/JSContextRefPrivate.h index 4f77aead..780a6030 100644 --- a/JavaScriptCore/API/JSContextRefPrivate.h +++ b/JavaScriptCore/API/JSContextRefPrivate.h @@ -38,23 +38,62 @@ 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); - - /*! @function @abstract Gets a Backtrace for the existing context @param ctx The JSContext whose backtrace you want to get @result A string containing the backtrace */ -JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) CF_AVAILABLE(10_6, 7_0); + +/*! +@typedef JSShouldTerminateCallback +@abstract The callback invoked when script execution has exceeded the allowed + time limit previously specified via JSContextGroupSetExecutionTimeLimit. +@param ctx The execution context to use. +@param context User specified context data previously passed to + JSContextGroupSetExecutionTimeLimit. +@discussion If you named your function Callback, you would declare it like this: + + bool Callback(JSContextRef ctx, void* context); + + If you return true, the timed out script will terminate. + If you return false, the script will run for another period of the allowed + time limit specified via JSContextGroupSetExecutionTimeLimit. + + Within this callback function, you may call JSContextGroupSetExecutionTimeLimit + to set a new time limit, or JSContextGroupClearExecutionTimeLimit to cancel the + timeout. +*/ +typedef bool +(*JSShouldTerminateCallback) (JSContextRef ctx, void* context); + +/*! +@function +@abstract Sets the script execution time limit. +@param group The JavaScript context group that this time limit applies to. +@param limit The time limit of allowed script execution time in seconds. +@param callback The callback function that will be invoked when the time limit + has been reached. This will give you a chance to decide if you want to + terminate the script or not. If you pass a NULL callback, the script will be + terminated unconditionally when the time limit has been reached. +@param context User data that you can provide to be passed back to you + in your callback. + + In order to guarantee that the execution time limit will take effect, you will + need to call JSContextGroupSetExecutionTimeLimit before you start executing + any scripts. +*/ +JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef, double limit, JSShouldTerminateCallback, void* context) CF_AVAILABLE(10_6, 7_0); + +/*! +@function +@abstract Clears the script execution time limit. +@param group The JavaScript context group that the time limit is cleared on. +*/ +JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef) CF_AVAILABLE(10_6, 7_0); + #ifdef __cplusplus } #endif diff --git a/JavaScriptCore/API/JSExport.h b/JavaScriptCore/API/JSExport.h new file mode 100644 index 00000000..2d78dcc7 --- /dev/null +++ b/JavaScriptCore/API/JSExport.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2013 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. + */ + +#import + +#if JSC_OBJC_API_ENABLED + +/*! +@protocol +@abstract JSExport provides a declarative way to export Objective-C instance methods, + class methods, and properties to JavaScript code. + +@discussion When a JavaScript value is created from an instance of an Objective-C class + for which no copying conversion is specified a JavaScript wrapper object will + be created. + + In JavaScript, inheritance is supported via a chain of prototype objects, and + for each Objective-C class (and per JSContext) an object appropriate for use + as a prototype will be provided. For the class NSObject the prototype object + will be the JavaScript context's Object Prototype. For all other Objective-C + classes a Prototype object will be created. The Prototype object for a given + Objective-C class will have its internal [Prototype] property set to point to + the Prototype object of the Objective-C class's superclass. As such the + prototype chain for a JavaScript wrapper object will reflect the wrapped + Objective-C type's inheritance hierarchy. + + In addition to the Prototype object a JavaScript Constructor object will also + be produced for each Objective-C class. The Constructor object has a property + named 'prototype' that references the Prototype object, and the Prototype + object has a property named 'constructor' that references the Constructor. + The Constructor object is not callable. + + By default no methods or properties of the Objective-C class will be exposed + to JavaScript; however methods and properties may explicitly be exported. + For each protocol that a class conforms to, if the protocol incorporates the + protocol JSExport, then the protocol will be interpreted as a list of methods + and properties to be exported to JavaScript. + + For each instance method being exported a corresponding JavaScript function + will be assigned as a property of the Prototype object. For each Objective-C + property being exported a JavaScript accessor property will be created on the + Prototype. For each class method exported a JavaScript function will be + created on the Constructor object. For example: + +
+@textblock
+    @protocol MyClassJavaScriptMethods 
+    - (void)foo;
+    @end
+
+    @interface MyClass : NSObject 
+    - (void)foo;
+    - (void)bar;
+    @end
+@/textblock
+
+ + Data properties that are created on the prototype or constructor objects have + the attributes: writable:true, enumerable:false, configurable:true. + Accessor properties have the attributes: enumerable:false and configurable:true. + + If an instance of MyClass is converted to a JavaScript value, the resulting + wrapper object will (via its prototype) export the method foo to JavaScript, + since the class conforms to the MyClassJavaScriptMethods protocol, and this + protocol incorporates JSExport. bar will not be exported. + + Properties, arguments, and return values of the following types are + supported: + + Primitive numbers: signed values of up to 32-bits are converted in a manner + consistent with valueWithInt32/toInt32, unsigned values of up to 32-bits + are converted in a manner consistent with valueWithUInt32/toUInt32, all + other numeric values are converted consistently with valueWithDouble/ + toDouble. + + BOOL: values are converted consistently with valueWithBool/toBool. + + id: values are converted consistently with valueWithObject/toObject. + + Objective-C Class: - where the type is a pointer to a specified Objective-C + class, conversion is consistent with valueWithObjectOfClass/toObject. + + struct types: C struct types are supported, where JSValue provides support + for the given type. Support is built in for CGPoint, NSRange, CGRect, and + CGSize. + + block types: Blocks can only be passed if they had been converted + successfully by valueWithObject/toObject previously. + + For any interface that conforms to JSExport the normal copying conversion for + built in types will be inhibited - so, for example, if an instance that + derives from NSString but conforms to JSExport is passed to valueWithObject: + then a wrapper object for the Objective-C object will be returned rather than + a JavaScript string primitive. +*/ +@protocol JSExport +@end + +/*! +@define +@abstract Rename a selector when it's exported to JavaScript. +@discussion When a selector that takes one or more arguments is converted to a JavaScript + property name, by default a property name will be generated by performing the + following conversion: + + - All colons are removed from the selector + + - Any lowercase letter that had followed a colon will be capitalized. + + Under the default conversion a selector doFoo:withBar: will be exported as + doFooWithBar. The default conversion may be overriden using the JSExportAs + macro, for example to export a method doFoo:withBar: as doFoo: + +
+@textblock
+    @protocol MyClassJavaScriptMethods 
+    JSExportAs(doFoo,
+    - (void)doFoo:(id)foo withBar:(id)bar
+    );
+    @end
+@/textblock
+
+ + Note that the JSExport macro may only be applied to a selector that takes one + or more argument. +*/ +#define JSExportAs(PropertyName, Selector) \ + @optional Selector __JS_EXPORT_AS__##PropertyName:(id)argument; @required Selector + +#endif diff --git a/JavaScriptCore/API/JSManagedValue.h b/JavaScriptCore/API/JSManagedValue.h new file mode 100644 index 00000000..4a15defc --- /dev/null +++ b/JavaScriptCore/API/JSManagedValue.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSManagedValue_h +#define JSManagedValue_h + +#import + +#if JSC_OBJC_API_ENABLED + +@class JSValue; +@class JSContext; + +/*! +@interface +@discussion JSManagedValue represents a "conditionally retained" JSValue. + "Conditionally retained" means that as long as either the JSManagedValue's + JavaScript value is reachable through the JavaScript object graph + or the JSManagedValue object is reachable through the external Objective-C + object graph as reported to the JSVirtualMachine using + addManagedReference:withOwner:, the corresponding JavaScript value will + be retained. However, if neither of these conditions are true, the + corresponding JSValue will be released and set to nil. + + The primary use case for JSManagedValue is for safely referencing JSValues + from the Objective-C heap. It is incorrect to store a JSValue into an + Objective-C heap object, as this can very easily create a reference cycle, + keeping the entire JSContext alive. +*/ +#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 +NS_CLASS_AVAILABLE(10_9, 7_0) +#else +OBJC_VISIBLE +#endif +@interface JSManagedValue : NSObject + +/*! +@method +@abstract Create a JSManagedValue from a JSValue. +@param value +@result The new JSManagedValue. +*/ ++ (JSManagedValue *)managedValueWithValue:(JSValue *)value; + +/*! +@method +@abstract Create a JSManagedValue. +@param value +@result The new JSManagedValue. +*/ +- (instancetype)initWithValue:(JSValue *)value; + +/*! +@property +@abstract Get the JSValue from the JSManagedValue. +@result The corresponding JSValue for this JSManagedValue or + nil if the JSValue has been collected. +*/ +@property (readonly, strong) JSValue *value; + +@end + +#endif // JSC_OBJC_API_ENABLED + +#endif // JSManagedValue_h diff --git a/JavaScriptCore/API/JSManagedValue.mm b/JavaScriptCore/API/JSManagedValue.mm new file mode 100644 index 00000000..19cfaed1 --- /dev/null +++ b/JavaScriptCore/API/JSManagedValue.mm @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import "config.h" +#import "JSManagedValue.h" + +#if JSC_OBJC_API_ENABLED + +#import "APICast.h" +#import "Heap.h" +#import "JSContextInternal.h" +#import "JSValueInternal.h" +#import "Weak.h" +#import "WeakHandleOwner.h" +#import "ObjcRuntimeExtras.h" +#import "Operations.h" + +class JSManagedValueHandleOwner : public JSC::WeakHandleOwner { +public: + virtual void finalize(JSC::Handle, void* context) OVERRIDE; + virtual bool isReachableFromOpaqueRoots(JSC::Handle, void* context, JSC::SlotVisitor&) OVERRIDE; +}; + +static JSManagedValueHandleOwner* managedValueHandleOwner() +{ + DEFINE_STATIC_LOCAL(JSManagedValueHandleOwner, jsManagedValueHandleOwner, ()); + return &jsManagedValueHandleOwner; +} + +class WeakValueRef { +public: + WeakValueRef() + : m_tag(NotSet) + { + } + + ~WeakValueRef() + { + clear(); + } + + void clear() + { + switch (m_tag) { + case NotSet: + return; + case Primitive: + u.m_primitive = JSC::JSValue(); + return; + case Object: + u.m_object.clear(); + return; + case String: + u.m_string.clear(); + return; + } + RELEASE_ASSERT_NOT_REACHED(); + } + + bool isClear() const + { + switch (m_tag) { + case NotSet: + return true; + case Primitive: + return !u.m_primitive; + case Object: + return !u.m_object; + case String: + return !u.m_string; + } + RELEASE_ASSERT_NOT_REACHED(); + } + + bool isSet() const { return m_tag != NotSet; } + bool isPrimitive() const { return m_tag == Primitive; } + bool isObject() const { return m_tag == Object; } + bool isString() const { return m_tag == String; } + + void setPrimitive(JSC::JSValue primitive) + { + ASSERT(!isSet()); + ASSERT(!u.m_primitive); + ASSERT(primitive.isPrimitive()); + m_tag = Primitive; + u.m_primitive = primitive; + } + + void setObject(JSC::JSObject* object, void* context) + { + ASSERT(!isSet()); + ASSERT(!u.m_object); + m_tag = Object; + JSC::Weak weak(object, managedValueHandleOwner(), context); + u.m_object.swap(weak); + } + + void setString(JSC::JSString* string, void* context) + { + ASSERT(!isSet()); + ASSERT(!u.m_object); + m_tag = String; + JSC::Weak weak(string, managedValueHandleOwner(), context); + u.m_string.swap(weak); + } + + JSC::JSObject* object() + { + ASSERT(isObject()); + return u.m_object.get(); + } + + JSC::JSValue primitive() + { + ASSERT(isPrimitive()); + return u.m_primitive; + } + + JSC::JSString* string() + { + ASSERT(isString()); + return u.m_string.get(); + } + +private: + enum WeakTypeTag { NotSet, Primitive, Object, String }; + WeakTypeTag m_tag; + union WeakValueUnion { + public: + WeakValueUnion () + : m_primitive(JSC::JSValue()) + { + } + + ~WeakValueUnion() + { + ASSERT(!m_primitive); + } + + JSC::JSValue m_primitive; + JSC::Weak m_object; + JSC::Weak m_string; + } u; +}; + +@implementation JSManagedValue { + JSC::Weak m_globalObject; + WeakValueRef m_weakValue; +} + ++ (JSManagedValue *)managedValueWithValue:(JSValue *)value +{ + return [[[self alloc] initWithValue:value] autorelease]; +} + +- (instancetype)init +{ + return [self initWithValue:nil]; +} + +- (instancetype)initWithValue:(JSValue *)value +{ + self = [super init]; + if (!self) + return nil; + + if (!value) + return self; + + JSC::ExecState* exec = toJS([value.context JSGlobalContextRef]); + JSC::JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + JSC::Weak weak(globalObject, managedValueHandleOwner(), self); + m_globalObject.swap(weak); + + JSC::JSValue jsValue = toJS(exec, [value JSValueRef]); + if (jsValue.isObject()) + m_weakValue.setObject(JSC::jsCast(jsValue.asCell()), self); + else if (jsValue.isString()) + m_weakValue.setString(JSC::jsCast(jsValue.asCell()), self); + else + m_weakValue.setPrimitive(jsValue); + return self; +} + +- (JSValue *)value +{ + if (!m_globalObject) + return nil; + if (m_weakValue.isClear()) + return nil; + JSC::ExecState* exec = m_globalObject->globalExec(); + JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(exec)]; + JSC::JSValue value; + if (m_weakValue.isPrimitive()) + value = m_weakValue.primitive(); + else if (m_weakValue.isString()) + value = m_weakValue.string(); + else + value = m_weakValue.object(); + return [JSValue valueWithJSValueRef:toRef(exec, value) inContext:context]; +} + +- (void)disconnectValue +{ + m_globalObject.clear(); + m_weakValue.clear(); +} + +@end + +@interface JSManagedValue (PrivateMethods) +- (void)disconnectValue; +@end + +bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle, void* context, JSC::SlotVisitor& visitor) +{ + JSManagedValue *managedValue = static_cast(context); + return visitor.containsOpaqueRoot(managedValue); +} + +void JSManagedValueHandleOwner::finalize(JSC::Handle, void* context) +{ + JSManagedValue *managedValue = static_cast(context); + [managedValue disconnectValue]; +} + +#endif // JSC_OBJC_API_ENABLED diff --git a/JavaScriptCore/API/JSObjectRef.cpp b/JavaScriptCore/API/JSObjectRef.cpp index e01214d5..af898713 100644 --- a/JavaScriptCore/API/JSObjectRef.cpp +++ b/JavaScriptCore/API/JSObjectRef.cpp @@ -29,12 +29,15 @@ #include "JSObjectRefPrivate.h" #include "APICast.h" +#include "ButterflyInlines.h" #include "CodeBlock.h" +#include "CopiedSpaceInlines.h" #include "DateConstructor.h" #include "ErrorConstructor.h" #include "FunctionConstructor.h" #include "Identifier.h" #include "InitializeThreading.h" +#include "JSAPIWrapperObject.h" #include "JSArray.h" #include "JSCallbackConstructor.h" #include "JSCallbackFunction.h" @@ -46,7 +49,9 @@ #include "JSRetainPtr.h" #include "JSString.h" #include "JSValueRef.h" +#include "ObjectConstructor.h" #include "ObjectPrototype.h" +#include "Operations.h" #include "PropertyNameArray.h" #include "RegExpConstructor.h" @@ -75,31 +80,40 @@ void JSClassRelease(JSClassRef jsClass) JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); if (!jsClass) return toRef(constructEmptyObject(exec)); - JSCallbackObject* object = JSCallbackObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data); + JSCallbackObject* object = JSCallbackObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data); if (JSObject* prototype = jsClass->prototype(exec)) - object->setPrototype(exec->globalData(), prototype); + object->setPrototype(exec->vm(), prototype); return toRef(object); } JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - - Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous"); - - return toRef(JSCallbackFunction::create(exec, exec->lexicalGlobalObject(), callAsFunction, nameID)); + return toRef(JSCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), callAsFunction, name ? name->string() : ASCIILiteral("anonymous"))); } JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -108,23 +122,27 @@ JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObje jsPrototype = exec->lexicalGlobalObject()->objectPrototype(); JSCallbackConstructor* constructor = JSCallbackConstructor::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor); - constructor->putDirect(exec->globalData(), exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly); + constructor->putDirect(exec->vm(), exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly); return toRef(constructor); } JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous"); + Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier(exec, "anonymous"); MarkedArgumentBuffer args; for (unsigned i = 0; i < parameterCount; i++) - args.append(jsString(exec, parameterNames[i]->ustring())); - args.append(jsString(exec, body->ustring())); + args.append(jsString(exec, parameterNames[i]->string())); + args.append(jsString(exec, body->string())); - JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL->ustring(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); @@ -136,6 +154,10 @@ JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned pa JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -145,9 +167,9 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa for (size_t i = 0; i < argumentCount; ++i) argList.append(toJS(exec, arguments[i])); - result = constructArray(exec, argList); + result = constructArray(exec, static_cast(0), argList); } else - result = constructEmptyArray(exec); + result = constructEmptyArray(exec, 0); if (exec->hadException()) { if (exception) @@ -161,6 +183,10 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -181,6 +207,10 @@ JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSVal JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -200,6 +230,10 @@ JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSVa JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -220,6 +254,10 @@ JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSV JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -229,33 +267,45 @@ JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object) void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); JSValue jsValue = toJS(exec, value); - jsObject->setPrototypeWithCycleCheck(exec->globalData(), jsValue.isObject() ? jsValue : jsNull()); + jsObject->setPrototypeWithCycleCheck(exec, jsValue.isObject() ? jsValue : jsNull()); } bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); - return jsObject->hasProperty(exec, propertyName->identifier(&exec->globalData())); + return jsObject->hasProperty(exec, propertyName->identifier(&exec->vm())); } JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); - JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->globalData())); + JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->vm())); if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); @@ -266,17 +316,22 @@ JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); - Identifier name(propertyName->identifier(&exec->globalData())); + Identifier name(propertyName->identifier(&exec->vm())); JSValue jsValue = toJS(exec, value); - if (attributes && !jsObject->hasProperty(exec, name)) - jsObject->methodTable()->putDirectVirtual(jsObject, exec, name, jsValue, attributes); - else { - PutPropertySlot slot; + if (attributes && !jsObject->hasProperty(exec, name)) { + PropertyDescriptor desc(jsValue, attributes); + jsObject->methodTable()->defineOwnProperty(jsObject, exec, name, desc, false); + } else { + PutPropertySlot slot(jsObject); jsObject->methodTable()->put(jsObject, exec, name, jsValue, slot); } @@ -289,6 +344,10 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -306,6 +365,10 @@ JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsi void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -322,12 +385,16 @@ void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned p bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); - bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->globalData())); + bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->vm())); if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); @@ -338,28 +405,38 @@ bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr void* JSObjectGetPrivate(JSObjectRef object) { - JSObject* jsObject = toJS(object); + JSObject* jsObject = uncheckedToJS(object); - if (jsObject->inherits(&JSCallbackObject::s_info)) + if (jsObject->inherits(JSCallbackObject::info())) return jsCast*>(jsObject)->getPrivate(); - if (jsObject->inherits(&JSCallbackObject::s_info)) - return jsCast*>(jsObject)->getPrivate(); + if (jsObject->inherits(JSCallbackObject::info())) + return jsCast*>(jsObject)->getPrivate(); +#if JSC_OBJC_API_ENABLED + if (jsObject->inherits(JSCallbackObject::info())) + return jsCast*>(jsObject)->getPrivate(); +#endif return 0; } bool JSObjectSetPrivate(JSObjectRef object, void* data) { - JSObject* jsObject = toJS(object); + JSObject* jsObject = uncheckedToJS(object); - if (jsObject->inherits(&JSCallbackObject::s_info)) { + if (jsObject->inherits(JSCallbackObject::info())) { jsCast*>(jsObject)->setPrivate(data); return true; } - if (jsObject->inherits(&JSCallbackObject::s_info)) { - jsCast*>(jsObject)->setPrivate(data); + if (jsObject->inherits(JSCallbackObject::info())) { + jsCast*>(jsObject)->setPrivate(data); + return true; + } +#if JSC_OBJC_API_ENABLED + if (jsObject->inherits(JSCallbackObject::info())) { + jsCast*>(jsObject)->setPrivate(data); return true; } +#endif return false; } @@ -370,11 +447,15 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); JSValue result; - Identifier name(propertyName->identifier(&exec->globalData())); - if (jsObject->inherits(&JSCallbackObject::s_info)) + Identifier name(propertyName->identifier(&exec->vm())); + if (jsObject->inherits(JSCallbackObject::info())) result = jsCast*>(jsObject)->getPrivateProperty(name); - else if (jsObject->inherits(&JSCallbackObject::s_info)) - result = jsCast*>(jsObject)->getPrivateProperty(name); + else if (jsObject->inherits(JSCallbackObject::info())) + result = jsCast*>(jsObject)->getPrivateProperty(name); +#if JSC_OBJC_API_ENABLED + else if (jsObject->inherits(JSCallbackObject::info())) + result = jsCast*>(jsObject)->getPrivateProperty(name); +#endif return toRef(exec, result); } @@ -384,15 +465,21 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); JSValue jsValue = value ? toJS(exec, value) : JSValue(); - Identifier name(propertyName->identifier(&exec->globalData())); - if (jsObject->inherits(&JSCallbackObject::s_info)) { - jsCast*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue); + Identifier name(propertyName->identifier(&exec->vm())); + if (jsObject->inherits(JSCallbackObject::info())) { + jsCast*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue); return true; } - if (jsObject->inherits(&JSCallbackObject::s_info)) { - jsCast*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue); + if (jsObject->inherits(JSCallbackObject::info())) { + jsCast*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue); return true; } +#if JSC_OBJC_API_ENABLED + if (jsObject->inherits(JSCallbackObject::info())) { + jsCast*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue); + return true; + } +#endif return false; } @@ -401,20 +488,28 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* jsObject = toJS(object); - Identifier name(propertyName->identifier(&exec->globalData())); - if (jsObject->inherits(&JSCallbackObject::s_info)) { + Identifier name(propertyName->identifier(&exec->vm())); + if (jsObject->inherits(JSCallbackObject::info())) { jsCast*>(jsObject)->deletePrivateProperty(name); return true; } - if (jsObject->inherits(&JSCallbackObject::s_info)) { - jsCast*>(jsObject)->deletePrivateProperty(name); + if (jsObject->inherits(JSCallbackObject::info())) { + jsCast*>(jsObject)->deletePrivateProperty(name); return true; } +#if JSC_OBJC_API_ENABLED + if (jsObject->inherits(JSCallbackObject::info())) { + jsCast*>(jsObject)->deletePrivateProperty(name); + return true; + } +#endif return false; } bool JSObjectIsFunction(JSContextRef, JSObjectRef object) { + if (!object) + return false; CallData callData; JSCell* cell = toJS(object); return cell->methodTable()->getCallData(cell, callData) != CallTypeNone; @@ -425,6 +520,9 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); + if (!object) + return 0; + JSObject* jsObject = toJS(object); JSObject* jsThisObject = toJS(thisObject); @@ -452,6 +550,8 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject bool JSObjectIsConstructor(JSContextRef, JSObjectRef object) { + if (!object) + return false; JSObject* jsObject = toJS(object); ConstructData constructData; return jsObject->methodTable()->getConstructData(jsObject, constructData) != ConstructTypeNone; @@ -462,6 +562,9 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); + if (!object) + return 0; + JSObject* jsObject = toJS(object); ConstructData constructData; @@ -485,33 +588,37 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size struct OpaqueJSPropertyNameArray { WTF_MAKE_FAST_ALLOCATED; public: - OpaqueJSPropertyNameArray(JSGlobalData* globalData) + OpaqueJSPropertyNameArray(VM* vm) : refCount(0) - , globalData(globalData) + , vm(vm) { } unsigned refCount; - JSGlobalData* globalData; - Vector > array; + VM* vm; + Vector> array; }; JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } JSObject* jsObject = toJS(object); ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); - JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(globalData); - PropertyNameArray array(globalData); + JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(vm); + PropertyNameArray array(vm); jsObject->methodTable()->getPropertyNames(jsObject, exec, array, ExcludeDontEnumProperties); size_t size = array.size(); propertyNames->array.reserveInitialCapacity(size); for (size_t i = 0; i < size; ++i) - propertyNames->array.append(JSRetainPtr(Adopt, OpaqueJSString::create(array[i].ustring()).leakRef())); + propertyNames->array.uncheckedAppend(JSRetainPtr(Adopt, OpaqueJSString::create(array[i].string()).leakRef())); return JSPropertyNameArrayRetain(propertyNames); } @@ -525,7 +632,7 @@ JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array) void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array) { if (--array->refCount == 0) { - APIEntryShim entryShim(array->globalData, false); + APIEntryShim entryShim(array->vm, false); delete array; } } @@ -543,6 +650,6 @@ JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName) { PropertyNameArray* propertyNames = toJS(array); - APIEntryShim entryShim(propertyNames->globalData()); - propertyNames->add(propertyName->identifier(propertyNames->globalData())); + APIEntryShim entryShim(propertyNames->vm()); + propertyNames->add(propertyName->identifier(propertyNames->vm())); } diff --git a/JavaScriptCore/API/JSObjectRef.h b/JavaScriptCore/API/JSObjectRef.h index 5014726b..6aa84358 100644 --- a/JavaScriptCore/API/JSObjectRef.h +++ b/JavaScriptCore/API/JSObjectRef.h @@ -441,7 +441,7 @@ JS_EXPORT JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsCla @discussion The behavior of this function does not exactly match the behavior of the built-in Array constructor. Specifically, if one argument is supplied, this function returns an array with one element. */ -JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0); /*! @function @@ -452,7 +452,7 @@ JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. @result A JSObject that is a Date. */ -JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0); /*! @function @@ -463,7 +463,7 @@ JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, c @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. @result A JSObject that is a Error. */ -JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0); /*! @function @@ -474,7 +474,7 @@ JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. @result A JSObject that is a RegExp. */ -JS_EXPORT JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0); /*! @function diff --git a/JavaScriptCore/API/JSProfilerPrivate.cpp b/JavaScriptCore/API/JSProfilerPrivate.cpp index ea277f05..0405b4b2 100644 --- a/JavaScriptCore/API/JSProfilerPrivate.cpp +++ b/JavaScriptCore/API/JSProfilerPrivate.cpp @@ -27,20 +27,20 @@ #include "JSProfilerPrivate.h" #include "APICast.h" +#include "LegacyProfiler.h" #include "OpaqueJSString.h" -#include "Profiler.h" using namespace JSC; void JSStartProfiling(JSContextRef ctx, JSStringRef title) { - Profiler::profiler()->startProfiling(toJS(ctx), title->ustring()); + LegacyProfiler::profiler()->startProfiling(toJS(ctx), title->string()); } void JSEndProfiling(JSContextRef ctx, JSStringRef title) { ExecState* exec = toJS(ctx); - Profiler* profiler = Profiler::profiler(); - profiler->stopProfiling(exec, title->ustring()); + LegacyProfiler* profiler = LegacyProfiler::profiler(); + profiler->stopProfiling(exec, title->string()); } diff --git a/JavaScriptCore/API/JSScriptRef.cpp b/JavaScriptCore/API/JSScriptRef.cpp new file mode 100644 index 00000000..9ba82a6f --- /dev/null +++ b/JavaScriptCore/API/JSScriptRef.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "APICast.h" +#include "APIShims.h" +#include "Completion.h" +#include "JSBasePrivate.h" +#include "VM.h" +#include "JSScriptRefPrivate.h" +#include "OpaqueJSString.h" +#include "Operations.h" +#include "Parser.h" +#include "SourceCode.h" +#include "SourceProvider.h" + +using namespace JSC; + +struct OpaqueJSScript : public SourceProvider { +public: + static WTF::PassRefPtr create(VM* vm, const String& url, int startingLineNumber, const String& source) + { + return WTF::adoptRef(new OpaqueJSScript(vm, url, startingLineNumber, source)); + } + + virtual const String& source() const OVERRIDE + { + return m_source; + } + + VM* vm() const { return m_vm; } + +private: + OpaqueJSScript(VM* vm, const String& url, int startingLineNumber, const String& source) + : SourceProvider(url, TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())) + , m_vm(vm) + , m_source(source) + { + } + + virtual ~OpaqueJSScript() { } + + VM* m_vm; + String m_source; +}; + +static bool parseScript(VM* vm, const SourceCode& source, ParserError& error) +{ + return JSC::parse(vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); +} + +extern "C" { + +JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupRef contextGroup, JSStringRef url, int startingLineNumber, const char* source, size_t length, JSStringRef* errorMessage, int* errorLine) +{ + VM* vm = toJS(contextGroup); + APIEntryShim entryShim(vm); + for (size_t i = 0; i < length; i++) { + if (!isASCII(source[i])) + return 0; + } + + RefPtr result = OpaqueJSScript::create(vm, url->string(), startingLineNumber, String(StringImpl::createFromLiteral(source, length))); + + ParserError error; + if (!parseScript(vm, SourceCode(result), error)) { + if (errorMessage) + *errorMessage = OpaqueJSString::create(error.m_message).leakRef(); + if (errorLine) + *errorLine = error.m_line; + return 0; + } + + return result.release().leakRef(); +} + +JSScriptRef JSScriptCreateFromString(JSContextGroupRef contextGroup, JSStringRef url, int startingLineNumber, JSStringRef source, JSStringRef* errorMessage, int* errorLine) +{ + VM* vm = toJS(contextGroup); + APIEntryShim entryShim(vm); + + RefPtr result = OpaqueJSScript::create(vm, url->string(), startingLineNumber, source->string()); + + ParserError error; + if (!parseScript(vm, SourceCode(result), error)) { + if (errorMessage) + *errorMessage = OpaqueJSString::create(error.m_message).leakRef(); + if (errorLine) + *errorLine = error.m_line; + return 0; + } + + return result.release().leakRef(); +} + +void JSScriptRetain(JSScriptRef script) +{ + APIEntryShim entryShim(script->vm()); + script->ref(); +} + +void JSScriptRelease(JSScriptRef script) +{ + APIEntryShim entryShim(script->vm()); + script->deref(); +} + +JSValueRef JSScriptEvaluate(JSContextRef context, JSScriptRef script, JSValueRef thisValueRef, JSValueRef* exception) +{ + ExecState* exec = toJS(context); + APIEntryShim entryShim(exec); + if (script->vm() != &exec->vm()) { + RELEASE_ASSERT_NOT_REACHED(); + return 0; + } + JSValue internalException; + JSValue thisValue = thisValueRef ? toJS(exec, thisValueRef) : jsUndefined(); + JSValue result = evaluate(exec, SourceCode(script), thisValue, &internalException); + if (internalException) { + if (exception) + *exception = toRef(exec, internalException); + return 0; + } + ASSERT(result); + return toRef(exec, result); +} + +} diff --git a/JavaScriptCore/API/JSScriptRefPrivate.h b/JavaScriptCore/API/JSScriptRefPrivate.h new file mode 100644 index 00000000..e1992052 --- /dev/null +++ b/JavaScriptCore/API/JSScriptRefPrivate.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSScriptRefPrivate_h +#define JSScriptRefPrivate_h + +#include +#include +#include + +/*! @typedef JSScriptRef A JavaScript script reference. */ +typedef struct OpaqueJSScript* JSScriptRef; + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + @function + @abstract Creates a script reference from an ascii string, without copying or taking ownership of the string + @param contextGroup The context group the script is to be used in. + @param url The source url to be reported in errors and exceptions. + @param startingLineNumber An integer value specifying the script's starting line number in the file located at sourceURL. This is only used when reporting exceptions. + @param source The source string. This is required to be pure ASCII and to never be deallocated. + @param length The length of the source string. + @param errorMessage A pointer to a JSStringRef in which to store the parse error message if the source is not valid. Pass NULL if you do not care to store an error message. + @param errorLine A pointer to an int in which to store the line number of a parser error. Pass NULL if you do not care to store an error line. + @result A JSScriptRef for the provided source, or NULL if any non-ASCII character is found in source or if the source is not a valid JavaScript program. Ownership follows the Create Rule. + @discussion Use this function to create a reusable script reference with a constant + buffer as the backing string. The source string must outlive the global context. + */ +JS_EXPORT JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupRef contextGroup, JSStringRef url, int startingLineNumber, const char* source, size_t length, JSStringRef* errorMessage, int* errorLine); + +/*! + @function + @abstract Creates a script reference from a string + @param contextGroup The context group the script is to be used in. + @param url The source url to be reported in errors and exceptions. + @param startingLineNumber An integer value specifying the script's starting line number in the file located at sourceURL. This is only used when reporting exceptions. + @param source The source string. + @param errorMessage A pointer to a JSStringRef in which to store the parse error message if the source is not valid. Pass NULL if you do not care to store an error message. + @param errorLine A pointer to an int in which to store the line number of a parser error. Pass NULL if you do not care to store an error line. + @result A JSScriptRef for the provided source, or NULL is the source is not a valid JavaScript program. Ownership follows the Create Rule. + */ +JS_EXPORT JSScriptRef JSScriptCreateFromString(JSContextGroupRef contextGroup, JSStringRef url, int startingLineNumber, JSStringRef source, JSStringRef* errorMessage, int* errorLine); + +/*! + @function + @abstract Retains a JavaScript script. + @param script The script to retain. + */ +JS_EXPORT void JSScriptRetain(JSScriptRef script); + +/*! + @function + @abstract Releases a JavaScript script. + @param script The script to release. + */ +JS_EXPORT void JSScriptRelease(JSScriptRef script); + +/*! + @function + @abstract Evaluates a JavaScript script. + @param ctx The execution context to use. + @param script The JSScript to evaluate. + @param thisValue The value to use as "this" when evaluating the script. + @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. + @result The JSValue that results from evaluating script, or NULL if an exception is thrown. + */ +JS_EXPORT JSValueRef JSScriptEvaluate(JSContextRef ctx, JSScriptRef script, JSValueRef thisValue, JSValueRef* exception); + + +#ifdef __cplusplus +} +#endif + +#endif /* JSScriptRefPrivate_h */ diff --git a/JavaScriptCore/API/JSStringRef.cpp b/JavaScriptCore/API/JSStringRef.cpp index ea31da66..a03afed5 100644 --- a/JavaScriptCore/API/JSStringRef.cpp +++ b/JavaScriptCore/API/JSStringRef.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "JSStringRef.h" +#include "JSStringRefPrivate.h" #include "InitializeThreading.h" #include "OpaqueJSString.h" @@ -46,14 +47,24 @@ JSStringRef JSStringCreateWithUTF8CString(const char* string) size_t length = strlen(string); Vector buffer(length); UChar* p = buffer.data(); - if (conversionOK == convertUTF8ToUTF16(&string, string + length, &p, p + length)) + bool sourceIsAllASCII; + const LChar* stringStart = reinterpret_cast(string); + if (conversionOK == convertUTF8ToUTF16(&string, string + length, &p, p + length, &sourceIsAllASCII)) { + if (sourceIsAllASCII) + return OpaqueJSString::create(stringStart, length).leakRef(); return OpaqueJSString::create(buffer.data(), p - buffer.data()).leakRef(); + } } - // Null string. return OpaqueJSString::create().leakRef(); } +JSStringRef JSStringCreateWithCharactersNoCopy(const JSChar* chars, size_t numChars) +{ + initializeThreading(); + return OpaqueJSString::create(StringImpl::createWithoutCopying(chars, numChars)).leakRef(); +} + JSStringRef JSStringRetain(JSStringRef string) { string->ref(); diff --git a/JavaScriptCore/API/JSStringRefCF.cpp b/JavaScriptCore/API/JSStringRefCF.cpp index 0877a13e..50593f19 100644 --- a/JavaScriptCore/API/JSStringRefCF.cpp +++ b/JavaScriptCore/API/JSStringRefCF.cpp @@ -28,11 +28,10 @@ #include "APICast.h" #include "InitializeThreading.h" +#include "JSCJSValue.h" #include "JSStringRef.h" #include "OpaqueJSString.h" -#include -#include -#include +#include JSStringRef JSStringCreateWithCFString(CFStringRef string) { @@ -42,16 +41,25 @@ JSStringRef JSStringCreateWithCFString(CFStringRef string) // it can hold. () size_t length = CFStringGetLength(string); if (length) { - OwnArrayPtr buffer = adoptArrayPtr(new UniChar[length]); + Vector lcharBuffer(length); + CFIndex usedBufferLength; + CFIndex convertedSize = CFStringGetBytes(string, CFRangeMake(0, length), kCFStringEncodingISOLatin1, 0, false, lcharBuffer.data(), length, &usedBufferLength); + if (static_cast(convertedSize) == length && static_cast(usedBufferLength) == length) + return OpaqueJSString::create(lcharBuffer.data(), length).leakRef(); + + auto buffer = std::make_unique(length); CFStringGetCharacters(string, CFRangeMake(0, length), buffer.get()); COMPILE_ASSERT(sizeof(UniChar) == sizeof(UChar), unichar_and_uchar_must_be_same_size); return OpaqueJSString::create(reinterpret_cast(buffer.get()), length).leakRef(); - } else { - return OpaqueJSString::create(0, 0).leakRef(); } + + return OpaqueJSString::create(reinterpret_cast(""), 0).leakRef(); } CFStringRef JSStringCopyCFString(CFAllocatorRef alloc, JSStringRef string) { + if (!string->length()) + return CFSTR(""); + return CFStringCreateWithCharacters(alloc, reinterpret_cast(string->characters()), string->length()); } diff --git a/JavaScriptCore/API/JSStringRefCF.h b/JavaScriptCore/API/JSStringRefCF.h index a4247656..a7555f96 100644 --- a/JavaScriptCore/API/JSStringRefCF.h +++ b/JavaScriptCore/API/JSStringRefCF.h @@ -51,7 +51,7 @@ JS_EXPORT JSStringRef JSStringCreateWithCFString(CFStringRef string); @param string The JSString to copy into the new CFString. @result A CFString containing string. Ownership follows the Create Rule. */ -JS_EXPORT CFStringRef JSStringCopyCFString(CFAllocatorRef alloc, JSStringRef string); +JS_EXPORT CFStringRef JSStringCopyCFString(CFAllocatorRef alloc, JSStringRef string) CF_RETURNS_RETAINED; #ifdef __cplusplus } diff --git a/JavaScriptCore/API/JSStringRefPrivate.h b/JavaScriptCore/API/JSStringRefPrivate.h new file mode 100644 index 00000000..f1db806e --- /dev/null +++ b/JavaScriptCore/API/JSStringRefPrivate.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013 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 JSStringRefPrivate_h +#define JSStringRefPrivate_h + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +JS_EXPORT JSStringRef JSStringCreateWithCharactersNoCopy(const JSChar* chars, size_t numChars); + +#ifdef __cplusplus +} +#endif + +#endif /* JSStringRefPrivate_h */ diff --git a/JavaScriptCore/API/JSTypedArray.cpp b/JavaScriptCore/API/JSTypedArray.cpp new file mode 100644 index 00000000..1ec2a0dc --- /dev/null +++ b/JavaScriptCore/API/JSTypedArray.cpp @@ -0,0 +1,130 @@ + +#include "config.h" + +#include "JSTypedArray.h" + +#include + +#include "JSObjectRef.h" +#include "APICast.h" +#include "InitializeThreading.h" +#include "JSCallbackObject.h" +#include "JSClassRef.h" +#include "JSGlobalObject.h" + +#include "JSArrayBuffer.h" +#include "JSFloat32Array.h" +#include "JSFloat64Array.h" +#include "JSInt8Array.h" +#include "JSInt16Array.h" +#include "JSInt32Array.h" +#include "JSUint8ClampedArray.h" +#include "JSUint8Array.h" +#include "JSUint16Array.h" +#include "JSUint32Array.h" + +#include "TypedArrayInlines.h" + +using namespace JSC; + +// Better be safe than sorry! +const JSTypedArrayType TypedArrayTypes[] = { + [NotTypedArray] = kJSTypedArrayTypeNone, + [TypeInt8] = kJSTypedArrayTypeInt8Array, + [TypeUint8] = kJSTypedArrayTypeUint8Array, + [TypeUint8Clamped] = kJSTypedArrayTypeUint8ClampedArray, + [TypeInt16] = kJSTypedArrayTypeInt16Array, + [TypeUint16] = kJSTypedArrayTypeUint16Array, + [TypeInt32] = kJSTypedArrayTypeInt32Array, + [TypeUint32] = kJSTypedArrayTypeUint32Array, + [TypeFloat32] = kJSTypedArrayTypeFloat32Array, + [TypeFloat64] = kJSTypedArrayTypeFloat64Array, + /* not a TypedArray */ kJSTypedArrayTypeArrayBuffer +}; + +const int kJSTypedArrayTypeLast = kJSTypedArrayTypeArrayBuffer; + + +template JSObject * CreateTypedArray(JSC::ExecState* exec, size_t length) { + return ArrayType::create(length)->wrap(exec, exec->lexicalGlobalObject()); +} + +template JSObject * CreateArrayBuffer(JSC::ExecState* exec, size_t length) { + RefPtr buffer = BufferType::create(length, 1); + if( !buffer ) { + return NULL; + } + + JSArrayBuffer* result = JSArrayBuffer::create( + exec->vm(), exec->lexicalGlobalObject()->arrayBufferStructure(), buffer); + return result; +} + +typedef JSObject*(*CreateTypedArrayFuncPtr)(JSC::ExecState*, size_t); +const CreateTypedArrayFuncPtr CreateTypedArrayFunc[] = { + [kJSTypedArrayTypeNone] = NULL, + [kJSTypedArrayTypeInt8Array] = CreateTypedArray, + [kJSTypedArrayTypeInt16Array] = CreateTypedArray, + [kJSTypedArrayTypeInt32Array] = CreateTypedArray, + [kJSTypedArrayTypeUint8Array] = CreateTypedArray, + [kJSTypedArrayTypeUint8ClampedArray] = CreateTypedArray, + [kJSTypedArrayTypeUint16Array] = CreateTypedArray, + [kJSTypedArrayTypeUint32Array] = CreateTypedArray, + [kJSTypedArrayTypeFloat32Array] = CreateTypedArray, + [kJSTypedArrayTypeFloat64Array] = CreateTypedArray, + [kJSTypedArrayTypeArrayBuffer] = CreateArrayBuffer, +}; + + + + +JSTypedArrayType JSObjectGetTypedArrayType(JSContextRef ctx, JSObjectRef object) { + ExecState* exec = toJS(ctx); + APIEntryShim entryShim(exec); + + JSObject* jsObject = toJS(object); + JSTypedArrayType type = kJSTypedArrayTypeNone; + if( jsObject->inherits(JSArrayBufferView::info()) ) { + type = TypedArrayTypes[jsObject->classInfo()->typedArrayStorageType]; + } + else if( jsObject->inherits(JSArrayBuffer::info()) ) { + type = kJSTypedArrayTypeArrayBuffer; + } + return type; +} + +JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t numElements) { + ExecState* exec = toJS(ctx); + APIEntryShim entryShim(exec); + + JSObject* result = NULL; + if( arrayType > kJSTypedArrayTypeNone && arrayType <= kJSTypedArrayTypeLast ) { + result = CreateTypedArrayFunc[arrayType]( exec, numElements ); + } + + return toRef(result); +} + +void* JSObjectGetTypedArrayDataPtr(JSContextRef ctx, JSObjectRef object, size_t* byteLength) { + ExecState* exec = toJS(ctx); + APIEntryShim entryShim(exec); + + JSObject* jsObject = toJS(object); + if( JSArrayBufferView * view = jsDynamicCast(jsObject) ) { + if( byteLength ) { + *byteLength = view->impl()->byteLength(); + } + return view->impl()->baseAddress(); + } + else if( ArrayBuffer* buffer = toArrayBuffer(jsObject) ) { + if( byteLength ) { + *byteLength = buffer->byteLength(); + } + return buffer->data(); + } + + if( byteLength ) { + *byteLength = 0; + } + return NULL; +} diff --git a/JavaScriptCore/API/JSTypedArray.h b/JavaScriptCore/API/JSTypedArray.h new file mode 100644 index 00000000..b7c827b6 --- /dev/null +++ b/JavaScriptCore/API/JSTypedArray.h @@ -0,0 +1,73 @@ +#ifndef JSTypedArray_h +#define JSTypedArray_h + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +@enum JSType +@abstract A constant identifying the Typed Array type of a JSValue. +@constant kJSTypedArrayTypeNone Not a Typed Array. +@constant kJSTypedArrayTypeInt8Array Int8Array +@constant kJSTypedArrayTypeInt16Array Int16Array +@constant kJSTypedArrayTypeInt32Array Int32Array +@constant kJSTypedArrayTypeUint8Array Int8Array +@constant kJSTypedArrayTypeUint8ClampedArray Int8ClampedArray +@constant kJSTypedArrayTypeUint16Array Uint16Array +@constant kJSTypedArrayTypeUint32Array Uint32Array +@constant kJSTypedArrayTypeFloat32Array Float32Array +@constant kJSTypedArrayTypeFloat64Array Float64Array +@constant kJSTypedArrayTypeArrayBuffer ArrayBuffer +*/ +typedef enum { + kJSTypedArrayTypeNone, + kJSTypedArrayTypeInt8Array, + kJSTypedArrayTypeInt16Array, + kJSTypedArrayTypeInt32Array, + kJSTypedArrayTypeUint8Array, + kJSTypedArrayTypeUint8ClampedArray, + kJSTypedArrayTypeUint16Array, + kJSTypedArrayTypeUint32Array, + kJSTypedArrayTypeFloat32Array, + kJSTypedArrayTypeFloat64Array, + kJSTypedArrayTypeArrayBuffer +} JSTypedArrayType; + +/*! +@function +@abstract Returns a JavaScript value's Typed Array type +@param ctx The execution context to use. +@param value The JSValue whose Typed Array type you want to obtain. +@result A value of type JSTypedArrayType that identifies value's Typed Array type. +*/ +JS_EXPORT JSTypedArrayType JSObjectGetTypedArrayType(JSContextRef ctx, JSObjectRef object); + +/*! +@function +@abstract Creates a JavaScript Typed Array with the given number of elements +@param ctx The execution context to use. +@param arrayType A value of type JSTypedArrayType identifying the type of array you want to create +@param numElements The number of elements for the array. +@result A JSObjectRef that is a Typed Array or NULL if there was an error +*/ +JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t numElements); + +/*! +@function +@abstract Returns a pointer to a Typed Array's data in memory +@param ctx The execution context to use. +@param value The JSValue whose Typed Array type data pointer you want to obtain. +@param byteLength A pointer to a size_t in which to store the byte length of the Typed Array +@result A pointer to the Typed Array's data or NULL if the JSValue is not a Typed Array. +*/ +JS_EXPORT void * JSObjectGetTypedArrayDataPtr(JSContextRef ctx, JSObjectRef object, size_t* byteLength); + + +#ifdef __cplusplus +} +#endif + +#endif /* JSTypedArray_h */ diff --git a/JavaScriptCore/API/JSValue.h b/JavaScriptCore/API/JSValue.h new file mode 100644 index 00000000..c5a824db --- /dev/null +++ b/JavaScriptCore/API/JSValue.h @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2013 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 JSValue_h +#define JSValue_h + +#if JSC_OBJC_API_ENABLED + +#import + +@class JSContext; + +/*! +@interface +@discussion A JSValue is a reference to a value within the JavaScript object space of a + JSVirtualMachine. All instances of JSValue originate from a JSContext and + hold a strong reference to this JSContext. As long as any value associated with + a particular JSContext is retained, that JSContext will remain alive. + Where an instance method is invoked upon a JSValue, and this returns another + JSValue, the returned JSValue will originate from the same JSContext as the + JSValue on which the method was invoked. + + All JavaScript values are associated with a particular JSVirtualMachine + (the associated JSVirtualMachine is available indirectly via the context + property). An instance of JSValue may only be passed as an argument to + methods on instances of JSValue and JSContext that belong to the same + JSVirtualMachine - passing a JSValue to a method on an object originating + from a different JSVirtualMachine will result in an Objective-C exception + being raised. +*/ +#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 +NS_CLASS_AVAILABLE(10_9, 7_0) +#else +OBJC_VISIBLE +#endif +@interface JSValue : NSObject + +/*! +@property +@abstract The JSContext that this value originates from. +*/ +@property (readonly, strong) JSContext *context; + +/*! +@methodgroup Creating JavaScript Values +*/ +/*! +@method +@abstract Create a JSValue by converting an Objective-C object. +@discussion The resulting JSValue retains the provided Objective-C object. +@param value The Objective-C object to be converted. +@result The new JSValue. +*/ ++ (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JavaScript value from a BOOL primitive. +@param value +@param context The JSContext in which the resulting JSValue will be created. +@result The new JSValue representing the equivalent boolean value. +*/ ++ (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JavaScript value from a double primitive. +@param value +@param context The JSContext in which the resulting JSValue will be created. +@result The new JSValue representing the equivalent boolean value. +*/ ++ (JSValue *)valueWithDouble:(double)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JavaScript value from an int32_t primitive. +@param value +@param context The JSContext in which the resulting JSValue will be created. +@result The new JSValue representing the equivalent boolean value. +*/ ++ (JSValue *)valueWithInt32:(int32_t)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JavaScript value from a uint32_t primitive. +@param value +@param context The JSContext in which the resulting JSValue will be created. +@result The new JSValue representing the equivalent boolean value. +*/ ++ (JSValue *)valueWithUInt32:(uint32_t)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a new, empty JavaScript object. +@param context The JSContext in which the resulting object will be created. +@result The new JavaScript object. +*/ ++ (JSValue *)valueWithNewObjectInContext:(JSContext *)context; + +/*! +@method +@abstract Create a new, empty JavaScript array. +@param context The JSContext in which the resulting array will be created. +@result The new JavaScript array. +*/ ++ (JSValue *)valueWithNewArrayInContext:(JSContext *)context; + +/*! +@method +@abstract Create a new JavaScript regular expression object. +@param pattern The regular expression pattern. +@param flags The regular expression flags. +@param context The JSContext in which the resulting regular expression object will be created. +@result The new JavaScript regular expression object. +*/ ++ (JSValue *)valueWithNewRegularExpressionFromPattern:(NSString *)pattern flags:(NSString *)flags inContext:(JSContext *)context; + +/*! +@method +@abstract Create a new JavaScript error object. +@param message The error message. +@param context The JSContext in which the resulting error object will be created. +@result The new JavaScript error object. +*/ ++ (JSValue *)valueWithNewErrorFromMessage:(NSString *)message inContext:(JSContext *)context; + +/*! +@method +@abstract Create the JavaScript value null. +@param context The JSContext to which the resulting JSValue belongs. +@result The JSValue representing the JavaScript value null. +*/ ++ (JSValue *)valueWithNullInContext:(JSContext *)context; + +/*! +@method +@abstract Create the JavaScript value undefined. +@param context The JSContext to which the resulting JSValue belongs. +@result The JSValue representing the JavaScript value undefined. +*/ ++ (JSValue *)valueWithUndefinedInContext:(JSContext *)context; + +/*! +@methodgroup Converting to Objective-C Types +@discussion When converting between JavaScript values and Objective-C objects a copy is + performed. Values of types listed below are copied to the corresponding + types on conversion in each direction. For NSDictionaries, entries in the + dictionary that are keyed by strings are copied onto a JavaScript object. + For dictionaries and arrays, conversion is recursive, with the same object + conversion being applied to all entries in the collection. + +
+@textblock
+   Objective-C type  |   JavaScript type
+ --------------------+---------------------
+         nil         |     undefined
+        NSNull       |        null
+       NSString      |       string
+       NSNumber      |   number, boolean
+     NSDictionary    |   Object object
+       NSArray       |    Array object
+        NSDate       |     Date object
+       NSBlock (1)   |   Function object (1)
+          id (2)     |   Wrapper object (2)
+        Class (3)    | Constructor object (3)
+@/textblock
+
+ + (1) Instances of NSBlock with supported arguments types will be presented to + JavaScript as a callable Function object. For more information on supported + argument types see JSExport.h. If a JavaScript Function originating from an + Objective-C block is converted back to an Objective-C object the block will + be returned. All other JavaScript functions will be converted in the same + manner as a JavaScript object of type Object. + + (2) For Objective-C instances that do not derive from the set of types listed + above, a wrapper object to provide a retaining handle to the Objective-C + instance from JavaScript. For more information on these wrapper objects, see + JSExport.h. When a JavaScript wrapper object is converted back to Objective-C + the Objective-C instance being retained by the wrapper is returned. + + (3) For Objective-C Class objects a constructor object containing exported + class methods will be returned. See JSExport.h for more information on + constructor objects. + + For all methods taking arguments of type id, arguments will be converted + into a JavaScript value according to the above conversion. +*/ +/*! +@method +@abstract Convert this JSValue to an Objective-C object. +@discussion The JSValue is converted to an Objective-C object according + to the conversion rules specified above. +@result The Objective-C representation of this JSValue. +*/ +- (id)toObject; + +/*! +@method +@abstract Convert a JSValue to an Objective-C object of a specific class. +@discussion The JSValue is converted to an Objective-C object of the specified Class. + If the result is not of the specified Class then nil will be returned. +@result An Objective-C object of the specified Class or nil. +*/ +- (id)toObjectOfClass:(Class)expectedClass; + +/*! +@method +@abstract Convert a JSValue to a boolean. +@discussion The JSValue is converted to a boolean according to the rules specified + by the JavaScript language. +@result The boolean result of the conversion. +*/ +- (BOOL)toBool; + +/*! +@method +@abstract Convert a JSValue to a double. +@discussion The JSValue is converted to a number according to the rules specified + by the JavaScript language. +@result The double result of the conversion. +*/ +- (double)toDouble; + +/*! +@method +@abstract Convert a JSValue to an int32_t. +@discussion The JSValue is converted to an integer according to the rules specified + by the JavaScript language. +@result The int32_t result of the conversion. +*/ +- (int32_t)toInt32; + +/*! +@method +@abstract Convert a JSValue to a uint32_t. +@discussion The JSValue is converted to an integer according to the rules specified + by the JavaScript language. +@result The uint32_t result of the conversion. +*/ +- (uint32_t)toUInt32; + +/*! +@method +@abstract Convert a JSValue to a NSNumber. +@discussion If the JSValue represents a boolean, a NSNumber value of YES or NO + will be returned. For all other types the value will be converted to a number according + to the rules specified by the JavaScript language. +@result The NSNumber result of the conversion. +*/ +- (NSNumber *)toNumber; + +/*! +@method +@abstract Convert a JSValue to a NSString. +@discussion The JSValue is converted to a string according to the rules specified + by the JavaScript language. +@result The NSString containing the result of the conversion. +*/ +- (NSString *)toString; + +/*! +@method +@abstract Convert a JSValue to a NSDate. +@discussion The value is converted to a number representing a time interval + since 1970 which is then used to create a new NSDate instance. +@result The NSDate created using the converted time interval. +*/ +- (NSDate *)toDate; + +/*! +@method +@abstract Convert a JSValue to a NSArray. +@discussion If the value is null or undefined then nil is returned. + If the value is not an object then a JavaScript TypeError will be thrown. + The property length is read from the object, converted to an unsigned + integer, and an NSArray of this size is allocated. Properties corresponding + to indicies within the array bounds will be copied to the array, with + JSValues converted to equivalent Objective-C objects as specified. +@result The NSArray containing the recursively converted contents of the + converted JavaScript array. +*/ +- (NSArray *)toArray; + +/*! +@method +@abstract Convert a JSValue to a NSDictionary. +@discussion If the value is null or undefined then nil is returned. + If the value is not an object then a JavaScript TypeError will be thrown. + All enumerable properties of the object are copied to the dictionary, with + JSValues converted to equivalent Objective-C objects as specified. +@result The NSDictionary containing the recursively converted contents of + the converted JavaScript object. +*/ +- (NSDictionary *)toDictionary; + +/*! +@methodgroup Accessing Properties +*/ +/*! +@method +@abstract Access a property of a JSValue. +@result The JSValue for the requested property or the JSValue undefined + if the property does not exist. +*/ +- (JSValue *)valueForProperty:(NSString *)property; + +/*! +@method +@abstract Set a property on a JSValue. +*/ +- (void)setValue:(id)value forProperty:(NSString *)property; + +/*! +@method +@abstract Delete a property from a JSValue. +@result YES if deletion is successful, NO otherwise. +*/ +- (BOOL)deleteProperty:(NSString *)property; + +/*! +@method +@abstract Check if a JSValue has a property. +@discussion This method has the same function as the JavaScript operator in. +@result Returns YES if property is present on the value. +*/ +- (BOOL)hasProperty:(NSString *)property; + +/*! +@method +@abstract Define properties with custom descriptors on JSValues. +@discussion This method may be used to create a data or accessor property on an object. + This method operates in accordance with the Object.defineProperty method in the + JavaScript language. +*/ +- (void)defineProperty:(NSString *)property descriptor:(id)descriptor; + +/*! +@method +@abstract Access an indexed (numerical) property on a JSValue. +@result The JSValue for the property at the specified index. + Returns the JavaScript value undefined if no property exists at that index. +*/ +- (JSValue *)valueAtIndex:(NSUInteger)index; + +/*! +@method +@abstract Set an indexed (numerical) property on a JSValue. +@discussion For JSValues that are JavaScript arrays, indices greater than + UINT_MAX - 1 will not affect the length of the array. +*/ +- (void)setValue:(id)value atIndex:(NSUInteger)index; + +/*! +@methodgroup Checking JavaScript Types +*/ +/*! +@method +@abstract Check if a JSValue corresponds to the JavaScript value undefined. +*/ +- (BOOL)isUndefined; + +/*! +@method +@abstract Check if a JSValue corresponds to the JavaScript value null. +*/ +- (BOOL)isNull; + +/*! +@method +@abstract Check if a JSValue is a boolean. +*/ +- (BOOL)isBoolean; + +/*! +@method +@abstract Check if a JSValue is a number. +@discussion In JavaScript, there is no differentiation between types of numbers. + Semantically all numbers behave like doubles except in special cases like bit + operations. +*/ +- (BOOL)isNumber; + +/*! +@method +@abstract Check if a JSValue is a string. +*/ +- (BOOL)isString; + +/*! +@method +@abstract Check if a JSValue is an object. +*/ +- (BOOL)isObject; + +/*! +@method +@abstract Compare two JSValues using JavaScript's === operator. +*/ +- (BOOL)isEqualToObject:(id)value; + +/*! +@method +@abstract Compare two JSValues using JavaScript's == operator. +*/ +- (BOOL)isEqualWithTypeCoercionToObject:(id)value; + +/*! +@method +@abstract Check if a JSValue is an instance of another object. +@discussion This method has the same function as the JavaScript operator instanceof. + If an object other than a JSValue is passed, it will first be converted according to + the aforementioned rules. +*/ +- (BOOL)isInstanceOf:(id)value; + +/*! +@methodgroup Calling Functions and Constructors +*/ +/*! +@method +@abstract Invoke a JSValue as a function. +@discussion In JavaScript, if a function doesn't explicitly return a value then it + implicitly returns the JavaScript value undefined. +@param arguments The arguments to pass to the function. +@result The return value of the function call. +*/ +- (JSValue *)callWithArguments:(NSArray *)arguments; + +/*! +@method +@abstract Invoke a JSValue as a constructor. +@discussion This is equivalent to using the new syntax in JavaScript. +@param arguments The arguments to pass to the constructor. +@result The return value of the constructor call. +*/ +- (JSValue *)constructWithArguments:(NSArray *)arguments; + +/*! +@method +@abstract Invoke a method on a JSValue. +@discussion Accesses the property named method from this value and + calls the resulting value as a function, passing this JSValue as the this + value along with the specified arguments. +@param method The name of the method to be invoked. +@param arguments The arguments to pass to the method. +@result The return value of the method call. +*/ +- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments; + +@end + +/*! +@category +@discussion Objective-C methods exported to JavaScript may have argument and/or return + values of struct types, provided that conversion to and from the struct is + supported by JSValue. Support is provided for any types where JSValue + contains both a class method valueWith:inContext:, and and instance + method to- where the string in these selector names match, + with the first argument to the former being of the same struct type as the + return type of the latter. + Support is provided for structs of type CGPoint, NSRange, CGRect and CGSize. +*/ +@interface JSValue (StructSupport) + +/*! +@method +@abstract Create a JSValue from a CGPoint. +@result A newly allocated JavaScript object containing properties + named x and y, with values from the CGPoint. +*/ ++ (JSValue *)valueWithPoint:(CGPoint)point inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JSValue from a NSRange. +@result A newly allocated JavaScript object containing properties + named location and length, with values from the NSRange. +*/ ++ (JSValue *)valueWithRange:(NSRange)range inContext:(JSContext *)context; + +/*! +@method +@abstract +Create a JSValue from a CGRect. +@result A newly allocated JavaScript object containing properties + named x, y, width, and height, with values from the CGRect. +*/ ++ (JSValue *)valueWithRect:(CGRect)rect inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JSValue from a CGSize. +@result A newly allocated JavaScript object containing properties + named width and height, with values from the CGSize. +*/ ++ (JSValue *)valueWithSize:(CGSize)size inContext:(JSContext *)context; + +/*! +@method +@abstract Convert a JSValue to a CGPoint. +@discussion Reads the properties named x and y from + this JSValue, and converts the results to double. +@result The new CGPoint. +*/ +- (CGPoint)toPoint; + +/*! +@method +@abstract Convert a JSValue to an NSRange. +@discussion Reads the properties named location and + length from this JSValue and converts the results to double. +@result The new NSRange. +*/ +- (NSRange)toRange; + +/*! +@method +@abstract Convert a JSValue to a CGRect. +@discussion Reads the properties named x, y, + width, and height from this JSValue and converts the results to double. +@result The new CGRect. +*/ +- (CGRect)toRect; + +/*! +@method +@abstract Convert a JSValue to a CGSize. +@discussion Reads the properties named width and + height from this JSValue and converts the results to double. +@result The new CGSize. +*/ +- (CGSize)toSize; + +@end + +/*! +@category +@discussion Instances of JSValue implement the following methods in order to enable + support for subscript access by key and index, for example: + +@textblock + JSValue *objectA, *objectB; + JSValue *v1 = object[@"X"]; // Get value for property "X" from 'object'. + JSValue *v2 = object[42]; // Get value for index 42 from 'object'. + object[@"Y"] = v1; // Assign 'v1' to property "Y" of 'object'. + object[101] = v2; // Assign 'v2' to index 101 of 'object'. +@/textblock + + An object key passed as a subscript will be converted to a JavaScript value, + and then the value converted to a string used as a property name. +*/ +@interface JSValue (SubscriptSupport) + +- (JSValue *)objectForKeyedSubscript:(id)key; +- (JSValue *)objectAtIndexedSubscript:(NSUInteger)index; +- (void)setObject:(id)object forKeyedSubscript:(NSObject *)key; +- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index; + +@end + +/*! +@category +@discussion These functions are for bridging between the C API and the Objective-C API. +*/ +@interface JSValue (JSValueRefSupport) + +/*! +@method +@abstract Creates a JSValue, wrapping its C API counterpart. +@param value +@param context +@result The Objective-C API equivalent of the specified JSValueRef. +*/ ++ (JSValue *)valueWithJSValueRef:(JSValueRef)value inContext:(JSContext *)context; + +/*! +@property +@abstract Returns the C API counterpart wrapped by a JSContext. +@result The C API equivalent of this JSValue. +*/ +@property (readonly) JSValueRef JSValueRef; +@end + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +@group Property Descriptor Constants +@discussion These keys may assist in creating a property descriptor for use with the + defineProperty method on JSValue. + Property descriptors must fit one of three descriptions: + + Data Descriptor: + - A descriptor containing one or both of the keys value and writable, + and optionally containing one or both of the keys enumerable and + configurable. A data descriptor may not contain either the get or + set key. + A data descriptor may be used to create or modify the attributes of a + data property on an object (replacing any existing accessor property). + + Accessor Descriptor: + - A descriptor containing one or both of the keys get and set, and + optionally containing one or both of the keys enumerable and + configurable. An accessor descriptor may not contain either the value + or writable key. + An accessor descriptor may be used to create or modify the attributes of + an accessor property on an object (replacing any existing data property). + + Generic Descriptor: + - A descriptor containing one or both of the keys enumerable and + configurable. A generic descriptor may not contain any of the keys + value, writable, get, or set. + A generic descriptor may be used to modify the attributes of an existing + data or accessor property, or to create a new data property. +*/ +/*! +@const +*/ +JS_EXPORT extern NSString * const JSPropertyDescriptorWritableKey; +/*! +@const +*/ +JS_EXPORT extern NSString * const JSPropertyDescriptorEnumerableKey; +/*! +@const +*/ +JS_EXPORT extern NSString * const JSPropertyDescriptorConfigurableKey; +/*! +@const +*/ +JS_EXPORT extern NSString * const JSPropertyDescriptorValueKey; +/*! +@const +*/ +JS_EXPORT extern NSString * const JSPropertyDescriptorGetKey; +/*! +@const +*/ +JS_EXPORT extern NSString * const JSPropertyDescriptorSetKey; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif + +#endif // JSValue_h diff --git a/JavaScriptCore/API/JSValue.mm b/JavaScriptCore/API/JSValue.mm new file mode 100644 index 00000000..95c129e4 --- /dev/null +++ b/JavaScriptCore/API/JSValue.mm @@ -0,0 +1,1132 @@ +/* + * Copyright (C) 2013 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" + +#import "APICast.h" +#import "APIShims.h" +#import "DateInstance.h" +#import "Error.h" +#import "JavaScriptCore.h" +#import "JSContextInternal.h" +#import "JSVirtualMachineInternal.h" +#import "JSValueInternal.h" +#import "JSWrapperMap.h" +#import "ObjcRuntimeExtras.h" +#import "Operations.h" +#import "JSCJSValue.h" +#import +#import +#import +#import +#import +#import +#import + +#if JSC_OBJC_API_ENABLED + +NSString * const JSPropertyDescriptorWritableKey = @"writable"; +NSString * const JSPropertyDescriptorEnumerableKey = @"enumerable"; +NSString * const JSPropertyDescriptorConfigurableKey = @"configurable"; +NSString * const JSPropertyDescriptorValueKey = @"value"; +NSString * const JSPropertyDescriptorGetKey = @"get"; +NSString * const JSPropertyDescriptorSetKey = @"set"; + +@implementation JSValue { + JSValueRef m_value; +} + +- (JSValueRef)JSValueRef +{ + return m_value; +} + ++ (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:objectToValue(context, value) inContext:context]; +} + ++ (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSValueMakeBoolean([context JSGlobalContextRef], value) inContext:context]; +} + ++ (JSValue *)valueWithDouble:(double)value inContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSValueMakeNumber([context JSGlobalContextRef], value) inContext:context]; +} + ++ (JSValue *)valueWithInt32:(int32_t)value inContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSValueMakeNumber([context JSGlobalContextRef], value) inContext:context]; +} + ++ (JSValue *)valueWithUInt32:(uint32_t)value inContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSValueMakeNumber([context JSGlobalContextRef], value) inContext:context]; +} + ++ (JSValue *)valueWithNewObjectInContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSObjectMake([context JSGlobalContextRef], 0, 0) inContext:context]; +} + ++ (JSValue *)valueWithNewArrayInContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSObjectMakeArray([context JSGlobalContextRef], 0, NULL, 0) inContext:context]; +} + ++ (JSValue *)valueWithNewRegularExpressionFromPattern:(NSString *)pattern flags:(NSString *)flags inContext:(JSContext *)context +{ + JSStringRef patternString = JSStringCreateWithCFString((CFStringRef)pattern); + JSStringRef flagsString = JSStringCreateWithCFString((CFStringRef)flags); + JSValueRef arguments[2] = { JSValueMakeString([context JSGlobalContextRef], patternString), JSValueMakeString([context JSGlobalContextRef], flagsString) }; + JSStringRelease(patternString); + JSStringRelease(flagsString); + + return [JSValue valueWithJSValueRef:JSObjectMakeRegExp([context JSGlobalContextRef], 2, arguments, 0) inContext:context]; +} + ++ (JSValue *)valueWithNewErrorFromMessage:(NSString *)message inContext:(JSContext *)context +{ + JSStringRef string = JSStringCreateWithCFString((CFStringRef)message); + JSValueRef argument = JSValueMakeString([context JSGlobalContextRef], string); + JSStringRelease(string); + + return [JSValue valueWithJSValueRef:JSObjectMakeError([context JSGlobalContextRef], 1, &argument, 0) inContext:context]; +} + ++ (JSValue *)valueWithNullInContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSValueMakeNull([context JSGlobalContextRef]) inContext:context]; +} + ++ (JSValue *)valueWithUndefinedInContext:(JSContext *)context +{ + return [JSValue valueWithJSValueRef:JSValueMakeUndefined([context JSGlobalContextRef]) inContext:context]; +} + +- (id)toObject +{ + return valueToObject(_context, m_value); +} + +- (id)toObjectOfClass:(Class)expectedClass +{ + id result = [self toObject]; + return [result isKindOfClass:expectedClass] ? result : nil; +} + +- (BOOL)toBool +{ + return JSValueToBoolean([_context JSGlobalContextRef], m_value); +} + +- (double)toDouble +{ + JSValueRef exception = 0; + double result = JSValueToNumber([_context JSGlobalContextRef], m_value, &exception); + if (exception) { + [_context notifyException:exception]; + return std::numeric_limits::quiet_NaN(); + } + + return result; +} + +- (int32_t)toInt32 +{ + return JSC::toInt32([self toDouble]); +} + +- (uint32_t)toUInt32 +{ + return JSC::toUInt32([self toDouble]); +} + +- (NSNumber *)toNumber +{ + JSValueRef exception = 0; + id result = valueToNumber([_context JSGlobalContextRef], m_value, &exception); + if (exception) + [_context notifyException:exception]; + return result; +} + +- (NSString *)toString +{ + JSValueRef exception = 0; + id result = valueToString([_context JSGlobalContextRef], m_value, &exception); + if (exception) + [_context notifyException:exception]; + return result; +} + +- (NSDate *)toDate +{ + JSValueRef exception = 0; + id result = valueToDate([_context JSGlobalContextRef], m_value, &exception); + if (exception) + [_context notifyException:exception]; + return result; +} + +- (NSArray *)toArray +{ + JSValueRef exception = 0; + id result = valueToArray([_context JSGlobalContextRef], m_value, &exception); + if (exception) + [_context notifyException:exception]; + return result; +} + +- (NSDictionary *)toDictionary +{ + JSValueRef exception = 0; + id result = valueToDictionary([_context JSGlobalContextRef], m_value, &exception); + if (exception) + [_context notifyException:exception]; + return result; +} + +- (JSValue *)valueForProperty:(NSString *)propertyName +{ + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName); + JSValueRef result = JSObjectGetProperty([_context JSGlobalContextRef], object, name, &exception); + JSStringRelease(name); + if (exception) + return [_context valueFromNotifyException:exception]; + + return [JSValue valueWithJSValueRef:result inContext:_context]; +} + +- (void)setValue:(id)value forProperty:(NSString *)propertyName +{ + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) { + [_context notifyException:exception]; + return; + } + + JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName); + JSObjectSetProperty([_context JSGlobalContextRef], object, name, objectToValue(_context, value), 0, &exception); + JSStringRelease(name); + if (exception) { + [_context notifyException:exception]; + return; + } +} + +- (BOOL)deleteProperty:(NSString *)propertyName +{ + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) + return [_context boolFromNotifyException:exception]; + + JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName); + BOOL result = JSObjectDeleteProperty([_context JSGlobalContextRef], object, name, &exception); + JSStringRelease(name); + if (exception) + return [_context boolFromNotifyException:exception]; + + return result; +} + +- (BOOL)hasProperty:(NSString *)propertyName +{ + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) + return [_context boolFromNotifyException:exception]; + + JSStringRef name = JSStringCreateWithCFString((CFStringRef)propertyName); + BOOL result = JSObjectHasProperty([_context JSGlobalContextRef], object, name); + JSStringRelease(name); + return result; +} + +- (void)defineProperty:(NSString *)property descriptor:(id)descriptor +{ + [[_context globalObject][@"Object"] invokeMethod:@"defineProperty" withArguments:@[ self, property, descriptor ]]; +} + +- (JSValue *)valueAtIndex:(NSUInteger)index +{ + // Properties that are higher than an unsigned value can hold are converted to a double then inserted as a normal property. + // Indices that are bigger than the max allowed index size (UINT_MAX - 1) will be handled internally in get(). + if (index != (unsigned)index) + return [self valueForProperty:[[JSValue valueWithDouble:index inContext:_context] toString]]; + + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + JSValueRef result = JSObjectGetPropertyAtIndex([_context JSGlobalContextRef], object, (unsigned)index, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + return [JSValue valueWithJSValueRef:result inContext:_context]; +} + +- (void)setValue:(id)value atIndex:(NSUInteger)index +{ + // Properties that are higher than an unsigned value can hold are converted to a double, then inserted as a normal property. + // Indices that are bigger than the max allowed index size (UINT_MAX - 1) will be handled internally in putByIndex(). + if (index != (unsigned)index) + return [self setValue:value forProperty:[[JSValue valueWithDouble:index inContext:_context] toString]]; + + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) { + [_context notifyException:exception]; + return; + } + + JSObjectSetPropertyAtIndex([_context JSGlobalContextRef], object, (unsigned)index, objectToValue(_context, value), &exception); + if (exception) { + [_context notifyException:exception]; + return; + } +} + +- (BOOL)isUndefined +{ + return JSValueIsUndefined([_context JSGlobalContextRef], m_value); +} + +- (BOOL)isNull +{ + return JSValueIsNull([_context JSGlobalContextRef], m_value); +} + +- (BOOL)isBoolean +{ + return JSValueIsBoolean([_context JSGlobalContextRef], m_value); +} + +- (BOOL)isNumber +{ + return JSValueIsNumber([_context JSGlobalContextRef], m_value); +} + +- (BOOL)isString +{ + return JSValueIsString([_context JSGlobalContextRef], m_value); +} + +- (BOOL)isObject +{ + return JSValueIsObject([_context JSGlobalContextRef], m_value); +} + +- (BOOL)isEqualToObject:(id)value +{ + return JSValueIsStrictEqual([_context JSGlobalContextRef], m_value, objectToValue(_context, value)); +} + +- (BOOL)isEqualWithTypeCoercionToObject:(id)value +{ + JSValueRef exception = 0; + BOOL result = JSValueIsEqual([_context JSGlobalContextRef], m_value, objectToValue(_context, value), &exception); + if (exception) + return [_context boolFromNotifyException:exception]; + + return result; +} + +- (BOOL)isInstanceOf:(id)value +{ + JSValueRef exception = 0; + JSObjectRef constructor = JSValueToObject([_context JSGlobalContextRef], objectToValue(_context, value), &exception); + if (exception) + return [_context boolFromNotifyException:exception]; + + BOOL result = JSValueIsInstanceOfConstructor([_context JSGlobalContextRef], m_value, constructor, &exception); + if (exception) + return [_context boolFromNotifyException:exception]; + + return result; +} + +- (JSValue *)callWithArguments:(NSArray *)argumentArray +{ + NSUInteger argumentCount = [argumentArray count]; + JSValueRef arguments[argumentCount]; + for (unsigned i = 0; i < argumentCount; ++i) + arguments[i] = objectToValue(_context, [argumentArray objectAtIndex:i]); + + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + JSValueRef result = JSObjectCallAsFunction([_context JSGlobalContextRef], object, 0, argumentCount, arguments, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + return [JSValue valueWithJSValueRef:result inContext:_context]; +} + +- (JSValue *)constructWithArguments:(NSArray *)argumentArray +{ + NSUInteger argumentCount = [argumentArray count]; + JSValueRef arguments[argumentCount]; + for (unsigned i = 0; i < argumentCount; ++i) + arguments[i] = objectToValue(_context, [argumentArray objectAtIndex:i]); + + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + JSObjectRef result = JSObjectCallAsConstructor([_context JSGlobalContextRef], object, argumentCount, arguments, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + return [JSValue valueWithJSValueRef:result inContext:_context]; +} + +- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments +{ + NSUInteger argumentCount = [arguments count]; + JSValueRef argumentArray[argumentCount]; + for (unsigned i = 0; i < argumentCount; ++i) + argumentArray[i] = objectToValue(_context, [arguments objectAtIndex:i]); + + JSValueRef exception = 0; + JSObjectRef thisObject = JSValueToObject([_context JSGlobalContextRef], m_value, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + JSStringRef name = JSStringCreateWithCFString((CFStringRef)method); + JSValueRef function = JSObjectGetProperty([_context JSGlobalContextRef], thisObject, name, &exception); + JSStringRelease(name); + if (exception) + return [_context valueFromNotifyException:exception]; + + JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], function, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + JSValueRef result = JSObjectCallAsFunction([_context JSGlobalContextRef], object, thisObject, argumentCount, argumentArray, &exception); + if (exception) + return [_context valueFromNotifyException:exception]; + + return [JSValue valueWithJSValueRef:result inContext:_context]; +} + +@end + +@implementation JSValue(StructSupport) + +- (CGPoint)toPoint +{ + return (CGPoint){ + static_cast([self[@"x"] toDouble]), + static_cast([self[@"y"] toDouble]) + }; +} + +- (NSRange)toRange +{ + return (NSRange){ + [[self[@"location"] toNumber] unsignedIntegerValue], + [[self[@"length"] toNumber] unsignedIntegerValue] + }; +} + +- (CGRect)toRect +{ + return (CGRect){ + [self toPoint], + [self toSize] + }; +} + +- (CGSize)toSize +{ + return (CGSize){ + static_cast([self[@"width"] toDouble]), + static_cast([self[@"height"] toDouble]) + }; +} + ++ (JSValue *)valueWithPoint:(CGPoint)point inContext:(JSContext *)context +{ + return [JSValue valueWithObject:@{ + @"x":@(point.x), + @"y":@(point.y) + } inContext:context]; +} + ++ (JSValue *)valueWithRange:(NSRange)range inContext:(JSContext *)context +{ + return [JSValue valueWithObject:@{ + @"location":@(range.location), + @"length":@(range.length) + } inContext:context]; +} + ++ (JSValue *)valueWithRect:(CGRect)rect inContext:(JSContext *)context +{ + return [JSValue valueWithObject:@{ + @"x":@(rect.origin.x), + @"y":@(rect.origin.y), + @"width":@(rect.size.width), + @"height":@(rect.size.height) + } inContext:context]; +} + ++ (JSValue *)valueWithSize:(CGSize)size inContext:(JSContext *)context +{ + return [JSValue valueWithObject:@{ + @"width":@(size.width), + @"height":@(size.height) + } inContext:context]; +} + +@end + +@implementation JSValue(SubscriptSupport) + +- (JSValue *)objectForKeyedSubscript:(id)key +{ + if (![key isKindOfClass:[NSString class]]) { + key = [[JSValue valueWithObject:key inContext:_context] toString]; + if (!key) + return [JSValue valueWithUndefinedInContext:_context]; + } + + return [self valueForProperty:(NSString *)key]; +} + +- (JSValue *)objectAtIndexedSubscript:(NSUInteger)index +{ + return [self valueAtIndex:index]; +} + +- (void)setObject:(id)object forKeyedSubscript:(NSObject *)key +{ + if (![key isKindOfClass:[NSString class]]) { + key = [[JSValue valueWithObject:key inContext:_context] toString]; + if (!key) + return; + } + + [self setValue:object forProperty:(NSString *)key]; +} + +- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index +{ + [self setValue:object atIndex:index]; +} + +@end + +inline bool isDate(JSObjectRef object, JSGlobalContextRef context) +{ + JSC::APIEntryShim entryShim(toJS(context)); + return toJS(object)->inherits(JSC::DateInstance::info()); +} + +inline bool isArray(JSObjectRef object, JSGlobalContextRef context) +{ + JSC::APIEntryShim entryShim(toJS(context)); + return toJS(object)->inherits(JSC::JSArray::info()); +} + +@implementation JSValue(Internal) + +enum ConversionType { + ContainerNone, + ContainerArray, + ContainerDictionary +}; + +class JSContainerConvertor { +public: + struct Task { + JSValueRef js; + id objc; + ConversionType type; + }; + + JSContainerConvertor(JSGlobalContextRef context) + : m_context(context) + { + } + + id convert(JSValueRef property); + void add(Task); + Task take(); + bool isWorkListEmpty() const { return !m_worklist.size(); } + +private: + JSGlobalContextRef m_context; + HashMap m_objectMap; + Vector m_worklist; +}; + +inline id JSContainerConvertor::convert(JSValueRef value) +{ + HashMap::iterator iter = m_objectMap.find(value); + if (iter != m_objectMap.end()) + return iter->value; + + Task result = valueToObjectWithoutCopy(m_context, value); + if (result.js) + add(result); + return result.objc; +} + +void JSContainerConvertor::add(Task task) +{ + m_objectMap.add(task.js, task.objc); + if (task.type != ContainerNone) + m_worklist.append(task); +} + +JSContainerConvertor::Task JSContainerConvertor::take() +{ + ASSERT(!isWorkListEmpty()); + Task last = m_worklist.last(); + m_worklist.removeLast(); + return last; +} + +static JSContainerConvertor::Task valueToObjectWithoutCopy(JSGlobalContextRef context, JSValueRef value) +{ + if (!JSValueIsObject(context, value)) { + id primitive; + if (JSValueIsBoolean(context, value)) + primitive = JSValueToBoolean(context, value) ? @YES : @NO; + else if (JSValueIsNumber(context, value)) { + // Normalize the number, so it will unique correctly in the hash map - + // it's nicer not to leak this internal implementation detail! + value = JSValueMakeNumber(context, JSValueToNumber(context, value, 0)); + primitive = [NSNumber numberWithDouble:JSValueToNumber(context, value, 0)]; + } else if (JSValueIsString(context, value)) { + // Would be nice to unique strings, too. + JSStringRef jsstring = JSValueToStringCopy(context, value, 0); + NSString * stringNS = (NSString *)JSStringCopyCFString(kCFAllocatorDefault, jsstring); + JSStringRelease(jsstring); + primitive = [stringNS autorelease]; + } else if (JSValueIsNull(context, value)) + primitive = [NSNull null]; + else { + ASSERT(JSValueIsUndefined(context, value)); + primitive = nil; + } + return (JSContainerConvertor::Task){ value, primitive, ContainerNone }; + } + + JSObjectRef object = JSValueToObject(context, value, 0); + + if (id wrapped = tryUnwrapObjcObject(context, object)) + return (JSContainerConvertor::Task){ object, wrapped, ContainerNone }; + + if (isDate(object, context)) + return (JSContainerConvertor::Task){ object, [NSDate dateWithTimeIntervalSince1970:JSValueToNumber(context, object, 0)], ContainerNone }; + + if (isArray(object, context)) + return (JSContainerConvertor::Task){ object, [NSMutableArray array], ContainerArray }; + + return (JSContainerConvertor::Task){ object, [NSMutableDictionary dictionary], ContainerDictionary }; +} + +static id containerValueToObject(JSGlobalContextRef context, JSContainerConvertor::Task task) +{ + ASSERT(task.type != ContainerNone); + JSContainerConvertor convertor(context); + convertor.add(task); + ASSERT(!convertor.isWorkListEmpty()); + + do { + JSContainerConvertor::Task current = convertor.take(); + ASSERT(JSValueIsObject(context, current.js)); + JSObjectRef js = JSValueToObject(context, current.js, 0); + + if (current.type == ContainerArray) { + ASSERT([current.objc isKindOfClass:[NSMutableArray class]]); + NSMutableArray *array = (NSMutableArray *)current.objc; + + JSStringRef lengthString = JSStringCreateWithUTF8CString("length"); + unsigned length = JSC::toUInt32(JSValueToNumber(context, JSObjectGetProperty(context, js, lengthString, 0), 0)); + JSStringRelease(lengthString); + + for (unsigned i = 0; i < length; ++i) { + id objc = convertor.convert(JSObjectGetPropertyAtIndex(context, js, i, 0)); + [array addObject:objc ? objc : [NSNull null]]; + } + } else { + ASSERT([current.objc isKindOfClass:[NSMutableDictionary class]]); + NSMutableDictionary *dictionary = (NSMutableDictionary *)current.objc; + + JSPropertyNameArrayRef propertyNameArray = JSObjectCopyPropertyNames(context, js); + size_t length = JSPropertyNameArrayGetCount(propertyNameArray); + + for (size_t i = 0; i < length; ++i) { + JSStringRef propertyName = JSPropertyNameArrayGetNameAtIndex(propertyNameArray, i); + if (id objc = convertor.convert(JSObjectGetProperty(context, js, propertyName, 0))) + dictionary[[(NSString *)JSStringCopyCFString(kCFAllocatorDefault, propertyName) autorelease]] = objc; + } + + JSPropertyNameArrayRelease(propertyNameArray); + } + + } while (!convertor.isWorkListEmpty()); + + return task.objc; +} + +id valueToObject(JSContext *context, JSValueRef value) +{ + JSContainerConvertor::Task result = valueToObjectWithoutCopy([context JSGlobalContextRef], value); + if (result.type == ContainerNone) + return result.objc; + return containerValueToObject([context JSGlobalContextRef], result); +} + +id valueToNumber(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception) +{ + ASSERT(!*exception); + if (id wrapped = tryUnwrapObjcObject(context, value)) { + if ([wrapped isKindOfClass:[NSNumber class]]) + return wrapped; + } + + if (JSValueIsBoolean(context, value)) + return JSValueToBoolean(context, value) ? @YES : @NO; + + double result = JSValueToNumber(context, value, exception); + return [NSNumber numberWithDouble:*exception ? std::numeric_limits::quiet_NaN() : result]; +} + +id valueToString(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception) +{ + ASSERT(!*exception); + if (id wrapped = tryUnwrapObjcObject(context, value)) { + if ([wrapped isKindOfClass:[NSString class]]) + return wrapped; + } + + JSStringRef jsstring = JSValueToStringCopy(context, value, exception); + if (*exception) { + ASSERT(!jsstring); + return nil; + } + + NSString *stringNS = CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, jsstring)); + JSStringRelease(jsstring); + return stringNS; +} + +id valueToDate(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception) +{ + ASSERT(!*exception); + if (id wrapped = tryUnwrapObjcObject(context, value)) { + if ([wrapped isKindOfClass:[NSDate class]]) + return wrapped; + } + + double result = JSValueToNumber(context, value, exception); + return *exception ? nil : [NSDate dateWithTimeIntervalSince1970:result]; +} + +id valueToArray(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception) +{ + ASSERT(!*exception); + if (id wrapped = tryUnwrapObjcObject(context, value)) { + if ([wrapped isKindOfClass:[NSArray class]]) + return wrapped; + } + + if (JSValueIsObject(context, value)) + return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableArray array], ContainerArray}); + + if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value))) + *exception = toRef(JSC::createTypeError(toJS(context), "Cannot convert primitive to NSArray")); + return nil; +} + +id valueToDictionary(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception) +{ + ASSERT(!*exception); + if (id wrapped = tryUnwrapObjcObject(context, value)) { + if ([wrapped isKindOfClass:[NSDictionary class]]) + return wrapped; + } + + if (JSValueIsObject(context, value)) + return containerValueToObject(context, (JSContainerConvertor::Task){ value, [NSMutableDictionary dictionary], ContainerDictionary}); + + if (!(JSValueIsNull(context, value) || JSValueIsUndefined(context, value))) + *exception = toRef(JSC::createTypeError(toJS(context), "Cannot convert primitive to NSDictionary")); + return nil; +} + +class ObjcContainerConvertor { +public: + struct Task { + id objc; + JSValueRef js; + ConversionType type; + }; + + ObjcContainerConvertor(JSContext *context) + : m_context(context) + { + } + + JSValueRef convert(id object); + void add(Task); + Task take(); + bool isWorkListEmpty() const { return !m_worklist.size(); } + +private: + JSContext *m_context; + HashMap m_objectMap; + Vector m_worklist; +}; + +JSValueRef ObjcContainerConvertor::convert(id object) +{ + ASSERT(object); + + auto it = m_objectMap.find(object); + if (it != m_objectMap.end()) + return it->value; + + ObjcContainerConvertor::Task task = objectToValueWithoutCopy(m_context, object); + add(task); + return task.js; +} + +void ObjcContainerConvertor::add(ObjcContainerConvertor::Task task) +{ + m_objectMap.add(task.objc, task.js); + if (task.type != ContainerNone) + m_worklist.append(task); +} + +ObjcContainerConvertor::Task ObjcContainerConvertor::take() +{ + ASSERT(!isWorkListEmpty()); + Task last = m_worklist.last(); + m_worklist.removeLast(); + return last; +} + +inline bool isNSBoolean(id object) +{ + ASSERT([@YES class] == [@NO class]); + ASSERT([@YES class] != [NSNumber class]); + ASSERT([[@YES class] isSubclassOfClass:[NSNumber class]]); + return [object isKindOfClass:[@YES class]]; +} + +static ObjcContainerConvertor::Task objectToValueWithoutCopy(JSContext *context, id object) +{ + JSGlobalContextRef contextRef = [context JSGlobalContextRef]; + + if (!object) + return (ObjcContainerConvertor::Task){ object, JSValueMakeUndefined(contextRef), ContainerNone }; + + if (!class_conformsToProtocol(object_getClass(object), getJSExportProtocol())) { + if ([object isKindOfClass:[NSArray class]]) + return (ObjcContainerConvertor::Task){ object, JSObjectMakeArray(contextRef, 0, NULL, 0), ContainerArray }; + + if ([object isKindOfClass:[NSDictionary class]]) + return (ObjcContainerConvertor::Task){ object, JSObjectMake(contextRef, 0, 0), ContainerDictionary }; + + if ([object isKindOfClass:[NSNull class]]) + return (ObjcContainerConvertor::Task){ object, JSValueMakeNull(contextRef), ContainerNone }; + + if ([object isKindOfClass:[JSValue class]]) + return (ObjcContainerConvertor::Task){ object, ((JSValue *)object)->m_value, ContainerNone }; + + if ([object isKindOfClass:[NSString class]]) { + JSStringRef string = JSStringCreateWithCFString((CFStringRef)object); + JSValueRef js = JSValueMakeString(contextRef, string); + JSStringRelease(string); + return (ObjcContainerConvertor::Task){ object, js, ContainerNone }; + } + + if ([object isKindOfClass:[NSNumber class]]) { + if (isNSBoolean(object)) + return (ObjcContainerConvertor::Task){ object, JSValueMakeBoolean(contextRef, [object boolValue]), ContainerNone }; + return (ObjcContainerConvertor::Task){ object, JSValueMakeNumber(contextRef, [object doubleValue]), ContainerNone }; + } + + if ([object isKindOfClass:[NSDate class]]) { + JSValueRef argument = JSValueMakeNumber(contextRef, [object timeIntervalSince1970]); + JSObjectRef result = JSObjectMakeDate(contextRef, 1, &argument, 0); + return (ObjcContainerConvertor::Task){ object, result, ContainerNone }; + } + + if ([object isKindOfClass:[JSManagedValue class]]) { + JSValue *value = [static_cast(object) value]; + if (!value) + return (ObjcContainerConvertor::Task) { object, JSValueMakeUndefined(contextRef), ContainerNone }; + return (ObjcContainerConvertor::Task){ object, value->m_value, ContainerNone }; + } + } + + return (ObjcContainerConvertor::Task){ object, valueInternalValue([context wrapperForObjCObject:object]), ContainerNone }; +} + +JSValueRef objectToValue(JSContext *context, id object) +{ + JSGlobalContextRef contextRef = [context JSGlobalContextRef]; + + ObjcContainerConvertor::Task task = objectToValueWithoutCopy(context, object); + if (task.type == ContainerNone) + return task.js; + + ObjcContainerConvertor convertor(context); + convertor.add(task); + ASSERT(!convertor.isWorkListEmpty()); + + do { + ObjcContainerConvertor::Task current = convertor.take(); + ASSERT(JSValueIsObject(contextRef, current.js)); + JSObjectRef js = JSValueToObject(contextRef, current.js, 0); + + if (current.type == ContainerArray) { + ASSERT([current.objc isKindOfClass:[NSArray class]]); + NSArray *array = (NSArray *)current.objc; + NSUInteger count = [array count]; + for (NSUInteger index = 0; index < count; ++index) + JSObjectSetPropertyAtIndex(contextRef, js, index, convertor.convert([array objectAtIndex:index]), 0); + } else { + ASSERT(current.type == ContainerDictionary); + ASSERT([current.objc isKindOfClass:[NSDictionary class]]); + NSDictionary *dictionary = (NSDictionary *)current.objc; + for (id key in [dictionary keyEnumerator]) { + if ([key isKindOfClass:[NSString class]]) { + JSStringRef propertyName = JSStringCreateWithCFString((CFStringRef)key); + JSObjectSetProperty(contextRef, js, propertyName, convertor.convert([dictionary objectForKey:key]), 0, 0); + JSStringRelease(propertyName); + } + } + } + + } while (!convertor.isWorkListEmpty()); + + return task.js; +} + +JSValueRef valueInternalValue(JSValue * value) +{ + return value->m_value; +} + ++ (JSValue *)valueWithJSValueRef:(JSValueRef)value inContext:(JSContext *)context +{ + return [context wrapperForJSObject:value]; +} + +- (JSValue *)init +{ + return nil; +} + +- (JSValue *)initWithValue:(JSValueRef)value inContext:(JSContext *)context +{ + if (!value || !context) + return nil; + + self = [super init]; + if (!self) + return nil; + + _context = [context retain]; + m_value = value; + JSValueProtect([_context JSGlobalContextRef], m_value); + return self; +} + +struct StructTagHandler { + SEL typeToValueSEL; + SEL valueToTypeSEL; +}; +typedef HashMap StructHandlers; + +static StructHandlers* createStructHandlerMap() +{ + StructHandlers* structHandlers = new StructHandlers(); + + size_t valueWithXinContextLength = strlen("valueWithX:inContext:"); + size_t toXLength = strlen("toX"); + + // Step 1: find all valueWith:inContext: class methods in JSValue. + forEachMethodInClass(object_getClass([JSValue class]), ^(Method method){ + SEL selector = method_getName(method); + const char* name = sel_getName(selector); + size_t nameLength = strlen(name); + // Check for valueWith:context: + if (nameLength < valueWithXinContextLength || memcmp(name, "valueWith", 9) || memcmp(name + nameLength - 11, ":inContext:", 11)) + return; + // Check for [ id, SEL, , ] + if (method_getNumberOfArguments(method) != 4) + return; + char idType[3]; + // Check 2nd argument type is "@" + char* secondType = method_copyArgumentType(method, 3); + if (strcmp(secondType, "@") != 0) { + free(secondType); + return; + } + free(secondType); + // Check result type is also "@" + method_getReturnType(method, idType, 3); + if (strcmp(idType, "@") != 0) + return; + char* type = method_copyArgumentType(method, 2); + structHandlers->add(StringImpl::create(type), (StructTagHandler){ selector, 0 }); + free(type); + }); + + // Step 2: find all to instance methods in JSValue. + forEachMethodInClass([JSValue class], ^(Method method){ + SEL selector = method_getName(method); + const char* name = sel_getName(selector); + size_t nameLength = strlen(name); + // Check for to + if (nameLength < toXLength || memcmp(name, "to", 2)) + return; + // Check for [ id, SEL ] + if (method_getNumberOfArguments(method) != 2) + return; + // Try to find a matching valueWith:context: method. + char* type = method_copyReturnType(method); + + StructHandlers::iterator iter = structHandlers->find(type); + free(type); + if (iter == structHandlers->end()) + return; + StructTagHandler& handler = iter->value; + + // check that strlen() == strlen() + const char* valueWithName = sel_getName(handler.typeToValueSEL); + size_t valueWithLength = strlen(valueWithName); + if (valueWithLength - valueWithXinContextLength != nameLength - toXLength) + return; + // Check that == + if (memcmp(valueWithName + 9, name + 2, nameLength - toXLength - 1)) + return; + handler.valueToTypeSEL = selector; + }); + + // Step 3: clean up - remove entries where we found prospective valueWith:inContext: conversions, but no matching to methods. + typedef HashSet RemoveSet; + RemoveSet removeSet; + for (StructHandlers::iterator iter = structHandlers->begin(); iter != structHandlers->end(); ++iter) { + StructTagHandler& handler = iter->value; + if (!handler.valueToTypeSEL) + removeSet.add(iter->key); + } + + for (RemoveSet::iterator iter = removeSet.begin(); iter != removeSet.end(); ++iter) + structHandlers->remove(*iter); + + return structHandlers; +} + +static StructTagHandler* handerForStructTag(const char* encodedType) +{ + static SpinLock handerForStructTagLock = SPINLOCK_INITIALIZER; + SpinLockHolder lockHolder(&handerForStructTagLock); + + static StructHandlers* structHandlers = createStructHandlerMap(); + + StructHandlers::iterator iter = structHandlers->find(encodedType); + if (iter == structHandlers->end()) + return 0; + return &iter->value; +} + ++ (SEL)selectorForStructToValue:(const char *)structTag +{ + StructTagHandler* handler = handerForStructTag(structTag); + return handler ? handler->typeToValueSEL : nil; +} + ++ (SEL)selectorForValueToStruct:(const char *)structTag +{ + StructTagHandler* handler = handerForStructTag(structTag); + return handler ? handler->valueToTypeSEL : nil; +} + +- (void)dealloc +{ + JSValueUnprotect([_context JSGlobalContextRef], m_value); + [_context release]; + _context = nil; + [super dealloc]; +} + +- (NSString *)description +{ + if (id wrapped = tryUnwrapObjcObject([_context JSGlobalContextRef], m_value)) + return [wrapped description]; + return [self toString]; +} + +NSInvocation *typeToValueInvocationFor(const char* encodedType) +{ + SEL selector = [JSValue selectorForStructToValue:encodedType]; + if (!selector) + return 0; + + const char* methodTypes = method_getTypeEncoding(class_getClassMethod([JSValue class], selector)); + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:methodTypes]]; + [invocation setSelector:selector]; + return invocation; +} + +NSInvocation *valueToTypeInvocationFor(const char* encodedType) +{ + SEL selector = [JSValue selectorForValueToStruct:encodedType]; + if (!selector) + return 0; + + const char* methodTypes = method_getTypeEncoding(class_getInstanceMethod([JSValue class], selector)); + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:methodTypes]]; + [invocation setSelector:selector]; + return invocation; +} + +@end + +#endif diff --git a/JavaScriptCore/API/JSValueInternal.h b/JavaScriptCore/API/JSValueInternal.h new file mode 100644 index 00000000..4f1a8f69 --- /dev/null +++ b/JavaScriptCore/API/JSValueInternal.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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 JSValueInternal_h +#define JSValueInternal_h + +#import +#import + +#if JSC_OBJC_API_ENABLED + +@interface JSValue(Internal) + +JSValueRef valueInternalValue(JSValue *); + +- (JSValue *)initWithValue:(JSValueRef)value inContext:(JSContext *)context; + +JSValueRef objectToValue(JSContext *, id); +id valueToObject(JSContext *, JSValueRef); +id valueToNumber(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToString(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToDate(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToArray(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToDictionary(JSGlobalContextRef, JSValueRef, JSValueRef* exception); + ++ (SEL)selectorForStructToValue:(const char *)structTag; ++ (SEL)selectorForValueToStruct:(const char *)structTag; + +@end + +NSInvocation *typeToValueInvocationFor(const char* encodedType); +NSInvocation *valueToTypeInvocationFor(const char* encodedType); + +#endif + +#endif // JSValueInternal_h diff --git a/JavaScriptCore/API/JSValueRef.cpp b/JavaScriptCore/API/JSValueRef.cpp index 9b7268a2..eb99f5dd 100644 --- a/JavaScriptCore/API/JSValueRef.cpp +++ b/JavaScriptCore/API/JSValueRef.cpp @@ -28,26 +28,45 @@ #include "APICast.h" #include "APIShims.h" +#include "JSAPIWrapperObject.h" +#include "JSCJSValue.h" #include "JSCallbackObject.h" - -#include -#include -#include -#include -#include -#include -#include -#include +#include "JSGlobalObject.h" +#include "JSONObject.h" +#include "JSString.h" +#include "LiteralParser.h" +#include "Operations.h" +#include "Protect.h" #include #include +#include #include // for std::min +#if PLATFORM(MAC) +#include +#endif + using namespace JSC; +#if PLATFORM(MAC) +static bool evernoteHackNeeded() +{ + static const int32_t webkitLastVersionWithEvernoteHack = 35133959; + static bool hackNeeded = CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote")) + && NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack; + + return hackNeeded; +} +#endif + ::JSType JSValueGetType(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return kJSTypeUndefined; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -69,6 +88,10 @@ ::JSType JSValueGetType(JSContextRef ctx, JSValueRef value) bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -78,6 +101,10 @@ bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value) bool JSValueIsNull(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -87,6 +114,10 @@ bool JSValueIsNull(JSContextRef ctx, JSValueRef value) bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -96,6 +127,10 @@ bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -105,6 +140,10 @@ bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) bool JSValueIsString(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -114,6 +153,10 @@ bool JSValueIsString(JSContextRef ctx, JSValueRef value) bool JSValueIsObject(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -123,22 +166,34 @@ bool JSValueIsObject(JSContextRef ctx, JSValueRef value) bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) { + if (!ctx || !jsClass) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSValue jsValue = toJS(exec, value); if (JSObject* o = jsValue.getObject()) { - if (o->inherits(&JSCallbackObject::s_info)) + if (o->inherits(JSCallbackObject::info())) return jsCast*>(o)->inherits(jsClass); - if (o->inherits(&JSCallbackObject::s_info)) - return jsCast*>(o)->inherits(jsClass); + if (o->inherits(JSCallbackObject::info())) + return jsCast*>(o)->inherits(jsClass); +#if JSC_OBJC_API_ENABLED + if (o->inherits(JSCallbackObject::info())) + return jsCast*>(o)->inherits(jsClass); +#endif } return false; } bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -156,6 +211,10 @@ bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* ex bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -167,6 +226,10 @@ bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b) bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -175,7 +238,7 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject JSObject* jsConstructor = toJS(constructor); if (!jsConstructor->structure()->typeInfo().implementsHasInstance()) return false; - bool result = jsConstructor->methodTable()->hasInstance(jsConstructor, exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown + bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); @@ -186,6 +249,10 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject JSValueRef JSValueMakeUndefined(JSContextRef ctx) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -194,6 +261,10 @@ JSValueRef JSValueMakeUndefined(JSContextRef ctx) JSValueRef JSValueMakeNull(JSContextRef ctx) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -202,6 +273,10 @@ JSValueRef JSValueMakeNull(JSContextRef ctx) JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -210,45 +285,62 @@ JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value) JSValueRef JSValueMakeNumber(JSContextRef ctx, double value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); // Our JSValue representation relies on a standard bit pattern for NaN. NaNs // generated internally to JavaScriptCore naturally have that representation, // but an external NaN might not. - if (isnan(value)) - value = std::numeric_limits::quiet_NaN(); + if (std::isnan(value)) + value = QNaN; return toRef(exec, jsNumber(value)); } JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - return toRef(exec, jsString(exec, string->ustring())); + return toRef(exec, jsString(exec, string->string())); } JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - UString str = string->ustring(); - if (str.is8Bit()) { - LiteralParser parser(exec, str.characters8(), str.length(), StrictJSON); + String str = string->string(); + unsigned length = str.length(); + if (length && str.is8Bit()) { + LiteralParser parser(exec, str.characters8(), length, StrictJSON); return toRef(exec, parser.tryLiteralParse()); } - LiteralParser parser(exec, str.characters16(), str.length(), StrictJSON); + LiteralParser parser(exec, str.characters(), length, StrictJSON); return toRef(exec, parser.tryLiteralParse()); } JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsigned indent, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSValue value = toJS(exec, apiValue); - UString result = JSONStringify(exec, value, indent); + String result = JSONStringify(exec, value, indent); if (exception) *exception = 0; if (exec->hadException()) { @@ -262,6 +354,10 @@ JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsig bool JSValueToBoolean(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -271,6 +367,10 @@ bool JSValueToBoolean(JSContextRef ctx, JSValueRef value) double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return QNaN; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -281,13 +381,17 @@ double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception if (exception) *exception = toRef(exec, exec->exception()); exec->clearException(); - number = std::numeric_limits::quiet_NaN(); + number = QNaN; } return number; } JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -305,6 +409,10 @@ JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -322,6 +430,10 @@ JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exce void JSValueProtect(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); @@ -331,6 +443,11 @@ void JSValueProtect(JSContextRef ctx, JSValueRef value) void JSValueUnprotect(JSContextRef ctx, JSValueRef value) { +#if PLATFORM(MAC) + if ((!value || !ctx) && evernoteHackNeeded()) + return; +#endif + ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); diff --git a/JavaScriptCore/API/JSValueRef.h b/JavaScriptCore/API/JSValueRef.h index 4186db82..97385c01 100644 --- a/JavaScriptCore/API/JSValueRef.h +++ b/JavaScriptCore/API/JSValueRef.h @@ -63,7 +63,7 @@ extern "C" { @param value The JSValue whose type you want to obtain. @result A value of type JSType that identifies value's type. */ -JS_EXPORT JSType JSValueGetType(JSContextRef ctx, JSValueRef value); +JS_EXPORT JSType JSValueGetType(JSContextRef ctx, JSValueRef); /*! @function @@ -218,7 +218,7 @@ JS_EXPORT JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string); @param string The JSString containing the JSON string to be parsed. @result A JSValue containing the parsed value, or NULL if the input is invalid. */ -JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) AVAILABLE_AFTER_WEBKIT_VERSION_4_0; +JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) CF_AVAILABLE(10_7, 7_0); /*! @function @@ -229,7 +229,7 @@ JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef str @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. @result A JSString with the result of serialization, or NULL if an exception is thrown. */ -JS_EXPORT JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef value, unsigned indent, JSValueRef* exception) AVAILABLE_AFTER_WEBKIT_VERSION_4_0; +JS_EXPORT JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef value, unsigned indent, JSValueRef* exception) CF_AVAILABLE(10_7, 7_0); /* Converting to primitive values */ diff --git a/JavaScriptCore/API/JSVirtualMachine.h b/JavaScriptCore/API/JSVirtualMachine.h new file mode 100644 index 00000000..dc9becba --- /dev/null +++ b/JavaScriptCore/API/JSVirtualMachine.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 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. + */ + +#import + +#if JSC_OBJC_API_ENABLED + +/*! +@interface +@discussion An instance of JSVirtualMachine represents a single JavaScript "object space" + or set of execution resources. Thread safety is supported by locking the + virtual machine, with concurrent JavaScript execution supported by allocating + separate instances of JSVirtualMachine. +*/ +#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 +NS_CLASS_AVAILABLE(10_9, 7_0) +#else +OBJC_VISIBLE +#endif +@interface JSVirtualMachine : NSObject + +/*! +@methodgroup Creating New Virtual Machines +*/ +/*! +@method +@abstract Create a new JSVirtualMachine. +*/ +- (instancetype)init; + +/*! +@methodgroup Memory Management +*/ +/*! +@method +@abstract Notify the JSVirtualMachine of an external object relationship. +@discussion Allows clients of JSVirtualMachine to make the JavaScript runtime aware of + arbitrary external Objective-C object graphs. The runtime can then use + this information to retain any JavaScript values that are referenced + from somewhere in said object graph. + + For correct behavior clients must make their external object graphs + reachable from within the JavaScript runtime. If an Objective-C object is + reachable from within the JavaScript runtime, all managed references + transitively reachable from it as recorded using + -addManagedReference:withOwner: will be scanned by the garbage collector. +@param object The object that the owner points to. +@param owner The object that owns the pointed to object. +*/ +- (void)addManagedReference:(id)object withOwner:(id)owner; + +/*! +@method +@abstract Notify the JSVirtualMachine that a previous object relationship no longer exists. +@discussion The JavaScript runtime will continue to scan any references that were + reported to it by -addManagedReference:withOwner: until those references are removed. +@param object The object that was formerly owned. +@param owner The former owner. +*/ +- (void)removeManagedReference:(id)object withOwner:(id)owner; + +@end + +#endif diff --git a/JavaScriptCore/API/JSVirtualMachine.mm b/JavaScriptCore/API/JSVirtualMachine.mm new file mode 100644 index 00000000..0222e320 --- /dev/null +++ b/JavaScriptCore/API/JSVirtualMachine.mm @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2013 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" + +#import "JavaScriptCore.h" + +#if JSC_OBJC_API_ENABLED + +#import "APICast.h" +#import "APIShims.h" +#import "JSVirtualMachine.h" +#import "JSVirtualMachineInternal.h" +#import "JSWrapperMap.h" +#import "SlotVisitorInlines.h" + +static NSMapTable *globalWrapperCache = 0; + +static Mutex& wrapperCacheLock() +{ + DEFINE_STATIC_LOCAL(Mutex, mutex, ()); + return mutex; +} + +static void initWrapperCache() +{ + ASSERT(!globalWrapperCache); + NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality; + NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; + globalWrapperCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; +} + +static NSMapTable *wrapperCache() +{ + if (!globalWrapperCache) + initWrapperCache(); + return globalWrapperCache; +} + +@interface JSVMWrapperCache : NSObject ++ (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group; ++ (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group; +@end + +@implementation JSVMWrapperCache + ++ (void)addWrapper:(JSVirtualMachine *)wrapper forJSContextGroupRef:(JSContextGroupRef)group +{ + MutexLocker locker(wrapperCacheLock()); + NSMapInsert(wrapperCache(), group, wrapper); +} + ++ (JSVirtualMachine *)wrapperForJSContextGroupRef:(JSContextGroupRef)group +{ + MutexLocker locker(wrapperCacheLock()); + return static_cast(NSMapGet(wrapperCache(), group)); +} + +@end + +@implementation JSVirtualMachine { + JSContextGroupRef m_group; + NSMapTable *m_contextCache; + NSMapTable *m_externalObjectGraph; +} + +- (instancetype)init +{ + JSContextGroupRef group = JSContextGroupCreate(); + self = [self initWithContextGroupRef:group]; + // The extra JSContextGroupRetain is balanced here. + JSContextGroupRelease(group); + return self; +} + +- (instancetype)initWithContextGroupRef:(JSContextGroupRef)group +{ + self = [super init]; + if (!self) + return nil; + + m_group = JSContextGroupRetain(group); + + NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality; + NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; + m_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; + + NSPointerFunctionsOptions weakIDOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; + NSPointerFunctionsOptions strongIDOptions = NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality; + m_externalObjectGraph = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:strongIDOptions capacity:0]; + + [JSVMWrapperCache addWrapper:self forJSContextGroupRef:group]; + + return self; +} + +- (void)dealloc +{ + JSContextGroupRelease(m_group); + [m_contextCache release]; + [m_externalObjectGraph release]; + [super dealloc]; +} + +static id getInternalObjcObject(id object) +{ + if ([object isKindOfClass:[JSManagedValue class]]) { + JSValue* value = [static_cast(object) value]; + id temp = tryUnwrapObjcObject([value.context JSGlobalContextRef], [value JSValueRef]); + if (temp) + return temp; + return object; + } + + if ([object isKindOfClass:[JSValue class]]) { + JSValue *value = static_cast(object); + object = tryUnwrapObjcObject([value.context JSGlobalContextRef], [value JSValueRef]); + } + + return object; +} + +- (void)addManagedReference:(id)object withOwner:(id)owner +{ + object = getInternalObjcObject(object); + owner = getInternalObjcObject(owner); + + if (!object || !owner) + return; + + JSC::APIEntryShim shim(toJS(m_group)); + + NSMapTable *ownedObjects = [m_externalObjectGraph objectForKey:owner]; + if (!ownedObjects) { + NSPointerFunctionsOptions weakIDOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; + NSPointerFunctionsOptions integerOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsIntegerPersonality; + ownedObjects = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:integerOptions capacity:1]; + + [m_externalObjectGraph setObject:ownedObjects forKey:owner]; + [ownedObjects release]; + } + NSMapInsert(ownedObjects, object, reinterpret_cast(reinterpret_cast(NSMapGet(ownedObjects, object)) + 1)); +} + +- (void)removeManagedReference:(id)object withOwner:(id)owner +{ + object = getInternalObjcObject(object); + owner = getInternalObjcObject(owner); + + if (!object || !owner) + return; + + JSC::APIEntryShim shim(toJS(m_group)); + + NSMapTable *ownedObjects = [m_externalObjectGraph objectForKey:owner]; + if (!ownedObjects) + return; + + size_t count = reinterpret_cast(NSMapGet(ownedObjects, object)); + if (count > 1) { + NSMapInsert(ownedObjects, object, reinterpret_cast(count - 1)); + return; + } + + if (count == 1) + NSMapRemove(ownedObjects, object); + + if (![ownedObjects count]) + [m_externalObjectGraph removeObjectForKey:owner]; +} + +@end + +@implementation JSVirtualMachine(Internal) + +JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine) +{ + return virtualMachine->m_group; +} + ++ (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group +{ + JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:group]; + if (!virtualMachine) + virtualMachine = [[[JSVirtualMachine alloc] initWithContextGroupRef:group] autorelease]; + return virtualMachine; +} + +- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext +{ + return static_cast(NSMapGet(m_contextCache, globalContext)); +} + +- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext +{ + NSMapInsert(m_contextCache, globalContext, wrapper); +} + +- (NSMapTable *)externalObjectGraph +{ + return m_externalObjectGraph; +} + +@end + +void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root) +{ + @autoreleasepool { + JSVirtualMachine *virtualMachine = [JSVMWrapperCache wrapperForJSContextGroupRef:toRef(&vm)]; + if (!virtualMachine) + return; + NSMapTable *externalObjectGraph = [virtualMachine externalObjectGraph]; + Vector stack; + stack.append(root); + while (!stack.isEmpty()) { + void* nextRoot = stack.last(); + stack.removeLast(); + if (visitor.containsOpaqueRootTriState(nextRoot) == TrueTriState) + continue; + visitor.addOpaqueRoot(nextRoot); + + NSMapTable *ownedObjects = [externalObjectGraph objectForKey:static_cast(nextRoot)]; + id ownedObject; + NSEnumerator *enumerator = [ownedObjects keyEnumerator]; + while ((ownedObject = [enumerator nextObject])) { + ASSERT(reinterpret_cast(NSMapGet(ownedObjects, ownedObject)) == 1); + stack.append(static_cast(ownedObject)); + } + } + } +} + +#endif + diff --git a/JavaScriptCore/API/JSVirtualMachineInternal.h b/JavaScriptCore/API/JSVirtualMachineInternal.h new file mode 100644 index 00000000..72922656 --- /dev/null +++ b/JavaScriptCore/API/JSVirtualMachineInternal.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 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 JSVirtualMachineInternal_h +#define JSVirtualMachineInternal_h + +#import + +#if JSC_OBJC_API_ENABLED + +namespace JSC { +class VM; +class SlotVisitor; +} + +#if defined(__OBJC__) +@interface JSVirtualMachine(Internal) + +JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *); + ++ (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group; + +- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext; +- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext; + +- (NSMapTable *)externalObjectGraph; + +@end +#endif // defined(__OBJC__) + +void scanExternalObjectGraph(JSC::VM&, JSC::SlotVisitor&, void* root); + +#endif + +#endif // JSVirtualMachineInternal_h diff --git a/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp b/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp index bdd56f60..6f9e457e 100644 --- a/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp +++ b/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp @@ -28,9 +28,11 @@ #include "APICast.h" #include "APIShims.h" +#include "JSCJSValue.h" #include "JSCallbackObject.h" -#include "JSValue.h" #include "JSWeakObjectMapRefInternal.h" +#include "Operations.h" +#include "Weak.h" #include #include @@ -52,17 +54,25 @@ JSWeakObjectMapRef JSWeakObjectMapCreate(JSContextRef context, void* privateData void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSObjectRef object) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); JSObject* obj = toJS(object); if (!obj) return; - ASSERT(obj->inherits(&JSCallbackObject::s_info) || obj->inherits(&JSCallbackObject::s_info)); - map->map().set(exec->globalData(), key, obj); + ASSERT(obj->inherits(JSCallbackObject::info()) || obj->inherits(JSCallbackObject::info())); + map->map().set(key, obj); } JSObjectRef JSWeakObjectMapGet(JSContextRef ctx, JSWeakObjectMapRef map, void* key) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); return toRef(jsCast(map->map().get(key))); @@ -70,9 +80,13 @@ JSObjectRef JSWeakObjectMapGet(JSContextRef ctx, JSWeakObjectMapRef map, void* k void JSWeakObjectMapRemove(JSContextRef ctx, JSWeakObjectMapRef map, void* key) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); APIEntryShim entryShim(exec); - map->map().take(key); + map->map().remove(key); } // We need to keep this function in the build to keep the nightlies running. diff --git a/JavaScriptCore/API/JSWrapperMap.h b/JavaScriptCore/API/JSWrapperMap.h new file mode 100644 index 00000000..c20bfb83 --- /dev/null +++ b/JavaScriptCore/API/JSWrapperMap.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 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. + */ + +#import +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +#if JSC_OBJC_API_ENABLED + +@interface JSWrapperMap : NSObject + +- (id)initWithContext:(JSContext *)context; + +- (JSValue *)jsWrapperForObject:(id)object; + +- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value; + +@end + +id tryUnwrapObjcObject(JSGlobalContextRef, JSValueRef); + +bool supportsInitMethodConstructors(); +Protocol *getJSExportProtocol(); +Class getNSBlockClass(); + +#endif diff --git a/JavaScriptCore/API/JSWrapperMap.mm b/JavaScriptCore/API/JSWrapperMap.mm new file mode 100644 index 00000000..2f62fcca --- /dev/null +++ b/JavaScriptCore/API/JSWrapperMap.mm @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2013 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" +#import "JavaScriptCore.h" + +#if JSC_OBJC_API_ENABLED + +#import "APICast.h" +#import "APIShims.h" +#import "JSAPIWrapperObject.h" +#import "JSCallbackObject.h" +#import "JSContextInternal.h" +#import "JSWrapperMap.h" +#import "ObjCCallbackFunction.h" +#import "ObjcRuntimeExtras.h" +#import "Operations.h" +#import "WeakGCMap.h" +#import +#import +#import + +#include + +static const int32_t webkitFirstVersionWithInitConstructorSupport = 0x21A0400; // 538.4.0 + +@class JSObjCClassInfo; + +@interface JSWrapperMap () + +- (JSObjCClassInfo*)classInfoForClass:(Class)cls; + +@end + +// Default conversion of selectors to property names. +// All semicolons are removed, lowercase letters following a semicolon are capitalized. +static NSString *selectorToPropertyName(const char* start) +{ + // Use 'index' to check for colons, if there are none, this is easy! + const char* firstColon = index(start, ':'); + if (!firstColon) + return [NSString stringWithUTF8String:start]; + + // 'header' is the length of string up to the first colon. + size_t header = firstColon - start; + // The new string needs to be long enough to hold 'header', plus the remainder of the string, excluding + // at least one ':', but including a '\0'. (This is conservative if there are more than one ':'). + char* buffer = static_cast(malloc(header + strlen(firstColon + 1) + 1)); + // Copy 'header' characters, set output to point to the end of this & input to point past the first ':'. + memcpy(buffer, start, header); + char* output = buffer + header; + const char* input = start + header + 1; + + // On entry to the loop, we have already skipped over a ':' from the input. + while (true) { + char c; + // Skip over any additional ':'s. We'll leave c holding the next character after the + // last ':', and input pointing past c. + while ((c = *(input++)) == ':'); + // Copy the character, converting to upper case if necessary. + // If the character we copy is '\0', then we're done! + if (!(*(output++) = toupper(c))) + goto done; + // Loop over characters other than ':'. + while ((c = *(input++)) != ':') { + // Copy the character. + // If the character we copy is '\0', then we're done! + if (!(*(output++) = c)) + goto done; + } + // If we get here, we've consumed a ':' - wash, rinse, repeat. + } +done: + NSString *result = [NSString stringWithUTF8String:buffer]; + free(buffer); + return result; +} + +static JSObjectRef makeWrapper(JSContextRef ctx, JSClassRef jsClass, id wrappedObject) +{ + JSC::ExecState* exec = toJS(ctx); + JSC::APIEntryShim entryShim(exec); + + ASSERT(jsClass); + JSC::JSCallbackObject* object = JSC::JSCallbackObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->objcWrapperObjectStructure(), jsClass, 0); + object->setWrappedObject(wrappedObject); + if (JSC::JSObject* prototype = jsClass->prototype(exec)) + object->setPrototype(exec->vm(), prototype); + + return toRef(object); +} + +// Make an object that is in all ways a completely vanilla JavaScript object, +// other than that it has a native brand set that will be displayed by the default +// Object.prototype.toString conversion. +static JSValue *objectWithCustomBrand(JSContext *context, NSString *brand, Class cls = 0) +{ + JSClassDefinition definition; + definition = kJSClassDefinitionEmpty; + definition.className = [brand UTF8String]; + JSClassRef classRef = JSClassCreate(&definition); + JSObjectRef result = makeWrapper([context JSGlobalContextRef], classRef, cls); + JSClassRelease(classRef); + return [JSValue valueWithJSValueRef:result inContext:context]; +} + +// Look for @optional properties in the prototype containing a selector to property +// name mapping, separated by a __JS_EXPORT_AS__ delimiter. +static NSMutableDictionary *createRenameMap(Protocol *protocol, BOOL isInstanceMethod) +{ + NSMutableDictionary *renameMap = [[NSMutableDictionary alloc] init]; + + forEachMethodInProtocol(protocol, NO, isInstanceMethod, ^(SEL sel, const char*){ + NSString *rename = @(sel_getName(sel)); + NSRange range = [rename rangeOfString:@"__JS_EXPORT_AS__"]; + if (range.location == NSNotFound) + return; + NSString *selector = [rename substringToIndex:range.location]; + NSUInteger begin = range.location + range.length; + NSUInteger length = [rename length] - begin - 1; + NSString *name = [rename substringWithRange:(NSRange){ begin, length }]; + renameMap[selector] = name; + }); + + return renameMap; +} + +inline void putNonEnumerable(JSValue *base, NSString *propertyName, JSValue *value) +{ + [base defineProperty:propertyName descriptor:@{ + JSPropertyDescriptorValueKey: value, + JSPropertyDescriptorWritableKey: @YES, + JSPropertyDescriptorEnumerableKey: @NO, + JSPropertyDescriptorConfigurableKey: @YES + }]; +} + +static bool isInitFamilyMethod(NSString *name) +{ + NSUInteger i = 0; + + // Skip over initial underscores. + for (; i < [name length]; ++i) { + if ([name characterAtIndex:i] != '_') + break; + } + + // Match 'init'. + NSUInteger initIndex = 0; + NSString* init = @"init"; + for (; i < [name length] && initIndex < [init length]; ++i, ++initIndex) { + if ([name characterAtIndex:i] != [init characterAtIndex:initIndex]) + return false; + } + + // We didn't match all of 'init'. + if (initIndex < [init length]) + return false; + + // If we're at the end or the next character is a capital letter then this is an init-family selector. + return i == [name length] || [[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[name characterAtIndex:i]]; +} + +static bool shouldSkipMethodWithName(NSString *name) +{ + // For clients that don't support init-based constructors just copy + // over the init method as we would have before. + if (!supportsInitMethodConstructors()) + return false; + + // Skip over init family methods because we handle those specially + // for the purposes of hooking up the constructor correctly. + return isInitFamilyMethod(name); +} + +// This method will iterate over the set of required methods in the protocol, and: +// * Determine a property name (either via a renameMap or default conversion). +// * If an accessorMap is provided, and contains this name, store the method in the map. +// * Otherwise, if the object doesn't already contain a property with name, create it. +static void copyMethodsToObject(JSContext *context, Class objcClass, Protocol *protocol, BOOL isInstanceMethod, JSValue *object, NSMutableDictionary *accessorMethods = nil) +{ + NSMutableDictionary *renameMap = createRenameMap(protocol, isInstanceMethod); + + forEachMethodInProtocol(protocol, YES, isInstanceMethod, ^(SEL sel, const char* types){ + const char* nameCStr = sel_getName(sel); + NSString *name = @(nameCStr); + + if (shouldSkipMethodWithName(name)) + return; + + if (accessorMethods && accessorMethods[name]) { + JSObjectRef method = objCCallbackFunctionForMethod(context, objcClass, protocol, isInstanceMethod, sel, types); + if (!method) + return; + accessorMethods[name] = [JSValue valueWithJSValueRef:method inContext:context]; + } else { + name = renameMap[name]; + if (!name) + name = selectorToPropertyName(nameCStr); + if ([object hasProperty:name]) + return; + JSObjectRef method = objCCallbackFunctionForMethod(context, objcClass, protocol, isInstanceMethod, sel, types); + if (method) + putNonEnumerable(object, name, [JSValue valueWithJSValueRef:method inContext:context]); + } + }); + + [renameMap release]; +} + +static bool parsePropertyAttributes(objc_property_t property, char*& getterName, char*& setterName) +{ + bool readonly = false; + unsigned attributeCount; + objc_property_attribute_t* attributes = property_copyAttributeList(property, &attributeCount); + if (attributeCount) { + for (unsigned i = 0; i < attributeCount; ++i) { + switch (*(attributes[i].name)) { + case 'G': + getterName = strdup(attributes[i].value); + break; + case 'S': + setterName = strdup(attributes[i].value); + break; + case 'R': + readonly = true; + break; + default: + break; + } + } + free(attributes); + } + return readonly; +} + +static char* makeSetterName(const char* name) +{ + size_t nameLength = strlen(name); + char* setterName = (char*)malloc(nameLength + 5); // "set" Name ":\0" + setterName[0] = 's'; + setterName[1] = 'e'; + setterName[2] = 't'; + setterName[3] = toupper(*name); + memcpy(setterName + 4, name + 1, nameLength - 1); + setterName[nameLength + 3] = ':'; + setterName[nameLength + 4] = '\0'; + return setterName; +} + +static void copyPrototypeProperties(JSContext *context, Class objcClass, Protocol *protocol, JSValue *prototypeValue) +{ + // First gather propreties into this list, then handle the methods (capturing the accessor methods). + struct Property { + const char* name; + char* getterName; + char* setterName; + }; + __block Vector propertyList; + + // Map recording the methods used as getters/setters. + NSMutableDictionary *accessorMethods = [NSMutableDictionary dictionary]; + + // Useful value. + JSValue *undefined = [JSValue valueWithUndefinedInContext:context]; + + forEachPropertyInProtocol(protocol, ^(objc_property_t property){ + char* getterName = 0; + char* setterName = 0; + bool readonly = parsePropertyAttributes(property, getterName, setterName); + const char* name = property_getName(property); + + // Add the names of the getter & setter methods to + if (!getterName) + getterName = strdup(name); + accessorMethods[@(getterName)] = undefined; + if (!readonly) { + if (!setterName) + setterName = makeSetterName(name); + accessorMethods[@(setterName)] = undefined; + } + + // Add the properties to a list. + propertyList.append((Property){ name, getterName, setterName }); + }); + + // Copy methods to the prototype, capturing accessors in the accessorMethods map. + copyMethodsToObject(context, objcClass, protocol, YES, prototypeValue, accessorMethods); + + // Iterate the propertyList & generate accessor properties. + for (size_t i = 0; i < propertyList.size(); ++i) { + Property& property = propertyList[i]; + + JSValue *getter = accessorMethods[@(property.getterName)]; + free(property.getterName); + ASSERT(![getter isUndefined]); + + JSValue *setter = undefined; + if (property.setterName) { + setter = accessorMethods[@(property.setterName)]; + free(property.setterName); + ASSERT(![setter isUndefined]); + } + + [prototypeValue defineProperty:@(property.name) descriptor:@{ + JSPropertyDescriptorGetKey: getter, + JSPropertyDescriptorSetKey: setter, + JSPropertyDescriptorEnumerableKey: @NO, + JSPropertyDescriptorConfigurableKey: @YES + }]; + } +} + +@interface JSObjCClassInfo : NSObject { + JSContext *m_context; + Class m_class; + bool m_block; + JSClassRef m_classRef; + JSC::Weak m_prototype; + JSC::Weak m_constructor; +} + +- (id)initWithContext:(JSContext *)context forClass:(Class)cls superClassInfo:(JSObjCClassInfo*)superClassInfo; +- (JSValue *)wrapperForObject:(id)object; +- (JSValue *)constructor; + +@end + +@implementation JSObjCClassInfo + +- (id)initWithContext:(JSContext *)context forClass:(Class)cls superClassInfo:(JSObjCClassInfo*)superClassInfo +{ + self = [super init]; + if (!self) + return nil; + + const char* className = class_getName(cls); + m_context = context; + m_class = cls; + m_block = [cls isSubclassOfClass:getNSBlockClass()]; + JSClassDefinition definition; + definition = kJSClassDefinitionEmpty; + definition.className = className; + m_classRef = JSClassCreate(&definition); + + [self allocateConstructorAndPrototypeWithSuperClassInfo:superClassInfo]; + + return self; +} + +- (void)dealloc +{ + JSClassRelease(m_classRef); + [super dealloc]; +} + +static JSValue *allocateConstructorForCustomClass(JSContext *context, const char* className, Class cls) +{ + if (!supportsInitMethodConstructors()) + return objectWithCustomBrand(context, [NSString stringWithFormat:@"%sConstructor", className], cls); + + // For each protocol that the class implements, gather all of the init family methods into a hash table. + __block HashMap initTable; + Protocol *exportProtocol = getJSExportProtocol(); + for (Class currentClass = cls; currentClass; currentClass = class_getSuperclass(currentClass)) { + forEachProtocolImplementingProtocol(currentClass, exportProtocol, ^(Protocol *protocol) { + forEachMethodInProtocol(protocol, YES, YES, ^(SEL selector, const char*) { + const char* name = sel_getName(selector); + if (!isInitFamilyMethod(@(name))) + return; + initTable.set(name, protocol); + }); + }); + } + + for (Class currentClass = cls; currentClass; currentClass = class_getSuperclass(currentClass)) { + __block unsigned numberOfInitsFound = 0; + __block SEL initMethod = 0; + __block Protocol *initProtocol = 0; + __block const char* types = 0; + forEachMethodInClass(currentClass, ^(Method method) { + SEL selector = method_getName(method); + const char* name = sel_getName(selector); + auto iter = initTable.find(name); + + if (iter == initTable.end()) + return; + + numberOfInitsFound++; + initMethod = selector; + initProtocol = iter->value; + types = method_getTypeEncoding(method); + }); + + if (!numberOfInitsFound) + continue; + + if (numberOfInitsFound > 1) { + NSLog(@"ERROR: Class %@ exported more than one init family method via JSExport. Class %@ will not have a callable JavaScript constructor function.", cls, cls); + break; + } + + JSObjectRef method = objCCallbackFunctionForInit(context, cls, initProtocol, initMethod, types); + return [JSValue valueWithJSValueRef:method inContext:context]; + } + return objectWithCustomBrand(context, [NSString stringWithFormat:@"%sConstructor", className], cls); +} + +- (void)allocateConstructorAndPrototypeWithSuperClassInfo:(JSObjCClassInfo*)superClassInfo +{ + ASSERT(!m_constructor || !m_prototype); + ASSERT((m_class == [NSObject class]) == !superClassInfo); + if (!superClassInfo) { + JSContextRef cContext = [m_context JSGlobalContextRef]; + JSValue *constructor = m_context[@"Object"]; + if (!m_constructor) + m_constructor = toJS(JSValueToObject(cContext, valueInternalValue(constructor), 0)); + + if (!m_prototype) { + JSValue *prototype = constructor[@"prototype"]; + m_prototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0)); + } + } else { + const char* className = class_getName(m_class); + + // Create or grab the prototype/constructor pair. + JSValue *prototype; + JSValue *constructor; + if (m_prototype) + prototype = [JSValue valueWithJSValueRef:toRef(m_prototype.get()) inContext:m_context]; + else + prototype = objectWithCustomBrand(m_context, [NSString stringWithFormat:@"%sPrototype", className]); + + if (m_constructor) + constructor = [JSValue valueWithJSValueRef:toRef(m_constructor.get()) inContext:m_context]; + else + constructor = allocateConstructorForCustomClass(m_context, className, m_class); + + JSContextRef cContext = [m_context JSGlobalContextRef]; + m_prototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0)); + m_constructor = toJS(JSValueToObject(cContext, valueInternalValue(constructor), 0)); + + putNonEnumerable(prototype, @"constructor", constructor); + putNonEnumerable(constructor, @"prototype", prototype); + + Protocol *exportProtocol = getJSExportProtocol(); + forEachProtocolImplementingProtocol(m_class, exportProtocol, ^(Protocol *protocol){ + copyPrototypeProperties(m_context, m_class, protocol, prototype); + copyMethodsToObject(m_context, m_class, protocol, NO, constructor); + }); + + // Set [Prototype]. + JSObjectSetPrototype([m_context JSGlobalContextRef], toRef(m_prototype.get()), toRef(superClassInfo->m_prototype.get())); + } +} + +- (void)reallocateConstructorAndOrPrototype +{ + [self allocateConstructorAndPrototypeWithSuperClassInfo:[m_context.wrapperMap classInfoForClass:class_getSuperclass(m_class)]]; +} + +- (JSValue *)wrapperForObject:(id)object +{ + ASSERT([object isKindOfClass:m_class]); + ASSERT(m_block == [object isKindOfClass:getNSBlockClass()]); + if (m_block) { + if (JSObjectRef method = objCCallbackFunctionForBlock(m_context, object)) { + JSValue *constructor = [JSValue valueWithJSValueRef:method inContext:m_context]; + JSValue *prototype = [JSValue valueWithNewObjectInContext:m_context]; + putNonEnumerable(constructor, @"prototype", prototype); + putNonEnumerable(prototype, @"constructor", constructor); + return constructor; + } + } + + if (!m_prototype) + [self reallocateConstructorAndOrPrototype]; + ASSERT(!!m_prototype); + + JSObjectRef wrapper = makeWrapper([m_context JSGlobalContextRef], m_classRef, object); + JSObjectSetPrototype([m_context JSGlobalContextRef], wrapper, toRef(m_prototype.get())); + return [JSValue valueWithJSValueRef:wrapper inContext:m_context]; +} + +- (JSValue *)constructor +{ + if (!m_constructor) + [self reallocateConstructorAndOrPrototype]; + ASSERT(!!m_constructor); + return [JSValue valueWithJSValueRef:toRef(m_constructor.get()) inContext:m_context]; +} + +@end + +@implementation JSWrapperMap { + JSContext *m_context; + NSMutableDictionary *m_classMap; + JSC::WeakGCMap m_cachedJSWrappers; + NSMapTable *m_cachedObjCWrappers; +} + +- (id)initWithContext:(JSContext *)context +{ + self = [super init]; + if (!self) + return nil; + + NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality; + NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; + m_cachedObjCWrappers = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; + + m_context = context; + m_classMap = [[NSMutableDictionary alloc] init]; + return self; +} + +- (void)dealloc +{ + [m_cachedObjCWrappers release]; + [m_classMap release]; + [super dealloc]; +} + +- (JSObjCClassInfo*)classInfoForClass:(Class)cls +{ + if (!cls) + return nil; + + // Check if we've already created a JSObjCClassInfo for this Class. + if (JSObjCClassInfo* classInfo = (JSObjCClassInfo*)m_classMap[cls]) + return classInfo; + + // Skip internal classes beginning with '_' - just copy link to the parent class's info. + if ('_' == *class_getName(cls)) + return m_classMap[cls] = [self classInfoForClass:class_getSuperclass(cls)]; + + return m_classMap[cls] = [[[JSObjCClassInfo alloc] initWithContext:m_context forClass:cls superClassInfo:[self classInfoForClass:class_getSuperclass(cls)]] autorelease]; +} + +- (JSValue *)jsWrapperForObject:(id)object +{ + JSC::JSObject* jsWrapper = m_cachedJSWrappers.get(object); + if (jsWrapper) + return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:m_context]; + + JSValue *wrapper; + if (class_isMetaClass(object_getClass(object))) + wrapper = [[self classInfoForClass:(Class)object] constructor]; + else { + JSObjCClassInfo* classInfo = [self classInfoForClass:[object class]]; + wrapper = [classInfo wrapperForObject:object]; + } + + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=105891 + // This general approach to wrapper caching is pretty effective, but there are a couple of problems: + // (1) For immortal objects JSValues will effectively leak and this results in error output being logged - we should avoid adding associated objects to immortal objects. + // (2) A long lived object may rack up many JSValues. When the contexts are released these will unprotect the associated JavaScript objects, + // but still, would probably nicer if we made it so that only one associated object was required, broadcasting object dealloc. + JSC::ExecState* exec = toJS([m_context JSGlobalContextRef]); + jsWrapper = toJS(exec, valueInternalValue(wrapper)).toObject(exec); + m_cachedJSWrappers.set(object, jsWrapper); + return wrapper; +} + +- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value +{ + JSValue *wrapper = static_cast(NSMapGet(m_cachedObjCWrappers, value)); + if (!wrapper) { + wrapper = [[[JSValue alloc] initWithValue:value inContext:m_context] autorelease]; + NSMapInsert(m_cachedObjCWrappers, value, wrapper); + } + return wrapper; +} + +@end + +id tryUnwrapObjcObject(JSGlobalContextRef context, JSValueRef value) +{ + if (!JSValueIsObject(context, value)) + return nil; + JSValueRef exception = 0; + JSObjectRef object = JSValueToObject(context, value, &exception); + ASSERT(!exception); + if (toJS(object)->inherits(JSC::JSCallbackObject::info())) + return (id)JSC::jsCast(toJS(object))->wrappedObject(); + if (id target = tryUnwrapConstructor(object)) + return target; + return nil; +} + +// This class ensures that the JSExport protocol is registered with the runtime. +NS_ROOT_CLASS @interface JSExport +@end +@implementation JSExport +@end + +bool supportsInitMethodConstructors() +{ + static int32_t versionOfLinkTimeLibrary = 0; + if (!versionOfLinkTimeLibrary) + versionOfLinkTimeLibrary = NSVersionOfLinkTimeLibrary("JavaScriptCore"); + return versionOfLinkTimeLibrary >= webkitFirstVersionWithInitConstructorSupport; +} + +Protocol *getJSExportProtocol() +{ + static Protocol *protocol = objc_getProtocol("JSExport"); + return protocol; +} + +Class getNSBlockClass() +{ + static Class cls = objc_getClass("NSBlock"); + return cls; +} + +#endif diff --git a/JavaScriptCore/API/JavaScriptCore.h b/JavaScriptCore/API/JavaScriptCore.h index 87d60185..40bea9c3 100644 --- a/JavaScriptCore/API/JavaScriptCore.h +++ b/JavaScriptCore/API/JavaScriptCore.h @@ -29,4 +29,14 @@ #include #include +#if defined(__OBJC__) && JSC_OBJC_API_ENABLED + +#import "JSContext.h" +#import "JSValue.h" +#import "JSManagedValue.h" +#import "JSVirtualMachine.h" +#import "JSExport.h" + +#endif + #endif /* JavaScriptCore_h */ diff --git a/JavaScriptCore/API/ObjCCallbackFunction.h b/JavaScriptCore/API/ObjCCallbackFunction.h new file mode 100644 index 00000000..046bf650 --- /dev/null +++ b/JavaScriptCore/API/ObjCCallbackFunction.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2013 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 ObjCCallbackFunction_h +#define ObjCCallbackFunction_h + +#include + +#if JSC_OBJC_API_ENABLED + +#import + +#if defined(__OBJC__) +JSObjectRef objCCallbackFunctionForMethod(JSContext *, Class, Protocol *, BOOL isInstanceMethod, SEL, const char* types); +JSObjectRef objCCallbackFunctionForBlock(JSContext *, id); +JSObjectRef objCCallbackFunctionForInit(JSContext *, Class, Protocol *, SEL, const char* types); + +id tryUnwrapConstructor(JSObjectRef); +#endif + +namespace JSC { + +class ObjCCallbackFunctionImpl; + +class ObjCCallbackFunction : public InternalFunction { + friend struct APICallbackFunction; +public: + typedef InternalFunction Base; + + static ObjCCallbackFunction* create(VM&, JSGlobalObject*, const String& name, PassOwnPtr); + static void destroy(JSCell*); + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + ASSERT(globalObject); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + DECLARE_EXPORT_INFO; + + ObjCCallbackFunctionImpl* impl() const { return m_impl.get(); } + +protected: + ObjCCallbackFunction(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, JSObjectCallAsConstructorCallback, PassOwnPtr); + +private: + static CallType getCallData(JSCell*, CallData&); + static ConstructType getConstructData(JSCell*, ConstructData&); + + JSObjectCallAsFunctionCallback functionCallback() { return m_functionCallback; } + JSObjectCallAsConstructorCallback constructCallback() { return m_constructCallback; } + + JSObjectCallAsFunctionCallback m_functionCallback; + JSObjectCallAsConstructorCallback m_constructCallback; + OwnPtr m_impl; +}; + +} // namespace JSC + +#endif + +#endif // ObjCCallbackFunction_h diff --git a/JavaScriptCore/API/ObjCCallbackFunction.mm b/JavaScriptCore/API/ObjCCallbackFunction.mm new file mode 100644 index 00000000..fc00e375 --- /dev/null +++ b/JavaScriptCore/API/ObjCCallbackFunction.mm @@ -0,0 +1,722 @@ +/* + * Copyright (C) 2013 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" +#import "JavaScriptCore.h" + +#if JSC_OBJC_API_ENABLED + +#import "APICallbackFunction.h" +#import "APICast.h" +#import "APIShims.h" +#import "DelayedReleaseScope.h" +#import "Error.h" +#import "JSCJSValueInlines.h" +#import "JSCell.h" +#import "JSCellInlines.h" +#import "JSContextInternal.h" +#import "JSWrapperMap.h" +#import "JSValueInternal.h" +#import "ObjCCallbackFunction.h" +#import "ObjcRuntimeExtras.h" +#import +#import + +class CallbackArgument { +public: + virtual ~CallbackArgument(); + virtual void set(NSInvocation *, NSInteger, JSContext *, JSValueRef, JSValueRef*) = 0; + + OwnPtr m_next; +}; + +CallbackArgument::~CallbackArgument() +{ +} + +class CallbackArgumentBoolean : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override + { + bool value = JSValueToBoolean([context JSGlobalContextRef], argument); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +template +class CallbackArgumentInteger : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + T value = (T)JSC::toInt32(JSValueToNumber([context JSGlobalContextRef], argument, exception)); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +template +class CallbackArgumentDouble : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + T value = (T)JSValueToNumber([context JSGlobalContextRef], argument, exception); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentJSValue : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override + { + JSValue *value = [JSValue valueWithJSValueRef:argument inContext:context]; + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentId : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override + { + id value = valueToObject(context, argument); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentOfClass : public CallbackArgument { +public: + CallbackArgumentOfClass(Class cls) + : CallbackArgument() + , m_class(cls) + { + [m_class retain]; + } + +private: + virtual ~CallbackArgumentOfClass() + { + [m_class release]; + } + + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + JSGlobalContextRef contextRef = [context JSGlobalContextRef]; + + id object = tryUnwrapObjcObject(contextRef, argument); + if (object && [object isKindOfClass:m_class]) { + [invocation setArgument:&object atIndex:argumentNumber]; + return; + } + + if (JSValueIsNull(contextRef, argument) || JSValueIsUndefined(contextRef, argument)) { + object = nil; + [invocation setArgument:&object atIndex:argumentNumber]; + return; + } + + *exception = toRef(JSC::createTypeError(toJS(contextRef), "Argument does not match Objective-C Class")); + } + + Class m_class; +}; + +class CallbackArgumentNSNumber : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + id value = valueToNumber([context JSGlobalContextRef], argument, exception); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentNSString : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + id value = valueToString([context JSGlobalContextRef], argument, exception); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentNSDate : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + id value = valueToDate([context JSGlobalContextRef], argument, exception); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentNSArray : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + id value = valueToArray([context JSGlobalContextRef], argument, exception); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentNSDictionary : public CallbackArgument { + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override + { + id value = valueToDictionary([context JSGlobalContextRef], argument, exception); + [invocation setArgument:&value atIndex:argumentNumber]; + } +}; + +class CallbackArgumentStruct : public CallbackArgument { +public: + CallbackArgumentStruct(NSInvocation *conversionInvocation, const char* encodedType) + : m_conversionInvocation(conversionInvocation) + , m_buffer(encodedType) + { + } + +private: + virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef*) override + { + JSValue *value = [JSValue valueWithJSValueRef:argument inContext:context]; + [m_conversionInvocation invokeWithTarget:value]; + [m_conversionInvocation getReturnValue:m_buffer]; + [invocation setArgument:m_buffer atIndex:argumentNumber]; + } + + RetainPtr m_conversionInvocation; + StructBuffer m_buffer; +}; + +class ArgumentTypeDelegate { +public: + typedef CallbackArgument* ResultType; + + template + static ResultType typeInteger() + { + return new CallbackArgumentInteger; + } + + template + static ResultType typeDouble() + { + return new CallbackArgumentDouble; + } + + static ResultType typeBool() + { + return new CallbackArgumentBoolean; + } + + static ResultType typeVoid() + { + RELEASE_ASSERT_NOT_REACHED(); + return 0; + } + + static ResultType typeId() + { + return new CallbackArgumentId; + } + + static ResultType typeOfClass(const char* begin, const char* end) + { + StringRange copy(begin, end); + Class cls = objc_getClass(copy); + if (!cls) + return 0; + + if (cls == [JSValue class]) + return new CallbackArgumentJSValue; + if (cls == [NSString class]) + return new CallbackArgumentNSString; + if (cls == [NSNumber class]) + return new CallbackArgumentNSNumber; + if (cls == [NSDate class]) + return new CallbackArgumentNSDate; + if (cls == [NSArray class]) + return new CallbackArgumentNSArray; + if (cls == [NSDictionary class]) + return new CallbackArgumentNSDictionary; + + return new CallbackArgumentOfClass(cls); + } + + static ResultType typeBlock(const char*, const char*) + { + return nil; + } + + static ResultType typeStruct(const char* begin, const char* end) + { + StringRange copy(begin, end); + if (NSInvocation *invocation = valueToTypeInvocationFor(copy)) + return new CallbackArgumentStruct(invocation, copy); + return 0; + } +}; + +class CallbackResult { +public: + virtual ~CallbackResult() + { + } + + virtual JSValueRef get(NSInvocation *, JSContext *, JSValueRef*) = 0; +}; + +class CallbackResultVoid : public CallbackResult { + virtual JSValueRef get(NSInvocation *, JSContext *context, JSValueRef*) override + { + return JSValueMakeUndefined([context JSGlobalContextRef]); + } +}; + +class CallbackResultId : public CallbackResult { + virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override + { + id value; + [invocation getReturnValue:&value]; + return objectToValue(context, value); + } +}; + +template +class CallbackResultNumeric : public CallbackResult { + virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override + { + T value; + [invocation getReturnValue:&value]; + return JSValueMakeNumber([context JSGlobalContextRef], value); + } +}; + +class CallbackResultBoolean : public CallbackResult { + virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override + { + bool value; + [invocation getReturnValue:&value]; + return JSValueMakeBoolean([context JSGlobalContextRef], value); + } +}; + +class CallbackResultStruct : public CallbackResult { +public: + CallbackResultStruct(NSInvocation *conversionInvocation, const char* encodedType) + : m_conversionInvocation(conversionInvocation) + , m_buffer(encodedType) + { + } + +private: + virtual JSValueRef get(NSInvocation *invocation, JSContext *context, JSValueRef*) override + { + [invocation getReturnValue:m_buffer]; + + [m_conversionInvocation setArgument:m_buffer atIndex:2]; + [m_conversionInvocation setArgument:&context atIndex:3]; + [m_conversionInvocation invokeWithTarget:[JSValue class]]; + + JSValue *value; + [m_conversionInvocation getReturnValue:&value]; + return valueInternalValue(value); + } + + RetainPtr m_conversionInvocation; + StructBuffer m_buffer; +}; + +class ResultTypeDelegate { +public: + typedef CallbackResult* ResultType; + + template + static ResultType typeInteger() + { + return new CallbackResultNumeric; + } + + template + static ResultType typeDouble() + { + return new CallbackResultNumeric; + } + + static ResultType typeBool() + { + return new CallbackResultBoolean; + } + + static ResultType typeVoid() + { + return new CallbackResultVoid; + } + + static ResultType typeId() + { + return new CallbackResultId(); + } + + static ResultType typeOfClass(const char*, const char*) + { + return new CallbackResultId(); + } + + static ResultType typeBlock(const char*, const char*) + { + return new CallbackResultId(); + } + + static ResultType typeStruct(const char* begin, const char* end) + { + StringRange copy(begin, end); + if (NSInvocation *invocation = typeToValueInvocationFor(copy)) + return new CallbackResultStruct(invocation, copy); + return 0; + } +}; + +enum CallbackType { + CallbackInitMethod, + CallbackInstanceMethod, + CallbackClassMethod, + CallbackBlock +}; + +namespace JSC { + +class ObjCCallbackFunctionImpl { +public: + ObjCCallbackFunctionImpl(NSInvocation *invocation, CallbackType type, Class instanceClass, PassOwnPtr arguments, PassOwnPtr result) + : m_type(type) + , m_instanceClass([instanceClass retain]) + , m_invocation(invocation) + , m_arguments(arguments) + , m_result(result) + { + ASSERT((type != CallbackInstanceMethod && type != CallbackInitMethod) || instanceClass); + } + + void destroy(Heap& heap) + { + // We need to explicitly release the target since we didn't call + // -retainArguments on m_invocation (and we don't want to do so). + if (m_type == CallbackBlock || m_type == CallbackClassMethod) + heap.releaseSoon(adoptNS([m_invocation.get() target])); + [m_instanceClass release]; + } + + JSValueRef call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + + id wrappedBlock() + { + return m_type == CallbackBlock ? [m_invocation target] : nil; + } + + id wrappedConstructor() + { + switch (m_type) { + case CallbackBlock: + return [m_invocation target]; + case CallbackInitMethod: + return m_instanceClass; + default: + return nil; + } + } + + bool isConstructible() + { + return !!wrappedBlock() || m_type == CallbackInitMethod; + } + + String name(); + +private: + CallbackType m_type; + Class m_instanceClass; + RetainPtr m_invocation; + OwnPtr m_arguments; + OwnPtr m_result; +}; + +static JSValueRef objCCallbackFunctionCallAsFunction(JSContextRef callerContext, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Retake the API lock - we need this for a few reasons: + // (1) We don't want to support the C-API's confusing drops-locks-once policy - should only drop locks if we can do so recursively. + // (2) We're calling some JSC internals that require us to be on the 'inside' - e.g. createTypeError. + // (3) We need to be locked (per context would be fine) against conflicting usage of the ObjCCallbackFunction's NSInvocation. + JSC::APIEntryShim entryShim(toJS(callerContext)); + + ObjCCallbackFunction* callback = static_cast(toJS(function)); + ObjCCallbackFunctionImpl* impl = callback->impl(); + JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(callback->globalObject()->globalExec())]; + + CallbackData callbackData; + JSValueRef result; + @autoreleasepool { + [context beginCallbackWithData:&callbackData thisValue:thisObject argumentCount:argumentCount arguments:arguments]; + result = impl->call(context, thisObject, argumentCount, arguments, exception); + if (context.exception) + *exception = valueInternalValue(context.exception); + [context endCallbackWithData:&callbackData]; + } + return result; +} + +static JSObjectRef objCCallbackFunctionCallAsConstructor(JSContextRef callerContext, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSC::APIEntryShim entryShim(toJS(callerContext)); + + ObjCCallbackFunction* callback = static_cast(toJS(constructor)); + ObjCCallbackFunctionImpl* impl = callback->impl(); + JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(toJS(callerContext)->lexicalGlobalObject()->globalExec())]; + + CallbackData callbackData; + JSValueRef result; + @autoreleasepool { + [context beginCallbackWithData:&callbackData thisValue:nil argumentCount:argumentCount arguments:arguments]; + result = impl->call(context, NULL, argumentCount, arguments, exception); + if (context.exception) + *exception = valueInternalValue(context.exception); + [context endCallbackWithData:&callbackData]; + } + + JSGlobalContextRef contextRef = [context JSGlobalContextRef]; + if (*exception) + return 0; + + if (!JSValueIsObject(contextRef, result)) { + *exception = toRef(JSC::createTypeError(toJS(contextRef), "Objective-C blocks called as constructors must return an object.")); + return 0; + } + return (JSObjectRef)result; +} + +const JSC::ClassInfo ObjCCallbackFunction::s_info = { "CallbackFunction", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ObjCCallbackFunction) }; + +ObjCCallbackFunction::ObjCCallbackFunction(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback functionCallback, JSObjectCallAsConstructorCallback constructCallback, PassOwnPtr impl) + : Base(vm, globalObject->objcCallbackFunctionStructure()) + , m_functionCallback(functionCallback) + , m_constructCallback(constructCallback) + , m_impl(impl) +{ +} + +ObjCCallbackFunction* ObjCCallbackFunction::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, const String& name, PassOwnPtr impl) +{ + ObjCCallbackFunction* function = new (NotNull, allocateCell(vm.heap)) ObjCCallbackFunction(vm, globalObject, objCCallbackFunctionCallAsFunction, objCCallbackFunctionCallAsConstructor, impl); + function->finishCreation(vm, name); + return function; +} + +void ObjCCallbackFunction::destroy(JSCell* cell) +{ + ObjCCallbackFunction& function = *jsCast(cell); + function.impl()->destroy(*Heap::heap(cell)); + function.~ObjCCallbackFunction(); +} + + +CallType ObjCCallbackFunction::getCallData(JSCell*, CallData& callData) +{ + callData.native.function = APICallbackFunction::call; + return CallTypeHost; +} + +ConstructType ObjCCallbackFunction::getConstructData(JSCell* cell, ConstructData& constructData) +{ + ObjCCallbackFunction* callback = jsCast(cell); + if (!callback->impl()->isConstructible()) + return Base::getConstructData(cell, constructData); + constructData.native.function = APICallbackFunction::construct; + return ConstructTypeHost; +} + +String ObjCCallbackFunctionImpl::name() +{ + if (m_type == CallbackInitMethod) + return class_getName(m_instanceClass); + // FIXME: Maybe we could support having the selector as the name of the non-init + // functions to make it a bit more user-friendly from the JS side? + return ""; +} + +JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + JSGlobalContextRef contextRef = [context JSGlobalContextRef]; + + id target; + size_t firstArgument; + switch (m_type) { + case CallbackInitMethod: { + RELEASE_ASSERT(!thisObject); + target = [m_instanceClass alloc]; + if (!target || ![target isKindOfClass:m_instanceClass]) { + *exception = toRef(JSC::createTypeError(toJS(contextRef), "self type check failed for Objective-C instance method")); + return JSValueMakeUndefined(contextRef); + } + [m_invocation setTarget:target]; + firstArgument = 2; + break; + } + case CallbackInstanceMethod: { + target = tryUnwrapObjcObject(contextRef, thisObject); + if (!target || ![target isKindOfClass:m_instanceClass]) { + *exception = toRef(JSC::createTypeError(toJS(contextRef), "self type check failed for Objective-C instance method")); + return JSValueMakeUndefined(contextRef); + } + [m_invocation setTarget:target]; + firstArgument = 2; + break; + } + case CallbackClassMethod: + firstArgument = 2; + break; + case CallbackBlock: + firstArgument = 1; + } + + size_t argumentNumber = 0; + for (CallbackArgument* argument = m_arguments.get(); argument; argument = argument->m_next.get()) { + JSValueRef value = argumentNumber < argumentCount ? arguments[argumentNumber] : JSValueMakeUndefined(contextRef); + argument->set(m_invocation.get(), argumentNumber + firstArgument, context, value, exception); + if (*exception) + return JSValueMakeUndefined(contextRef); + ++argumentNumber; + } + + [m_invocation invoke]; + + JSValueRef result = m_result->get(m_invocation.get(), context, exception); + + // Balance our call to -alloc with a call to -autorelease. We have to do this after calling -init + // because init family methods are allowed to release the allocated object and return something + // else in its place. + if (m_type == CallbackInitMethod) { + id objcResult = tryUnwrapObjcObject(contextRef, result); + if (objcResult) + [objcResult autorelease]; + } + + return result; +} + +} // namespace JSC + +static bool blockSignatureContainsClass() +{ + static bool containsClass = ^{ + id block = ^(NSString *string){ return string; }; + return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString"); + }(); + return containsClass; +} + +inline bool skipNumber(const char*& position) +{ + if (!isASCIIDigit(*position)) + return false; + while (isASCIIDigit(*++position)) { } + return true; +} + +static JSObjectRef objCCallbackFunctionForInvocation(JSContext *context, NSInvocation *invocation, CallbackType type, Class instanceClass, const char* signatureWithObjcClasses) +{ + const char* position = signatureWithObjcClasses; + + OwnPtr result = adoptPtr(parseObjCType(position)); + if (!result || !skipNumber(position)) + return nil; + + switch (type) { + case CallbackInitMethod: + case CallbackInstanceMethod: + case CallbackClassMethod: + // Methods are passed two implicit arguments - (id)self, and the selector. + if ('@' != *position++ || !skipNumber(position) || ':' != *position++ || !skipNumber(position)) + return nil; + break; + case CallbackBlock: + // Blocks are passed one implicit argument - the block, of type "@?". + if (('@' != *position++) || ('?' != *position++) || !skipNumber(position)) + return nil; + // Only allow arguments of type 'id' if the block signature contains the NS type information. + if ((!blockSignatureContainsClass() && strchr(position, '@'))) + return nil; + break; + } + + OwnPtr arguments = 0; + OwnPtr* nextArgument = &arguments; + unsigned argumentCount = 0; + while (*position) { + OwnPtr argument = adoptPtr(parseObjCType(position)); + if (!argument || !skipNumber(position)) + return nil; + + *nextArgument = argument.release(); + nextArgument = &(*nextArgument)->m_next; + ++argumentCount; + } + + JSC::ExecState* exec = toJS([context JSGlobalContextRef]); + JSC::APIEntryShim shim(exec); + OwnPtr impl = adoptPtr(new JSC::ObjCCallbackFunctionImpl(invocation, type, instanceClass, arguments.release(), result.release())); + return toRef(JSC::ObjCCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), impl->name(), impl.release())); +} + +JSObjectRef objCCallbackFunctionForInit(JSContext *context, Class cls, Protocol *protocol, SEL sel, const char* types) +{ + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]]; + [invocation setSelector:sel]; + return objCCallbackFunctionForInvocation(context, invocation, CallbackInitMethod, cls, _protocol_getMethodTypeEncoding(protocol, sel, YES, YES)); +} + +JSObjectRef objCCallbackFunctionForMethod(JSContext *context, Class cls, Protocol *protocol, BOOL isInstanceMethod, SEL sel, const char* types) +{ + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]]; + [invocation setSelector:sel]; + // We need to retain the target Class because m_invocation doesn't retain it + // by default (and we don't want it to). + if (!isInstanceMethod) + [invocation setTarget:[cls retain]]; + return objCCallbackFunctionForInvocation(context, invocation, isInstanceMethod ? CallbackInstanceMethod : CallbackClassMethod, isInstanceMethod ? cls : nil, _protocol_getMethodTypeEncoding(protocol, sel, YES, isInstanceMethod)); +} + +JSObjectRef objCCallbackFunctionForBlock(JSContext *context, id target) +{ + if (!_Block_has_signature(target)) + return 0; + const char* signature = _Block_signature(target); + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:signature]]; + + // We don't want to use -retainArguments because that leaks memory. Arguments + // would be retained indefinitely between invocations of the callback. + // Additionally, we copy the target because we want the block to stick around + // until the ObjCCallbackFunctionImpl is destroyed. + [invocation setTarget:[target copy]]; + + return objCCallbackFunctionForInvocation(context, invocation, CallbackBlock, nil, signature); +} + +id tryUnwrapConstructor(JSObjectRef object) +{ + if (!toJS(object)->inherits(JSC::ObjCCallbackFunction::info())) + return nil; + JSC::ObjCCallbackFunctionImpl* impl = static_cast(toJS(object))->impl(); + if (!impl->isConstructible()) + return nil; + return impl->wrappedConstructor(); +} + +#endif diff --git a/JavaScriptCore/API/ObjcRuntimeExtras.h b/JavaScriptCore/API/ObjcRuntimeExtras.h new file mode 100644 index 00000000..48c11209 --- /dev/null +++ b/JavaScriptCore/API/ObjcRuntimeExtras.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2013 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. + */ + +#import +#import +#import + +inline bool protocolImplementsProtocol(Protocol *candidate, Protocol *target) +{ + unsigned protocolProtocolsCount; + Protocol ** protocolProtocols = protocol_copyProtocolList(candidate, &protocolProtocolsCount); + for (unsigned i = 0; i < protocolProtocolsCount; ++i) { + if (protocol_isEqual(protocolProtocols[i], target)) { + free(protocolProtocols); + return true; + } + } + free(protocolProtocols); + return false; +} + +inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, void (^callback)(Protocol *)) +{ + ASSERT(cls); + ASSERT(target); + + Vector worklist; + HashSet visited; + + // Initially fill the worklist with the Class's protocols. + unsigned protocolsCount; + Protocol ** protocols = class_copyProtocolList(cls, &protocolsCount); + worklist.append(protocols, protocolsCount); + free(protocols); + + while (!worklist.isEmpty()) { + Protocol *protocol = worklist.last(); + worklist.removeLast(); + + // Are we encountering this Protocol for the first time? + if (!visited.add(protocol).isNewEntry) + continue; + + // If it implements the protocol, make the callback. + if (protocolImplementsProtocol(protocol, target)) + callback(protocol); + + // Add incorporated protocols to the worklist. + protocols = protocol_copyProtocolList(protocol, &protocolsCount); + worklist.append(protocols, protocolsCount); + free(protocols); + } +} + +inline void forEachMethodInClass(Class cls, void (^callback)(Method)) +{ + unsigned count; + Method* methods = class_copyMethodList(cls, &count); + for (unsigned i = 0; i < count; ++i) + callback(methods[i]); + free(methods); +} + +inline void forEachMethodInProtocol(Protocol *protocol, BOOL isRequiredMethod, BOOL isInstanceMethod, void (^callback)(SEL, const char*)) +{ + unsigned count; + struct objc_method_description* methods = protocol_copyMethodDescriptionList(protocol, isRequiredMethod, isInstanceMethod, &count); + for (unsigned i = 0; i < count; ++i) + callback(methods[i].name, methods[i].types); + free(methods); +} + +inline void forEachPropertyInProtocol(Protocol *protocol, void (^callback)(objc_property_t)) +{ + unsigned count; + objc_property_t* properties = protocol_copyPropertyList(protocol, &count); + for (unsigned i = 0; i < count; ++i) + callback(properties[i]); + free(properties); +} + +template +void skipPair(const char*& position) +{ + size_t count = 1; + do { + char c = *position++; + if (!c) + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Malformed type encoding" userInfo:nil]; + if (c == open) + ++count; + else if (c == close) + --count; + } while (count); +} + +class StringRange { + WTF_MAKE_NONCOPYABLE(StringRange); +public: + StringRange(const char* begin, const char* end) : m_ptr(strndup(begin, end - begin)) { } + ~StringRange() { free(m_ptr); } + operator const char*() const { return m_ptr; } + const char* get() const { return m_ptr; } + +private: + char* m_ptr; +}; + +class StructBuffer { + WTF_MAKE_NONCOPYABLE(StructBuffer); +public: + StructBuffer(const char* encodedType) + { + NSUInteger size, alignment; + NSGetSizeAndAlignment(encodedType, &size, &alignment); + --alignment; + m_allocation = static_cast(malloc(size + alignment)); + m_buffer = reinterpret_cast((reinterpret_cast(m_allocation) + alignment) & ~alignment); + } + + ~StructBuffer() { free(m_allocation); } + operator void*() const { return m_buffer; } + +private: + void* m_allocation; + void* m_buffer; +}; + +template +typename DelegateType::ResultType parseObjCType(const char*& position) +{ + ASSERT(*position); + + switch (*position++) { + case 'c': + return DelegateType::template typeInteger(); + case 'i': + return DelegateType::template typeInteger(); + case 's': + return DelegateType::template typeInteger(); + case 'l': + return DelegateType::template typeInteger(); + case 'q': + return DelegateType::template typeDouble(); + case 'C': + return DelegateType::template typeInteger(); + case 'I': + return DelegateType::template typeInteger(); + case 'S': + return DelegateType::template typeInteger(); + case 'L': + return DelegateType::template typeInteger(); + case 'Q': + return DelegateType::template typeDouble(); + case 'f': + return DelegateType::template typeDouble(); + case 'd': + return DelegateType::template typeDouble(); + case 'B': + return DelegateType::typeBool(); + case 'v': + return DelegateType::typeVoid(); + + case '@': { // An object (whether statically typed or typed id) + if (position[0] == '?' && position[1] == '<') { + position += 2; + const char* begin = position; + skipPair<'<','>'>(position); + return DelegateType::typeBlock(begin, position - 1); + } + + if (*position == '"') { + const char* begin = ++position; + position = index(position, '"'); + return DelegateType::typeOfClass(begin, position++); + } + + return DelegateType::typeId(); + } + + case '{': { // {name=type...} A structure + const char* begin = position - 1; + skipPair<'{','}'>(position); + return DelegateType::typeStruct(begin, position); + } + + // NOT supporting C strings, arrays, pointers, unions, bitfields, function pointers. + case '*': // A character string (char *) + case '[': // [array type] An array + case '(': // (name=type...) A union + case 'b': // bnum A bit field of num bits + case '^': // ^type A pointer to type + case '?': // An unknown type (among other things, this code is used for function pointers) + // NOT supporting Objective-C Class, SEL + case '#': // A class object (Class) + case ':': // A method selector (SEL) + default: + return nil; + } +} + +extern "C" { + // Forward declare some Objective-C runtime internal methods that are not API. + const char *_protocol_getMethodTypeEncoding(Protocol *, SEL, BOOL isRequiredMethod, BOOL isInstanceMethod); + id objc_initWeak(id *, id); + void objc_destroyWeak(id *); + bool _Block_has_signature(void *); + const char * _Block_signature(void *); +} diff --git a/JavaScriptCore/API/OpaqueJSString.cpp b/JavaScriptCore/API/OpaqueJSString.cpp index 9a116e6b..4a476200 100644 --- a/JavaScriptCore/API/OpaqueJSString.cpp +++ b/JavaScriptCore/API/OpaqueJSString.cpp @@ -26,30 +26,44 @@ #include "config.h" #include "OpaqueJSString.h" -#include -#include -#include +#include "CallFrame.h" +#include "Identifier.h" +#include "JSGlobalObject.h" using namespace JSC; -PassRefPtr OpaqueJSString::create(const UString& ustring) +PassRefPtr OpaqueJSString::create(const String& string) { - if (!ustring.isNull()) - return adoptRef(new OpaqueJSString(ustring.characters(), ustring.length())); + if (!string.isNull()) + return adoptRef(new OpaqueJSString(string)); return 0; } -UString OpaqueJSString::ustring() const +String OpaqueJSString::string() const { - if (this && m_characters) - return UString(m_characters, m_length); - return UString(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-bool-conversion" + if (!this) +#pragma clang diagnostic pop + return String(); + + // Return a copy of the wrapped string, because the caller may make it an Identifier. + return m_string.isolatedCopy(); } -Identifier OpaqueJSString::identifier(JSGlobalData* globalData) const +Identifier OpaqueJSString::identifier(VM* vm) const { - if (!this || !m_characters) - return Identifier(globalData, static_cast(0)); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-bool-conversion" + if (!this || m_string.isNull()) +#pragma clang diagnostic pop + return Identifier(); + + if (m_string.isEmpty()) + return Identifier(Identifier::EmptyIdentifier); + + if (m_string.is8Bit()) + return Identifier(vm, m_string.characters8(), m_string.length()); - return Identifier(globalData, m_characters, m_length); + return Identifier(vm, m_string.characters16(), m_string.length()); } diff --git a/JavaScriptCore/API/OpaqueJSString.h b/JavaScriptCore/API/OpaqueJSString.h index 1c63150c..cb6c1276 100644 --- a/JavaScriptCore/API/OpaqueJSString.h +++ b/JavaScriptCore/API/OpaqueJSString.h @@ -27,11 +27,11 @@ #define OpaqueJSString_h #include -#include +#include namespace JSC { class Identifier; - class JSGlobalData; + class VM; } struct OpaqueJSString : public ThreadSafeRefCounted { @@ -41,42 +41,50 @@ struct OpaqueJSString : public ThreadSafeRefCounted { return adoptRef(new OpaqueJSString); } + static PassRefPtr create(const LChar* characters, unsigned length) + { + return adoptRef(new OpaqueJSString(characters, length)); + } + static PassRefPtr create(const UChar* characters, unsigned length) { return adoptRef(new OpaqueJSString(characters, length)); } - JS_EXPORT_PRIVATE static PassRefPtr create(const JSC::UString&); + JS_EXPORT_PRIVATE static PassRefPtr create(const String&); - UChar* characters() { return this ? m_characters : 0; } - unsigned length() { return this ? m_length : 0; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-bool-conversion" + const UChar* characters() { return !!this ? m_string.characters() : 0; } + unsigned length() { return !!this ? m_string.length() : 0; } +#pragma clang diagnostic pop - JSC::UString ustring() const; - JSC::Identifier identifier(JSC::JSGlobalData*) const; + JS_EXPORT_PRIVATE String string() const; + JSC::Identifier identifier(JSC::VM*) const; private: friend class WTF::ThreadSafeRefCounted; OpaqueJSString() - : m_characters(0) - , m_length(0) { } - OpaqueJSString(const UChar* characters, unsigned length) - : m_length(length) + OpaqueJSString(const String& string) + : m_string(string.isolatedCopy()) { - m_characters = new UChar[length]; - memcpy(m_characters, characters, length * sizeof(UChar)); } - ~OpaqueJSString() + OpaqueJSString(const LChar* characters, unsigned length) + { + m_string = String(characters, length); + } + + OpaqueJSString(const UChar* characters, unsigned length) { - delete[] m_characters; + m_string = String(characters, length); } - UChar* m_characters; - unsigned m_length; + String m_string; }; #endif diff --git a/JavaScriptCore/API/WebKitAvailability.h b/JavaScriptCore/API/WebKitAvailability.h index 7846058f..ebb33bce 100644 --- a/JavaScriptCore/API/WebKitAvailability.h +++ b/JavaScriptCore/API/WebKitAvailability.h @@ -43,7 +43,9 @@ #ifdef __APPLE__ #include +#include #else +#define CF_AVAILABLE(_mac, _ios) /* * For non-Mac platforms, require the newest version. */ diff --git a/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h b/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h new file mode 100644 index 00000000..f228333c --- /dev/null +++ b/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CurrentThisInsideBlockGetterTest_h +#define CurrentThisInsideBlockGetterTest_h + +#include + +#if JSC_OBJC_API_ENABLED + +void currentThisInsideBlockGetterTest(); + +#endif // JSC_OBJC_API_ENABLED + + +#endif // CurrentThisInsideBlockGetterTest_h diff --git a/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.mm b/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.mm new file mode 100644 index 00000000..5ec54202 --- /dev/null +++ b/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.mm @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "CurrentThisInsideBlockGetterTest.h" + +#if JSC_OBJC_API_ENABLED + +#import +#import + +static JSObjectRef CallAsConstructor(JSContextRef ctx, JSObjectRef constructor, size_t, const JSValueRef[], JSValueRef*) +{ + JSObjectRef newObjectRef = NULL; + NSMutableDictionary *constructorPrivateProperties = (__bridge NSMutableDictionary *)(JSObjectGetPrivate(constructor)); + NSDictionary *constructorDescriptor = constructorPrivateProperties[@"constructorDescriptor"]; + newObjectRef = JSObjectMake(ctx, NULL, NULL); + NSDictionary *objectProperties = constructorDescriptor[@"objectProperties"]; + + if (objectProperties) { + JSValue *newObject = [JSValue valueWithJSValueRef:newObjectRef inContext:[JSContext contextWithJSGlobalContextRef:JSContextGetGlobalContext(ctx)]]; + for (NSString *objectProperty in objectProperties) { + [newObject defineProperty:objectProperty descriptor:objectProperties[objectProperty]]; + } + } + + return newObjectRef; +} + +static void ConstructorFinalize(JSObjectRef object) +{ + NSMutableDictionary *privateProperties = (__bridge NSMutableDictionary *)(JSObjectGetPrivate(object)); + CFBridgingRelease((__bridge CFTypeRef)(privateProperties)); + JSObjectSetPrivate(object, NULL); +} + +static JSClassRef ConstructorClass(void) +{ + static JSClassRef constructorClass = NULL; + + if (constructorClass == NULL) { + JSClassDefinition classDefinition = kJSClassDefinitionEmpty; + classDefinition.className = "Constructor"; + classDefinition.callAsConstructor = CallAsConstructor; + classDefinition.finalize = ConstructorFinalize; + constructorClass = JSClassCreate(&classDefinition); + } + + return constructorClass; +} + +@interface JSValue (ConstructorCreation) + ++ (JSValue *)valueWithConstructorDescriptor:(NSDictionary *)constructorDescriptor inContext:(JSContext *)context; + +@end + +@implementation JSValue (ConstructorCreation) + ++ (JSValue *)valueWithConstructorDescriptor:(id)constructorDescriptor inContext:(JSContext *)context +{ + NSMutableDictionary *privateProperties = [@{ @"constructorDescriptor" : constructorDescriptor } mutableCopy]; + JSGlobalContextRef ctx = [context JSGlobalContextRef]; + JSObjectRef constructorRef = JSObjectMake(ctx, ConstructorClass(), (void *)CFBridgingRetain(privateProperties)); + JSValue *constructor = [JSValue valueWithJSValueRef:constructorRef inContext:context]; + return constructor; +} + +@end + +@interface JSContext (ConstructorCreation) + +- (JSValue *)valueWithConstructorDescriptor:(NSDictionary *)constructorDescriptor; + +@end + +@implementation JSContext (ConstructorCreation) + +- (JSValue *)valueWithConstructorDescriptor:(id)constructorDescriptor +{ + return [JSValue valueWithConstructorDescriptor:constructorDescriptor inContext:self]; +} + +@end + +void currentThisInsideBlockGetterTest() +{ + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + + JSValue *myConstructor = [context valueWithConstructorDescriptor:@{ + @"objectProperties" : @{ + @"currentThis" : @{ JSPropertyDescriptorGetKey : ^{ return JSContext.currentThis; } }, + }, + }]; + + JSValue *myObj1 = [myConstructor constructWithArguments:nil]; + NSLog(@"myObj1.currentThis: %@", myObj1[@"currentThis"]); + JSValue *myObj2 = [myConstructor constructWithArguments:@[ @"bar" ]]; + NSLog(@"myObj2.currentThis: %@", myObj2[@"currentThis"]); + } +} + +#endif // JSC_OBJC_API_ENABLED diff --git a/JavaScriptCore/API/tests/JSNode.c b/JavaScriptCore/API/tests/JSNode.c index 052c88a0..d9a40bea 100644 --- a/JavaScriptCore/API/tests/JSNode.c +++ b/JavaScriptCore/API/tests/JSNode.c @@ -30,7 +30,6 @@ #include "JSValueRef.h" #include "Node.h" #include "NodeList.h" -#include #include static JSValueRef JSNode_appendChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) diff --git a/JavaScriptCore/API/tests/JSNodeList.c b/JavaScriptCore/API/tests/JSNodeList.c index 0d194845..61d7041a 100644 --- a/JavaScriptCore/API/tests/JSNodeList.c +++ b/JavaScriptCore/API/tests/JSNodeList.c @@ -27,7 +27,6 @@ #include "JSNodeList.h" #include "JSObjectRef.h" #include "JSValueRef.h" -#include #include static JSValueRef JSNodeList_item(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) diff --git a/JavaScriptCore/API/tests/minidom.c b/JavaScriptCore/API/tests/minidom.c index 43ae2c1a..f4ccf91e 100644 --- a/JavaScriptCore/API/tests/minidom.c +++ b/JavaScriptCore/API/tests/minidom.c @@ -31,7 +31,6 @@ #include #include #include -#include static char* createStringWithContentsOfFile(const char* fileName); static JSValueRef print(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); @@ -106,6 +105,7 @@ static char* createStringWithContentsOfFile(const char* fileName) FILE* f = fopen(fileName, "r"); if (!f) { fprintf(stderr, "Could not open file: %s\n", fileName); + free(buffer); return 0; } diff --git a/JavaScriptCore/API/tests/testapi.c b/JavaScriptCore/API/tests/testapi.c index 91978bbf..f4a14996 100644 --- a/JavaScriptCore/API/tests/testapi.c +++ b/JavaScriptCore/API/tests/testapi.c @@ -20,35 +20,37 @@ * 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 "JavaScriptCore.h" #include "JSBasePrivate.h" #include "JSContextRefPrivate.h" #include "JSObjectRefPrivate.h" +#include "JSScriptRefPrivate.h" +#include "JSStringRefPrivate.h" #include #define ASSERT_DISABLED 0 #include -#include + +#if PLATFORM(MAC) || PLATFORM(IOS) +#include +#include +#include +#endif #if OS(WINDOWS) #include #endif -#if COMPILER(MSVC) - -#include - -static double nan(const char*) -{ - return std::numeric_limits::quiet_NaN(); -} - +#if JSC_OBJC_API_ENABLED +void testObjectiveCAPI(void); #endif +extern void JSSynchronousGarbageCollectForDebugging(JSContextRef); + static JSGlobalContextRef context; -static int failed; +int failed; static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue) { if (JSValueToBoolean(context, value) != expectedValue) { @@ -481,6 +483,11 @@ static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef obje return true; } + if (JSStringIsEqualToUTF8CString(propertyName, "make_throw") || JSStringIsEqualToUTF8CString(propertyName, "0")) { + *exception = JSValueMakeNumber(context, 5); + return true; + } + return false; } @@ -1022,6 +1029,72 @@ static bool checkForCycleInPrototypeChain() return result; } +static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + JSValueRef jsUndefined = JSValueMakeUndefined(JSContextGetGlobalContext(ctx)); + JSValueToObject(JSContextGetGlobalContext(ctx), jsUndefined, exception); + + return JSValueMakeUndefined(ctx); +} +static bool valueToObjectExceptionTest() +{ + JSGlobalContextRef testContext; + JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; + globalObjectClassDefinition.initialize = globalObject_initialize; + globalObjectClassDefinition.staticValues = globalObject_staticValues; + globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; + globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); + testContext = JSGlobalContextCreateInGroup(NULL, globalObjectClass); + JSObjectRef globalObject = JSContextGetGlobalObject(testContext); + + JSStringRef valueToObject = JSStringCreateWithUTF8CString("valueToObject"); + JSObjectRef valueToObjectFunction = JSObjectMakeFunctionWithCallback(testContext, valueToObject, valueToObjectExceptionCallAsFunction); + JSObjectSetProperty(testContext, globalObject, valueToObject, valueToObjectFunction, kJSPropertyAttributeNone, NULL); + JSStringRelease(valueToObject); + + JSStringRef test = JSStringCreateWithUTF8CString("valueToObject();"); + JSEvaluateScript(testContext, test, NULL, NULL, 1, NULL); + + JSStringRelease(test); + JSClassRelease(globalObjectClass); + JSGlobalContextRelease(testContext); + + return true; +} + +static bool globalContextNameTest() +{ + bool result = true; + JSGlobalContextRef context = JSGlobalContextCreate(0); + + JSStringRef str = JSGlobalContextCopyName(context); + result &= assertTrue(!str, "Default context name is NULL"); + + JSStringRef name1 = JSStringCreateWithUTF8CString("name1"); + JSStringRef name2 = JSStringCreateWithUTF8CString("name2"); + + JSGlobalContextSetName(context, name1); + JSStringRef fetchName1 = JSGlobalContextCopyName(context); + JSGlobalContextSetName(context, name2); + JSStringRef fetchName2 = JSGlobalContextCopyName(context); + + result &= assertTrue(JSStringIsEqual(name1, fetchName1), "Unexpected Context name"); + result &= assertTrue(JSStringIsEqual(name2, fetchName2), "Unexpected Context name"); + result &= assertTrue(!JSStringIsEqual(fetchName1, fetchName2), "Unexpected Context name"); + + JSStringRelease(name1); + JSStringRelease(name2); + JSStringRelease(fetchName1); + JSStringRelease(fetchName2); + + return result; +} + static void checkConstnessInJSObjectNames() { JSStaticFunction fun; @@ -1030,6 +1103,68 @@ static void checkConstnessInJSObjectNames() val.name = "something"; } +#if PLATFORM(MAC) || PLATFORM(IOS) +static double currentCPUTime() +{ + mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + + /* Get thread information */ + mach_port_t threadPort = mach_thread_self(); + thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount); + mach_port_deallocate(mach_task_self(), threadPort); + + double time = info.user_time.seconds + info.user_time.microseconds / 1000000.; + time += info.system_time.seconds + info.system_time.microseconds / 1000000.; + + return time; +} + +static JSValueRef currentCPUTime_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(functionObject); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + ASSERT(JSContextGetGlobalContext(ctx) == context); + return JSValueMakeNumber(ctx, currentCPUTime()); +} + +bool shouldTerminateCallbackWasCalled = false; +static bool shouldTerminateCallback(JSContextRef ctx, void* context) +{ + UNUSED_PARAM(ctx); + UNUSED_PARAM(context); + shouldTerminateCallbackWasCalled = true; + return true; +} + +bool cancelTerminateCallbackWasCalled = false; +static bool cancelTerminateCallback(JSContextRef ctx, void* context) +{ + UNUSED_PARAM(ctx); + UNUSED_PARAM(context); + cancelTerminateCallbackWasCalled = true; + return false; +} + +int extendTerminateCallbackCalled = 0; +static bool extendTerminateCallback(JSContextRef ctx, void* context) +{ + UNUSED_PARAM(context); + extendTerminateCallbackCalled++; + if (extendTerminateCallbackCalled == 1) { + JSContextGroupRef contextGroup = JSContextGetGroup(ctx); + JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); + return false; + } + return true; +} +#endif /* PLATFORM(MAC) || PLATFORM(IOS) */ + + int main(int argc, char* argv[]) { #if OS(WINDOWS) @@ -1039,6 +1174,10 @@ int main(int argc, char* argv[]) ::SetErrorMode(0); #endif +#if JSC_OBJC_API_ENABLED + testObjectiveCAPI(); +#endif + const char *scriptPath = "testapi.js"; if (argc > 1) { scriptPath = argv[1]; @@ -1061,6 +1200,8 @@ int main(int argc, char* argv[]) JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); context = JSGlobalContextCreateInGroup(NULL, globalObjectClass); + JSContextGroupRef contextGroup = JSContextGetGroup(context); + JSGlobalContextRetain(context); JSGlobalContextRelease(context); ASSERT(JSContextGetGlobalContext(context) == context); @@ -1117,6 +1258,12 @@ int main(int argc, char* argv[]) free(buffer); JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters); + JSChar constantString[] = { 'H', 'e', 'l', 'l', 'o', }; + JSStringRef constantStringRef = JSStringCreateWithCharactersNoCopy(constantString, sizeof(constantString) / sizeof(constantString[0])); + ASSERT(JSStringGetCharactersPtr(constantStringRef) == constantString); + JSStringRelease(constantStringRef); + + ASSERT(JSValueGetType(context, NULL) == kJSTypeNull); ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined); ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull); ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean); @@ -1131,6 +1278,49 @@ int main(int argc, char* argv[]) ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString); ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString); + ASSERT(!JSValueIsBoolean(context, NULL)); + ASSERT(!JSValueIsObject(context, NULL)); + ASSERT(!JSValueIsString(context, NULL)); + ASSERT(!JSValueIsNumber(context, NULL)); + ASSERT(!JSValueIsUndefined(context, NULL)); + ASSERT(JSValueIsNull(context, NULL)); + ASSERT(!JSObjectCallAsFunction(context, NULL, NULL, 0, NULL, NULL)); + ASSERT(!JSObjectCallAsConstructor(context, NULL, 0, NULL, NULL)); + ASSERT(!JSObjectIsConstructor(context, NULL)); + ASSERT(!JSObjectIsFunction(context, NULL)); + + JSStringRef nullString = JSStringCreateWithUTF8CString(0); + const JSChar* characters = JSStringGetCharactersPtr(nullString); + if (characters) { + printf("FAIL: Didn't return null when accessing character pointer of a null String.\n"); + failed = 1; + } else + printf("PASS: returned null when accessing character pointer of a null String.\n"); + + JSStringRef emptyString = JSStringCreateWithCFString(CFSTR("")); + characters = JSStringGetCharactersPtr(emptyString); + if (!characters) { + printf("FAIL: Returned null when accessing character pointer of an empty String.\n"); + failed = 1; + } else + printf("PASS: returned empty when accessing character pointer of an empty String.\n"); + + size_t length = JSStringGetLength(nullString); + if (length) { + printf("FAIL: Didn't return 0 length for null String.\n"); + failed = 1; + } else + printf("PASS: returned 0 length for null String.\n"); + JSStringRelease(nullString); + + length = JSStringGetLength(emptyString); + if (length) { + printf("FAIL: Didn't return 0 length for empty String.\n"); + failed = 1; + } else + printf("PASS: returned 0 length for empty String.\n"); + JSStringRelease(emptyString); + JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL); JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls"); JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL); @@ -1208,6 +1398,15 @@ int main(int argc, char* argv[]) } else printf("PASS: Retrieved private property.\n"); + JSStringRef nullJSON = JSStringCreateWithUTF8CString(0); + JSValueRef nullJSONObject = JSValueMakeFromJSONString(context, nullJSON); + if (nullJSONObject) { + printf("FAIL: Did not parse null String as JSON correctly\n"); + failed = 1; + } else + printf("PASS: Parsed null String as JSON correctly.\n"); + JSStringRelease(nullJSON); + JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}"); JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON); JSStringRelease(validJSON); @@ -1374,9 +1573,12 @@ int main(int argc, char* argv[]) JSValueUnprotect(context, jsNumberValue); JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;"); - JSStringRef badSyntax = JSStringCreateWithUTF8CString("x := 1;"); + const char* badSyntaxConstant = "x := 1;"; + JSStringRef badSyntax = JSStringCreateWithUTF8CString(badSyntaxConstant); ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL)); ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL)); + ASSERT(!JSScriptCreateFromString(contextGroup, 0, 0, badSyntax, 0, 0)); + ASSERT(!JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, badSyntaxConstant, strlen(badSyntaxConstant), 0, 0)); JSValueRef result; JSValueRef v; @@ -1565,13 +1767,21 @@ int main(int argc, char* argv[]) v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL); ASSERT(JSValueIsEqual(context, v, o, NULL)); - JSStringRef script = JSStringCreateWithUTF8CString("this;"); + const char* thisScript = "this;"; + JSStringRef script = JSStringCreateWithUTF8CString(thisScript); v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); v = JSEvaluateScript(context, script, o, NULL, 1, NULL); ASSERT(JSValueIsEqual(context, v, o, NULL)); JSStringRelease(script); + JSScriptRef scriptObject = JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, thisScript, strlen(thisScript), 0, 0); + v = JSScriptEvaluate(context, scriptObject, NULL, NULL); + ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); + v = JSScriptEvaluate(context, scriptObject, o, NULL); + ASSERT(JSValueIsEqual(context, v, o, NULL)); + JSScriptRelease(scriptObject); + script = JSStringCreateWithUTF8CString("eval(this);"); v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); @@ -1591,8 +1801,23 @@ int main(int argc, char* argv[]) printf("FAIL: Test script could not be loaded.\n"); failed = 1; } else { - script = JSStringCreateWithUTF8CString(scriptUTF8); - result = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); + JSStringRef url = JSStringCreateWithUTF8CString(scriptPath); + JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8); + JSStringRef errorMessage = 0; + int errorLine = 0; + JSScriptRef scriptObject = JSScriptCreateFromString(contextGroup, url, 1, script, &errorMessage, &errorLine); + ASSERT((!scriptObject) != (!errorMessage)); + if (!scriptObject) { + printf("FAIL: Test script did not parse\n\t%s:%d\n\t", scriptPath, errorLine); + CFStringRef errorCF = JSStringCopyCFString(kCFAllocatorDefault, errorMessage); + CFShow(errorCF); + CFRelease(errorCF); + JSStringRelease(errorMessage); + failed = 1; + } + + JSStringRelease(script); + result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0; if (result && JSValueIsUndefined(context, result)) printf("PASS: Test script executed successfully.\n"); else { @@ -1604,10 +1829,163 @@ int main(int argc, char* argv[]) JSStringRelease(exceptionIString); failed = 1; } - JSStringRelease(script); + JSScriptRelease(scriptObject); free(scriptUTF8); } +#if PLATFORM(MAC) || PLATFORM(IOS) + JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime"); + JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTime_callAsFunction); + JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, NULL); + JSStringRelease(currentCPUTimeStr); + + /* Test script timeout: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = NULL; + shouldTerminateCallbackWasCalled = false; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) + printf("PASS: script timed out as expected.\n"); + else { + if (!((endTime - startTime) < .150f)) + printf("FAIL: script did not timed out as expected.\n"); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: script timeout callback was not called.\n"); + failed = true; + } + + if (!exception) { + printf("FAIL: TerminatedExecutionException was not thrown.\n"); + failed = true; + } + } + + /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }"; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = NULL; + shouldTerminateCallbackWasCalled = false; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) { + if (!((endTime - startTime) < .150f)) + printf("FAIL: script did not timed out as expected.\n"); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: script timeout callback was not called.\n"); + failed = true; + } + + if (exception) + printf("PASS: TerminatedExecutionException was not catchable as expected.\n"); + else { + printf("FAIL: TerminatedExecutionException was caught.\n"); + failed = true; + } + } + + /* Test script timeout with no callback: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = NULL; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) + printf("PASS: script timed out as expected when no callback is specified.\n"); + else { + if (!((endTime - startTime) < .150f)) + printf("FAIL: script did not timed out as expected when no callback is specified.\n"); + failed = true; + } + + if (!exception) { + printf("FAIL: TerminatedExecutionException was not thrown.\n"); + failed = true; + } + } + + /* Test script timeout cancellation: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = NULL; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception) + printf("PASS: script timeout was cancelled as expected.\n"); + else { + if (((endTime - startTime) < .150) || exception) + printf("FAIL: script timeout was not cancelled.\n"); + if (!cancelTerminateCallbackWasCalled) + printf("FAIL: script timeout callback was not called.\n"); + failed = true; + } + + if (exception) { + printf("FAIL: Unexpected TerminatedExecutionException thrown.\n"); + failed = true; + } + } + + /* Test script timeout extension: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + double deltaTime; + exception = NULL; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); + endTime = currentCPUTime(); + deltaTime = endTime - startTime; + + if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception) + printf("PASS: script timeout was extended as expected.\n"); + else { + if (deltaTime < .200f) + printf("FAIL: script timeout was not extended as expected.\n"); + else if (deltaTime >= .500f) + printf("FAIL: script did not timeout.\n"); + + if (extendTerminateCallbackCalled < 1) + printf("FAIL: script timeout callback was not called.\n"); + if (extendTerminateCallbackCalled < 2) + printf("FAIL: script timeout callback was not called after timeout extension.\n"); + + if (!exception) + printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n"); + + failed = true; + } + } +#endif /* PLATFORM(MAC) || PLATFORM(IOS) */ + // Clear out local variables pointing at JSObjectRefs to allow their values to be collected function = NULL; v = NULL; @@ -1649,6 +2027,11 @@ int main(int argc, char* argv[]) printf("FAIL: A cycle in a prototype chain can be created.\n"); failed = true; } + if (valueToObjectExceptionTest()) + printf("PASS: throwException did not crash when handling an error with appendMessageToError set and no codeBlock available.\n"); + + if (globalContextNameTest()) + printf("PASS: global context name behaves as expected.\n"); if (failed) { printf("FAIL: Some tests failed.\n"); @@ -1670,6 +2053,7 @@ static char* createStringWithContentsOfFile(const char* fileName) FILE* f = fopen(fileName, "r"); if (!f) { fprintf(stderr, "Could not open file: %s\n", fileName); + free(buffer); return 0; } diff --git a/JavaScriptCore/API/tests/testapi.js b/JavaScriptCore/API/tests/testapi.js index 28fa5443..47c20a83 100644 --- a/JavaScriptCore/API/tests/testapi.js +++ b/JavaScriptCore/API/tests/testapi.js @@ -262,6 +262,10 @@ shouldBe("PropertyCatchalls.x", 4); for (var i = 0; i < 6; ++i) var x = PropertyCatchalls.x; shouldBe("x", null); +var make_throw = 'make_throw'; +shouldThrow("PropertyCatchalls[make_throw]=1"); +make_throw = 0; +shouldThrow("PropertyCatchalls[make_throw]=1"); for (var i = 0; i < 10; ++i) { for (var p in PropertyCatchalls) { diff --git a/JavaScriptCore/API/tests/testapi.mm b/JavaScriptCore/API/tests/testapi.mm new file mode 100644 index 00000000..f22194c6 --- /dev/null +++ b/JavaScriptCore/API/tests/testapi.mm @@ -0,0 +1,1228 @@ +/* + * Copyright (C) 2013 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. + */ + +#import + +#import "CurrentThisInsideBlockGetterTest.h" + +extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef); + +extern "C" bool _Block_has_signature(id); +extern "C" const char * _Block_signature(id); + +extern int failed; +extern "C" void testObjectiveCAPI(void); + +#if JSC_OBJC_API_ENABLED + +@protocol ParentObject +@end + +@interface ParentObject : NSObject ++ (NSString *)parentTest; +@end + +@implementation ParentObject ++ (NSString *)parentTest +{ + return [self description]; +} +@end + +@protocol TestObject +- (id)init; +@property int variable; +@property (readonly) int six; +@property CGPoint point; ++ (NSString *)classTest; ++ (NSString *)parentTest; +- (NSString *)getString; +JSExportAs(testArgumentTypes, +- (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o +); +- (void)callback:(JSValue *)function; +- (void)bogusCallback:(void(^)(int))function; +@end + +@interface TestObject : ParentObject +@property int six; ++ (id)testObject; +@end + +@implementation TestObject +@synthesize variable; +@synthesize six; +@synthesize point; ++ (id)testObject +{ + return [[TestObject alloc] init]; +} ++ (NSString *)classTest +{ + return @"classTest - okay"; +} +- (NSString *)getString +{ + return @"42"; +} +- (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o +{ + return [NSString stringWithFormat:@"%d,%g,%d,%@,%d,%@,%@", i, d, b==YES?true:false,s,[n intValue],a[1],o[@"x"]]; +} +- (void)callback:(JSValue *)function +{ + [function callWithArguments:[NSArray arrayWithObject:[NSNumber numberWithInt:42]]]; +} +- (void)bogusCallback:(void(^)(int))function +{ + function(42); +} +@end + +bool testXYZTested = false; + +@protocol TextXYZ +- (id)initWithString:(NSString*)string; +@property int x; +@property (readonly) int y; +@property (assign) JSValue *onclick; +@property (assign) JSValue *weakOnclick; +- (void)test:(NSString *)message; +@end + +@interface TextXYZ : NSObject +@property int x; +@property int y; +@property int z; +- (void)click; +@end + +@implementation TextXYZ { + JSManagedValue *m_weakOnclickHandler; + JSManagedValue *m_onclickHandler; +} +@synthesize x; +@synthesize y; +@synthesize z; +- (id)initWithString:(NSString*)string +{ + self = [super init]; + if (!self) + return nil; + + NSLog(@"%@", string); + + return self; +} +- (void)test:(NSString *)message +{ + testXYZTested = [message isEqual:@"test"] && x == 13 & y == 4 && z == 5; +} +- (void)setWeakOnclick:(JSValue *)value +{ + m_weakOnclickHandler = [JSManagedValue managedValueWithValue:value]; +} + +- (void)setOnclick:(JSValue *)value +{ + m_onclickHandler = [JSManagedValue managedValueWithValue:value]; + [value.context.virtualMachine addManagedReference:m_onclickHandler withOwner:self]; +} +- (JSValue *)weakOnclick +{ + return [m_weakOnclickHandler value]; +} +- (JSValue *)onclick +{ + return [m_onclickHandler value]; +} +- (void)click +{ + if (!m_onclickHandler) + return; + + JSValue *function = [m_onclickHandler value]; + [function callWithArguments:[NSArray array]]; +} +- (void)dealloc +{ + [[m_onclickHandler value].context.virtualMachine removeManagedReference:m_onclickHandler withOwner:self]; +#if !__has_feature(objc_arc) + [super dealloc]; +#endif +} +@end + +@class TinyDOMNode; + +@protocol TinyDOMNode +- (void)appendChild:(TinyDOMNode *)child; +- (NSUInteger)numberOfChildren; +- (TinyDOMNode *)childAtIndex:(NSUInteger)index; +- (void)removeChildAtIndex:(NSUInteger)index; +@end + +@interface TinyDOMNode : NSObject +@end + +@implementation TinyDOMNode { + NSMutableArray *m_children; + JSVirtualMachine *m_sharedVirtualMachine; +} + +- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine +{ + self = [super init]; + if (!self) + return nil; + + m_children = [[NSMutableArray alloc] initWithCapacity:0]; + m_sharedVirtualMachine = virtualMachine; +#if !__has_feature(objc_arc) + [m_sharedVirtualMachine retain]; +#endif + + return self; +} + +- (void)dealloc +{ + for (TinyDOMNode *child in m_children) + [m_sharedVirtualMachine removeManagedReference:child withOwner:self]; + +#if !__has_feature(objc_arc) + [m_children release]; + [m_sharedVirtualMachine release]; + [super dealloc]; +#endif +} + +- (void)appendChild:(TinyDOMNode *)child +{ + [m_sharedVirtualMachine addManagedReference:child withOwner:self]; + [m_children addObject:child]; +} + +- (NSUInteger)numberOfChildren +{ + return [m_children count]; +} + +- (TinyDOMNode *)childAtIndex:(NSUInteger)index +{ + if (index >= [m_children count]) + return nil; + return [m_children objectAtIndex:index]; +} + +- (void)removeChildAtIndex:(NSUInteger)index +{ + if (index >= [m_children count]) + return; + [m_sharedVirtualMachine removeManagedReference:[m_children objectAtIndex:index] withOwner:self]; + [m_children removeObjectAtIndex:index]; +} + +@end + +@interface JSCollection : NSObject +- (void)setValue:(JSValue *)value forKey:(NSString *)key; +- (JSValue *)valueForKey:(NSString *)key; +@end + +@implementation JSCollection { + NSMutableDictionary *_dict; +} +- (id)init +{ + self = [super init]; + if (!self) + return nil; + + _dict = [[NSMutableDictionary alloc] init]; + + return self; +} + +- (void)setValue:(JSValue *)value forKey:(NSString *)key +{ + JSManagedValue *oldManagedValue = [_dict objectForKey:key]; + if (oldManagedValue) { + JSValue* oldValue = [oldManagedValue value]; + if (oldValue) + [oldValue.context.virtualMachine removeManagedReference:oldManagedValue withOwner:self]; + } + JSManagedValue *managedValue = [JSManagedValue managedValueWithValue:value]; + [value.context.virtualMachine addManagedReference:managedValue withOwner:self]; + [_dict setObject:managedValue forKey:key]; +} + +- (JSValue *)valueForKey:(NSString *)key +{ + JSManagedValue *managedValue = [_dict objectForKey:key]; + if (!managedValue) + return nil; + return [managedValue value]; +} +@end + +@protocol InitA +- (id)initWithA:(int)a; +- (int)initialize; +@end + +@protocol InitB +- (id)initWithA:(int)a b:(int)b; +@end + +@protocol InitC +- (id)_init; +@end + +@interface ClassA : NSObject +@end + +@interface ClassB : ClassA +@end + +@interface ClassC : ClassB +@end + +@interface ClassCPrime : ClassB +@end + +@interface ClassD : NSObject +- (id)initWithA:(int)a; +@end + +@interface ClassE : ClassD +- (id)initWithA:(int)a; +@end + +@implementation ClassA { + int _a; +} +- (id)initWithA:(int)a +{ + self = [super init]; + if (!self) + return nil; + + _a = a; + + return self; +} +- (int)initialize +{ + return 42; +} +@end + +@implementation ClassB { + int _b; +} +- (id)initWithA:(int)a b:(int)b +{ + self = [super initWithA:a]; + if (!self) + return nil; + + _b = b; + + return self; +} +@end + +@implementation ClassC { + int _c; +} +- (id)initWithA:(int)a +{ + return [self initWithA:a b:0]; +} +- (id)initWithA:(int)a b:(int)b +{ + self = [super initWithA:a b:b]; + if (!self) + return nil; + + _c = a + b; + + return self; +} +@end + +@implementation ClassCPrime +- (id)initWithA:(int)a +{ + self = [super initWithA:a b:0]; + if (!self) + return nil; + return self; +} +- (id)_init +{ + return [self initWithA:42]; +} +@end + +@implementation ClassD + +- (id)initWithA:(int)a +{ + self = nil; + return [[ClassE alloc] initWithA:a]; +} +- (int)initialize +{ + return 0; +} +@end + +@implementation ClassE { + int _a; +} + +- (id)initWithA:(int)a +{ + self = [super init]; + if (!self) + return nil; + + _a = a; + + return self; +} +@end + +static bool evilAllocationObjectWasDealloced = false; + +@interface EvilAllocationObject : NSObject +- (JSValue *)doEvilThingsWithContext:(JSContext *)context; +@end + +@implementation EvilAllocationObject { + JSContext *m_context; +} +- (id)initWithContext:(JSContext *)context +{ + self = [super init]; + if (!self) + return nil; + + m_context = context; + + return self; +} +- (void)dealloc +{ + [self doEvilThingsWithContext:m_context]; + evilAllocationObjectWasDealloced = true; +#if !__has_feature(objc_arc) + [super dealloc]; +#endif +} + +- (JSValue *)doEvilThingsWithContext:(JSContext *)context +{ + return [context evaluateScript:@" \ + (function() { \ + var a = []; \ + var sum = 0; \ + for (var i = 0; i < 10000; ++i) { \ + sum += i; \ + a[i] = sum; \ + } \ + return sum; \ + })()"]; +} +@end + +static void checkResult(NSString *description, bool passed) +{ + NSLog(@"TEST: \"%@\": %@", description, passed ? @"PASSED" : @"FAILED"); + if (!passed) + failed = 1; +} + +static bool blockSignatureContainsClass() +{ + static bool containsClass = ^{ + id block = ^(NSString *string){ return string; }; + return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString"); + }(); + return containsClass; +} + +void testObjectiveCAPI() +{ + NSLog(@"Testing Objective-C API"); + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *result = [context evaluateScript:@"2 + 2"]; + checkResult(@"2 + 2", [result isNumber] && [result toInt32] == 4); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + NSString *result = [NSString stringWithFormat:@"Two plus two is %@", [context evaluateScript:@"2 + 2"]]; + checkResult(@"stringWithFormat", [result isEqual:@"Two plus two is 4"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"message"] = @"Hello"; + JSValue *result = [context evaluateScript:@"message + ', World!'"]; + checkResult(@"Hello, World!", [result isString] && [result isEqualToObject:@"Hello, World!"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *result = [context evaluateScript:@"({ x:42 })"]; + checkResult(@"({ x:42 })", [result isObject] && [result[@"x"] isEqualToObject:@42]); + id obj = [result toObject]; + checkResult(@"Check dictionary literal", [obj isKindOfClass:[NSDictionary class]]); + id num = (NSDictionary *)obj[@"x"]; + checkResult(@"Check numeric literal", [num isKindOfClass:[NSNumber class]]); + } + + @autoreleasepool { + JSCollection* myPrivateProperties = [[JSCollection alloc] init]; + + @autoreleasepool { + JSContext* context = [[JSContext alloc] init]; + TestObject* rootObject = [TestObject testObject]; + context[@"root"] = rootObject; + [context.virtualMachine addManagedReference:myPrivateProperties withOwner:rootObject]; + [myPrivateProperties setValue:[JSValue valueWithBool:true inContext:context] forKey:@"is_ham"]; + [myPrivateProperties setValue:[JSValue valueWithObject:@"hello!" inContext:context] forKey:@"message"]; + [myPrivateProperties setValue:[JSValue valueWithInt32:42 inContext:context] forKey:@"my_number"]; + [myPrivateProperties setValue:[JSValue valueWithNullInContext:context] forKey:@"definitely_null"]; + [myPrivateProperties setValue:[JSValue valueWithUndefinedInContext:context] forKey:@"not_sure_if_undefined"]; + + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + + JSValue *isHam = [myPrivateProperties valueForKey:@"is_ham"]; + JSValue *message = [myPrivateProperties valueForKey:@"message"]; + JSValue *myNumber = [myPrivateProperties valueForKey:@"my_number"]; + JSValue *definitelyNull = [myPrivateProperties valueForKey:@"definitely_null"]; + JSValue *notSureIfUndefined = [myPrivateProperties valueForKey:@"not_sure_if_undefined"]; + checkResult(@"is_ham is true", [isHam isBoolean] && [isHam toBool]); + checkResult(@"message is hello!", [message isString] && [@"hello!" isEqualToString:[message toString]]); + checkResult(@"my_number is 42", [myNumber isNumber] && [myNumber toInt32] == 42); + checkResult(@"definitely_null is null", [definitelyNull isNull]); + checkResult(@"not_sure_if_undefined is undefined", [notSureIfUndefined isUndefined]); + } + + checkResult(@"is_ham is nil", ![myPrivateProperties valueForKey:@"is_ham"]); + checkResult(@"message is nil", ![myPrivateProperties valueForKey:@"message"]); + checkResult(@"my_number is 42", ![myPrivateProperties valueForKey:@"my_number"]); + checkResult(@"definitely_null is null", ![myPrivateProperties valueForKey:@"definitely_null"]); + checkResult(@"not_sure_if_undefined is undefined", ![myPrivateProperties valueForKey:@"not_sure_if_undefined"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + __block int result; + context[@"blockCallback"] = ^(int value){ + result = value; + }; + [context evaluateScript:@"blockCallback(42)"]; + checkResult(@"blockCallback", result == 42); + } + + if (blockSignatureContainsClass()) { + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + __block bool result = false; + context[@"blockCallback"] = ^(NSString *value){ + result = [@"42" isEqualToString:value] == YES; + }; + [context evaluateScript:@"blockCallback(42)"]; + checkResult(@"blockCallback(NSString *)", result); + } + } else + NSLog(@"Skipping 'blockCallback(NSString *)' test case"); + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + checkResult(@"!context.exception", !context.exception); + [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"]; + checkResult(@"context.exception", context.exception); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + __block bool caught = false; + context.exceptionHandler = ^(JSContext *context, JSValue *exception) { + (void)context; + (void)exception; + caught = true; + }; + [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"]; + checkResult(@"JSContext.exceptionHandler", caught); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"callback"] = ^{ + JSContext *context = [JSContext currentContext]; + context.exception = [JSValue valueWithNewErrorFromMessage:@"Something went wrong." inContext:context]; + }; + JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"]; + checkResult(@"Explicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]); + checkResult(@"Explicit throw in callback - not thrown to Objective-C", !context.exception); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"callback"] = ^{ + JSContext *context = [JSContext currentContext]; + [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"]; + }; + JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"]; + checkResult(@"Implicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]); + checkResult(@"Implicit throw in callback - not thrown to Objective-C", !context.exception); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + [context evaluateScript: + @"function sum(array) { \ + var result = 0; \ + for (var i in array) \ + result += array[i]; \ + return result; \ + }"]; + JSValue *array = [JSValue valueWithObject:@[@13, @2, @7] inContext:context]; + JSValue *sumFunction = context[@"sum"]; + JSValue *result = [sumFunction callWithArguments:@[ array ]]; + checkResult(@"sum([13, 2, 7])", [result toInt32] == 22); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *mulAddFunction = [context evaluateScript: + @"(function(array, object) { \ + var result = []; \ + for (var i in array) \ + result.push(array[i] * object.x + object.y); \ + return result; \ + })"]; + JSValue *result = [mulAddFunction callWithArguments:@[ @[ @2, @4, @8 ], @{ @"x":@0.5, @"y":@42 } ]]; + checkResult(@"mulAddFunction", [result isObject] && [[result toString] isEqual:@"43,44,46"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *array = [JSValue valueWithNewArrayInContext:context]; + checkResult(@"arrayLengthEmpty", [[array[@"length"] toNumber] unsignedIntegerValue] == 0); + JSValue *value1 = [JSValue valueWithInt32:42 inContext:context]; + JSValue *value2 = [JSValue valueWithInt32:24 inContext:context]; + NSUInteger lowIndex = 5; + NSUInteger maxLength = UINT_MAX; + + [array setValue:value1 atIndex:lowIndex]; + checkResult(@"array.length after put to low index", [[array[@"length"] toNumber] unsignedIntegerValue] == (lowIndex + 1)); + + [array setValue:value1 atIndex:(maxLength - 1)]; + checkResult(@"array.length after put to maxLength - 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength); + + [array setValue:value2 atIndex:maxLength]; + checkResult(@"array.length after put to maxLength", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength); + + [array setValue:value2 atIndex:(maxLength + 1)]; + checkResult(@"array.length after put to maxLength + 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength); + + if (sizeof(NSUInteger) == 8) + checkResult(@"valueAtIndex:0 is undefined", [[array valueAtIndex:0] isUndefined]); + else + checkResult(@"valueAtIndex:0", [[array valueAtIndex:0] toInt32] == 24); + checkResult(@"valueAtIndex:lowIndex", [[array valueAtIndex:lowIndex] toInt32] == 42); + checkResult(@"valueAtIndex:maxLength - 1", [[array valueAtIndex:(maxLength - 1)] toInt32] == 42); + checkResult(@"valueAtIndex:maxLength", [[array valueAtIndex:maxLength] toInt32] == 24); + checkResult(@"valueAtIndex:maxLength + 1", [[array valueAtIndex:(maxLength + 1)] toInt32] == 24); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *object = [JSValue valueWithNewObjectInContext:context]; + + object[@"point"] = @{ @"x":@1, @"y":@2 }; + object[@"point"][@"x"] = @3; + CGPoint point = [object[@"point"] toPoint]; + checkResult(@"toPoint", point.x == 3 && point.y == 2); + + object[@{ @"toString":^{ return @"foo"; } }] = @"bar"; + checkResult(@"toString in object literal used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]); + + object[[@"foobar" substringToIndex:3]] = @"bar"; + checkResult(@"substring used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TextXYZ *testXYZ = [[TextXYZ alloc] init]; + context[@"testXYZ"] = testXYZ; + testXYZ.x = 3; + testXYZ.y = 4; + testXYZ.z = 5; + [context evaluateScript:@"testXYZ.x = 13; testXYZ.y = 14;"]; + [context evaluateScript:@"testXYZ.test('test')"]; + checkResult(@"TextXYZ - testXYZTested", testXYZTested); + JSValue *result = [context evaluateScript:@"testXYZ.x + ',' + testXYZ.y + ',' + testXYZ.z"]; + checkResult(@"TextXYZ - result", [result isEqualToObject:@"13,4,undefined"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + [context[@"Object"][@"prototype"] defineProperty:@"getterProperty" descriptor:@{ + JSPropertyDescriptorGetKey:^{ + return [JSContext currentThis][@"x"]; + } + }]; + JSValue *object = [JSValue valueWithObject:@{ @"x":@101 } inContext:context]; + int result = [object [@"getterProperty"] toInt32]; + checkResult(@"getterProperty", result == 101); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"concatenate"] = ^{ + NSArray *arguments = [JSContext currentArguments]; + if (![arguments count]) + return @""; + NSString *message = [arguments[0] description]; + for (NSUInteger index = 1; index < [arguments count]; ++index) + message = [NSString stringWithFormat:@"%@ %@", message, arguments[index]]; + return message; + }; + JSValue *result = [context evaluateScript:@"concatenate('Hello,', 'World!')"]; + checkResult(@"concatenate", [result isEqualToObject:@"Hello, World!"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"foo"] = @YES; + checkResult(@"@YES is boolean", [context[@"foo"] isBoolean]); + JSValue *result = [context evaluateScript:@"typeof foo"]; + checkResult(@"@YES is boolean", [result isEqualToObject:@"boolean"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + JSValue *result = [context evaluateScript:@"String(testObject)"]; + checkResult(@"String(testObject)", [result isEqualToObject:@"[object TestObject]"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + JSValue *result = [context evaluateScript:@"String(testObject.__proto__)"]; + checkResult(@"String(testObject.__proto__)", [result isEqualToObject:@"[object TestObjectPrototype]"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"TestObject"] = [TestObject class]; + JSValue *result = [context evaluateScript:@"String(TestObject)"]; + checkResult(@"String(TestObject)", [result isEqualToObject:@"function TestObject() {\n [native code]\n}"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue* value = [JSValue valueWithObject:[TestObject class] inContext:context]; + checkResult(@"[value toObject] == [TestObject class]", [value toObject] == [TestObject class]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"TestObject"] = [TestObject class]; + JSValue *result = [context evaluateScript:@"TestObject.parentTest()"]; + checkResult(@"TestObject.parentTest()", [result isEqualToObject:@"TestObject"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObjectA"] = testObject; + context[@"testObjectB"] = testObject; + JSValue *result = [context evaluateScript:@"testObjectA == testObjectB"]; + checkResult(@"testObjectA == testObjectB", [result isBoolean] && [result toBool]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + testObject.point = (CGPoint){3,4}; + JSValue *result = [context evaluateScript:@"var result = JSON.stringify(testObject.point); testObject.point = {x:12,y:14}; result"]; + checkResult(@"testObject.point - result", [result isEqualToObject:@"{\"x\":3,\"y\":4}"]); + checkResult(@"testObject.point - {x:12,y:14}", testObject.point.x == 12 && testObject.point.y == 14); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + testObject.six = 6; + context[@"testObject"] = testObject; + context[@"mul"] = ^(int x, int y){ return x * y; }; + JSValue *result = [context evaluateScript:@"mul(testObject.six, 7)"]; + checkResult(@"mul(testObject.six, 7)", [result isNumber] && [result toInt32] == 42); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + context[@"testObject"][@"variable"] = @4; + [context evaluateScript:@"++testObject.variable"]; + checkResult(@"++testObject.variable", testObject.variable == 5); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"point"] = @{ @"x":@6, @"y":@7 }; + JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"]; + checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"point"] = @{ @"x":@6, @"y":@7 }; + JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"]; + checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + JSValue *result = [context evaluateScript:@"testObject.getString()"]; + checkResult(@"testObject.getString()", [result isString] && [result toInt32] == 42); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + JSValue *result = [context evaluateScript:@"testObject.testArgumentTypes(101,0.5,true,'foo',666,[false,'bar',false],{x:'baz'})"]; + checkResult(@"testObject.testArgumentTypes", [result isEqualToObject:@"101,0.5,1,foo,666,bar,baz"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + JSValue *result = [context evaluateScript:@"testObject.getString.call(testObject)"]; + checkResult(@"testObject.getString.call(testObject)", [result isString] && [result toInt32] == 42); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + checkResult(@"testObject.getString.call({}) pre", !context.exception); + [context evaluateScript:@"testObject.getString.call({})"]; + checkResult(@"testObject.getString.call({}) post", context.exception); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject* testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + JSValue *result = [context evaluateScript:@"var result = 0; testObject.callback(function(x){ result = x; }); result"]; + checkResult(@"testObject.callback", [result isNumber] && [result toInt32] == 42); + result = [context evaluateScript:@"testObject.bogusCallback"]; + checkResult(@"testObject.bogusCallback == undefined", [result isUndefined]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject *testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + JSValue *result = [context evaluateScript:@"Function.prototype.toString.call(testObject.callback)"]; + checkResult(@"Function.prototype.toString", !context.exception && ![result isUndefined]); + } + + @autoreleasepool { + JSContext *context1 = [[JSContext alloc] init]; + JSContext *context2 = [[JSContext alloc] initWithVirtualMachine:context1.virtualMachine]; + JSValue *value = [JSValue valueWithDouble:42 inContext:context2]; + context1[@"passValueBetweenContexts"] = value; + JSValue *result = [context1 evaluateScript:@"passValueBetweenContexts"]; + checkResult(@"[value isEqualToObject:result]", [value isEqualToObject:result]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"handleTheDictionary"] = ^(NSDictionary *dict) { + NSDictionary *expectedDict = @{ + @"foo" : [NSNumber numberWithInt:1], + @"bar" : @{ + @"baz": [NSNumber numberWithInt:2] + } + }; + checkResult(@"recursively convert nested dictionaries", [dict isEqualToDictionary:expectedDict]); + }; + [context evaluateScript:@"var myDict = { \ + 'foo': 1, \ + 'bar': {'baz': 2} \ + }; \ + handleTheDictionary(myDict);"]; + + context[@"handleTheArray"] = ^(NSArray *array) { + NSArray *expectedArray = @[@"foo", @"bar", @[@"baz"]]; + checkResult(@"recursively convert nested arrays", [array isEqualToArray:expectedArray]); + }; + [context evaluateScript:@"var myArray = ['foo', 'bar', ['baz']]; handleTheArray(myArray);"]; + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject *testObject = [TestObject testObject]; + @autoreleasepool { + context[@"testObject"] = testObject; + [context evaluateScript:@"var constructor = Object.getPrototypeOf(testObject).constructor; constructor.prototype = undefined;"]; + [context evaluateScript:@"testObject = undefined"]; + } + + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + + @autoreleasepool { + context[@"testObject"] = testObject; + } + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TextXYZ *testXYZ = [[TextXYZ alloc] init]; + + @autoreleasepool { + context[@"testXYZ"] = testXYZ; + + [context evaluateScript:@" \ + didClick = false; \ + testXYZ.onclick = function() { \ + didClick = true; \ + }; \ + \ + testXYZ.weakOnclick = function() { \ + return 'foo'; \ + }; \ + "]; + } + + @autoreleasepool { + [testXYZ click]; + JSValue *result = [context evaluateScript:@"didClick"]; + checkResult(@"Event handler onclick", [result toBool]); + } + + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + + @autoreleasepool { + JSValue *result = [context evaluateScript:@"testXYZ.onclick"]; + checkResult(@"onclick still around after GC", !([result isNull] || [result isUndefined])); + } + + + @autoreleasepool { + JSValue *result = [context evaluateScript:@"testXYZ.weakOnclick"]; + checkResult(@"weakOnclick not around after GC", [result isNull] || [result isUndefined]); + } + + @autoreleasepool { + [context evaluateScript:@" \ + didClick = false; \ + testXYZ = null; \ + "]; + } + + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + + @autoreleasepool { + [testXYZ click]; + JSValue *result = [context evaluateScript:@"didClick"]; + checkResult(@"Event handler onclick doesn't fire", ![result toBool]); + } + } + + @autoreleasepool { + JSVirtualMachine *vm = [[JSVirtualMachine alloc] init]; + TestObject *testObject = [TestObject testObject]; + JSManagedValue *weakValue; + @autoreleasepool { + JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; + context[@"testObject"] = testObject; + weakValue = [[JSManagedValue alloc] initWithValue:context[@"testObject"]]; + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; + context[@"testObject"] = testObject; + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + checkResult(@"weak value == nil", ![weakValue value]); + checkResult(@"root is still alive", ![context[@"testObject"] isUndefined]); + } + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine]; + TinyDOMNode *lastNode = root; + for (NSUInteger i = 0; i < 3; i++) { + TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine]; + [lastNode appendChild:newNode]; + lastNode = newNode; + } + + @autoreleasepool { + context[@"root"] = root; + context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){ + TinyDOMNode *lastNode = nil; + while (head) { + lastNode = head; + head = [lastNode childAtIndex:0]; + } + return lastNode; + }; + [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"]; + } + + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + + JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"]; + checkResult(@"My custom property == 42", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine]; + TinyDOMNode *lastNode = root; + for (NSUInteger i = 0; i < 3; i++) { + TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine]; + [lastNode appendChild:newNode]; + lastNode = newNode; + } + + @autoreleasepool { + context[@"root"] = root; + context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){ + TinyDOMNode *lastNode = nil; + while (head) { + lastNode = head; + head = [lastNode childAtIndex:0]; + } + return lastNode; + }; + [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"]; + + [root appendChild:[root childAtIndex:0]]; + [root removeChildAtIndex:0]; + } + + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + + JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"]; + checkResult(@"duplicate calls to addManagedReference don't cause things to die", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *o = [JSValue valueWithNewObjectInContext:context]; + o[@"foo"] = @"foo"; + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + + checkResult(@"JSValue correctly protected its internal value", [[o[@"foo"] toString] isEqualToString:@"foo"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + TestObject *testObject = [TestObject testObject]; + context[@"testObject"] = testObject; + [context evaluateScript:@"testObject.__lookupGetter__('variable').call({})"]; + checkResult(@"Make sure we throw an exception when calling getter on incorrect |this|", context.exception); + } + + @autoreleasepool { + TestObject *testObject = [TestObject testObject]; + JSManagedValue *managedTestObject; + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"testObject"] = testObject; + managedTestObject = [JSManagedValue managedValueWithValue:context[@"testObject"]]; + [context.virtualMachine addManagedReference:managedTestObject withOwner:testObject]; + } + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"MyClass"] = ^{ + JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]]; + JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef]; + JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL); + JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentContext][@"MyClass"][@"prototype"] JSValueRef]); + return newThis; + }; + + context[@"MyOtherClass"] = ^{ + JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]]; + JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef]; + JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL); + JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentContext][@"MyOtherClass"][@"prototype"] JSValueRef]); + return newThis; + }; + + context.exceptionHandler = ^(JSContext *context, JSValue *exception) { + NSLog(@"EXCEPTION: %@", [exception toString]); + context.exception = nil; + }; + + JSValue *constructor1 = context[@"MyClass"]; + JSValue *constructor2 = context[@"MyOtherClass"]; + + JSValue *value1 = [context evaluateScript:@"new MyClass()"]; + checkResult(@"value1 instanceof MyClass", [value1 isInstanceOf:constructor1]); + checkResult(@"!(value1 instanceof MyOtherClass)", ![value1 isInstanceOf:constructor2]); + checkResult(@"MyClass.prototype.constructor === MyClass", [[context evaluateScript:@"MyClass.prototype.constructor === MyClass"] toBool]); + checkResult(@"MyClass instanceof Function", [[context evaluateScript:@"MyClass instanceof Function"] toBool]); + + JSValue *value2 = [context evaluateScript:@"new MyOtherClass()"]; + checkResult(@"value2 instanceof MyOtherClass", [value2 isInstanceOf:constructor2]); + checkResult(@"!(value2 instanceof MyClass)", ![value2 isInstanceOf:constructor1]); + checkResult(@"MyOtherClass.prototype.constructor === MyOtherClass", [[context evaluateScript:@"MyOtherClass.prototype.constructor === MyOtherClass"] toBool]); + checkResult(@"MyOtherClass instanceof Function", [[context evaluateScript:@"MyOtherClass instanceof Function"] toBool]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"MyClass"] = ^{ + NSLog(@"I'm intentionally not returning anything."); + }; + JSValue *result = [context evaluateScript:@"new MyClass()"]; + checkResult(@"result === undefined", [result isUndefined]); + checkResult(@"exception.message is correct'", context.exception + && [@"Objective-C blocks called as constructors must return an object." isEqualToString:[context.exception[@"message"] toString]]); + } + + @autoreleasepool { + checkResult(@"[JSContext currentThis] == nil outside of callback", ![JSContext currentThis]); + checkResult(@"[JSContext currentArguments] == nil outside of callback", ![JSContext currentArguments]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"TestObject"] = [TestObject class]; + JSValue *testObject = [context evaluateScript:@"(new TestObject())"]; + checkResult(@"testObject instanceof TestObject", [testObject isInstanceOf:context[@"TestObject"]]); + + context[@"TextXYZ"] = [TextXYZ class]; + JSValue *textObject = [context evaluateScript:@"(new TextXYZ(\"Called TextXYZ constructor!\"))"]; + checkResult(@"textObject instanceof TextXYZ", [textObject isInstanceOf:context[@"TextXYZ"]]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"ClassA"] = [ClassA class]; + context[@"ClassB"] = [ClassB class]; + context[@"ClassC"] = [ClassC class]; // Should print error message about too many inits found. + context[@"ClassCPrime"] = [ClassCPrime class]; // Ditto. + + JSValue *a = [context evaluateScript:@"(new ClassA(42))"]; + checkResult(@"a instanceof ClassA", [a isInstanceOf:context[@"ClassA"]]); + checkResult(@"a.initialize() is callable", [[a invokeMethod:@"initialize" withArguments:@[]] toInt32] == 42); + + JSValue *b = [context evaluateScript:@"(new ClassB(42, 53))"]; + checkResult(@"b instanceof ClassB", [b isInstanceOf:context[@"ClassB"]]); + + JSValue *canConstructClassC = [context evaluateScript:@"(function() { \ + try { \ + (new ClassC(1, 2)); \ + return true; \ + } catch(e) { \ + return false; \ + } \ + })()"]; + checkResult(@"shouldn't be able to construct ClassC", ![canConstructClassC toBool]); + JSValue *canConstructClassCPrime = [context evaluateScript:@"(function() { \ + try { \ + (new ClassCPrime(1)); \ + return true; \ + } catch(e) { \ + return false; \ + } \ + })()"]; + checkResult(@"shouldn't be able to construct ClassCPrime", ![canConstructClassCPrime toBool]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + context[@"ClassD"] = [ClassD class]; + context[@"ClassE"] = [ClassE class]; + + JSValue *d = [context evaluateScript:@"(new ClassD())"]; + checkResult(@"Returning instance of ClassE from ClassD's init has correct class", [d isInstanceOf:context[@"ClassE"]]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + @autoreleasepool { + EvilAllocationObject *evilObject = [[EvilAllocationObject alloc] initWithContext:context]; + context[@"evilObject"] = evilObject; + context[@"evilObject"] = nil; + } + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + checkResult(@"EvilAllocationObject was successfully dealloced without crashing", evilAllocationObjectWasDealloced); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + checkResult(@"default context.name is nil", context.name == nil); + NSString *name1 = @"Name1"; + NSString *name2 = @"Name2"; + context.name = name1; + NSString *fetchedName1 = context.name; + context.name = name2; + NSString *fetchedName2 = context.name; + checkResult(@"fetched context.name was expected", [fetchedName1 isEqualToString:name1]); + checkResult(@"fetched context.name was expected", [fetchedName2 isEqualToString:name2]); + checkResult(@"fetched context.name was expected", ![fetchedName1 isEqualToString:fetchedName2]); + } + + currentThisInsideBlockGetterTest(); +} + +#else + +void testObjectiveCAPI() +{ +} + +#endif // JSC_OBJC_API_ENABLED diff --git a/JavaScriptCore/CMakeLists.txt b/JavaScriptCore/CMakeLists.txt index bf48f970..36b7118e 100644 --- a/JavaScriptCore/CMakeLists.txt +++ b/JavaScriptCore/CMakeLists.txt @@ -1,14 +1,18 @@ -SET(JavaScriptCore_INCLUDE_DIRECTORIES +set(JavaScriptCore_INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}" "${JAVASCRIPTCORE_DIR}" "${JAVASCRIPTCORE_DIR}/API" "${JAVASCRIPTCORE_DIR}/ForwardingHeaders" "${JAVASCRIPTCORE_DIR}/assembler" + "${JAVASCRIPTCORE_DIR}/bindings" "${JAVASCRIPTCORE_DIR}/bytecode" "${JAVASCRIPTCORE_DIR}/bytecompiler" "${JAVASCRIPTCORE_DIR}/dfg" + "${JAVASCRIPTCORE_DIR}/disassembler" + "${JAVASCRIPTCORE_DIR}/ftl" "${JAVASCRIPTCORE_DIR}/heap" "${JAVASCRIPTCORE_DIR}/debugger" + "${JAVASCRIPTCORE_DIR}/inspector" "${JAVASCRIPTCORE_DIR}/interpreter" "${JAVASCRIPTCORE_DIR}/jit" "${JAVASCRIPTCORE_DIR}/llint" @@ -22,8 +26,9 @@ SET(JavaScriptCore_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/Source" ) -SET(JavaScriptCore_SOURCES +set(JavaScriptCore_SOURCES API/JSBase.cpp + API/JSCTestRunnerUtils.cpp API/JSCallbackConstructor.cpp API/JSCallbackFunction.cpp API/JSCallbackObject.cpp @@ -31,126 +36,289 @@ SET(JavaScriptCore_SOURCES API/JSContextRef.cpp API/JSObjectRef.cpp API/JSProfilerPrivate.cpp + API/JSScriptRef.cpp API/JSStringRef.cpp API/JSValueRef.cpp API/JSWeakObjectMapRefPrivate.cpp API/OpaqueJSString.cpp + assembler/LinkBuffer.cpp + assembler/MacroAssembler.cpp + assembler/MacroAssemblerX86Common.cpp + + bindings/ScriptFunctionCall.cpp + bindings/ScriptObject.cpp + bindings/ScriptValue.cpp + + bytecode/ArrayAllocationProfile.cpp + bytecode/ArrayProfile.cpp + bytecode/BytecodeBasicBlock.cpp + bytecode/BytecodeLivenessAnalysis.cpp bytecode/CallLinkInfo.cpp bytecode/CallLinkStatus.cpp bytecode/CodeBlock.cpp + bytecode/CodeBlockHash.cpp + bytecode/CodeBlockJettisoningWatchpoint.cpp + bytecode/CodeOrigin.cpp + bytecode/CodeType.cpp bytecode/DFGExitProfile.cpp + bytecode/DeferredCompilationCallback.cpp bytecode/ExecutionCounter.cpp + bytecode/ExitKind.cpp bytecode/GetByIdStatus.cpp + bytecode/InlineCallFrameSet.cpp bytecode/JumpTable.cpp bytecode/LazyOperandValueProfile.cpp - bytecode/MethodCallLinkInfo.cpp - bytecode/MethodCallLinkStatus.cpp bytecode/MethodOfGettingAValueProfile.cpp bytecode/Opcode.cpp bytecode/PolymorphicPutByIdList.cpp - bytecode/PredictedType.cpp + bytecode/PreciseJumpTargets.cpp + bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp bytecode/PutByIdStatus.cpp + bytecode/ReduceWhitespace.cpp bytecode/SamplingTool.cpp + bytecode/SpecialPointer.cpp + bytecode/SpeculatedType.cpp + bytecode/StructureStubClearingWatchpoint.cpp bytecode/StructureStubInfo.cpp + bytecode/UnlinkedCodeBlock.cpp + bytecode/ValueRecovery.cpp + bytecode/Watchpoint.cpp bytecompiler/BytecodeGenerator.cpp bytecompiler/NodesCodegen.cpp - dfg/DFGAbstractState.cpp - dfg/DFGAssemblyHelpers.cpp + debugger/Debugger.cpp + debugger/DebuggerActivation.cpp + debugger/DebuggerCallFrame.cpp + + dfg/DFGAbstractHeap.cpp + dfg/DFGAbstractValue.cpp + dfg/DFGArgumentsSimplificationPhase.cpp + dfg/DFGArrayMode.cpp + dfg/DFGAtTailAbstractState.cpp + dfg/DFGAvailability.cpp + dfg/DFGBackwardsPropagationPhase.cpp + dfg/DFGBasicBlock.cpp + dfg/DFGBinarySwitch.cpp + dfg/DFGBlockInsertionSet.cpp dfg/DFGByteCodeParser.cpp - dfg/DFGCapabilities.cpp dfg/DFGCFAPhase.cpp - dfg/DFGCorrectableJumpPoint.cpp + dfg/DFGCFGSimplificationPhase.cpp + dfg/DFGCPSRethreadingPhase.cpp dfg/DFGCSEPhase.cpp + dfg/DFGCapabilities.cpp + dfg/DFGClobberSet.cpp + dfg/DFGClobberize.cpp + dfg/DFGCommon.cpp + dfg/DFGCommonData.cpp + dfg/DFGCompilationKey.cpp + dfg/DFGCompilationMode.cpp + dfg/DFGConstantFoldingPhase.cpp + dfg/DFGCriticalEdgeBreakingPhase.cpp + dfg/DFGDCEPhase.cpp + dfg/DFGDesiredIdentifiers.cpp + dfg/DFGDesiredStructureChains.cpp + dfg/DFGDesiredTransitions.cpp + dfg/DFGDesiredWatchpoints.cpp + dfg/DFGDesiredWeakReferences.cpp + dfg/DFGDesiredWriteBarriers.cpp + dfg/DFGDisassembler.cpp + dfg/DFGDominators.cpp dfg/DFGDriver.cpp + dfg/DFGEdge.cpp + dfg/DFGFailedFinalizer.cpp + dfg/DFGFinalizer.cpp dfg/DFGFixupPhase.cpp + dfg/DFGFlushFormat.cpp + dfg/DFGFlushLivenessAnalysisPhase.cpp + dfg/DFGFlushedAt.cpp dfg/DFGGraph.cpp + dfg/DFGInPlaceAbstractState.cpp + dfg/DFGInvalidationPointInjectionPhase.cpp + dfg/DFGJITCode.cpp dfg/DFGJITCompiler.cpp + dfg/DFGJITFinalizer.cpp + dfg/DFGJumpReplacement.cpp + dfg/DFGLICMPhase.cpp + dfg/DFGLazyJSValue.cpp + dfg/DFGLivenessAnalysisPhase.cpp + dfg/DFGLongLivedState.cpp + dfg/DFGLoopPreHeaderCreationPhase.cpp + dfg/DFGMinifiedNode.cpp + dfg/DFGNaturalLoops.cpp + dfg/DFGNode.cpp dfg/DFGNodeFlags.cpp + dfg/DFGOSRAvailabilityAnalysisPhase.cpp dfg/DFGOSREntry.cpp + dfg/DFGOSREntrypointCreationPhase.cpp dfg/DFGOSRExit.cpp + dfg/DFGOSRExitBase.cpp dfg/DFGOSRExitCompiler.cpp dfg/DFGOSRExitCompiler32_64.cpp dfg/DFGOSRExitCompiler64.cpp + dfg/DFGOSRExitCompilerCommon.cpp + dfg/DFGOSRExitJumpPlaceholder.cpp + dfg/DFGOSRExitPreparation.cpp dfg/DFGOperations.cpp dfg/DFGPhase.cpp + dfg/DFGPlan.cpp + dfg/DFGPredictionInjectionPhase.cpp dfg/DFGPredictionPropagationPhase.cpp - dfg/DFGRedundantPhiEliminationPhase.cpp - dfg/DFGRepatch.cpp + dfg/DFGResurrectionForValidationPhase.cpp + dfg/DFGSSAConversionPhase.cpp + dfg/DFGSSALoweringPhase.cpp dfg/DFGSpeculativeJIT.cpp dfg/DFGSpeculativeJIT32_64.cpp dfg/DFGSpeculativeJIT64.cpp + dfg/DFGStackLayoutPhase.cpp + dfg/DFGStoreBarrierElisionPhase.cpp + dfg/DFGStrengthReductionPhase.cpp dfg/DFGThunks.cpp + dfg/DFGTierUpCheckInjectionPhase.cpp + dfg/DFGTypeCheckHoistingPhase.cpp + dfg/DFGUnificationPhase.cpp + dfg/DFGUseKind.cpp + dfg/DFGValidate.cpp + dfg/DFGValueSource.cpp + dfg/DFGVariableAccessDataDump.cpp + dfg/DFGVariableEvent.cpp + dfg/DFGVariableEventStream.cpp dfg/DFGVirtualRegisterAllocationPhase.cpp + dfg/DFGWatchpointCollectionPhase.cpp + dfg/DFGWorklist.cpp + + disassembler/ARMv7Disassembler.cpp + disassembler/Disassembler.cpp + disassembler/LLVMDisassembler.cpp + disassembler/UDis86Disassembler.cpp + disassembler/X86Disassembler.cpp heap/BlockAllocator.cpp - heap/CopiedSpace.cpp + heap/CodeBlockSet.cpp heap/ConservativeRoots.cpp - heap/DFGCodeBlocks.cpp + heap/CopiedSpace.cpp + heap/CopyVisitor.cpp + heap/DeferGC.cpp + heap/GCThread.cpp + heap/GCThreadSharedData.cpp heap/HandleSet.cpp heap/HandleStack.cpp heap/Heap.cpp + heap/HeapStatistics.cpp + heap/HeapTimer.cpp + heap/IncrementalSweeper.cpp + heap/JITStubRoutineSet.cpp heap/MachineStackMarker.cpp + heap/MarkStack.cpp heap/MarkedAllocator.cpp heap/MarkedBlock.cpp heap/MarkedSpace.cpp - heap/MarkStack.cpp - heap/WeakSet.cpp - heap/WeakHandleOwner.cpp + heap/SlotVisitor.cpp + heap/SuperRegion.cpp + heap/Weak.cpp heap/WeakBlock.cpp + heap/WeakHandleOwner.cpp + heap/WeakSet.cpp + heap/WriteBarrierBuffer.cpp + heap/WriteBarrierSupport.cpp + + inspector/InspectorAgentRegistry.cpp + inspector/InspectorBackendDispatcher.cpp + inspector/InspectorValues.cpp - debugger/Debugger.cpp - debugger/DebuggerActivation.cpp - debugger/DebuggerCallFrame.cpp - interpreter/AbstractPC.cpp interpreter/CallFrame.cpp interpreter/Interpreter.cpp - interpreter/RegisterFile.cpp + interpreter/JSStack.cpp + interpreter/ProtoCallFrame.cpp + interpreter/StackVisitor.cpp + interpreter/VMInspector.cpp + jit/AssemblyHelpers.cpp + jit/ClosureCallStubRoutine.cpp jit/ExecutableAllocator.cpp + jit/ExecutableAllocatorFixedVMPool.cpp + jit/GCAwareJITStubRoutine.cpp jit/HostCallReturnValue.cpp - jit/JITArithmetic32_64.cpp + jit/JIT.cpp jit/JITArithmetic.cpp - jit/JITCall32_64.cpp + jit/JITArithmetic32_64.cpp jit/JITCall.cpp - jit/JIT.cpp + jit/JITCall32_64.cpp + jit/JITCode.cpp + jit/JITDisassembler.cpp jit/JITExceptions.cpp - jit/JITOpcodes32_64.cpp + jit/JITInlineCacheGenerator.cpp jit/JITOpcodes.cpp - jit/JITPropertyAccess32_64.cpp + jit/JITOpcodes32_64.cpp + jit/JITOperations.cpp jit/JITPropertyAccess.cpp + jit/JITPropertyAccess32_64.cpp + jit/JITStubRoutine.cpp jit/JITStubs.cpp + jit/JITThunks.cpp + jit/JITToDFGDeferredCompilationCallback.cpp + jit/RegisterSet.cpp + jit/Repatch.cpp + jit/TempRegisterSet.cpp jit/ThunkGenerators.cpp parser/Lexer.cpp parser/Nodes.cpp parser/Parser.cpp parser/ParserArena.cpp + parser/SourceCode.cpp + parser/SourceProvider.cpp parser/SourceProviderCache.cpp + profiler/LegacyProfiler.cpp profiler/Profile.cpp profiler/ProfileGenerator.cpp profiler/ProfileNode.cpp - profiler/Profiler.cpp + profiler/ProfilerBytecode.cpp + profiler/ProfilerBytecodeSequence.cpp + profiler/ProfilerBytecodes.cpp + profiler/ProfilerCompilation.cpp + profiler/ProfilerCompilationKind.cpp + profiler/ProfilerCompiledBytecode.cpp + profiler/ProfilerDatabase.cpp + profiler/ProfilerOSRExit.cpp + profiler/ProfilerOSRExitSite.cpp + profiler/ProfilerOrigin.cpp + profiler/ProfilerOriginStack.cpp + profiler/ProfilerProfiledBytecodes.cpp runtime/ArgList.cpp runtime/Arguments.cpp + runtime/ArgumentsIteratorConstructor.cpp + runtime/ArgumentsIteratorPrototype.cpp + runtime/ArrayBuffer.cpp + runtime/ArrayBufferNeuteringWatchpoint.cpp + runtime/ArrayBufferView.cpp runtime/ArrayConstructor.cpp + runtime/ArrayIteratorConstructor.cpp + runtime/ArrayIteratorPrototype.cpp runtime/ArrayPrototype.cpp runtime/BooleanConstructor.cpp runtime/BooleanObject.cpp runtime/BooleanPrototype.cpp runtime/CallData.cpp + runtime/CodeCache.cpp + runtime/CodeSpecializationKind.cpp runtime/CommonIdentifiers.cpp + runtime/CommonSlowPaths.cpp + runtime/CommonSlowPathsExceptions.cpp + runtime/CompilationResult.cpp runtime/Completion.cpp runtime/ConstructData.cpp + runtime/DataView.cpp + runtime/DataView.h runtime/DateConstructor.cpp runtime/DateConversion.cpp runtime/DateInstance.cpp runtime/DatePrototype.cpp + runtime/DumpContext.cpp runtime/Error.cpp runtime/ErrorConstructor.cpp runtime/ErrorInstance.cpp @@ -158,37 +326,75 @@ SET(JavaScriptCore_SOURCES runtime/ExceptionHelpers.cpp runtime/Executable.cpp runtime/FunctionConstructor.cpp + runtime/FunctionExecutableDump.cpp runtime/FunctionPrototype.cpp runtime/GCActivityCallback.cpp runtime/GetterSetter.cpp runtime/Identifier.cpp + runtime/IndexingType.cpp runtime/InitializeThreading.cpp + runtime/IntendedStructureChain.cpp runtime/InternalFunction.cpp - runtime/JSActivation.cpp runtime/JSAPIValueWrapper.cpp + runtime/JSActivation.cpp + runtime/JSArgumentsIterator.cpp runtime/JSArray.cpp + runtime/JSArrayBuffer.cpp + runtime/JSArrayBufferConstructor.cpp + runtime/JSArrayBufferPrototype.cpp + runtime/JSArrayBufferView.cpp + runtime/JSArrayIterator.cpp + runtime/JSBoundFunction.cpp + runtime/JSCJSValue.cpp runtime/JSCell.cpp + runtime/JSDataView.cpp + runtime/JSDataViewPrototype.cpp runtime/JSDateMath.cpp runtime/JSFunction.cpp - runtime/JSBoundFunction.cpp - runtime/JSGlobalData.cpp runtime/JSGlobalObject.cpp runtime/JSGlobalObjectFunctions.cpp - runtime/JSGlobalThis.cpp runtime/JSLock.cpp + runtime/JSMap.cpp + runtime/JSMapIterator.cpp + runtime/JSNameScope.cpp runtime/JSNotAnObject.cpp - runtime/JSObject.cpp runtime/JSONObject.cpp + runtime/JSObject.cpp + runtime/JSPromise.cpp + runtime/JSPromiseConstructor.cpp + runtime/JSPromiseDeferred.cpp + runtime/JSPromiseFunctions.cpp + runtime/JSPromiseReaction.cpp + runtime/JSPromisePrototype.cpp runtime/JSPropertyNameIterator.cpp + runtime/JSProxy.cpp + runtime/JSScope.cpp + runtime/JSSegmentedVariableObject.cpp + runtime/JSSet.cpp + runtime/JSSetIterator.cpp runtime/JSStaticScopeObject.cpp runtime/JSString.cpp runtime/JSStringJoiner.cpp - runtime/JSValue.cpp + runtime/JSSymbolTableObject.cpp + runtime/JSTypedArrayConstructors.cpp + runtime/JSTypedArrayPrototypes.cpp + runtime/JSTypedArrays.cpp runtime/JSVariableObject.cpp + runtime/JSWeakMap.cpp + runtime/JSWithScope.cpp runtime/JSWrapperObject.cpp runtime/LiteralParser.cpp runtime/Lookup.cpp + runtime/MapConstructor.cpp + runtime/MapData.cpp + runtime/MapIteratorConstructor.cpp + runtime/MapIteratorPrototype.cpp + runtime/MapPrototype.cpp runtime/MathObject.cpp + runtime/MemoryStatistics.cpp + runtime/NameConstructor.cpp + runtime/NameInstance.cpp + runtime/NamePrototype.cpp runtime/NativeErrorConstructor.cpp runtime/NativeErrorPrototype.cpp runtime/NumberConstructor.cpp @@ -201,15 +407,23 @@ SET(JavaScriptCore_SOURCES runtime/PropertyDescriptor.cpp runtime/PropertyNameArray.cpp runtime/PropertySlot.cpp + runtime/PropertyTable.cpp + runtime/PrototypeMap.cpp runtime/RegExp.cpp runtime/RegExpCache.cpp - runtime/RegExpConstructor.cpp runtime/RegExpCachedResult.cpp + runtime/RegExpConstructor.cpp runtime/RegExpMatchesArray.cpp runtime/RegExpObject.cpp runtime/RegExpPrototype.cpp - runtime/ScopeChain.cpp + runtime/SamplingCounter.cpp + runtime/SetConstructor.cpp + runtime/SetIteratorConstructor.cpp + runtime/SetIteratorPrototype.cpp + runtime/SetPrototype.cpp + runtime/SimpleTypedArrayController.cpp runtime/SmallStrings.cpp + runtime/SparseArrayValueMap.cpp runtime/StrictEvalActivation.cpp runtime/StringConstructor.cpp runtime/StringObject.cpp @@ -217,106 +431,342 @@ SET(JavaScriptCore_SOURCES runtime/StringRecursionChecker.cpp runtime/Structure.cpp runtime/StructureChain.cpp - runtime/TimeoutChecker.cpp - runtime/UString.cpp + runtime/StructureRareData.cpp + runtime/SymbolTable.cpp + runtime/TestRunnerUtils.cpp + runtime/TypedArrayController.cpp + runtime/TypedArrayType.cpp + runtime/VM.cpp + runtime/VMEntryScope.cpp + runtime/Watchdog.cpp + runtime/WatchdogNone.cpp + runtime/WeakMapConstructor.cpp + runtime/WeakMapData.cpp + runtime/WeakMapPrototype.cpp tools/CodeProfile.cpp tools/CodeProfiling.cpp yarr/YarrCanonicalizeUCS2.cpp - yarr/YarrPattern.cpp yarr/YarrInterpreter.cpp yarr/YarrJIT.cpp + yarr/YarrPattern.cpp yarr/YarrSyntaxChecker.cpp ) -SET(JavaScriptCore_LUT_FILES +set(JavaScriptCore_LUT_FILES runtime/ArrayConstructor.cpp runtime/ArrayPrototype.cpp runtime/BooleanPrototype.cpp runtime/DateConstructor.cpp runtime/DatePrototype.cpp runtime/ErrorPrototype.cpp + runtime/JSDataViewPrototype.cpp runtime/JSGlobalObject.cpp runtime/JSONObject.cpp - runtime/MathObject.cpp + runtime/JSPromiseConstructor.cpp + runtime/JSPromisePrototype.cpp + runtime/NamePrototype.cpp runtime/NumberConstructor.cpp runtime/NumberPrototype.cpp runtime/ObjectConstructor.cpp - runtime/ObjectPrototype.cpp runtime/RegExpConstructor.cpp runtime/RegExpObject.cpp runtime/RegExpPrototype.cpp runtime/StringConstructor.cpp - runtime/StringPrototype.cpp ) -SET(JavaScriptCore_LIBRARIES - ${WTF_LIBRARY_NAME} +set(JavaScriptCore_LIBRARIES + WTF ) +if (WTF_USE_ICU_UNICODE) + list(APPEND JavaScriptCore_INCLUDE_DIRECTORIES + ${ICU_INCLUDE_DIRS} + ) + list(APPEND JavaScriptCore_LIBRARIES + ${ICU_I18N_LIBRARIES} + ) +endif () + +if (ENABLE_LLINT) + # We cannot check for RUBY_FOUND because it is set only when the full package is installed and + # the only thing we need is the interpreter. Unlike Python, cmake does not provide a macro + # for finding the only Ruby interpreter. + if (NOT RUBY_EXECUTABLE) + message(FATAL_ERROR "The Ruby interpreter is needed to generate LLInt files.") + endif () + + set(LLINT_ASM + llint/LowLevelInterpreter.asm + llint/LowLevelInterpreter32_64.asm + llint/LowLevelInterpreter64.asm + ) + + set(OFFLINE_ASM + offlineasm/arm.rb + offlineasm/ast.rb + offlineasm/backends.rb + offlineasm/cloop.rb + offlineasm/config.rb + offlineasm/instructions.rb + offlineasm/offsets.rb + offlineasm/opt.rb + offlineasm/parser.rb + offlineasm/registers.rb + offlineasm/risc.rb + offlineasm/self_hash.rb + offlineasm/settings.rb + offlineasm/transform.rb + offlineasm/x86.rb + ) + + add_custom_command( + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntDesiredOffsets.h + MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/offlineasm/generate_offset_extractor.rb + DEPENDS ${LLINT_ASM} ${OFFLINE_ASM} + COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/offlineasm/generate_offset_extractor.rb ${JAVASCRIPTCORE_DIR}/llint/LowLevelInterpreter.asm ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntDesiredOffsets.h + VERBATIM) + + # We add the header file directly to the ADD_EXECUTABLE call instead of setting the + # OBJECT_DEPENDS property in LLIntOffsetsExtractor.cpp because generate_offset_extractor.rb may + # not regenerate it in case the hash it calculates does not change. + # In this case, if some of the dependencies specified in the ADD_CUSTOM_COMMAND above have + # changed the command will always be called because the mtime of LLIntDesiredOffsets.h will + # always be older than that of its dependencies. + # Additionally, setting the OBJECT_DEPENDS property will make LLIntDesiredOffsets.h a Makefile + # dependency of both LLIntOffsetsExtractor and LLIntOffsetsExtractor.cpp, so the command will + # actually be run twice! + add_executable(LLIntOffsetsExtractor + ${JAVASCRIPTCORE_DIR}/llint/LLIntOffsetsExtractor.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntDesiredOffsets.h + ) + target_link_libraries(LLIntOffsetsExtractor WTF) + + # The build system will execute asm.rb every time LLIntOffsetsExtractor's mtime is newer than + # LLIntAssembly.h's mtime. The problem we have here is: asm.rb has some built-in optimization + # that generates a checksum of the LLIntOffsetsExtractor binary, if the checksum of the new + # LLIntOffsetsExtractor matches, no output is generated. To make this target consistent and avoid + # running this command for every build, we artificially update LLIntAssembly.h's mtime (using touch) + # after every asm.rb run. + add_custom_command( + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h + MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/offlineasm/asm.rb + DEPENDS LLIntOffsetsExtractor ${LLINT_ASM} ${OFFLINE_ASM} + COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/offlineasm/asm.rb ${JAVASCRIPTCORE_DIR}/llint/LowLevelInterpreter.asm $ ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h + COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h + VERBATIM) + + # The explanation for not making LLIntAssembly.h part of the OBJECT_DEPENDS property of some of + # the .cpp files below is similar to the one in the previous comment. However, since these .cpp + # files are used to build JavaScriptCore itself, we can just add LLIntAssembly.h to JSC_HEADERS + # since it is used in the add_library() call at the end of this file. + list(APPEND JavaScriptCore_HEADERS + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h + ) + list(APPEND JavaScriptCore_SOURCES + llint/LLIntCLoop.cpp + llint/LLIntData.cpp + llint/LLIntEntrypoint.cpp + llint/LLIntExceptions.cpp + llint/LLIntSlowPaths.cpp + llint/LLIntThunks.cpp + llint/LowLevelInterpreter.cpp + ) +endif () + +set(HASH_LUT_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/create_hash_table) +macro(GENERATE_HASH_LUT _input _output) + add_custom_command( + OUTPUT ${_output} + DEPENDS ${HASH_LUT_GENERATOR} ${_input} + COMMAND ${PERL_EXECUTABLE} ${HASH_LUT_GENERATOR} ${_input} -i > ${_output} + VERBATIM) + list(APPEND JavaScriptCore_HEADERS ${_output}) +endmacro() # GENERATOR 1-A: LUT creator -FOREACH (_file ${JavaScriptCore_LUT_FILES}) - GET_FILENAME_COMPONENT(_name ${_file} NAME_WE) - GENERATE_HASH_LUT(${JAVASCRIPTCORE_DIR}/${_file} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${_name}.lut.h) - LIST(APPEND JavaScriptCore_HEADERS ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${_name}.lut.h) -ENDFOREACH () +foreach (_file ${JavaScriptCore_LUT_FILES}) + get_filename_component(_name ${_file} NAME_WE) + GENERATE_HASH_LUT(${CMAKE_CURRENT_SOURCE_DIR}/${_file} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${_name}.lut.h) +endforeach () + +set(JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES + assembler + bindings + bytecode + collector/handles + debugger + heap + inspector + interpreter + jit + llint + parser + profiler + runtime + yarr +) + +set(JavaScriptCore_FORWARDING_HEADERS_FILES + API/APICast.h + API/APIShims.h + API/JSBase.h + API/JSCTestRunnerUtils.h + API/JSContextRef.h + API/JSContextRefPrivate.h + API/JSObjectRef.h + API/JSObjectRefPrivate.h + API/JSRetainPtr.h + API/JSScriptRefPrivate.h + API/JSStringRef.h + API/JSStringRefBSTR.h + API/JSStringRefCF.h + API/JSValueRef.h + API/JSWeakObjectMapRefInternal.h + API/JSWeakObjectMapRefPrivate.h + API/JavaScript.h + API/JavaScriptCore.h + API/OpaqueJSString.h + API/WebKitAvailability.h + + assembler/LinkBuffer.h + assembler/MacroAssembler.h + assembler/MacroAssemblerCodeRef.h + jit/GPRInfo.h + runtime/VM.h +) # GENERATOR 1-B: particular LUT creator (for 1 file only) -GENERATE_HASH_LUT(${JAVASCRIPTCORE_DIR}/parser/Keywords.table ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/Lexer.lut.h MAIN_DEPENDENCY) -LIST(APPEND JavaScriptCore_HEADERS ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/Lexer.lut.h) +GENERATE_HASH_LUT(${CMAKE_CURRENT_SOURCE_DIR}/parser/Keywords.table ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/Lexer.lut.h) #GENERATOR: "RegExpJitTables.h": tables used by Yarr -ADD_CUSTOM_COMMAND( +add_custom_command( OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h - MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/create_regex_tables - COMMAND ${PYTHON_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/create_regex_tables > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/create_regex_tables + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/create_regex_tables > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h VERBATIM) -ADD_SOURCE_DEPENDENCIES(${JAVASCRIPTCORE_DIR}/yarr/YarrPattern.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h) +ADD_SOURCE_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/yarr/YarrPattern.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/RegExpJitTables.h) #GENERATOR: "KeywordLookup.h": keyword decision tree used by the lexer -ADD_CUSTOM_COMMAND( +add_custom_command( OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h - MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/KeywordLookupGenerator.py - COMMAND ${PYTHON_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/KeywordLookupGenerator.py ${JAVASCRIPTCORE_DIR}/parser/Keywords.table > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/KeywordLookupGenerator.py + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/KeywordLookupGenerator.py ${CMAKE_CURRENT_SOURCE_DIR}/parser/Keywords.table > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h VERBATIM) -ADD_SOURCE_DEPENDENCIES(${JAVASCRIPTCORE_DIR}/parser/Lexer.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h) +ADD_SOURCE_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/parser/Lexer.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h) + -IF (WTF_CPU_ARM) - LIST(APPEND JavaScriptCore_SOURCES +# Inspector Interfaces + +set(JavaScriptCore_INSPECTOR_SCRIPTS_DIR "${JAVASCRIPTCORE_DIR}/inspector/scripts") + +set(JavaScriptCore_INSPECTOR_DOMAINS + inspector/protocol/Debugger.json + inspector/protocol/GenericTypes.json + inspector/protocol/InspectorDomain.json + inspector/protocol/Runtime.json +) + +add_custom_command( + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json + MAIN_DEPENDENCY ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/generate-combined-inspector-json.py + DEPENDS ${JavaScriptCore_INSPECTOR_DOMAINS} + COMMAND ${PYTHON_EXECUTABLE} ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/generate-combined-inspector-json.py ${JAVASCRIPTCORE_DIR}/inspector/protocol > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json + VERBATIM) + +# Inspector Backend Dispatchers, Frontend Dispatchers, Type Builders +add_custom_command( + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.h + MAIN_DEPENDENCY ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json + DEPENDS ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/CodeGeneratorInspector.py ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/CodeGeneratorInspectorStrings.py + COMMAND ${PYTHON_EXECUTABLE} ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/CodeGeneratorInspector.py ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json --output_h_dir "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}" --output_cpp_dir "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}" --output_js_dir "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}" --output_type JavaScript --write_always && mkdir -p ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector && cp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector + VERBATIM) + +list(APPEND JavaScriptCore_SOURCES + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.cpp +) + +list(APPEND JavaScriptCore_HEADERS + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.h +) + + +if (WTF_CPU_ARM) + list(APPEND JavaScriptCore_SOURCES assembler/ARMAssembler.cpp assembler/ARMv7Assembler.cpp assembler/MacroAssemblerARM.cpp ) -ELSEIF (WTF_CPU_MIPS) -ELSEIF (WTF_CPU_X86) -ELSEIF (WTF_CPU_X86_64) -ELSE () - MESSAGE(FATAL_ERROR "Unknown CPU") -ENDIF () + if (MSVC AND ENABLE_JIT) + add_custom_command( + OUTPUT ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm + MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/create_jit_stubs + DEPENDS ${JAVASCRIPTCORE_DIR}/jit/JITStubsARM.h + DEPENDS ${JAVASCRIPTCORE_DIR}/jit/JITStubs.cpp + COMMAND ${PERL_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/create_jit_stubs --prefix=MSVC --header ${JAVASCRIPTCORE_DIR}/jit/JITStubsARM.h ${JAVASCRIPTCORE_DIR}/jit/JITStubs.cpp > ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm + VERBATIM) + + add_custom_command( + OUTPUT ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj + MAIN_DEPENDENCY ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm + COMMAND armasm -nologo ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj + VERBATIM) + + list(APPEND JavaScriptCore_SOURCES ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj) + endif () +elseif (WTF_CPU_MIPS) +elseif (WTF_CPU_SH4) +elseif (WTF_CPU_X86) + list(APPEND JavaScriptCore_SOURCES + assembler/MacroAssemblerX86Common.cpp + ) +elseif (WTF_CPU_X86_64) + if (MSVC AND ENABLE_JIT) + add_custom_command( + OUTPUT ${DERIVED_SOURCES_DIR}/JITStubsMSVC64.obj + MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/jit/JITStubsMSVC64.asm + COMMAND ml64 -nologo -c -Fo ${DERIVED_SOURCES_DIR}/JITStubsMSVC64.obj ${JAVASCRIPTCORE_DIR}/jit/JITStubsMSVC64.asm + VERBATIM) + + list(APPEND JavaScriptCore_SOURCES ${DERIVED_SOURCES_DIR}/JITStubsMSVC64.obj) + endif () + list(APPEND JavaScriptCore_SOURCES + assembler/MacroAssemblerX86Common.cpp + ) +else () + message(FATAL_ERROR "Unknown CPU") +endif () WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() +WEBKIT_CREATE_FORWARDING_HEADERS(JavaScriptCore DIRECTORIES ${JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES} FILES ${JavaScriptCore_FORWARDING_HEADERS_FILES}) + -ADD_SUBDIRECTORY(shell) +add_subdirectory(shell) WEBKIT_WRAP_SOURCELIST(${JavaScriptCore_SOURCES}) -INCLUDE_DIRECTORIES(${JavaScriptCore_INCLUDE_DIRECTORIES}) -ADD_DEFINITIONS(-DBUILDING_JavaScriptCore) -ADD_LIBRARY(${JavaScriptCore_LIBRARY_NAME} ${JavaScriptCore_LIBRARY_TYPE} ${JavaScriptCore_HEADERS} ${JavaScriptCore_SOURCES}) -TARGET_LINK_LIBRARIES(${JavaScriptCore_LIBRARY_NAME} ${JavaScriptCore_LIBRARIES}) -SET_TARGET_PROPERTIES(${JavaScriptCore_LIBRARY_NAME} PROPERTIES FOLDER "JavaScriptCore") -SET_TARGET_PROPERTIES(${JavaScriptCore_LIBRARY_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") - -IF (JavaScriptCore_LINK_FLAGS) - ADD_TARGET_PROPERTIES(${JavaScriptCore_LIBRARY_NAME} LINK_FLAGS "${JavaScriptCore_LINK_FLAGS}") -ENDIF () - -IF (SHARED_CORE) - SET_TARGET_PROPERTIES(${JavaScriptCore_LIBRARY_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) - INSTALL(TARGETS ${JavaScriptCore_LIBRARY_NAME} DESTINATION "${LIB_INSTALL_DIR}") -ENDIF () +include_directories(${JavaScriptCore_INCLUDE_DIRECTORIES}) +add_definitions(-DSTATICALLY_LINKED_WITH_WTF) +add_library(JavaScriptCore ${JavaScriptCore_LIBRARY_TYPE} ${JavaScriptCore_HEADERS} ${JavaScriptCore_SOURCES}) +target_link_libraries(JavaScriptCore ${JavaScriptCore_LIBRARIES}) +set_target_properties(JavaScriptCore PROPERTIES COMPILE_DEFINITIONS "BUILDING_JavaScriptCore") +set_target_properties(JavaScriptCore PROPERTIES FOLDER "JavaScriptCore") +set_target_properties(JavaScriptCore PROPERTIES LINK_INTERFACE_LIBRARIES "") + +if (JavaScriptCore_OUTPUT_NAME) + set_target_properties(JavaScriptCore PROPERTIES OUTPUT_NAME ${JavaScriptCore_OUTPUT_NAME}) +endif () + +if (${JavaScriptCore_LIBRARY_TYPE} STREQUAL "SHARED") + POPULATE_LIBRARY_VERSION(JAVASCRIPTCORE) + set_target_properties(JavaScriptCore PROPERTIES VERSION ${JAVASCRIPTCORE_VERSION} SOVERSION ${JAVASCRIPTCORE_VERSION_MAJOR}) + install(TARGETS JavaScriptCore DESTINATION "${LIB_INSTALL_DIR}") +endif () diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index e88692c7..625a49b4 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,69230 +1,12268 @@ -2012-10-16 Lucas Forschler +2014-01-14 Lucas Forschler - Merge + Merge r161574 - 2012-10-10 Filip Pizlo - - SUSundance: JSArray::sort with an evil compare function allows access into arbitrary memory - - Reviewed by Geoffrey Garen. - - This patch correctly omits the removal of the !header check in unshift(). - - * runtime/ArrayPrototype.cpp: - (JSC::arrayProtoFuncSort): - * runtime/JSArray.cpp: - (JSC::JSArray::sortNumeric): - (JSC::JSArray::sort): - (JSC::JSArray::compactForSorting): - * runtime/JSArray.h: - (JSArray): - (JSC::JSArray::hasSparseMap): + 2014-01-09 Filip Pizlo -2012-10-16 Lucas Forschler + AI for CreateArguments should pass through non-SpecEmpty input values + https://bugs.webkit.org/show_bug.cgi?id=126709 - Merge r129577 + Reviewed by Mark Hahnenberg. - 2012-09-25 Filip Pizlo + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter::executeEffects): + * tests/stress/use-arguments-as-object-pointer.js: Added. + (foo): - We shouldn't use the optimized versions of shift/unshift if the user is doing crazy things to the array - https://bugs.webkit.org/show_bug.cgi?id=97603 - +2014-01-05 Sam Weinig - Reviewed by Gavin Barraclough. + [JS] Implement Promise.race() + https://bugs.webkit.org/show_bug.cgi?id=126506 - You changed the length behind our backs? No optimizations for you then! + Reviewed by Oliver Hunt. - * runtime/ArrayPrototype.cpp: - (JSC::shift): - (JSC::unshift): - * runtime/JSArray.cpp: - (JSC::JSArray::shiftCount): + * runtime/CommonIdentifiers.h: + Add identifier for "cast". + + * runtime/JSPromiseConstructor.cpp: + (JSC::abruptRejection): + Helper for the RejectIfAbrupt abstract operation. + + (JSC::JSPromiseConstructorFuncRace): + Add implementation of Promise.race() -2012-08-14 Lucas Forschler +2014-01-05 Martin Robinson - Merge r124272. + [GTK] [CMake] Ensure that the autotools build and the CMake install the same files + https://bugs.webkit.org/show_bug.cgi?id=116379 - 2012-07-31 Sam Weinig + Reviewed by Gustavo Noronha Silva. - Fix the Windows build. + * PlatformGTK.cmake: Install API headers, gir files, and the pkg-config file. - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: +2014-01-04 Yusuke Suzuki -2012-08-14 Lucas Forschler + Use Compiler macros instead of raw "final" and "override" + https://bugs.webkit.org/show_bug.cgi?id=126490 - Merge r124268. + Reviewed by Sam Weinig. - 2012-07-31 Sam Weinig + * runtime/JSPromiseReaction.cpp: - Stop masking 8 bits off of the visited link hash. We need all the bits! - https://bugs.webkit.org/show_bug.cgi?id=92799 +2014-01-04 Martin Robinson - Reviewed by Anders Carlsson. + [GTK] [CMake] Improve the way we locate gobject-introspection + https://bugs.webkit.org/show_bug.cgi?id=126452 - * runtime/Identifier.cpp: - (JSC::IdentifierCStringTranslator::hash): - (JSC::IdentifierLCharFromUCharTranslator::hash): - * runtime/Identifier.h: - (JSC::IdentifierCharBufferTranslator::hash): - Update for new function names. + Reviewed by Philippe Normand. -2012-08-10 Lucas Forschler - - Windows build fix after merging radar 12050720. - Add missing symbols. - - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * PlatformGTK.cmake: Use the new introspection variables. -2012-08-10 Lucas Forschler +2014-01-04 Zan Dobersek - Windows build fix after merging radar 12050720. - Part 2 - removing symbols. + Explicitly use the std:: nested name specifier when using std::pair, std::make_pair + https://bugs.webkit.org/show_bug.cgi?id=126439 - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + Reviewed by Andreas Kling. -2012-08-10 Lucas Forschler + Instead of relying on std::pair and std::make_pair symbols being present in the current scope + through the pair and make_pair symbols, the std:: specifier should be used explicitly. - Windows Build fix after merging radar 12050720. - - * runtime/JSLock.cpp: - (JSC::JSLock::DropAllLocks::DropAllLocks): + * bytecode/Opcode.cpp: + (JSC::compareOpcodePairIndices): + (JSC::OpcodeStats::~OpcodeStats): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::makeBinaryNode): + * parser/Parser.cpp: + (JSC::Parser::parseIfStatement): + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + (JSC::StructureTransitionTable::add): -2012-08-06 Lucas Forschler +2014-01-03 David Farler - Merge patch for - - 2012-07-24 Filip Pizlo + [super dealloc] missing in Source/JavaScriptCore/API/tests/testapi.mm, fails to build with -Werror,-Wobjc-missing-super-calls + https://bugs.webkit.org/show_bug.cgi?id=126454 - DFG method checks should keep the receiver of the property access alive until all checks complete. - - - Reviewed by Gavin Barraclough. + Reviewed by Geoffrey Garen. - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::parseBlock): + * API/tests/testapi.mm: + (-[TextXYZ dealloc]): + add [super dealloc] + (-[EvilAllocationObject dealloc]): + add [super dealloc] -2012-08-02 Lucas Forschler +2014-01-02 Carlos Garcia Campos - Merge 121307 + REGRESSION(r160304): [GTK] Disable libtool fast install + https://bugs.webkit.org/show_bug.cgi?id=126381 - 2012-06-26 Filip Pizlo + Reviewed by Martin Robinson. - DFG PutByValAlias is too aggressive - https://bugs.webkit.org/show_bug.cgi?id=90026 - + Remove -no-fast-install ld flag since fast install is now disabled + globally. - Reviewed by Gavin Barraclough. + * GNUmakefile.am: - For CSE on normal arrays, we now treat PutByVal as impure. This does not appear to affect - performance by much. +2014-01-02 Sam Weinig - For CSE on typed arrays, we fix PutByValAlias by making GetByVal speculate that the access - is within bounds. This also has the effect of making our out-of-bounds handling consistent - with WebCore. + Update Promises to the https://github.com/domenic/promises-unwrapping spec + https://bugs.webkit.org/show_bug.cgi?id=120954 - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::performNodeCSE): - * dfg/DFGGraph.h: - (JSC::DFG::Graph::byValIsPure): - (JSC::DFG::Graph::clobbersWorld): - * dfg/DFGNodeType.h: - (DFG): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): - (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + Reviewed by Filip Pizlo. -2012-07-30 Lucas Forschler + Update Promises to the revised spec. Notable changes: + - JSPromiseResolver is gone. + - TaskContext has been renamed Microtask and now has a virtual run() function. + - Instead of using custom InternalFunction subclasses, JSFunctions are used + with PrivateName properties for internal slots. - Merge 121391 + * CMakeLists.txt: + * DerivedSources.make: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * interpreter/CallFrame.h: + (JSC::ExecState::promiseConstructorTable): + * runtime/CommonIdentifiers.cpp: + (JSC::CommonIdentifiers::CommonIdentifiers): + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + (JSC::JSGlobalObject::queueMicrotask): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::promiseConstructor): + (JSC::JSGlobalObject::promisePrototype): + (JSC::JSGlobalObject::promiseStructure): + * runtime/JSPromise.cpp: + (JSC::JSPromise::create): + (JSC::JSPromise::JSPromise): + (JSC::JSPromise::finishCreation): + (JSC::JSPromise::visitChildren): + (JSC::JSPromise::reject): + (JSC::JSPromise::resolve): + (JSC::JSPromise::appendResolveReaction): + (JSC::JSPromise::appendRejectReaction): + (JSC::triggerPromiseReactions): + * runtime/JSPromise.h: + (JSC::JSPromise::status): + (JSC::JSPromise::result): + (JSC::JSPromise::constructor): + * runtime/JSPromiseCallback.cpp: Removed. + * runtime/JSPromiseCallback.h: Removed. + * runtime/JSPromiseConstructor.cpp: + (JSC::constructPromise): + (JSC::JSPromiseConstructor::getCallData): + (JSC::JSPromiseConstructorFuncCast): + (JSC::JSPromiseConstructorFuncResolve): + (JSC::JSPromiseConstructorFuncReject): + * runtime/JSPromiseConstructor.h: + * runtime/JSPromiseDeferred.cpp: Added. + (JSC::JSPromiseDeferred::create): + (JSC::JSPromiseDeferred::JSPromiseDeferred): + (JSC::JSPromiseDeferred::finishCreation): + (JSC::JSPromiseDeferred::visitChildren): + (JSC::createJSPromiseDeferredFromConstructor): + (JSC::updateDeferredFromPotentialThenable): + * runtime/JSPromiseDeferred.h: Added. + (JSC::JSPromiseDeferred::createStructure): + (JSC::JSPromiseDeferred::promise): + (JSC::JSPromiseDeferred::resolve): + (JSC::JSPromiseDeferred::reject): + * runtime/JSPromiseFunctions.cpp: Added. + (JSC::deferredConstructionFunction): + (JSC::createDeferredConstructionFunction): + (JSC::identifyFunction): + (JSC::createIdentifyFunction): + (JSC::promiseAllCountdownFunction): + (JSC::createPromiseAllCountdownFunction): + (JSC::promiseResolutionHandlerFunction): + (JSC::createPromiseResolutionHandlerFunction): + (JSC::rejectPromiseFunction): + (JSC::createRejectPromiseFunction): + (JSC::resolvePromiseFunction): + (JSC::createResolvePromiseFunction): + (JSC::throwerFunction): + (JSC::createThrowerFunction): + * runtime/JSPromiseFunctions.h: Added. + * runtime/JSPromisePrototype.cpp: + (JSC::JSPromisePrototypeFuncThen): + (JSC::JSPromisePrototypeFuncCatch): + * runtime/JSPromiseReaction.cpp: Added. + (JSC::createExecutePromiseReactionMicroTask): + (JSC::ExecutePromiseReactionMicroTask::run): + (JSC::JSPromiseReaction::create): + (JSC::JSPromiseReaction::JSPromiseReaction): + (JSC::JSPromiseReaction::finishCreation): + (JSC::JSPromiseReaction::visitChildren): + * runtime/JSPromiseReaction.h: Added. + (JSC::JSPromiseReaction::createStructure): + (JSC::JSPromiseReaction::deferred): + (JSC::JSPromiseReaction::handler): + * runtime/JSPromiseResolver.cpp: Removed. + * runtime/JSPromiseResolver.h: Removed. + * runtime/JSPromiseResolverConstructor.cpp: Removed. + * runtime/JSPromiseResolverConstructor.h: Removed. + * runtime/JSPromiseResolverPrototype.cpp: Removed. + * runtime/JSPromiseResolverPrototype.h: Removed. + * runtime/Microtask.h: Added. + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::~VM): + * runtime/VM.h: + +2014-01-02 Mark Hahnenberg + + Add support for StoreBarrier and friends to the FTL + https://bugs.webkit.org/show_bug.cgi?id=126040 - 2012-06-27 Filip Pizlo + Reviewed by Filip Pizlo. - Javascript SHA-512 gives wrong hash on second and subsequent runs unless Web Inspector Javascript Debugging is on - https://bugs.webkit.org/show_bug.cgi?id=90053 - + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileStoreBarrier): + (JSC::FTL::LowerDFGToLLVM::compileConditionalStoreBarrier): + (JSC::FTL::LowerDFGToLLVM::compileStoreBarrierWithNullCheck): + (JSC::FTL::LowerDFGToLLVM::loadMarkByte): + (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): + * heap/Heap.cpp: + (JSC::Heap::Heap): + * heap/Heap.h: + (JSC::Heap::writeBarrierBuffer): - Reviewed by Mark Hahnenberg. +2014-01-02 Mark Hahnenberg - The problem is that the code was assuming that the recovery should be Undefined if the source of - the SetLocal was !shouldGenerate(). But that's wrong, since the DFG optimizer may skip around a - UInt32ToNumber node (hence making it !shouldGenerate()) and keep the source of that node alive. - In that case we should base the recovery on the source of the UInt32ToNumber. The logic for this - was already in place but the fast check for !shouldGenerate() broke it. + Storing new CopiedSpace memory into a JSObject should fire a write barrier + https://bugs.webkit.org/show_bug.cgi?id=126025 - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): + Reviewed by Filip Pizlo. -2012-06-06 Mark Rowe + Technically this is creating a pointer between a (potentially) old generation object and a young + generation chunk of memory, thus there needs to be a barrier. - Merge r118995. + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGOperations.cpp: + * heap/CopyWriteBarrier.h: Added. This class functions similarly to the WriteBarrier class. It + acts as a proxy for pointers to CopiedSpace. Assignments to the field cause a write barrier to + fire for the object that is the owner of the CopiedSpace memory. This is to ensure during nursery + collections that objects with new backing stores are visited, even if they are old generation objects. + (JSC::CopyWriteBarrier::CopyWriteBarrier): + (JSC::CopyWriteBarrier::operator!): + (JSC::CopyWriteBarrier::operator UnspecifiedBoolType*): + (JSC::CopyWriteBarrier::get): + (JSC::CopyWriteBarrier::operator*): + (JSC::CopyWriteBarrier::operator->): + (JSC::CopyWriteBarrier::set): + (JSC::CopyWriteBarrier::setWithoutWriteBarrier): + (JSC::CopyWriteBarrier::clear): + * heap/Heap.h: + * runtime/JSArray.cpp: + (JSC::JSArray::unshiftCountSlowCase): + (JSC::JSArray::shiftCountWithArrayStorage): + (JSC::JSArray::unshiftCountWithArrayStorage): + * runtime/JSCell.h: + (JSC::JSCell::unvalidatedStructure): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView::slowDownAndWasteMemory): + * runtime/JSObject.cpp: + (JSC::JSObject::copyButterfly): + (JSC::JSObject::getOwnPropertySlotByIndex): + (JSC::JSObject::putByIndex): + (JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists): + (JSC::JSObject::createInitialIndexedStorage): + (JSC::JSObject::createArrayStorage): + (JSC::JSObject::deletePropertyByIndex): + (JSC::JSObject::getOwnPropertyNames): + (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes): + (JSC::JSObject::countElements): + (JSC::JSObject::increaseVectorLength): + (JSC::JSObject::ensureLengthSlow): + * runtime/JSObject.h: + (JSC::JSObject::butterfly): + (JSC::JSObject::setStructureAndButterfly): + (JSC::JSObject::setButterflyWithoutChangingStructure): + (JSC::JSObject::JSObject): + (JSC::JSObject::putDirectInternal): + (JSC::JSObject::putDirectWithoutTransition): + * runtime/MapData.cpp: + (JSC::MapData::ensureSpaceForAppend): + * runtime/Structure.cpp: + (JSC::Structure::materializePropertyMap): - 2012-05-30 Oliver Hunt +2013-12-23 Oliver Hunt - Really provide error information with the inspector disabled - https://bugs.webkit.org/show_bug.cgi?id=87910 + Refactor PutPropertySlot to be aware of custom properties + https://bugs.webkit.org/show_bug.cgi?id=126187 - Reviewed by Filip Pizlo. + Reviewed by Antti Koivisto. - Don't bother checking for anything other than pre-existing error info. - In the absence of complete line number information you'll only get the - line a function starts on, but at least it's something. + Refactor PutPropertySlot, making the constructor take the thisValue + used as a target. This results in a wide range of boilerplate changes + to pass the new parameter. + * API/JSObjectRef.cpp: + (JSObjectSetProperty): + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): * interpreter/Interpreter.cpp: - (JSC::Interpreter::throwException): - -2012-06-06 Mark Rowe - - Merge r118992. + (JSC::Interpreter::execute): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::putByIndex): + * runtime/ArrayPrototype.cpp: + (JSC::putProperty): + (JSC::arrayProtoFuncPush): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitiveByIndex): + * runtime/JSCell.cpp: + (JSC::JSCell::putByIndex): + * runtime/JSFunction.cpp: + (JSC::JSFunction::put): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView::putByIndex): + * runtime/JSONObject.cpp: + (JSC::Walker::walk): + * runtime/JSObject.cpp: + (JSC::JSObject::putByIndex): + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::deleteProperty): + * runtime/JSObject.h: + (JSC::JSObject::putDirect): + * runtime/Lookup.h: + (JSC::putEntry): + (JSC::lookupPut): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::PutPropertySlot): + (JSC::PutPropertySlot::setCustomProperty): + (JSC::PutPropertySlot::thisValue): + (JSC::PutPropertySlot::isCacheable): - 2012-05-30 Filip Pizlo +2014-01-01 Filip Pizlo - LLInt broken on x86-32 with JIT turned off - https://bugs.webkit.org/show_bug.cgi?id=87906 + Rationalize DFG DCE + https://bugs.webkit.org/show_bug.cgi?id=125523 - Reviewed by Geoffrey Garen. + Reviewed by Mark Hahnenberg. - Fixed the code to not clobber registers that contain important things, like the call frame. + Adds the ability to DCE more things. It's now the case that if a node is completely + pure, we clear NodeMustGenerate and the node becomes a DCE candidate. - * llint/LowLevelInterpreter32_64.asm: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter::executeEffects): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::cleanVariables): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::clobbersWorld): + * dfg/DFGNodeType.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileAdd): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileValueAdd): -2012-05-31 Ojan Vafai +2014-01-02 Benjamin Poulain - add back the ability to disable flexbox - https://bugs.webkit.org/show_bug.cgi?id=87147 + Attempt to fix the build of WebCore's code generator on CMake based system + https://bugs.webkit.org/show_bug.cgi?id=126271 - Reviewed by Tony Chang. + Reviewed by Sam Weinig. - * Configurations/FeatureDefines.xcconfig: + * CMakeLists.txt: -2012-05-31 Tim Horton +2013-12-30 Commit Queue - Disable CSS3 flexbox - + Unreviewed, rolling out r161157, r161158, r161160, r161161, + r161163, and r161165. + http://trac.webkit.org/changeset/161157 + http://trac.webkit.org/changeset/161158 + http://trac.webkit.org/changeset/161160 + http://trac.webkit.org/changeset/161161 + http://trac.webkit.org/changeset/161163 + http://trac.webkit.org/changeset/161165 + https://bugs.webkit.org/show_bug.cgi?id=126332 - Reviewed by John Sullivan. + Broke WebKit2 on Mountain Lion (Requested by ap on #webkit). - * Configurations/FeatureDefines.xcconfig: + * heap/BlockAllocator.cpp: + (JSC::BlockAllocator::~BlockAllocator): + (JSC::BlockAllocator::waitForRelativeTimeWhileHoldingLock): + (JSC::BlockAllocator::waitForRelativeTime): + (JSC::BlockAllocator::blockFreeingThreadMain): + * heap/BlockAllocator.h: + (JSC::BlockAllocator::deallocate): -2012-05-31 Tim Horton +2013-12-30 Anders Carlsson - Add feature defines for web-facing parts of CSS Regions and Exclusions - https://bugs.webkit.org/show_bug.cgi?id=87442 - + Fix build. - Reviewed by Dan Bernstein. + * heap/BlockAllocator.h: - * Configurations/FeatureDefines.xcconfig: +2013-12-30 Anders Carlsson -2012-05-30 Lucas Forschler + Stop using ThreadCondition in BlockAllocator + https://bugs.webkit.org/show_bug.cgi?id=126313 - Merge 118956 + Reviewed by Sam Weinig. - 2012-05-30 Oliver Hunt + * heap/BlockAllocator.cpp: + (JSC::BlockAllocator::~BlockAllocator): + (JSC::BlockAllocator::waitForDuration): + (JSC::BlockAllocator::blockFreeingThreadMain): + * heap/BlockAllocator.h: + (JSC::BlockAllocator::deallocate): - DFG does not correctly handle exceptions caught in the LLInt - https://bugs.webkit.org/show_bug.cgi?id=87885 +2013-12-30 Anders Carlsson - Reviewed by Filip Pizlo. + Stop using ThreadCondition in jsc.cpp + https://bugs.webkit.org/show_bug.cgi?id=126311 - Make the DFG use genericThrow, rather than reimplementing a small portion of it. - Also make the LLInt slow paths validate that their PC is correct. + Reviewed by Sam Weinig. - * dfg/DFGOperations.cpp: - * llint/LLIntSlowPaths.cpp: - (LLInt): + * jsc.cpp: + (timeoutThreadMain): + (main): -2012-05-30 Lucas Forschler +2013-12-30 Anders Carlsson - Merge 118810 + Replace WTF::ThreadingOnce with std::call_once + https://bugs.webkit.org/show_bug.cgi?id=126215 - 2012-05-29 Mark Hahnenberg + Reviewed by Sam Weinig. - CopiedSpace::doneCopying could start another collection - https://bugs.webkit.org/show_bug.cgi?id=86538 + * dfg/DFGWorklist.cpp: + (JSC::DFG::globalWorklist): + * runtime/InitializeThreading.cpp: + (JSC::initializeThreading): - Reviewed by Geoffrey Garen. +2013-12-30 Martin Robinson - It's possible that if we don't have anything at the head of to-space - after a collection and the BlockAllocator doesn't have any fresh blocks - to give us right now we could start another collection while still in - the middle of the first collection when we call CopiedSpace::addNewBlock(). + [CMake] [GTK] Add support for GObject introspection + https://bugs.webkit.org/show_bug.cgi?id=126162 - One way to resolve this would be to have Heap::shouldCollect() check that - m_operationInProgress is NoOperation. This would prevent the path in - getFreshBlock() that starts the collection if we're already in the middle of one. + Reviewed by Daniel Bates. - I could not come up with a test case to reproduce this crash on ToT. + * PlatformGTK.cmake: Add the GIR targets. - * heap/Heap.h: - (JSC::Heap::shouldCollect): We shouldn't collect if we're already in the middle - of a collection, i.e. the current operation should be NoOperation. +2013-12-28 Filip Pizlo -2012-05-30 Lucas Forschler + Get rid of DFG forward exiting + https://bugs.webkit.org/show_bug.cgi?id=125531 - Merge + Reviewed by Oliver Hunt. + + This finally gets rid of forward exiting. Forward exiting was always a fragile concept + since it involved the compiler trying to figure out how to "roll forward" the + execution from some DFG node to the next bytecode index. It was always easy to find + counterexamples where it broke, and it has always served as an obstacle to adding + compiler improvements - the latest being http://webkit.org/b/125523, which tried to + make DCE work for more things. + + This change finishes the work of removing forward exiting. A lot of forward exiting + was already removed in some other bugs, but SetLocal still did forward exits. SetLocal + is in many ways the hardest to remove, since the forward exiting of SetLocal also + implied that any conversion nodes inserted before the SetLocal would then also be + marked as forward-exiting. Hence SetLocal's forward-exiting made a bunch of other + things also forward-exiting, and this was always a source of weirdo bugs. + + SetLocal must be able to exit in case it performs a hoisted type speculation. Nodes + inserted just before SetLocal must also be able to exit - for example type check + hoisting may insert a CheckStructure, or fixup phase may insert something like + Int32ToDouble. But if any of those nodes tried to backward exit, then this could lead + to the reexecution of a side-effecting operation, for example: + + a: Call(...) + b: SetLocal(@a, r1) + + For a long time it seemed like SetLocal *had* to exit forward because of this. But + this change side-steps the problem by changing the ByteCodeParser to always emit a + kind of "two-phase commit" for stores to local variables. Now when the ByteCodeParser + wishes to store to a local, it first emits a MovHint and then enqueues a SetLocal. + The SetLocal isn't actually emitted until the beginning of the next bytecode + instruction (which the exception of op_enter and op_ret, which emit theirs immediately + since it's always safe to reexecute those bytecode instructions and since deferring + SetLocals would be weird there - op_enter has many SetLocals and op_ret is a set + followed by a jump in case of inlining, so we'd have to emit the SetLocal "after" the + jump and that would be awkward). This means that the above IR snippet would look + something like: + + a: Call(..., bc#42) + b: MovHint(@a, r1, bc#42) + c: SetLocal(@a, r1, bc#47) + + Where the SetLocal exits "backwards" but appears at the beginning of the next bytecode + instruction. This means that by the time we get to that SetLocal, the OSR exit + analysis already knows that r1 is associated with @a, and it means that the SetLocal + or anything hoisted above it can exit backwards as normal. + + This change also means that the "forward rewiring" can be killed. Previously, we might + have inserted a conversion node on SetLocal and then the SetLocal died (i.e. turned + into a MovHint) and the conversion node either died completely or had its lifetime + truncated to be less than the actual value's bytecode lifetime. This no longer happens + since conversion nodes are only inserted at SetLocals. + + More precisely, this change introduces two laws that we were basically already + following anyway: + + 1) A MovHint's child should never be changed except if all other uses of that child + are also replaced. Specifically, this prohibits insertion of conversion nodes at + MovHints. + + 2) Anytime any child is replaced with something else, and all other uses aren't also + replaced, we must insert a Phantom use of the original child. -2012-05-23 Lucas Forschler + This is a slight compile-time regression but has no effect on code-gen. It unlocks a + bunch of optimization opportunities so I think it's worth it. - Merge 117860 + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpAssumingJITType): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::instructionCount): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter::executeEffects): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGArrayifySlowPathGenerator.h: + (JSC::DFG::ArrayifySlowPathGenerator::ArrayifySlowPathGenerator): + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::setDirect): + (JSC::DFG::ByteCodeParser::DelayedSetLocal::DelayedSetLocal): + (JSC::DFG::ByteCodeParser::DelayedSetLocal::execute): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::eliminate): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + (JSC::DFG::DCEPhase::fixupBlock): + (JSC::DFG::DCEPhase::cleanVariables): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::fixEdge): + (JSC::DFG::FixupPhase::injectInt32ToDoubleNode): + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::run): + (JSC::DFG::LICMPhase::attemptHoist): + * dfg/DFGMinifiedNode.cpp: + (JSC::DFG::MinifiedNode::fromNode): + * dfg/DFGMinifiedNode.h: + (JSC::DFG::belongsInMinifiedGraph): + (JSC::DFG::MinifiedNode::constantNumber): + (JSC::DFG::MinifiedNode::weakConstant): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::hasVariableAccessData): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPhantom): + (JSC::DFG::Node::convertToPhantomUnchecked): + (JSC::DFG::Node::convertToIdentity): + (JSC::DFG::Node::containsMovHint): + (JSC::DFG::Node::hasUnlinkedLocal): + (JSC::DFG::Node::willHaveCodeGenOrOSR): + * dfg/DFGNodeFlags.cpp: + (JSC::DFG::dumpNodeFlags): + * dfg/DFGNodeFlags.h: + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::OSRAvailabilityAnalysisPhase::run): + * dfg/DFGOSREntrypointCreationPhase.cpp: + (JSC::DFG::OSREntrypointCreationPhase::run): + * dfg/DFGOSRExit.cpp: + * dfg/DFGOSRExit.h: + * dfg/DFGOSRExitBase.cpp: + * dfg/DFGOSRExitBase.h: + (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::speculationCheck): + (JSC::DFG::SpeculativeJIT::emitInvalidationPoint): + (JSC::DFG::SpeculativeJIT::typeCheck): + (JSC::DFG::SpeculativeJIT::compileMovHint): + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + (JSC::DFG::SpeculativeJIT::checkArgumentTypes): + (JSC::DFG::SpeculativeJIT::compileInt32ToDouble): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::detectPeepHoleBranch): + (JSC::DFG::SpeculativeJIT::needsTypeCheck): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::run): + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateCPS): + * dfg/DFGVariableAccessData.h: + (JSC::DFG::VariableAccessData::VariableAccessData): + * dfg/DFGVariableEventStream.cpp: + (JSC::DFG::VariableEventStream::reconstruct): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetArgument): + (JSC::FTL::LowerDFGToLLVM::compileSetLocal): + (JSC::FTL::LowerDFGToLLVM::compileMovHint): + (JSC::FTL::LowerDFGToLLVM::compileZombieHint): + (JSC::FTL::LowerDFGToLLVM::compileInt32ToDouble): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::typeCheck): + (JSC::FTL::LowerDFGToLLVM::appendTypeCheck): + (JSC::FTL::LowerDFGToLLVM::appendOSRExit): + (JSC::FTL::LowerDFGToLLVM::emitOSRExitCall): + * ftl/FTLOSRExit.cpp: + * ftl/FTLOSRExit.h: + * tests/stress/dead-int32-to-double.js: Added. + (foo): + * tests/stress/dead-uint32-to-number.js: Added. + (foo): + +2013-12-25 Commit Queue + + Unreviewed, rolling out r161033 and r161074. + http://trac.webkit.org/changeset/161033 + http://trac.webkit.org/changeset/161074 + https://bugs.webkit.org/show_bug.cgi?id=126240 + + Oliver says that a rollout would be better (Requested by ap on + #webkit). - 2012-05-21 Michael Saboff + * API/JSObjectRef.cpp: + (JSObjectSetProperty): + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::putByIndex): + * runtime/ArrayPrototype.cpp: + (JSC::putProperty): + (JSC::arrayProtoFuncPush): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitiveByIndex): + * runtime/JSCell.cpp: + (JSC::JSCell::putByIndex): + * runtime/JSFunction.cpp: + (JSC::JSFunction::put): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView::putByIndex): + * runtime/JSONObject.cpp: + (JSC::Walker::walk): + * runtime/JSObject.cpp: + (JSC::JSObject::putByIndex): + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::deleteProperty): + * runtime/JSObject.h: + (JSC::JSObject::putDirect): + * runtime/Lookup.h: + (JSC::putEntry): + (JSC::lookupPut): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::PutPropertySlot): + (JSC::PutPropertySlot::setNewProperty): + (JSC::PutPropertySlot::isCacheable): - Cleanup of Calls to operationStrCat and operationNewArray and Use Constructor after r117729 - https://bugs.webkit.org/show_bug.cgi?id=87027 +2013-12-25 Filip Pizlo - Reviewed by Oliver Hunt. + DFG PhantomArguments shouldn't rely on a dead Phi graph + https://bugs.webkit.org/show_bug.cgi?id=126218 - Change calls to operationStrCat and operationNewArray to provide the - pointer to the EncodedJSValue* data buffer instead of the ScratchBuffer - that contains it. Added a ScratchBuffer::create() function. - This is a clean-up to r117729. + Reviewed by Oliver Hunt. + + This change dramatically rationalizes our handling of PhantomArguments (i.e. + speculative elision of arguments object allocation). + + It's now the case that if we decide that we can elide arguments allocation, we just + turn the arguments-creating node into a PhantomArguments and mark all locals that + it's stored to as being arguments aliases. Being an arguments alias and being a + PhantomArguments means basically the same thing: in DFG execution you have the empty + value, on OSR exit an arguments object is allocated in your place, and all operations + that use the value now just refer directly to the actual arguments in the call frame + header (or the arguments we know that we passed to the call, in case of inlining). + + This means that we no longer have arguments simplification creating a dead Phi graph + that then has to be interpreted by the OSR exit logic. That sort of never made any + sense. + + This means that PhantomArguments now has a clear story in SSA: basically SSA just + gets rid of the "locals" but everything else is the same. + + Finally, this means that we can more easily get rid of forward exiting. As I was + working on the code to get rid of forward exiting, I realized that I'd have to + carefully preserve the special meanings of MovHint and SetLocal in the case of + PhantomArguments. It was really bizarre: even the semantics of MovHint were tied to + our specific treatment of PhantomArguments. After this change this is no longer the + case. + + One of the really cool things about this change is that arguments reification now + just becomes a special kind of FlushFormat. This further unifies things: it means + that a MovHint(PhantomArguments) and a SetLocal(PhantomArguments) both have the same + meaning, since both of them dictate that the way we recover the local on exit is by + reifying arguments. Previously, the SetLocal(PhantomArguments) case needed some + special handling to accomplish this. + + A downside of this approach is that we will now emit code to store the empty value + into aliased arguments variables, and we will even emit code to load that empty value + as well. As far as I can tell this doesn't cost anything, since PhantomArguments are + most profitable in cases where it allows us to simplify control flow and kill the + arguments locals entirely. Of course, this isn't an issue in SSA form since SSA form + also eliminates the locals. + + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + (JSC::DFG::ArgumentsSimplificationPhase::detypeArgumentsReferencingPhantomChild): + * dfg/DFGFlushFormat.cpp: + (WTF::printInternal): + * dfg/DFGFlushFormat.h: + (JSC::DFG::resultFor): + (JSC::DFG::useKindFor): + (JSC::DFG::dataFormatFor): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGValueSource.h: + (JSC::DFG::ValueSource::ValueSource): + (JSC::DFG::ValueSource::forFlushFormat): + * dfg/DFGVariableAccessData.h: + (JSC::DFG::VariableAccessData::flushFormat): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): - * dfg/DFGOperations.cpp: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * runtime/JSGlobalData.h: - (JSC::ScratchBuffer::create): - (JSC::ScratchBuffer::dataBuffer): - (JSC::JSGlobalData::scratchBufferForSize): +2013-12-23 Oliver Hunt -2012-05-23 Lucas Forschler + Refactor PutPropertySlot to be aware of custom properties + https://bugs.webkit.org/show_bug.cgi?id=126187 - Merge 117729 + Reviewed by msaboff. - 2012-05-20 Michael Saboff + Refactor PutPropertySlot, making the constructor take the thisValue + used as a target. This results in a wide range of boilerplate changes + to pass the new parameter. - JSGlobalData ScratchBuffers Are Not Visited During Garbage Collection - https://bugs.webkit.org/show_bug.cgi?id=86553 + * API/JSObjectRef.cpp: + (JSObjectSetProperty): + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::putByIndex): + * runtime/ArrayPrototype.cpp: + (JSC::putProperty): + (JSC::arrayProtoFuncPush): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitiveByIndex): + * runtime/JSCell.cpp: + (JSC::JSCell::putByIndex): + * runtime/JSFunction.cpp: + (JSC::JSFunction::put): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView::putByIndex): + * runtime/JSONObject.cpp: + (JSC::Walker::walk): + * runtime/JSObject.cpp: + (JSC::JSObject::putByIndex): + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::deleteProperty): + * runtime/JSObject.h: + (JSC::JSObject::putDirect): + * runtime/Lookup.h: + (JSC::putEntry): + (JSC::lookupPut): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::PutPropertySlot): + (JSC::PutPropertySlot::setCustomProperty): + (JSC::PutPropertySlot::thisValue): + (JSC::PutPropertySlot::isCacheable): - Reviewed by Gavin Barraclough. +2013-12-23 Benjamin Poulain - Scratch buffers can contain the only reference to live objects. - Therefore visit scratch buffer contents as conservative roots. - Changed the scratch buffers to be a struct with an "active" - length and the actual buffer. The users of the scratch - buffer emit code where needed to set and clear the active - length as appropriate. During marking, the active count is - used for conservative marking. + Add class matching to the Selector Code Generator + https://bugs.webkit.org/show_bug.cgi?id=126176 - * dfg/DFGAssemblyHelpers.h: - (JSC::DFG::AssemblyHelpers::debugCall): - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOperations.cpp: - * dfg/DFGOperations.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGThunks.cpp: - (JSC::DFG::osrExitGenerationThunkGenerator): - * heap/Heap.cpp: - (JSC::Heap::markRoots): - * runtime/JSGlobalData.cpp: - (JSC::JSGlobalData::gatherConservativeRoots): - * runtime/JSGlobalData.h: - (JSC::ScratchBuffer::ScratchBuffer): - (ScratchBuffer): - (JSC::ScratchBuffer::allocationSize): - (JSC::ScratchBuffer::setActiveLength): - (JSC::ScratchBuffer::activeLength): - (JSC::ScratchBuffer::activeLengthPtr): - (JSC::ScratchBuffer::dataBuffer): - (JSGlobalData): - (JSC::JSGlobalData::scratchBufferForSize): + Reviewed by Antti Koivisto and Oliver Hunt. -2012-05-21 Lucas Forschler + Add test and branch based on BaseIndex addressing for x86_64. + Fast loops are needed to compete with clang on tight loops. - Merge 117523 + * assembler/MacroAssembler.h: + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::branch64): + (JSC::MacroAssemblerX86_64::branchPtr): + * assembler/X86Assembler.h: + (JSC::X86Assembler::cmpq_rm): - 2012-05-17 Filip Pizlo +2013-12-23 Oliver Hunt - Setting array index -1 and looping over array causes bad behavior - https://bugs.webkit.org/show_bug.cgi?id=86733 - + Update custom setter implementations to perform type checks + https://bugs.webkit.org/show_bug.cgi?id=126171 - Reviewed by Oliver Hunt. + Reviewed by Daniel Bates. - * dfg/DFGOperations.cpp: + Modify the setter function signature to take encoded values + as we're changing the setter usage everywhere anyway. -2012-05-21 Lucas Forschler + * runtime/Lookup.h: + (JSC::putEntry): - Merge 117193 +2013-12-23 Lucas Forschler - 2012-05-15 Oliver Hunt + Update copyright strings + + Reviewed by Dan Bernstein. - Make error information available even if all we have is line number information. - https://bugs.webkit.org/show_bug.cgi?id=86547 + * Info.plist: + * JavaScriptCore.vcxproj/JavaScriptCore.resources/Info.plist: - Reviewed by Filip Pizlo. +2013-12-23 Zan Dobersek - We don't need expression information to generate useful line, file, and stack information, - so only require that we have line number info available. + [GTK] Clean up compiler optimizations flags for libWTF, libJSC + https://bugs.webkit.org/show_bug.cgi?id=126157 - * interpreter/Interpreter.cpp: - (JSC::Interpreter::throwException): - * runtime/Executable.h: - (JSC): + Reviewed by Gustavo Noronha Silva. -2012-05-21 Lucas Forschler + * GNUmakefile.am: Remove the -fstrict-aliasing and -O3 compiler flags for libWTF.la. -O3 gets + overridden by -O2 that's listed in CXXFLAGS (or -O0 in case of debug builds) and -fstrict-aliasing + is enabled when -O2 is used (and shouldn't be enabled in debug builds anyway). - Merge 117201 +2013-12-22 Martin Robinson - 2012-05-15 Mark Hahnenberg + [CMake] Fix typo from r160812 + https://bugs.webkit.org/show_bug.cgi?id=126145 - Block freeing thread should not free blocks when we are actively requesting them - https://bugs.webkit.org/show_bug.cgi?id=86519 + Reviewed by Gustavo Noronha Silva. - Reviewed by Geoff Garen. + * CMakeLists.txt: Fix typo when detecting the type of library. - * heap/BlockAllocator.h: - (JSC::BlockAllocator::allocate): Reordering the setting of the flag so its done - while we hold the lock to ensure proper locking. +2013-12-22 Martin Robinson -2012-05-21 Lucas Forschler + [GTK][CMake] libtool-compatible soversion calculation + https://bugs.webkit.org/show_bug.cgi?id=125511 - Merge 117183 + Reviewed by Gustavo Noronha Silva. - 2012-05-15 Mark Hahnenberg + * CMakeLists.txt: Use the POPULATE_LIBRARY_VERSION macro and the + library-specific version information. - Block freeing thread should not free blocks when we are actively requesting them - https://bugs.webkit.org/show_bug.cgi?id=86519 +2013-12-23 Gustavo Noronha Silva - Reviewed by Geoffrey Garen. + [GTK] [CMake] Generate pkg-config files + https://bugs.webkit.org/show_bug.cgi?id=125685 - The block freeing thread shoots us in the foot if it decides to run while we're actively - requesting blocks and returning them. This situation can arise when there is a lot of copying - collection going on in steady state. We allocate a large swath of pages to copy into, then we - return all the newly free old pages to the BlockAllocator. In this state, if the block freeing - thread wakes up in between collections (which is more likely than it waking up during a - collection) and frees half of these pages, they will be needed almost immediately during the - next collection, causing a storm of VM allocations which we know are going to be very slow. + Reviewed by Martin Robinson. - What we'd like is for when things have quieted down the block freeing thread can then return - memory to the OS. Usually this will be when a page has fully loaded and has a low allocation - rate. In this situation, our opportunistic collections will only be running at least every few - seconds, thus the extra time spent doing VM allocations won't matter nearly as much as, say, - while a page is loading. + * PlatformGTK.cmake: Added. Generate javascriptcoregtk-3.0.pc. - * heap/BlockAllocator.cpp: - (JSC::BlockAllocator::BlockAllocator): Initialize our new field. - (JSC::BlockAllocator::blockFreeingThreadMain): We check if we've seen any block requests recently. - If so, reset our flag and go back to sleep. We also don't bother with locking here. If we miss out - on an update, we'll see it when we wake up again. - * heap/BlockAllocator.h: Add new field to track whether or not we've received recent block requests. - (BlockAllocator): - (JSC::BlockAllocator::allocate): If we receive a request for a block, set our field that tracks - that to true. We don't bother locking since we assume that writing to a bool is atomic. +2013-12-22 Benjamin Poulain -2012-05-15 Lucas Forschler + Create a skeleton for CSS Selector code generation + https://bugs.webkit.org/show_bug.cgi?id=126044 - Merge 116785 + Reviewed by Antti Koivisto and Gavin Barraclough. - 2012-05-11 Sam Weinig + * assembler/LinkBuffer.h: + Add a new owner UID for code compiled for CSS. + Export the symbols needed to link code from WebCore. - Fix crash seen when running with libgmalloc - - https://bugs.webkit.org/show_bug.cgi?id=86232 +2013-12-19 Mark Hahnenberg - Reviewed by Gavin Barraclough. + Clean up DFG write barriers + https://bugs.webkit.org/show_bug.cgi?id=126047 - * heap/MarkStack.cpp: - (JSC::MarkStackThreadSharedData::markingThreadMain): - Don't delete the SlotVisitor before the ParallelModeEnabler has had a chance to run its - destructor. + Reviewed by Filip Pizlo. -2012-05-15 Sam Weinig + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::storeToWriteBarrierBuffer): Use the register allocator to + determine which registers need saving instead of saving every single one of them. + (JSC::DFG::SpeculativeJIT::osrWriteBarrier): We don't need to save live register state + because the write barriers during OSR execute when there are no live registers. Also we + don't need to use pushes to pad the stack pointer for pokes on x86; we can just use an add. + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT.h: + * jit/Repatch.cpp: + (JSC::emitPutReplaceStub): + (JSC::emitPutTransitionStub): + * runtime/VM.h: Get rid of writeBarrierRegisterBuffer since it's no longer used. - ENABLE_IFRAME_SEAMLESS should be turned off on the branch +2013-12-20 Balazs Kilvady - Reviewed by Andy Estes. + [MIPS] Missing MacroAssemblerMIPS::branchTest8(ResultCondition, BaseIndex, TrustedImm32) + https://bugs.webkit.org/show_bug.cgi?id=126062 - * Configurations/FeatureDefines.xcconfig: - Disable ENABLE_IFRAME_SEAMLESS. + Reviewed by Mark Hahnenberg. -2012-05-15 Lucas Forschler + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::branchTest8): - Merge 116925 +2013-12-20 Julien Brianceau - 2012-05-13 Filip Pizlo + [sh4] Add missing implementation in MacroAssembler to fix build. + https://bugs.webkit.org/show_bug.cgi?id=126063 - DFG performs incorrect constant folding on double-to-uint32 conversion in - Uint32Array PutByVal - https://bugs.webkit.org/show_bug.cgi?id=86330 + Reviewed by Mark Hahnenberg. - Reviewed by Darin Adler. + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::branchTest8): - static_cast(d) is wrong, since JS semantics require us to use toInt32(d). - In particular, C++ casts on typical hardware (like x86 and similar) will - return 0x80000000 for double values that are out of range of the int32 domain - (i.e. less than -2^31 or greater than or equal to 2^31). But JS semantics call - for wrap-around; for example the double value 4294967297 ought to become the - int32 value 1, not 0x80000000. +2013-12-20 Julien Brianceau - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + [arm] Add missing implementation in MacroAssembler to fix CPU(ARM_TRADITIONAL) build. + https://bugs.webkit.org/show_bug.cgi?id=126064 -2012-05-15 Lucas Forschler + Reviewed by Mark Hahnenberg. - Merge 116809 + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::branchTest8): - 2012-05-11 Geoffrey Garen +2013-12-19 Joseph Pecoraro - Clarified JSGlobalData (JavaScript VM) lifetime - https://bugs.webkit.org/show_bug.cgi?id=85142 + Web Inspector: Add InspectorFrontendHost.debuggableType to let the frontend know it's backend is JavaScript or Web + https://bugs.webkit.org/show_bug.cgi?id=126016 - Reviewed by Alexey Proskuryakov. + Reviewed by Timothy Hatcher. - (Follow-up fix.) + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::listingForDebuggable): + * inspector/remote/RemoteInspectorConstants.h: + Include a debuggable type identifier in the debuggable listing, + so the remote frontend can know if it is debugging a Web Page + or JS Context. - * API/JSContextRef.cpp: - (JSGlobalContextCreate): Restored some code I removed because I misread an #ifdef. - (We don't need to test BUILDING_ON_LEOPARD, but we still need the linked-on - test, because apps might have been linked on older OS's.) +2013-12-19 Benjamin Poulain -2012-05-15 Lucas Forschler + Add an utility class to simplify generating function calls + https://bugs.webkit.org/show_bug.cgi?id=125972 - Merge 116813 + Reviewed by Geoffrey Garen. - 2012-05-11 Filip Pizlo + Split branchTest32 in two functions: test32AndSetFlags and branchOnFlags. + This is done to allow code where the flags are set, multiple operation that + do not modify the flags occur, then the flags are used. - JIT memory allocator is not returning memory to the OS on Darwin - https://bugs.webkit.org/show_bug.cgi?id=86047 + This is used for function calls to test the return value while discarding the + return register. - Reviewed by Geoff Garen. + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::test32AndSetFlags): + (JSC::MacroAssemblerX86Common::branchOnFlags): + (JSC::MacroAssemblerX86Common::branchTest32): - * jit/ExecutableAllocatorFixedVMPool.cpp: - (JSC::FixedVMPoolExecutableAllocator::notifyPageIsFree): +2013-12-19 Mark Hahnenberg -2012-05-15 Lucas Forschler + Put write barriers in the right places in the baseline JIT + https://bugs.webkit.org/show_bug.cgi?id=125975 - Merge 116593 + Reviewed by Filip Pizlo. - 2012-05-09 Filip Pizlo + * jit/JIT.cpp: + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + (JSC::JIT::emitArrayProfilingSite): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_enter): + (JSC::JIT::emitSlow_op_enter): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_enter): + (JSC::JIT::emitSlow_op_enter): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::emitGenericContiguousPutByVal): + (JSC::JIT::emitArrayStoragePutByVal): + (JSC::JIT::emit_op_put_by_id): + (JSC::JIT::emitPutGlobalProperty): + (JSC::JIT::emitPutGlobalVar): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emit_op_init_global_const): + (JSC::JIT::checkMarkWord): + (JSC::JIT::emitWriteBarrier): + (JSC::JIT::privateCompilePutByVal): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitGenericContiguousPutByVal): + (JSC::JIT::emitArrayStoragePutByVal): + (JSC::JIT::emit_op_put_by_id): + (JSC::JIT::emitSlow_op_put_by_id): + (JSC::JIT::emitPutGlobalProperty): + (JSC::JIT::emitPutGlobalVar): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emit_op_init_global_const): + * jit/Repatch.cpp: + (JSC::emitPutReplaceStub): + (JSC::emitPutTransitionStub): + (JSC::repatchPutByID): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: - JIT memory allocator is not returning memory to the OS on Darwin - https://bugs.webkit.org/show_bug.cgi?id=86047 - +2013-12-19 Brent Fulgham - Reviewed by Geoff Garen. + Implement ArrayBuffer.isView + https://bugs.webkit.org/show_bug.cgi?id=126004 - Work around the problem by using a different madvise() flag, but only for the JIT memory - allocator. Also put in ASSERTs that the call is actually working. + Reviewed by Filip Pizlo. - * jit/ExecutableAllocatorFixedVMPool.cpp: - (JSC::FixedVMPoolExecutableAllocator::notifyNeedPage): - (JSC::FixedVMPoolExecutableAllocator::notifyPageIsFree): + Test coverage in webgl/1.0.2/resources/webgl_test_files/conformance/typedarrays/array-unit-tests.html -2012-05-15 Lucas Forschler + * runtime/JSArrayBufferConstructor.cpp: + (JSC::JSArrayBufferConstructor::finishCreation): Add 'isView' to object constructor. + (JSC::arrayBufferFuncIsView): New method. - Merge 116565 +2013-12-19 Mark Lam - 2012-05-09 Mark Hahnenberg + Fix broken C loop LLINT build. + https://bugs.webkit.org/show_bug.cgi?id=126024. - CopiedSpace does not add pinned blocks back to the to-space filter - https://bugs.webkit.org/show_bug.cgi?id=86011 + Reviewed by Oliver Hunt. - Reviewed by Geoffrey Garen. + * runtime/VM.h: - After a collection has finished, we go through the blocks in from-space - and move any of them that are pinned into to-space. At the beginning of - collection, we reset the to-space block filter that is used during - conservative scanning and add back the blocks that are filled during the - collection. However, we neglect to add back those blocks that are moved - from from-space to to-space, which can cause the conservative scan to - think that some pinned items are not actually in CopiedSpace. +2013-12-18 Mark Hahnenberg - * heap/CopiedSpace.cpp: - (JSC::CopiedSpace::doneCopying): Add the pinned blocks back to the - to-space filter. Also added a comment and assert for future readers that - indicates that it's okay that we don't also add the block to the - to-space block set since it was never removed. + DelayedReleaseScope is in the wrong place + https://bugs.webkit.org/show_bug.cgi?id=125876 -2012-05-15 Lucas Forschler + Reviewed by Geoffrey Garen. - Merge 116484 + The DelayedReleaseScope needs to be around the free list sweeping in MarkedAllocator::tryAllocateHelper. + This location gives us a good safe point between getting ready to allocate (i.e. identifying a non-empty + free list) and doing the actual allocation (popping the free list). - 2012-05-08 Mark Hahnenberg + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::tryAllocateHelper): + (JSC::MarkedAllocator::allocateSlowCase): + (JSC::MarkedAllocator::addBlock): + * runtime/JSCellInlines.h: + (JSC::allocateCell): - Heap should not continually allocate new pages in steady state - https://bugs.webkit.org/show_bug.cgi?id=85936 +2013-12-18 Gustavo Noronha Silva - Reviewed by Geoff Garen. + [GTK][CMake] make libjavascriptcoregtk a public shared library again + https://bugs.webkit.org/show_bug.cgi?id=125512 - Currently, in steady state (i.e. a constant amount of live GC - memory with a constant rate of allocation) assuming we've just - finished a collection with X live blocks in CopiedSpace, we - increase our working set by X blocks in CopiedSpace with each - collection we perform. This is due to the fact that we allocate - until we run out of free blocks to use in the Heap before we - consider whether we should run a collection. + Reviewed by Martin Robinson. - In the longer term, this issue will be mostly resolved by - implementing quick release for the CopiedSpace. In the shorter - term, we should change our policy to check whether we should - allocate before trying to use a free block from the Heap. We - can change our policy to something more appropriate once we - have implemented quick release. + * CMakeLists.txt: use target type instead of SHARED_CORE to decide whether + JavaScriptCore is a shared library, since it's always shared for GTK+ regardless + of SHARED_CORE. - This change should also have the convenient side effect of - reducing the variance in GC-heavy tests (e.g. v8-splay) due - to fact that we are doing less VM allocation during copying - collection. Overall, this patch is performance neutral across - the benchmarks we track. +2013-12-18 Benjamin Poulain - * heap/CopiedSpace.cpp: - (JSC::CopiedSpace::getFreshBlock): Shuffle the request from the BlockAllocator - around so that we only do it if the block request must succeed - i.e. after we've already checked whether we should do a collection. - * heap/MarkedAllocator.cpp: - (JSC::MarkedAllocator::allocateSlowCase): Ditto. - (JSC::MarkedAllocator::allocateBlock): We no longer have a failure mode in this - function because by the time we've called it, we've already checked whether we - should run a collection so there's no point in returning null. - * heap/MarkedAllocator.h: Removing old arguments from function declaration. - (MarkedAllocator): + Add a simple stack abstraction for x86_64 + https://bugs.webkit.org/show_bug.cgi?id=125908 -2012-05-15 Lucas Forschler + Reviewed by Geoffrey Garen. - Merge 116372 + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::addPtrNoFlags): + Add an explicit abstraction for the "lea" instruction. This is needed + by the experimental JIT to have add and substract without changing the flags. - 2012-05-07 Oliver Hunt + This is useful for function calls to test the return value, restore the registers, + then branch on the flags from the return value. - Rolling out r110287 +2013-12-18 Mark Hahnenberg - RS=Filip Pizlo + DFG should have a separate StoreBarrier node + https://bugs.webkit.org/show_bug.cgi?id=125530 - r110287 was meant to be refactoring only, but changed behavior - enough to break some websites, including qq.com. + Reviewed by Filip Pizlo. -2012-05-15 Lucas Forschler + This is in preparation for GenGC. We use a separate StoreBarrier node instead of making them implicitly + part of other nodes so that it's easier to run analyses on them, e.g. for the StoreBarrierElisionPhase. + They are inserted during the fixup phase. Initially they do not generate any code. - Merge 116363 + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractHeap.h: + * dfg/DFGAbstractInterpreter.h: + (JSC::DFG::AbstractInterpreter::isKnownNotCell): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberizeForAllocation): + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): Whenever we insert new nodes that require StoreBarriers, + we have to add those new StoreBarriers too. It's important to note that AllocatePropertyStorage and + ReallocatePropertyStorage nodes require their StoreBarriers to come after them since they allocate first, + which could cause a GC, and then store the resulting buffer into their JSCell, which requires the barrier. + If we ever require that write barriers occur before stores, we'll have to split these nodes into + AllocatePropertyStorage + StoreBarrier + PutPropertyStorage. + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::insertStoreBarrier): + * dfg/DFGNode.h: + (JSC::DFG::Node::isStoreBarrier): + * dfg/DFGNodeType.h: + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage): + (JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage): + (JSC::DFG::SpeculativeJIT::compileStoreBarrier): + (JSC::DFG::SpeculativeJIT::genericWriteBarrier): The fast path write barrier check. It loads the + byte that contains the mark bit of the object. + (JSC::DFG::SpeculativeJIT::storeToWriteBarrierBuffer): If the fast path check fails we try to store the + cell in the WriteBarrierBuffer so as to avoid frequently flushing all registers in order to make a C call. + (JSC::DFG::SpeculativeJIT::writeBarrier): + (JSC::DFG::SpeculativeJIT::osrWriteBarrier): More barebones version of the write barrier to be executed + during an OSR exit into baseline code. We must do this so that the baseline JIT object and array profiles + are properly cleared during GC. + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compileBaseValueStoreBarrier): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compileBaseValueStoreBarrier): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGStoreBarrierElisionPhase.cpp: Added. New DFG phase that does block-local elision of redundant + StoreBarriers. Every time a StoreBarrier on a particular object is executed, a bit is set indicating that + that object doesn't need any more StoreBarriers. + (JSC::DFG::StoreBarrierElisionPhase::StoreBarrierElisionPhase): + (JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): Nodes that could cause a GC reset the bits for all of the + objects known in the current block. + (JSC::DFG::StoreBarrierElisionPhase::allocatesFreshObject): A node that creates a new object automatically + sets the bit for that object since if a GC occurred as the result of that object's allocation then that + object would not need a barrier since it would be guaranteed to be a young generation object until the + next GC point. + (JSC::DFG::StoreBarrierElisionPhase::noticeFreshObject): + (JSC::DFG::StoreBarrierElisionPhase::getBaseOfStore): + (JSC::DFG::StoreBarrierElisionPhase::shouldBeElided): + (JSC::DFG::StoreBarrierElisionPhase::elideBarrier): + (JSC::DFG::StoreBarrierElisionPhase::handleNode): + (JSC::DFG::StoreBarrierElisionPhase::handleBlock): + (JSC::DFG::StoreBarrierElisionPhase::run): + (JSC::DFG::performStoreBarrierElision): + * dfg/DFGStoreBarrierElisionPhase.h: Added. + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::flushWriteBarrierBuffer): + * heap/Heap.h: + (JSC::Heap::writeBarrier): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::offsetOfMarks): + * heap/WriteBarrierBuffer.cpp: Added. The WriteBarrierBuffer buffers a set of JSCells that are awaiting + a pending WriteBarrier. This buffer is used by the DFG to avoid the overhead of calling out to C repeatedly + to invoke a write barrier on a single JSCell. Instead the DFG has inline code to fill the WriteBarrier buffer + until its full, and then to call out to C to flush it. The WriteBarrierBuffer will also be flushed prior to + each EdenCollection. + (JSC::WriteBarrierBuffer::WriteBarrierBuffer): + (JSC::WriteBarrierBuffer::~WriteBarrierBuffer): + (JSC::WriteBarrierBuffer::flush): + (JSC::WriteBarrierBuffer::reset): + (JSC::WriteBarrierBuffer::add): + * heap/WriteBarrierBuffer.h: Added. + (JSC::WriteBarrierBuffer::currentIndexOffset): + (JSC::WriteBarrierBuffer::capacityOffset): + (JSC::WriteBarrierBuffer::bufferOffset): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * runtime/VM.h: + +2013-12-18 Carlos Garcia Campos - 2012-05-07 Oliver Hunt + Unreviewed. Fix make distcheck. - Fix release build. + * GNUmakefile.am: - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): +2013-12-17 Julien Brianceau -2012-05-15 Lucas Forschler + Fix armv7 and sh4 builds. + https://bugs.webkit.org/show_bug.cgi?id=125848 - Merge 116361 + Reviewed by Csaba Osztrogonác. - 2012-05-07 Oliver Hunt + * assembler/ARMv7Assembler.h: Include limits.h for INT_MIN. + * assembler/SH4Assembler.h: Include limits.h for INT_MIN. - LLInt doesn't check for Ropes when performing a character switch - https://bugs.webkit.org/show_bug.cgi?id=85837 +2013-12-16 Oliver Hunt - Reviewed by Filip Pizlo. + Avoid indirect function calls for custom getters + https://bugs.webkit.org/show_bug.cgi?id=125821 - Make LLint check if the scrutinee of a char switch is a rope, and if - so fall back to a slow case. + Reviewed by Mark Hahnenberg. - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - (LLInt): - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: + Rather than invoking a helper function to perform an indirect call + through a function pointer, just have the JIT call the function directly. -2012-05-15 Lucas Forschler + Unfortunately this only works in JSVALUE64 at the moment as there + is not an obvious way to pass two EncodedJSValues uniformly over + the various effected JITs. - Merge 116367 + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArguments): + * jit/Repatch.cpp: + (JSC::generateProtoChainAccessStub): + (JSC::tryBuildGetByIDList): - 2012-05-07 Andy Estes +2013-12-16 Joseph Pecoraro - ENABLE_IFRAME_SEAMLESS should be part of FEATURE_DEFINES. + Fix some whitespace issues in inspector code + https://bugs.webkit.org/show_bug.cgi?id=125814 - * Configurations/FeatureDefines.xcconfig: + Reviewed by Darin Adler. -2012-05-15 Lucas Forschler + * inspector/protocol/Debugger.json: + * inspector/protocol/Runtime.json: + * inspector/scripts/CodeGeneratorInspector.py: + (Generator.process_command): - Merge 116356 +2013-12-16 Mark Hahnenberg - 2012-05-07 Eric Seidel + Add some missing functions to MacroAssembler + https://bugs.webkit.org/show_bug.cgi?id=125809 - Add ENABLE_IFRAME_SEAMLESS so Apple can turn off SEAMLESS if needed - https://bugs.webkit.org/show_bug.cgi?id=85822 + Reviewed by Oliver Hunt. - Reviewed by Adam Barth. + * assembler/AbstractMacroAssembler.h: + * assembler/AssemblerBuffer.h: + * assembler/LinkBuffer.cpp: + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::storePtr): + (JSC::MacroAssembler::andPtr): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::and64): + (JSC::MacroAssemblerARM64::branchTest8): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::branchTest8): + * assembler/X86Assembler.h: - * Configurations/FeatureDefines.xcconfig: +2013-12-16 Brent Fulgham -2012-05-04 Filip Pizlo + [Win] Remove dead code after conversion to VS2013 + https://bugs.webkit.org/show_bug.cgi?id=125795 - DFG should not Flush GetLocal's - https://bugs.webkit.org/show_bug.cgi?id=85663 - + Reviewed by Darin Adler. - Reviewed by Oliver Hunt. + * API/tests/testapi.c: Remove local nan implementation - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::flushArgument): - (JSC::DFG::ByteCodeParser::handleCall): +2013-12-16 Oliver Hunt -2012-05-04 Allan Sandfeld Jensen + Cache getters and custom accessors on the prototype chain + https://bugs.webkit.org/show_bug.cgi?id=125602 - Doesn't build with ENABLE_JIT=0 - https://bugs.webkit.org/show_bug.cgi?id=85042 + Reviewed by Michael Saboff. - Reviewed by Gavin Barraclough. + Support caching of custom getters and accessors on the prototype chain. + This is relatively trivial and just requires a little work compared to + the direct access mode as we're under more register pressure. - * bytecode/Operands.h: + * bytecode/StructureStubInfo.h: + Removed the unsued initGetByIdProto as it was confusing to still have it present. + * jit/Repatch.cpp: + (JSC::generateProtoChainAccessStub): + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): -2012-05-03 Oliver Hunt +2013-12-16 Mark Lam - Regression(r114702): Clobbering the caller frame register before we've stored it. - https://bugs.webkit.org/show_bug.cgi?id=85564 + Change slow path result to take a void* instead of a ExecState*. + https://bugs.webkit.org/show_bug.cgi?id=125802. Reviewed by Filip Pizlo. - Don't use t0 as a temporary, when we're about to use the value in t0. + This is in preparation for C Stack OSR entry work that is coming soon. + In the OSR entry case, we'll be returning a topOfFrame pointer value + instead of the ExecState*. - * llint/LowLevelInterpreter32_64.asm: - -2012-05-03 Mark Hahnenberg - - Removing remainder of accidental printfs. - - * heap/Heap.cpp: - (JSC::Heap::collect): + * offlineasm/cloop.rb: + * runtime/CommonSlowPaths.h: + (JSC::encodeResult): + (JSC::decodeResult): -2012-05-03 Andy Estes +2013-12-16 Alex Christensen - If you add printf()s to your garbage collector, the layout tests are gonna have a bad time. + Fixed Win64 build on VS2013. + https://bugs.webkit.org/show_bug.cgi?id=125753 - * runtime/GCActivityCallbackCF.cpp: - (JSC::DefaultGCActivityCallbackPlatformData::timerDidFire): + Reviewed by Brent Fulgham. -2012-05-03 Mark Hahnenberg + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractor.vcxproj: + * JavaScriptCore.vcxproj/jsc/jsc.vcxproj: + * JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: + Added correct PlatformToolset for 64-bit builds. - Heap::reportAbandonedObjectGraph should not hasten an allocation-triggered collection - https://bugs.webkit.org/show_bug.cgi?id=85543 +2013-12-16 Peter Szanka - Reviewed by Filip Pizlo. + Delete RVCT related code parts. + https://bugs.webkit.org/show_bug.cgi?id=125626 - Currently reportAbandonedObjectGraph causes the Heap to think it is closer to its - allocation limit for the current cycle, thus hastening an allocation-triggered collection. - In reality, it should just affect the opportunistic GC timer. We should track the bytes - we think have been abandoned and the bytes that have been allocated separately. - - * heap/Heap.cpp: Added a new field m_abandonedBytes to Heap to keep track of how much - we think we've abandoned. - (JSC::Heap::Heap): - (JSC::Heap::reportAbandonedObjectGraph): - (JSC): - (JSC::Heap::didAbandon): Added this function for reportAbandonedObjectGraph to call - rather than didAllocate. Works the same as didAllocate, but modifies bytes abandoned rather - than bytes allocated. Also notifies the timer, summing the two values together. - (JSC::Heap::collect): - (JSC::Heap::didAllocate): Now adds the bytes allocated and bytes abandoned when reporting - to GCActivityCallback. - * heap/Heap.h: - (Heap): + Reviewed by Darin Adler. -2012-05-02 Eric Seidel + * assembler/ARMAssembler.cpp: + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::cacheFlush): + * assembler/MacroAssemblerARM.cpp: + (JSC::isVFPPresent): + * jit/JITStubsARM.h: + * jit/JITStubsARMv7.h: - Sort ENABLE_ defines in FeatureDefines.xcconfig files to make them easier to compare with one another (and easier to autogenerate) - https://bugs.webkit.org/show_bug.cgi?id=85433 +2013-12-15 Ryosuke Niwa - Reviewed by Adam Barth. + REGRESSION: 2x regression on Dromaeo DOM query tests + https://bugs.webkit.org/show_bug.cgi?id=125377 - I have a script which can autogenerate these xcconfig files as well as the - vsprops files (and soon the Chromium, cmake, gnumake and qmake) feature lists - from a central feature list file. - In preparation for posting such a tool, I'm re-sorting these xcconfig files to be - alphabetically ordered (currently they're close, but not quite). - There is also at least one inconsistency between these files (CSS_LEGACY_PREFIXES) which - I will fix in a second pass. I will also sort the FEATURE_DEFINES = line in a follow-up patch. + Reviewed by Filip Pizlo. - * Configurations/FeatureDefines.xcconfig: + The bug was caused by JSC not JIT'ing property access on "document" due to its type info having + HasImpureGetOwnPropertySlot flag. -2012-05-02 Hojong Han + Fixed the bug by new type info flag NewImpurePropertyFiresWatchpoints, which allows the baseline + JIT to generate byte code for access properties on an object with named properties (a.k.a. + custom name getter) in DOM. When a new named property appears on the object, VM is notified via + VM::addImpureProperty and fires StructureStubClearingWatchpoint added during the repatch. - ARM_TRADITIONAL build fix - https://bugs.webkit.org/show_bug.cgi?id=85358 + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): Take the slow path if we have any object with impure + properties in the prototype chain. + (JSC::GetByIdStatus::computeForChain): Ditto. - Reviewed by Gavin Barraclough. + * jit/Repatch.cpp: + (JSC::repatchByIdSelfAccess): Throw away the byte code when a new impure property is added on any + object in the prototype chain via StructureStubClearingWatchpoint. + (JSC::generateProtoChainAccessStub): Ditto. + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::tryRepatchIn): Ditto. - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::lshift32): - (MacroAssemblerARM): - (JSC::MacroAssemblerARM::or32): - (JSC::MacroAssemblerARM::urshift32): - (JSC::MacroAssemblerARM::xor32): - (JSC::MacroAssemblerARM::branchSub32): + * runtime/JSTypeInfo.h: Added NewImpurePropertyFiresWatchpoints. + (JSC::TypeInfo::newImpurePropertyFiresWatchpoints): Added. -2012-05-02 Mark Hahnenberg + * runtime/Operations.h: + (JSC::normalizePrototypeChainForChainAccess): Don't exit early if VM will be notified of new + impure property even if the object had impure properties. - Opportunistic GC should give up if the Heap is paged out - https://bugs.webkit.org/show_bug.cgi?id=85411 + * runtime/Structure.h: + (JSC::Structure::takesSlowPathInDFGForImpureProperty): Added. Wraps hasImpureGetOwnPropertySlot and + asserts that newImpurePropertyFiresWatchpoints is true whenever hasImpureGetOwnPropertySlot is true. - Reviewed by Filip Pizlo. + * runtime/VM.cpp: + (JSC::VM::registerWatchpointForImpureProperty): Added. + (JSC::VM::addImpureProperty): Added. HTMLDocument calls it to notify JSC of a new impure property. - Opportunistic GC is punishing us severely in limited memory situations because its - assumptions about how much time a collection will take are way out of whack when the Heap - has been paged out by the OS. We should add a simple detection function to the Heap that - detects if its is paged out. It will do this by iterating each block of both the MarkedSpace - and CopiedSpace. If that operation takes longer than a fixed amount of time (e.g. 100ms), - the function returns true. This function will only be run prior to an opportunistic - collection (i.e. it will not run during our normal allocation-triggered collections). - - In my tests, steady state was drastically improved in high memory pressure situations (i.e. - the browser was still usable, significant reduction in SPODs). Occasionally, a normal GC - would be triggered due to pages doing things in the background, which would cause a - significant pause. As we close pages we now cause normal collections rather than full - collections, which prevents us from collecting all of the dead memory immediately. One - nice way to deal with this issue might be to do incremental sweeping. - - - * heap/CopiedSpace.cpp: - (JSC::isBlockListPagedOut): Helper function to reduce code duplication when iterating over - to-space, from-space, and the oversize blocks. - (JSC): - (JSC::CopiedSpace::isPagedOut): Tries to determine whether or not CopiedSpace is paged out - by iterating all of the blocks. - * heap/CopiedSpace.h: - (CopiedSpace): - * heap/Heap.cpp: - (JSC::Heap::isPagedOut): Tries to determine whether the Heap is paged out by asking the - MarkedSpace and CopiedSpace if they are paged out. - (JSC): - * heap/Heap.h: - (Heap): - (JSC::Heap::increaseLastGCLength): Added this so that the GC timer can linearly back off - each time it determines that the Heap is paged out. - * heap/MarkedAllocator.cpp: - (JSC::MarkedAllocator::isPagedOut): Tries to determine if this particular MarkedAllocator's - list of blocks are paged out. - (JSC): - * heap/MarkedAllocator.h: - (MarkedAllocator): - * heap/MarkedSpace.cpp: - (JSC::MarkedSpace::isPagedOut): For each MarkedAllocator, check to see if they're paged out. - * heap/MarkedSpace.h: - (MarkedSpace): - * runtime/GCActivityCallback.cpp: - (JSC::DefaultGCActivityCallback::cancel): - (JSC): - * runtime/GCActivityCallback.h: - (JSC::GCActivityCallback::cancel): - (DefaultGCActivityCallback): - * runtime/GCActivityCallbackCF.cpp: Added a constant of 100ms for the timeout in determining - whether the Heap is paged out or not. - (JSC): - (JSC::DefaultGCActivityCallbackPlatformData::timerDidFire): Added the check to see if we - should attempt a collection based on whether or not we can iterate the blocks of the Heap in - 100ms. If we can't, we cancel the timer and tell the Heap we just wasted 100ms more trying to - do a collection. This gives us a nice linear backoff so we're not constantly re-trying in - steady state paged-out-ness. - (JSC::DefaultGCActivityCallback::cancel): Added this function which, while currently doing - exactly the same thing as willCollect, is more obvious as to what it's doing when we call it - in timerDidFire. - -2012-05-02 Yong Li - - Fix GCC X86 build error - https://bugs.webkit.org/show_bug.cgi?id=85379 - - Reviewed by Rob Buis. - - Always explicitly claim ".text" to make sure - functions defined with inline assembly will be - created in the correct section. + * runtime/VM.h: - * dfg/DFGOperations.cpp: - (JSC): +2013-12-15 Andy Estes -2012-05-02 Oliver Hunt + [iOS] Upstream changes to FeatureDefines.xcconfig + https://bugs.webkit.org/show_bug.cgi?id=125742 - Unreviewed, rolling out r115388. - http://trac.webkit.org/changeset/115388 - https://bugs.webkit.org/show_bug.cgi?id=85011 + Reviewed by Dan Bernstein. - This caused many weird performance problems, and needs to be - landed in pieces. + * Configurations/FeatureDefines.xcconfig: - * dfg/DFGOperations.cpp: - * heap/Heap.cpp: - (JSC::Heap::getConservativeRegisterRoots): - (JSC::Heap::markRoots): - * interpreter/CallFrame.cpp: - (JSC::CallFrame::dumpCaller): - (JSC): - * interpreter/CallFrame.h: - (JSC::ExecState::init): - (ExecState): - * interpreter/Interpreter.cpp: - (JSC::Interpreter::execute): - (JSC::Interpreter::executeCall): - (JSC::Interpreter::executeConstruct): - (JSC::Interpreter::prepareForRepeatCall): - (JSC::Interpreter::privateExecute): - * interpreter/Interpreter.h: - (JSC::Interpreter::execute): - * interpreter/RegisterFile.cpp: - (JSC::RegisterFile::growSlowCase): - (JSC::RegisterFile::gatherConservativeRoots): - * interpreter/RegisterFile.h: - (JSC::RegisterFile::end): - (JSC::RegisterFile::size): - (JSC::RegisterFile::addressOfEnd): - (RegisterFile): - (JSC::RegisterFile::RegisterFile): - (JSC::RegisterFile::shrink): - (JSC::RegisterFile::grow): - * jit/JITStubs.cpp: - (JSC::DEFINE_STUB_FUNCTION): - (JSC::jitCompileFor): - (JSC::lazyLinkFor): - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - (JSC::LLInt::handleHostCall): - * llint/LowLevelInterpreter.asm: - * runtime/CommonSlowPaths.h: - (JSC::CommonSlowPaths::arityCheckFor): +2013-12-14 Filip Pizlo -2012-05-01 Oliver Hunt + FTL should *really* know when things are flushed + https://bugs.webkit.org/show_bug.cgi?id=125747 - Physijs demo crashes due to DFG not updating topCallFrame correctly. - https://bugs.webkit.org/show_bug.cgi?id=85311 + Reviewed by Sam Weinig. + + Fix more codegen badness. This makes V8v7's crypto am3() function run faster in the FTL + than in DFG. This means that even if we just compile those functions in V8v7 that don't + make calls, the FTL gives us a 2% speed-up over the DFG. That's pretty good considering + that we have still more optimizations to fix and we can make calls work. - Reviewed by Filip Pizlo. + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): - A few of the dfg operations failed to correctly set the topCallFrame, - and so everything goes wrong. This patch corrects the effected operations, - and makes debug builds poison topCallFrame before calling a dfg operation. +2013-12-14 Andy Estes - * dfg/DFGOperations.cpp: - (JSC::DFG::putByVal): - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::callOperation): - (SpeculativeJIT): - (JSC::DFG::SpeculativeJIT::prepareForExternalCall): - (JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheck): - (JSC::DFG::SpeculativeJIT::appendCallSetResult): + Unify FeatureDefines.xcconfig + https://bugs.webkit.org/show_bug.cgi?id=125741 -2012-04-30 Gavin Barraclough + Rubber-stamped by Dan Bernstein. - Should be able to use YARR JIT without the JS language JIT - https://bugs.webkit.org/show_bug.cgi?id=85252 + * Configurations/FeatureDefines.xcconfig: Enable ENABLE_MEDIA_SOURCE. - Reviewed by Geoff Garen. +2013-12-14 Mark Rowe - Need to split canUseRegExpJIT out of canUseJIT. - - * runtime/JSGlobalData.cpp: - (JSC): - (JSC::useJIT): - (JSC::JSGlobalData::JSGlobalData): - - replace m_canUseJIT with m_canUseAssembler - * runtime/JSGlobalData.h: - (JSGlobalData): - (JSC::JSGlobalData::canUseRegExpJIT): - - Added canUseRegExpJIT, distinct from canUseJIT. - * runtime/RegExp.cpp: - (JSC::RegExp::compile): - (JSC::RegExp::compileMatchOnly): - - Call canUseRegExpJIT instead of canUseJIT. + Build fix after r160557. -2012-04-30 Gavin Barraclough + r160557 added the first generated header to JavaScriptCore that needs to be installed in to + the framework wrapper. Sadly JavaScriptCore's Derived Sources target was not set to generate + headers when invoked as part of the installhdrs action. This resulted in the build failing + due to Xcode being unable to find the header file to install. The fix for this is to configure + the Derived Sources target to use JavaScriptCore.xcconfig, which sets INSTALLHDRS_SCRIPT_PHASE + to YES and allows Xcode to generate derived sources during the installhdrs action. - Should be able to build YARR JIT without the JS language JIT - https://bugs.webkit.org/show_bug.cgi?id=85242 + Enabling INSTALLHDRS_SCRIPT_PHASE required tweaking the Generate Derived Sources script build + phase to skip running code related to offlineasm that depends on JSCLLIntOffsetExtractor + having been compiled, which isn't the case at installhdrs time. - Reviewed by Michael Saboff. + * JavaScriptCore.xcodeproj/project.pbxproj: - Some build macros are wrong. +2013-12-13 Joseph Pecoraro - * assembler/RepatchBuffer.h: - * jit/ExecutableAllocator.h: - (JSC): - * jit/JITExceptions.cpp: - * runtime/InitializeThreading.cpp: - (JSC::initializeThreadingOnce): + Some Set and Map prototype functions have incorrect function lengths + https://bugs.webkit.org/show_bug.cgi?id=125732 -2012-04-26 Gavin Barraclough + Reviewed by Oliver Hunt. - Arguments object resets attributes on redefinition of a parameter - https://bugs.webkit.org/show_bug.cgi?id=84994 + * runtime/MapPrototype.cpp: + (JSC::MapPrototype::finishCreation): + * runtime/SetPrototype.cpp: + (JSC::SetPrototype::finishCreation): - Rubber stamped by Oliver Hunt. +2013-12-13 Joseph Pecoraro - There is a bug that we always re-add the original property before - redefinition, doing so in a way that will reset the attributes - without checking configurability. + Web Inspector: Move Inspector and Debugger protocol domains into JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=125707 - * runtime/Arguments.cpp: - (JSC::Arguments::defineOwnProperty): - - Only instantiate the property once - do not re-add if - it has already been added, or if it has been deleted. + Reviewed by Timothy Hatcher. -2012-04-30 Ryosuke Niwa + * CMakeLists.txt: + * DerivedSources.make: + * GNUmakefile.am: + * inspector/protocol/Debugger.json: Renamed from Source/WebCore/inspector/protocol/Debugger.json. + * inspector/protocol/GenericTypes.json: Added. + * inspector/protocol/InspectorDomain.json: Renamed from Source/WebCore/inspector/protocol/InspectorDomain.json. + Add new files to inspector generation. - Remove an erroneous assertion after r115655. + * inspector/scripts/CodeGeneratorInspector.py: + (Generator.go): + Only build TypeBuilder output if the domain only has types. Avoid + backend/frontend dispatchers and backend commands. - * runtime/NumberPrototype.cpp: - (JSC::toUStringWithRadix): + (TypeBindings.create_type_declaration_.EnumBinding.get_setter_value_expression_pattern): + (format_setter_value_expression): + (Generator.process_command): + (Generator.generate_send_method): + * inspector/scripts/CodeGeneratorInspectorStrings.py: + Export and name the get{JS,Web}EnumConstant function. -2012-04-30 Myles Maxfield +2013-12-11 Filip Pizlo - End of Interpreter::tryCacheGetByID can trigger the garbage collector - https://bugs.webkit.org/show_bug.cgi?id=84927 + Get rid of forward exit on UInt32ToNumber by adding an op_unsigned bytecode instruction + https://bugs.webkit.org/show_bug.cgi?id=125553 Reviewed by Oliver Hunt. + + UInt32ToNumber was a super complicated node because it had to do a speculation, but it + would do it after we already had computed the urshift. It couldn't just back to the + beginning of the urshift because the inputs to the urshift weren't necessarily live + anymore. We couldn't jump forward to the beginning of the next instruction because the + result of the urshift was not yet unsigned-converted. + + For a while we solved this by forward-exiting in UInt32ToNumber. But that's really + gross and I want to get rid of all forward exits. They cause a lot of bugs. + + We could also have turned UInt32ToNumber to a backwards exit by forcing the inputs to + the urshift to be live. I figure that this might be a bit too extreme. + + So, I just created a new place that we can exit to: I split op_urshift into op_urshift + followed by op_unsigned. op_unsigned is an "unsigned cast" along the lines of what + UInt32ToNumber does. This allows me to get rid of all of the nastyness in the DFG for + forward exiting in UInt32ToNumber. + + This patch enables massive code carnage in the DFG and FTL, and brings us closer to + eliminating one of the DFG's most confusing concepts. On the flipside, it does make the + bytecode slightly more complex (one new instruction). This is a profitable trade. We + want the DFG and FTL to trend towards simplicity, since they are both currently too + complicated. - * interpreter/Interpreter.cpp: - (JSC::Interpreter::tryCacheGetByID): - -2012-04-30 Benjamin Poulain - - jsSingleCharacterString and jsSingleCharacterSubstring are not inlined - https://bugs.webkit.org/show_bug.cgi?id=85147 + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecode/ValueRecovery.cpp: + (JSC::ValueRecovery::dumpInContext): + * bytecode/ValueRecovery.h: + (JSC::ValueRecovery::gpr): + * bytecompiler/NodesCodegen.cpp: + (JSC::BinaryOpNode::emitBytecode): + (JSC::emitReadModifyAssignment): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::toInt32): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGNodeType.h: + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileMovHint): + (JSC::DFG::SpeculativeJIT::compileUInt32ToNumber): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + * dfg/DFGSpeculativeJIT64.cpp: + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + (JSC::DFG::StrengthReductionPhase::convertToIdentityOverChild): + (JSC::DFG::StrengthReductionPhase::convertToIdentityOverChild1): + (JSC::DFG::StrengthReductionPhase::convertToIdentityOverChild2): + * ftl/FTLFormattedValue.h: + (JSC::FTL::int32Value): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileUInt32ToNumber): + * ftl/FTLValueFormat.cpp: + (JSC::FTL::reboxAccordingToFormat): + (WTF::printInternal): + * ftl/FTLValueFormat.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_urshift): + (JSC::JIT::emitSlow_op_urshift): + (JSC::JIT::emit_op_unsigned): + (JSC::JIT::emitSlow_op_unsigned): + * jit/JITArithmetic32_64.cpp: + (JSC::JIT::emitRightShift): + (JSC::JIT::emitRightShiftSlowCase): + (JSC::JIT::emit_op_unsigned): + (JSC::JIT::emitSlow_op_unsigned): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: - Reviewed by Darin Adler. +2013-12-13 Mark Hahnenberg - The functions jsSingleCharacterString() and jsSingleCharacterSubstring() were not inlined - by the compiler. This annihilate the gains of using SmallStrings. + LLInt should not conditionally branch to to labels outside of its function + https://bugs.webkit.org/show_bug.cgi?id=125713 - On stringProtoFuncCharAt(), this patch improves the performance by 11%. + Reviewed by Geoffrey Garen. - * runtime/JSString.h: - (JSC::jsSingleCharacterString): - (JSC::jsSingleCharacterSubstring): + Conditional branches are insufficient for jumping to out-of-function labels. + The fix is to use an unconditional jmp to the label combined with a conditional branch around the jmp. -2012-04-30 Benjamin Poulain + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: - Add fast patch for radix == 10 on numberProtoFuncToString - https://bugs.webkit.org/show_bug.cgi?id=85120 +2013-12-13 Joseph Pecoraro - Reviewed by Darin Adler. + [GTK] Remove Warnings in building about duplicate INSPECTOR variables + https://bugs.webkit.org/show_bug.cgi?id=125710 - When radix, we use to turn the doubleValue into a JSValue just to convert - it to a String. The problem is that was using the slow path for conversion and - for the toString() operation. + Reviewed by Tim Horton. - This patch shortcuts the creation of a JSValue and uses NumericStrings directly. - The conversion is split between Integer and Double to ensure the fastest conversion - for the common case of integer arguments. + * GNUmakefile.am: - Converting number with radix 10 becomes 5% faster. +2013-12-13 Joseph Pecoraro - Due to the simpler conversion of number to string for integer, converting - integers that do not fall in the two previous optimizations get 32% faster. + Cleanup CodeGeneratorInspectorStrings a bit + https://bugs.webkit.org/show_bug.cgi?id=125705 - * runtime/NumberPrototype.cpp: - (JSC::extractRadixFromArgs): - (JSC::integerValueToString): - (JSC::numberProtoFuncToString): + Reviewed by Timothy Hatcher. -2012-04-30 Carlos Garcia Campos + * inspector/scripts/CodeGeneratorInspectorStrings.py: + Use ${foo} variable syntax and add an ASCIILiteral. - Unreviewed. Fix make distcheck. +2013-12-13 Brent Fulgham - * GNUmakefile.list.am: Add missing header. + [Win] Unreviewed build fix after r160563 -2012-04-28 Geoffrey Garen + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj: Missed the Debug + target in my last patch. - Factored threaded block allocation into a separate object - https://bugs.webkit.org/show_bug.cgi?id=85148 +2013-12-13 Brent Fulgham - Reviewed by Sam Weinig. + [Win] Unreviewed build fix after r160548 - 99% of this patch just moves duplicated block allocation and - deallocation code into a new object named BlockAllocator, with these - exceptions: + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj: Specify + that we are using the vs12_xp target for Makefile-based projects. + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj: Ditto + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj: Ditto. - * heap/BlockAllocator.h: Added. - (BlockAllocator::BlockAllocator): The order of declarations here now - guards us against an unlikely race condition during startup. +2013-12-13 Joseph Pecoraro - * heap/BlockAllocator.cpp: - JSC::BlockAllocator::blockFreeingThreadMain): Added a FIXME to - highlight a lack of clarity we have in our block deallocation routines. + Make inspector folder groups smarter in JavaScriptCore.xcodeproj + https://bugs.webkit.org/show_bug.cgi?id=125663 -2012-04-28 Sam Weinig + Reviewed by Darin Adler. - Try to fix the Qt build. + * JavaScriptCore.xcodeproj/project.pbxproj: - * heap/Heap.cpp: - (JSC::Heap::lastChanceToFinalize): +2013-12-13 Joseph Pecoraro -2012-04-28 Geoffrey Garen + Web Inspector: Add Inspector Code Generation to JavaScriptCore for Runtime Domain + https://bugs.webkit.org/show_bug.cgi?id=125595 - Try to fix the Windows build. + Reviewed by Timothy Hatcher. - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + - Move CodeGeneration scripts from WebCore into JavaScriptCore/inspector/scripts + - For ports that build WebKit frameworks separately, export the scripts as PrivateHeaders + - Update CodeGeneratorInspector.py in a few ways: + - output dynamic filenames, so JavaScriptCore generates InspectorJSFoo.* and WebCore generates InspectorWebFoo.* + - take in more then one protocol JSON file. The first contains domains to generate, the others are dependencies + that are generated elsewhere that we can depend on for Types. + - Add DerivedSources build step to generate the Inspector Interfaces -2012-04-28 Geoffrey Garen + * CMakeLists.txt: + * DerivedSources.make: + * GNUmakefile.am: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.xcodeproj/project.pbxproj: + Add scripts and code generation. - Clarified JSGlobalData (JavaScript VM) lifetime - https://bugs.webkit.org/show_bug.cgi?id=85142 + * inspector/protocol/Runtime.json: Renamed from Source/WebCore/inspector/protocol/Runtime.json. + Move protocol file into JavaScriptCore so its types will be generated in JavaScriptCore. - Reviewed by Anders Carlsson. + * inspector/scripts/CodeGeneratorInspector.py: Renamed from Source/WebCore/inspector/CodeGeneratorInspector.py. + Updates to the script as listed above. - This was so confusing that I didn't feel like I could reason about - memory lifetime in the heap without fixing it. + * inspector/scripts/CodeGeneratorInspectorStrings.py: Renamed from Source/WebCore/inspector/CodeGeneratorInspectorStrings.py. + * inspector/scripts/generate-combined-inspector-json.py: Renamed from Source/WebCore/inspector/Scripts/generate-combined-inspector-json.py. + Moved from WebCore into JavaScriptCore for code generation. - The rules are: +2013-12-13 Peter Szanka - (1) JSGlobalData owns the virtual machine and all memory in it. + Delete INTEL C compiler related code parts. + https://bugs.webkit.org/show_bug.cgi?id=125625 - (2) Deleting a JSGlobalData frees the virtual machine and all memory - in it. + Reviewed by Darin Adler. - (Caveat emptor: if you delete the virtual machine while you're running - JIT code or accessing GC objects, you're gonna have a bad time.) + * jsc.cpp: + * testRegExp.cpp: - (I opted not to make arbitrary sub-objects keep the virtual machine - alive automatically because: +2013-12-13 Brent Fulgham - (a) doing that right would be complex and slow; + [Win] Switch WebKit solution to Visual Studio 2013 + https://bugs.webkit.org/show_bug.cgi?id=125192 - (b) in the case of an exiting thread or process, there's no - clear way to give the garbage collector a chance to try again - later; + Reviewed by Anders Carlsson. - (c) continuing to run the garbage collector after we've been - asked to shut down the virtual machine seems rude; + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Update for VS2013 + * JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractor.vcxproj: + Ditto + * JavaScriptCore.vcxproj/jsc/jsc.vcxproj: Ditto + * JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj: Ditto + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: Ditto - (d) we've never really supported that feature, anyway.) +2013-12-12 Joseph Pecoraro - (3) Normal ref-counting will do. No need to call a battery of - specialty functions to tear down a JSGlobalData. Its foibles - notwithstanding, C++ does in fact know how to execute destructors in - order. + Add a few more ASCIILiterals + https://bugs.webkit.org/show_bug.cgi?id=125662 - * API/JSContextRef.cpp: - (JSGlobalContextCreate): Removed compatibility shim for older - operating systems because it's no longer used. + Reviewed by Darin Adler. - (JSGlobalContextRelease): Now that we can rely on JSGlobalData to "do - the right thing", this code is much simpler. We still have one special - case to notify the garbage collector if we're removing the last - reference to the global object, since this can improve memory behavior. + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::InspectorBackendDispatcher::dispatch): - * heap/CopiedSpace.cpp: - (JSC::CopiedSpace::freeAllBlocks): - * heap/CopiedSpace.h: - (CopiedSpace): Renamed "destroy" => "freeAllBlocks" because true - destruction-time behaviors should be limited to our C++ destructor. +2013-12-12 Joseph Pecoraro - * heap/Heap.cpp: - (JSC::Heap::~Heap): - (JSC): - (JSC::Heap::lastChanceToFinalize): - * heap/Heap.h: - (Heap): - (JSC::Heap::heap): Renamed "destroy" => "lastChanceToFinalize" because - true destruction-time behaviors should be limited to our C++ - destructor. + Test new JSContext name APIs + https://bugs.webkit.org/show_bug.cgi?id=125607 - Reorganized the code, putting code that must run before any objects - get torn down into lastChanceToFinalize, and code that just tears down - objects into our destructor. + Reviewed by Darin Adler. - * heap/Local.h: - (JSC::LocalStack::LocalStack): - (JSC::LocalStack::push): - (LocalStack): See rule (2). + * API/JSContext.h: + * API/JSContextRef.h: + Fix whitespace issues. - * jsc.cpp: - (functionQuit): - (main): - (printUsageStatement): - (parseArguments): - (jscmain): - * testRegExp.cpp: + * API/tests/testapi.c: + (globalContextNameTest): (main): - (printUsageStatement): - (parseArguments): - (realMain): See rule (3). - - I removed the feature of ensuring orderly tear-down when calling quit() - or running in --help mode because it didn't seem very useful and - making it work with Windows structured exception handling and - NO_RETURN didn't seem like a fun way to spend a Saturday. - - * runtime/JSGlobalData.h: - * runtime/JSGlobalData.cpp: - (JSC::JSGlobalData::JSGlobalData): Moved heap to be the first data - member in JSGlobalData to ensure that it's destructed last, so other - objects that reference it destruct without crashing. This allowed me - to remove clearBuiltinStructures() altogether, and helped guarantee - rule (3). - - (JSC::JSGlobalData::~JSGlobalData): Explicitly call - lastChanceToFinalize() at the head of our destructor to ensure that - all pending finalizers run while the virtual machine is still in a - valid state. Trying to resurrect (re-ref) the virtual machine at this - point is not valid, but all other operations are. - - Changed a null to a 0xbbadbeef to clarify just how bad this beef is. + * API/tests/testapi.mm: + Add tests for JSContext set/get name APIs. - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::init): - * runtime/JSGlobalObject.h: - (JSGlobalObject): - (JSC::JSGlobalObject::globalData): See rule (3). +2013-12-11 Filip Pizlo -2012-04-27 Geoffrey Garen + ARM64: Hang running pdfjs test, suspect DFG generated code for "in" + https://bugs.webkit.org/show_bug.cgi?id=124727 + - Try to fix the Windows build. + Reviewed by Michael Saboff. + + Get rid of In's hackish use of StructureStubInfo. Previously it was using hotPathBegin, + and it was the only IC that used that field, which was wasteful. Moreover, it used it + to store two separate locations: the label for patching the jump and the label right + after the jump. The code was relying on those two being the same label, which is true + on X86 and some other platforms, but it isn't true on ARM64. + + This gets rid of hotPathBegin and makes In express those two locations as offsets from + the callReturnLocation, which is analogous to what the other IC's do. + + This fixes a bug where any successful In patching would result in a trivially infinite + loop - and hence a hang - on ARM64. - * heap/WeakBlock.h: - (WeakBlock): + * bytecode/StructureStubInfo.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGJITCompiler.h: + (JSC::DFG::InRecord::InRecord): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + * jit/JITInlineCacheGenerator.cpp: + (JSC::JITByIdGenerator::finalize): + * jit/Repatch.cpp: + (JSC::replaceWithJump): + (JSC::patchJumpToGetByIdStub): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + (JSC::tryRepatchIn): + (JSC::resetGetByID): + (JSC::resetPutByID): + (JSC::resetIn): + +2013-12-11 Joseph Pecoraro + + Web Inspector: Push More Inspector Required Classes Down into JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=125324 -2012-04-27 Geoffrey Garen + Reviewed by Timothy Hatcher. - Made WeakSet::allocate() static and removed its JSGlobalData argument - https://bugs.webkit.org/show_bug.cgi?id=85128 + * CMakeLists.txt: + * GNUmakefile.am: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.vcxproj/JavaScriptCoreCommon.props: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bindings/ScriptFunctionCall.cpp: Renamed from Source/WebCore/bindings/js/ScriptFunctionCall.cpp. + * bindings/ScriptFunctionCall.h: Renamed from Source/WebCore/bindings/js/ScriptFunctionCall.h. + * bindings/ScriptObject.cpp: Copied from Source/WebCore/inspector/WorkerConsoleAgent.cpp. + * bindings/ScriptObject.h: Renamed from Source/WebCore/inspector/InspectorBaseAgent.h. + * bindings/ScriptValue.cpp: Renamed from Source/WebCore/bindings/js/ScriptValue.cpp. + * bindings/ScriptValue.h: Renamed from Source/WebCore/bindings/js/ScriptValue.h. + * inspector/InspectorAgentBase.h: Copied from Source/WebCore/inspector/InspectorAgentRegistry.h. + * inspector/InspectorAgentRegistry.cpp: Renamed from Source/WebCore/inspector/InspectorAgentRegistry.cpp. + * inspector/InspectorBackendDispatcher.h: Renamed from Source/WebCore/inspector/InspectorBackendDispatcher.h. + (Inspector::InspectorSupplementalBackendDispatcher::InspectorSupplementalBackendDispatcher): + (Inspector::InspectorSupplementalBackendDispatcher::~InspectorSupplementalBackendDispatcher): + * inspector/InspectorValues.cpp: Renamed from Source/WebCore/inspector/InspectorValues.cpp. + * inspector/InspectorValues.h: Renamed from Source/WebCore/inspector/InspectorValues.h. - Reviewed by Anders Carlsson. +2013-12-11 Laszlo Vidacs - This is a step toward faster finalization. + Store SHA1 hash in std::array + https://bugs.webkit.org/show_bug.cgi?id=125446 - WeakSet::allocate() now deduces which WeakSet to allocate from based on - its JSCell* argument. (Currently, there's only one WeakSet, but soon - there will be many.) + Reviewed by Darin Adler. - This was a global replace of "globalData.heap.weakSet()->allocate" with - "WeakSet::allocate", plus by-hand removal of the JSGlobalData argument. + Change Vector to std::array and use typedef. - * heap/WeakSetInlines.h: Copied from Source/JavaScriptCore/heap/WeakSet.h. + * bytecode/CodeBlockHash.cpp: + (JSC::CodeBlockHash::CodeBlockHash): - I had to split out WeakSet::allocate() in to a separate header to avoid - a cycle. +2013-12-11 Mark Rowe - (JSC::WeakSet::allocate): We can mask the pointer we're passed to - figure out where to allocate our WeakImpl. (Soon, we'll use this to - associate the WeakImpl with the GC block it references.) + Modernize the JavaScriptCore API headers + -2012-04-27 Geoffrey Garen + This consists of three main changes: + 1) Converting the return type of initializer methods to instancetype. + 2) Declaring properties rather than getters and setters. + 3) Tagging C API methods with information about their memory management semantics. - Stop using aligned allocation for WeakBlock - https://bugs.webkit.org/show_bug.cgi?id=85124 + Changing the declarations from getters and setters to properties also required + updating the headerdoc in a number of places. Reviewed by Anders Carlsson. - We don't actually use the alignment for anything. - - * heap/WeakBlock.cpp: - (JSC::WeakBlock::create): - (JSC::WeakBlock::WeakBlock): Switched from aligned allocation to regular - allocation. - - * heap/WeakBlock.h: - (WeakBlock): Don't use HeapBlock because HeapBlock requires aligned - allocation. This change required me to add some declarations that we used - to inherit from HeapBlock. - - (WeakBlock::blockFor): Removed. This function relied on aligned allocation - but didn't do anything for us. - - (WeakBlock::deallocate): Removed. WeakBlock doesn't own any of the deallocation - logic, so it shouldn't own the function. - - * heap/WeakSet.cpp: - (JSC::WeakSet::~WeakSet): - (JSC::WeakSet::finalizeAll): - (JSC::WeakSet::visitLiveWeakImpls): - (JSC::WeakSet::visitDeadWeakImpls): - (JSC::WeakSet::sweep): - (JSC::WeakSet::shrink): - (JSC::WeakSet::resetAllocator): - (JSC::WeakSet::tryFindAllocator): - * heap/WeakSet.h: - (WeakSet): Updated declarations to reflect WeakBlock not inheriting from - HeapBlock. This allowed me to remove some casts, which was nice. + * API/JSContext.h: + * API/JSContext.mm: + * API/JSManagedValue.h: + * API/JSManagedValue.mm: + * API/JSStringRefCF.h: + * API/JSValue.h: + * API/JSVirtualMachine.h: + * API/JSVirtualMachine.mm: - (JSC::WeakSet::deallocate): Directly set the deallocated flag instead of - asking WeakBlock to do it for us. We don't need to have a WeakBlock - pointer to set the flag, so stop asking for one. +2013-12-11 Mark Rowe -2012-04-27 Kentaro Hara + Move JavaScriptCore off the legacy WebKit availability macros - [JSC] Implement a helper method createNotEnoughArgumentsError() - https://bugs.webkit.org/show_bug.cgi?id=85102 + The legacy WebKit availability macros are verbose, confusing, and provide no benefit over + using the system availability macros directly. The original vision was that they'd serve + a cross-platform purpose but that never came to be. - Reviewed by Geoffrey Garen. - - In bug 84787, kbr@ requested to avoid hard-coding - createTypeError(exec, "Not enough arguments") here and there. - This patch implements createNotEnoughArgumentsError(exec) - and uses it in JSC bindings. - - c.f. a corresponding bug for V8 bindings is bug 85097. - - * runtime/Error.cpp: - (JSC::createNotEnoughArgumentsError): - (JSC): - * runtime/Error.h: - (JSC): + Map from WebKit version to OS X version based on the mapping in WebKitAvailability.h. + All iOS versions are specified as 7.0 as that is when the JavaScriptCore C API was made + public. -2012-04-27 Geoffrey Garen + Part of . - Only allow non-null pointers in the WeakSet - https://bugs.webkit.org/show_bug.cgi?id=85119 + Reviewed by Anders Carlsson. - Reviewed by Darin Adler. + * API/JSBasePrivate.h: + * API/JSContextRef.h: + * API/JSContextRefPrivate.h: + * API/JSObjectRef.h: + * API/JSValueRef.h: - This is a step toward more efficient finalization. +2013-12-10 Filip Pizlo - No clients put non-pointers (JSValues) into Weak and PassWeak. + Get rid of forward exit on DoubleAsInt32 + https://bugs.webkit.org/show_bug.cgi?id=125552 - Some clients put null pointers into Weak and PassWeak, but this is - more efficient and straight-forward to model with a null in the Weak - or PassWeak instead of allocating a WeakImpl just to hold null. + Reviewed by Oliver Hunt. + + The forward exit was just there so that we wouldn't have to keep the inputs alive up to + the DoubleAsInt32. That's dumb. Forward exits are a complicated piece of machinery and + we shouldn't have it just for a bit of liveness micro-optimization. + + Also add a bunch of machinery to test this case on X86. - * heap/PassWeak.h: - (JSC): Removed the Unknown (JSValue) type of weak pointer because it's - unused now. + * assembler/AbstractMacroAssembler.h: + (JSC::optimizeForARMv7s): + (JSC::optimizeForARM64): + (JSC::optimizeForX86): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNodeType.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileDoubleAsInt32): + * runtime/Options.h: + * tests/stress/double-as-int32.js: Added. + (foo): + (test): - (PassWeak): Don't provide a default initializer for our JSCell* argument. - This feature was only used in one place, and it was a bug. +2013-12-10 Filip Pizlo - (JSC::::get): Don't check for a null stored inside our WeakImpl: that's - not allowed anymore. + Simplify CSE's treatment of NodeRelevantToOSR + https://bugs.webkit.org/show_bug.cgi?id=125538 - (JSC::PassWeak::PassWeak): Handle null as a null WeakImpl instead of - allocating a WeakImpl and storing null into it. + Reviewed by Oliver Hunt. + + Make the NodeRelevantToOSR thing obvious: if there is any MovHint on a node then the + node is relevant to OSR. - * heap/Weak.h: - (Weak): - (JSC::::Weak): Same changes as in PassWeak. + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::run): + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::performBlockCSE): - * heap/WeakBlock.cpp: - (JSC::WeakBlock::visitLiveWeakImpls): - (JSC::WeakBlock::visitDeadWeakImpls): Only non-null cells are valid in - the WeakSet now, so no need to check for non-cells and null cell pointers. +2013-12-10 Filip Pizlo - * heap/WeakImpl.h: - (JSC::WeakImpl::WeakImpl): Only non-null cells are valid in the WeakSet - now, so ASSERT that. + Get rid of forward exit in GetByVal on Uint32Array + https://bugs.webkit.org/show_bug.cgi?id=125543 -2012-04-27 Gavin Barraclough + Reviewed by Oliver Hunt. - Math in JavaScript is inaccurate on iOS + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): - By defalut IEEE754 denormal support is disabled on iOS; - turn it on. +2013-12-10 Balazs Kilvady - Reviewed by Filip Pizlo. + [MIPS] Redundant instructions in code generated from offlineasm. + https://bugs.webkit.org/show_bug.cgi?id=125528 - * jsc.cpp: - (main): - - clear the appropriate bit in the fpscr. + Reviewed by Michael Saboff. -2012-04-27 Michael Saboff + Optimize lowering of offlineasm BaseIndex Addresses. - Memory wasted in JSString for non-rope strings - https://bugs.webkit.org/show_bug.cgi?id=84907 + * offlineasm/mips.rb: - Reviewed by Geoffrey Garen. +2013-12-10 Oliver Hunt - Split JSString into two classes, JSString as a base class that does not - include the fibers of a Rope, and a subclass JSRopeString that has the - rope functionality. Both classes "share" the same ClassInfo. Added - a bool to JSString to indicate that the string was allocated as a JSRopeString - to properly handle visiting the fiber children when the rope is resolved and - the JSRopeString appears as a JSString. Didn't change the interface of JSString - to require any JIT changes. - - As part of this change, removed "cellSize" from ClassInfo since both classes - share the same ClassInfo, but have different sizes. The only use I could find - for cellSize was an ASSERT in allocateCell(). - - This appears to be neutral on performance tests. - - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Changed JSString::resolveRope - to JSRopeString::resolveRope - * runtime/ClassInfo.h: - (JSC): - (ClassInfo): - * runtime/JSCell.h: - (JSC::allocateCell): - * runtime/JSString.cpp: - (JSC::JSRopeString::RopeBuilder::expand): - (JSC::JSString::visitChildren): - (JSC): - (JSC::JSRopeString::visitFibers): - (JSC::JSRopeString::resolveRope): - (JSC::JSRopeString::resolveRopeSlowCase8): - (JSC::JSRopeString::resolveRopeSlowCase): - (JSC::JSRopeString::outOfMemory): - (JSC::JSRopeString::getIndexSlowCase): - * runtime/JSString.h: - (JSC): - (JSString): - (JSC::JSString::finishCreation): - (JSC::JSString::create): - (JSC::JSString::isRope): - (JSC::JSString::is8Bit): - (JSRopeString): - (RopeBuilder): - (JSC::JSRopeString::RopeBuilder::RopeBuilder): - (JSC::JSRopeString::RopeBuilder::append): - (JSC::JSRopeString::RopeBuilder::release): - (JSC::JSRopeString::RopeBuilder::length): - (JSC::JSRopeString::JSRopeString): - (JSC::JSRopeString::finishCreation): - (JSC::JSRopeString::createNull): - (JSC::JSRopeString::create): - (JSC::JSString::value): - (JSC::JSString::tryGetValue): - (JSC::JSString::getIndex): - (JSC::jsStringBuilder): - * runtime/Operations.h: - (JSC::jsString): - (JSC::jsStringFromArguments): + Reduce the mass templatizing of the JS parser + https://bugs.webkit.org/show_bug.cgi?id=125535 -2012-04-27 Oliver Hunt + Reviewed by Michael Saboff. - Correct assertion. + The various caches we have now have removed the need for many of + the template vs. regular parameters. This patch converts those + template parameters to regular parameters and updates the call + sites. This reduces the code size of the parser by around 15%. - * interpreter/Interpreter.cpp: - (JSC::Interpreter::throwException): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createProperty): + * parser/Parser.cpp: + (JSC::::parseInner): + (JSC::::parseSourceElements): + (JSC::::parseVarDeclarationList): + (JSC::::createBindingPattern): + (JSC::::tryParseDeconstructionPatternExpression): + (JSC::::parseDeconstructionPattern): + (JSC::::parseSwitchClauses): + (JSC::::parseSwitchDefaultClause): + (JSC::::parseBlockStatement): + (JSC::::parseFormalParameters): + (JSC::::parseFunctionInfo): + (JSC::::parseFunctionDeclaration): + (JSC::::parseProperty): + (JSC::::parseObjectLiteral): + (JSC::::parseStrictObjectLiteral): + (JSC::::parseMemberExpression): + * parser/Parser.h: + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createProperty): + (JSC::SyntaxChecker::createGetterOrSetterProperty): -2012-04-27 Oliver Hunt +2013-12-10 Mark Hahnenberg - Lazy link phase of baseline jit fails to propagate exception - https://bugs.webkit.org/show_bug.cgi?id=85092 + ASSERT !heap.vm()->isInitializingObject() when finishing DFG compilation at beginning of GC + https://bugs.webkit.org/show_bug.cgi?id=125472 - Reviewed by Filip Pizlo. + Reviewed by Geoff Garen. - Very simple patch, when linking produces an error we need to actually store - the exception prior to throwing it. I can't find any other examples of this, - but as we're already in the slow path when throwing an exception I've hardened - exception throwing against null exceptions. + This patch makes it look like it's okay to allocate so that the DFG plan finalization stuff + can do what it needs to do. We already expected that we might do allocation during plan + finalization and we increased the deferral depth to handle this, but we need to fix this other + ASSERT stuff too. - * interpreter/Interpreter.cpp: - (JSC::Interpreter::throwException): - * jit/JITStubs.cpp: - (JSC::lazyLinkFor): + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/Heap.cpp: + (JSC::Heap::collect): + * heap/Heap.h: + * heap/RecursiveAllocationScope.h: Added. + (JSC::RecursiveAllocationScope::RecursiveAllocationScope): + (JSC::RecursiveAllocationScope::~RecursiveAllocationScope): + * runtime/VM.h: -2012-04-27 Benjamin Poulain +2013-12-09 Filip Pizlo - Generalize the single character optimization of numberProtoFuncToString - https://bugs.webkit.org/show_bug.cgi?id=85027 + Impose and enforce some basic rules of sanity for where Phi functions are allowed to occur and where their (optional) corresponding MovHints can be + https://bugs.webkit.org/show_bug.cgi?id=125480 Reviewed by Geoffrey Garen. + + Previously, if you wanted to insert some speculation right after where a value was + produced, you'd get super confused if that value was produced by a Phi node. You can't + necessarily insert speculations after a Phi node because Phi nodes appear in this + special sequence of Phis and MovHints that establish the OSR exit state for a block. + So, you'd probably want to search for the next place where it's safe to insert things. + We already do this "search for beginning of next bytecode instruction" search by + looking at the next node that has a different CodeOrigin. But this would be hard for a + Phi because those Phis and MovHints have basically random CodeOrigins and they can all + have different CodeOrigins. - The function numberProtoFuncToString() has an optimization to use SmallStrings::singleCharacterString() - when the radix is 36. - - This patch generalize the optimization for any radix. Any positive number smaller than its radix - can be represented by a single character of radixDigits. - - This makes numberProtoFuncToString() about twice as fast for this case of single digit conversion. - - * runtime/NumberPrototype.cpp: - (JSC::numberProtoFuncToString): - -2012-04-27 Gavin Peters - - Add new ENABLE_LINK_PRERENDER define to control the Prerendering API - https://bugs.webkit.org/show_bug.cgi?id=84871 - - Reviewed by Adam Barth. - - Prerendering is currently covered by the ENABLE_LINK_PREFETCH macro, but the new Prerendering - API separates it from prefetching. Having separate include guards lets ports enable prefetching, - a relatively easy change, without needing to build the infrastructure for prerendering, which - is considerably more complicated. - - * Configurations/FeatureDefines.xcconfig: - -2012-04-26 Oliver Hunt - - Allocating WeakImpl should not trigger GC, as that makes the world very tricksy. - https://bugs.webkit.org/show_bug.cgi?id=85020 - - Reviewed by Gavin Barraclough. - - Now in the event that we are unable to find an allocator for a new handle, just - add a new allocator rather than trying to recover "dead" handles through a GC. + This change imposes some sanity for this situation: - Find allocator is now much simpler, and addAllocator directly reports the - increased memory usage to the heap without causing any GC to happen immediately. + - Phis must have unset CodeOrigins. - * heap/WeakSet.cpp: - (JSC::WeakSet::findAllocator): - (JSC::WeakSet::addAllocator): + - In each basic block, all nodes that have unset CodeOrigins must come before all nodes + that have set CodeOrigins. -2012-04-26 Oliver Hunt + This all ends up working out just great because prior to this change we didn't have a + use for unset CodeOrigins. I think it's appropriate to make "unset CodeOrigin" mean + that we're in the prologue of a basic block. - Remove RegisterFile::end()/m_end - https://bugs.webkit.org/show_bug.cgi?id=85011 + It's interesting what this means for block merging, which we don't yet do in SSA. + Consider merging the edge A->B. One possibility is that the block merger is now + required to clean up Phi/Upsilons, and reascribe the MovHints to have the CodeOrigin of + the A's block terminal. But an answer that might be better is that the originless + nodes at the top of the B are just given the origin of the terminal and we keep the + Phis. That would require changing the above rules. We'll see how it goes, and what we + end up picking... - Reviewed by Gavin Barraclough. + Overall, this special-things-at-the-top rule is analogous to what other SSA-based + compilers do. For example, LLVM has rules mandating that Phis appear at the top of a + block. - Get rid of end() and m_end from RegisterFile. From now on - we only care about the end of the committed region when calling - code. When re-entering the VM we now plant the new CallFrame - immediately after whatever the current topCallFrame is. This - required adding a routine to CallFrame to determine exactly what - we should be doing (in the absence of an existing CallFrame, we - can't reason about the frameExtent() so we check for that). + * bytecode/CodeOrigin.cpp: + (JSC::CodeOrigin::dump): + * dfg/DFGOSRExitBase.h: + (JSC::DFG::OSRExitBase::OSRExitBase): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + (JSC::DFG::Validate::validateSSA): - This also now means that the GC only marks the portion of the - RegisterFile that is actually in use, and that VM re-entry doesn't - exhaust the RegisterFile as rapidly. +2013-12-08 Filip Pizlo - * dfg/DFGOperations.cpp: - * heap/Heap.cpp: - (JSC::Heap::getConservativeRegisterRoots): - (JSC::Heap::markRoots): - * interpreter/CallFrame.h: - (JSC::ExecState::init): - (JSC::ExecState::startOfReusableRegisterFile): - (ExecState): - * interpreter/Interpreter.cpp: - (JSC::Interpreter::execute): - (JSC::Interpreter::executeCall): - (JSC::Interpreter::executeConstruct): - (JSC::Interpreter::prepareForRepeatCall): - (JSC::Interpreter::privateExecute): - * interpreter/Interpreter.h: - (JSC::Interpreter::execute): - * interpreter/RegisterFile.cpp: - (JSC::RegisterFile::growSlowCase): - (JSC::RegisterFile::gatherConservativeRoots): - * interpreter/RegisterFile.h: - (JSC::RegisterFile::commitEnd): - (JSC::RegisterFile::addressOfEnd): - (RegisterFile): - (JSC::RegisterFile::RegisterFile): - (JSC::RegisterFile::shrink): - (JSC::RegisterFile::grow): - * jit/JITStubs.cpp: - (JSC::DEFINE_STUB_FUNCTION): - (JSC::jitCompileFor): - (JSC::lazyLinkFor): - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - (JSC::LLInt::handleHostCall): - * llint/LowLevelInterpreter.asm: - * runtime/CommonSlowPaths.h: - (JSC::CommonSlowPaths::arityCheckFor): + Reveal array bounds checks in DFG IR + https://bugs.webkit.org/show_bug.cgi?id=125253 -2012-04-26 Filip Pizlo + Reviewed by Oliver Hunt and Mark Hahnenberg. + + In SSA mode, this reveals array bounds checks and the load of array length in DFG IR, + making this a candidate for LICM. - DFG ARMv7 backend should optimize Float32 arrays - https://bugs.webkit.org/show_bug.cgi?id=85000 - + This also fixes a long-standing performance bug where the JSObject slow paths would + always create contiguous storage, rather than type-specialized storage, when doing a + "storage creating" storage, like: + + var o = {}; + o[0] = 42; - Reviewed by Gavin Barraclough. + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/ExitKind.cpp: + (JSC::exitKindToString): + (JSC::exitKindIsCountable): + * bytecode/ExitKind.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): + * dfg/DFGArrayMode.cpp: + (JSC::DFG::permitsBoundsCheckLowering): + (JSC::DFG::ArrayMode::permitsBoundsCheckLowering): + * dfg/DFGArrayMode.h: + (JSC::DFG::ArrayMode::lengthNeedsStorage): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNodeType.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSSALoweringPhase.cpp: Added. + (JSC::DFG::SSALoweringPhase::SSALoweringPhase): + (JSC::DFG::SSALoweringPhase::run): + (JSC::DFG::SSALoweringPhase::handleNode): + (JSC::DFG::SSALoweringPhase::lowerBoundsCheck): + (JSC::DFG::performSSALowering): + * dfg/DFGSSALoweringPhase.h: Added. + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileDoublePutByVal): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileContiguousPutByVal): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCheckInBounds): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::contiguousPutByValOutOfBounds): + * runtime/JSObject.cpp: + (JSC::JSObject::convertUndecidedForValue): + (JSC::JSObject::createInitialForValueAndSet): + (JSC::JSObject::putByIndexBeyondVectorLength): + (JSC::JSObject::putDirectIndexBeyondVectorLength): + * runtime/JSObject.h: + * tests/stress/float32array-out-of-bounds.js: Added. + (make): + (foo): + (test): + * tests/stress/int32-object-out-of-bounds.js: Added. + (make): + (foo): + (test): + * tests/stress/int32-out-of-bounds.js: Added. + (foo): + (test): - * assembler/ARMv7Assembler.h: - (ARMv7Assembler): - (JSC::ARMv7Assembler::flds): - (JSC::ARMv7Assembler::fsts): - (JSC::ARMv7Assembler::vcvtds): - (JSC::ARMv7Assembler::vcvtsd): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::loadFloat): - (MacroAssemblerARMv7): - (JSC::MacroAssemblerARMv7::storeFloat): - (JSC::MacroAssemblerARMv7::convertFloatToDouble): - (JSC::MacroAssemblerARMv7::convertDoubleToFloat): - * bytecode/PredictedType.h: - (JSC::isActionableFloatMutableArrayPrediction): - * dfg/DFGNode.h: - (JSC::DFG::Node::shouldSpeculateFloat32Array): +2013-12-09 Sam Weinig -2012-04-25 Benjamin Poulain + Replace use of WTF::FixedArray with std::array + https://bugs.webkit.org/show_bug.cgi?id=125475 - Add a version of StringImpl::find() without offset - https://bugs.webkit.org/show_bug.cgi?id=83968 + Reviewed by Anders Carlsson. - Reviewed by Sam Weinig. + * bytecode/CodeBlockHash.cpp: + (JSC::CodeBlockHash::dump): + * bytecode/Opcode.cpp: + (JSC::OpcodeStats::~OpcodeStats): + * dfg/DFGCSEPhase.cpp: + * ftl/FTLAbstractHeap.h: + * heap/MarkedSpace.h: + * parser/ParserArena.h: + * runtime/CodeCache.h: + * runtime/DateInstanceCache.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSGlobalObject.h: + * runtime/JSString.h: + * runtime/LiteralParser.h: + * runtime/NumericStrings.h: + * runtime/RegExpCache.h: + * runtime/SmallStrings.h: - Add support for the new StringImpl::find() to UString. +2013-12-09 Joseph Pecoraro - Change stringProtoFuncIndexOf() to specifically take advatage of the feature. - This gives a 12% gains on a distribution of strings between 30 and 100 characters. + Remove miscellaneous unnecessary build statements + https://bugs.webkit.org/show_bug.cgi?id=125466 - * runtime/StringPrototype.cpp: - (JSC::substituteBackreferences): - (JSC::stringProtoFuncIndexOf): - * runtime/UString.h: - (UString): - (JSC::UString::find): + Reviewed by Darin Adler. -2012-04-25 Mark Hahnenberg + * DerivedSources.make: + * JavaScriptCore.vcxproj/build-generated-files.sh: + * JavaScriptCore.xcodeproj/project.pbxproj: + * make-generated-sources.sh: - WebCore shouldn't call collectAllGarbage directly - https://bugs.webkit.org/show_bug.cgi?id=84897 +2013-12-08 Filip Pizlo - Reviewed by Geoffrey Garen. + CSE should work in SSA + https://bugs.webkit.org/show_bug.cgi?id=125430 - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Exported symbol - for reportAbanondedObjectGraph so WebCore can use it. - * heap/Heap.h: Ditto. + Reviewed by Oliver Hunt and Mark Hahnenberg. -2012-04-25 Oliver Hunt + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::run): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): - Biolab disaster crashes on ToT - https://bugs.webkit.org/show_bug.cgi?id=84898 +2013-12-09 Joseph Pecoraro - Reviewed by Filip Pizlo. + Remove docs/make-bytecode-docs.pl + https://bugs.webkit.org/show_bug.cgi?id=125462 - Whoops, committed without saving reviewer requested change. + This sript is very old and no longer outputs useful data since the + op code definitions have moved from Interpreter.cpp. - * dfg/DFGVirtualRegisterAllocationPhase.cpp: - (JSC::DFG::VirtualRegisterAllocationPhase::run): + Reviewed by Darin Adler. -2012-04-25 Oliver Hunt + * DerivedSources.make: + * docs/make-bytecode-docs.pl: Removed. - Biolab disaster crashes on ToT - https://bugs.webkit.org/show_bug.cgi?id=84898 +2013-12-09 Julien Brianceau - Reviewed by Filip Pizlo. + Fix sh4 LLINT build. + https://bugs.webkit.org/show_bug.cgi?id=125454 - I recently added an assertion to the Interpreter to catch incorrect - updates of topCallFrame. This caused a bunch of sites (including biolab - disaster) to crash as we were not correctly handling callee registers - of inlined functions, leading to a mismatch. + Reviewed by Michael Saboff. - I could not actually make this trigger directly, although it does trigger - already on some of the GTK and QT bots. + In LLINT, sh4 backend implementation didn't handle properly conditional jumps using + a LabelReference instance. This patch fixes it through sh4LowerMisplacedLabels phase. + Also, to avoid the need of a 4th temporary gpr, this phase is triggered later in + getModifiedListSH4. - * dfg/DFGVirtualRegisterAllocationPhase.cpp: - (JSC::DFG::VirtualRegisterAllocationPhase::run): + * offlineasm/sh4.rb: -2012-04-25 Kenneth Russell +2013-12-08 Filip Pizlo - Delete CanvasPixelArray, ByteArray, JSByteArray and JSC code once unreferenced - https://bugs.webkit.org/show_bug.cgi?id=83655 + Add the notion of ConstantStoragePointer to DFG IR + https://bugs.webkit.org/show_bug.cgi?id=125395 Reviewed by Oliver Hunt. + + This pushes more typed array folding into StrengthReductionPhase, and enables CSE on + storage pointers. Previously, you might have separate nodes for the same storage + pointer and this would cause some bad register pressure in the DFG. Note that this + was really a theoretical problem and not, to my knowledge a practical one - so this + patch is basically just a clean-up. - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.gypi: - * JavaScriptCore.order: - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * Target.pri: - * bytecode/PredictedType.cpp: - (JSC::predictionToString): - (JSC::predictionToAbbreviatedString): - (JSC::predictionFromClassInfo): - * bytecode/PredictedType.h: - (JSC): - (JSC::isActionableIntMutableArrayPrediction): - * dfg/DFGAbstractState.cpp: - (JSC::DFG::AbstractState::initialize): - (JSC::DFG::AbstractState::execute): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::constantStoragePointerCSE): (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): * dfg/DFGNode.h: + (JSC::DFG::Node::convertToConstantStoragePointer): + (JSC::DFG::Node::hasStoragePointer): + (JSC::DFG::Node::storagePointer): * dfg/DFGNodeType.h: - (DFG): - * dfg/DFGOperations.cpp: - (JSC::DFG::putByVal): * dfg/DFGPredictionPropagationPhase.cpp: (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::checkArgumentTypes): + (JSC::DFG::SpeculativeJIT::compileConstantStoragePointer): (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::ValueSource::forPrediction): - (SpeculativeJIT): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): - * interpreter/Interpreter.cpp: - (JSC::Interpreter::privateExecute): - * jit/JITStubs.cpp: - (JSC::DEFINE_STUB_FUNCTION): - * jit/JITStubs.h: - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::getByVal): - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * runtime/JSByteArray.cpp: Removed. - * runtime/JSByteArray.h: Removed. - * runtime/JSGlobalData.cpp: + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + (JSC::DFG::StrengthReductionPhase::foldTypedArrayPropertyToConstant): + (JSC::DFG::StrengthReductionPhase::prepareToFoldTypedArray): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileConstantStoragePointer): + (JSC::FTL::LowerDFGToLLVM::compileGetIndexedPropertyStorage): -2012-04-25 Filip Pizlo +2013-12-08 Filip Pizlo - http://bellard.org/jslinux/ triggers an assertion failure in the DFG JIT - https://bugs.webkit.org/show_bug.cgi?id=84815 - + FTL should support UntypedUse versions of Compare nodes + https://bugs.webkit.org/show_bug.cgi?id=125426 - Reviewed by Gavin Barraclough. + Reviewed by Oliver Hunt. + + This adds UntypedUse versions of all comparisons except CompareStrictEq, which is + sufficiently different that I thought I'd do it in another patch. + + This also extends our ability to abstract over comparison kind and removes a bunch of + copy-paste code. - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompare): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareLess): + (JSC::FTL::LowerDFGToLLVM::compileCompareLessEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareGreater): + (JSC::FTL::LowerDFGToLLVM::compileCompareGreaterEq): + (JSC::FTL::LowerDFGToLLVM::compare): + (JSC::FTL::LowerDFGToLLVM::nonSpeculativeCompare): + * ftl/FTLOutput.h: + (JSC::FTL::Output::icmp): + (JSC::FTL::Output::equal): + (JSC::FTL::Output::notEqual): + (JSC::FTL::Output::above): + (JSC::FTL::Output::aboveOrEqual): + (JSC::FTL::Output::below): + (JSC::FTL::Output::belowOrEqual): + (JSC::FTL::Output::greaterThan): + (JSC::FTL::Output::greaterThanOrEqual): + (JSC::FTL::Output::lessThan): + (JSC::FTL::Output::lessThanOrEqual): + (JSC::FTL::Output::fcmp): + (JSC::FTL::Output::doubleEqual): + (JSC::FTL::Output::doubleNotEqualOrUnordered): + (JSC::FTL::Output::doubleLessThan): + (JSC::FTL::Output::doubleLessThanOrEqual): + (JSC::FTL::Output::doubleGreaterThan): + (JSC::FTL::Output::doubleGreaterThanOrEqual): + (JSC::FTL::Output::doubleEqualOrUnordered): + (JSC::FTL::Output::doubleNotEqual): + (JSC::FTL::Output::doubleLessThanOrUnordered): + (JSC::FTL::Output::doubleLessThanOrEqualOrUnordered): + (JSC::FTL::Output::doubleGreaterThanOrUnordered): + (JSC::FTL::Output::doubleGreaterThanOrEqualOrUnordered): + * tests/stress/untyped-equality.js: Added. + (foo): + * tests/stress/untyped-less-than.js: Added. + (foo): + +2013-12-07 Filip Pizlo + + Fold typedArray.length if typedArray is constant + https://bugs.webkit.org/show_bug.cgi?id=125252 + + Reviewed by Sam Weinig. + + This was meant to be easy. The problem is that there was no good place for putting + the folding of typedArray.length to a constant. You can't quite do it in the + bytecode parser because at that point you don't yet know if typedArray is really + a typed array. You can't do it as part of constant folding because the folder + assumes that it can opportunistically forward-flow a constant value without changing + the IR; this doesn't work since we need to first change the IR to register a + desired watchpoint and only after that can we introduce that constant. We could have + done it in Fixup but that would have been awkward since Fixup's code for turning a + GetById of "length" into GetArrayLength is already somewhat complex. We could have + done it in CSE but CSE is already fairly gnarly and will probably get rewritten. + + So I introduced a new phase, called StrengthReduction. This phase should have any + transformations that don't requite CFA or CSE and that it would be weird to put into + those other phases. + + I also took the opportunity to refactor some of the other folding code. + + This also adds a test, but the test couldn't quite be a LayoutTests/js/regress so I + introduced the notion of JavaScriptCore/tests/stress. + + The goal of this patch isn't really to improve performance or anything like that. + It adds an optimization for completeness, and in doing so it unlocks a bunch of new + possibilities. The one that I'm most excited about is revealing array length checks + in DFG IR, which will allow for array bounds check hoisting and elimination. -2012-04-25 Michael Saboff + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetFoldableView): + (JSC::DFG::Graph::tryGetFoldableViewForChild1): + * dfg/DFGGraph.h: + * dfg/DFGNode.h: + (JSC::DFG::Node::hasTypedArray): + (JSC::DFG::Node::typedArray): + * dfg/DFGNodeType.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds): + (JSC::DFG::SpeculativeJIT::compileConstantIndexedPropertyStorage): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStrengthReductionPhase.cpp: Added. + (JSC::DFG::StrengthReductionPhase::StrengthReductionPhase): + (JSC::DFG::StrengthReductionPhase::run): + (JSC::DFG::StrengthReductionPhase::handleNode): + (JSC::DFG::StrengthReductionPhase::foldTypedArrayPropertyToConstant): + (JSC::DFG::performStrengthReduction): + * dfg/DFGStrengthReductionPhase.h: Added. + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetIndexedPropertyStorage): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::typedArrayLength): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionTransferArrayBuffer): + * runtime/ArrayBufferView.h: + * tests/stress: Added. + * tests/stress/fold-typed-array-properties.js: Added. + (foo): - Closure in try {} with catch captures all locals from the enclosing function - https://bugs.webkit.org/show_bug.cgi?id=84804 +2013-12-07 peavo@outlook.com - Reviewed by Oliver Hunt. + [Win][64-bit] Hitting breakpoint assembler instruction in callToJavaScript. + https://bugs.webkit.org/show_bug.cgi?id=125382 - Changed the capturing of local variables from capturing when eval is used, - within a "with" or within a "catch" to be just when an eval is used. - Renamed the function returning that we should capture from - getCapturedVariables() to usesEval(), since that what it noew returns. - Needed to fix the "with" code to only range check when the activation - has actually been torn off. Added m_isTornOff to JSActivation to - track this. + Reviewed by Michael Saboff. - * parser/Parser.h: - (JSC::Scope::usesEval): - (JSC::Scope::getCapturedVariables): - * runtime/JSActivation.cpp: - (JSC::JSActivation::JSActivation): - (JSC::JSActivation::symbolTableGet): - (JSC::JSActivation::symbolTablePut): - * runtime/JSActivation.h: - (JSActivation): - (JSC::JSActivation::tearOff): + The WinCairo results from run-javascriptcore-tests are the same as the WinCairo 32-bits results, when removing these breakpoints. -2012-04-24 Mark Hahnenberg + * jit/JITStubsMSVC64.asm: Remove breakpoint instructions. - GC Activity Callback timer should be based on how much has been allocated since the last collection - https://bugs.webkit.org/show_bug.cgi?id=84763 +2013-12-06 Filip Pizlo - Reviewed by Geoffrey Garen. + FTL should support all of Branch/LogicalNot + https://bugs.webkit.org/show_bug.cgi?id=125370 - The desired behavior for the GC timer is to collect at some point in the future, - regardless of how little we've allocated. A secondary goal, which is almost if not - as important, is for the timer to collect sooner if there is the potential to - collect a greater amount of memory. Conversely, as we allocate more memory we'd - like to reduce the delay to the next collection. If we're allocating quickly enough, - the timer should be preempted in favor of a normal allocation-triggered collection. - If allocation were to slow or stop, we'd like the timer to be able to opportunistically - run a collection without us having to allocate to the hard limit set by the Heap. - - This type of policy can be described in terms of the amount of CPU we are willing - to dedicate to reclaim a single MB of memory. For example, we might be willing to - dedicate 1% of our CPU to reclaim 1 MB. We base our CPU usage off of the length of - the last collection, e.g. if our last collection took 1ms, we would want to wait about - 100ms before running another collection to reclaim 1 MB. These constants should be - tune-able, e.g. 0.1% CPU = 1 MB vs. 1% CPU = 1 MB vs. 10% CPU = 1 MB. - - * API/JSBase.cpp: Use the new reportAbandonedObjectGraph. - (JSGarbageCollect): - * API/JSContextRef.cpp: Ditto. - * heap/Heap.cpp: - (JSC::Heap::Heap): - (JSC::Heap::reportAbandonedObjectGraph): Similar to reportExtraMemoryCost. Clients call - this function to notify the Heap that some unknown number of JSC objects might have just - been abandoned and are now garbage. The Heap might schedule a new collection timer based - on this notification. - (JSC): - (JSC::Heap::collect): Renamed m_lastFullGCSize to the less confusing m_sizeAfterLastCollect. - * heap/Heap.h: - (Heap): - * heap/MarkedAllocator.h: - (JSC::MarkedAllocator::zapFreeList): Fixed a bug in zapFreeList that failed to nullify the - current allocator's FreeList once zapping was complete. - * runtime/GCActivityCallback.cpp: Removed didAbandonObjectGraph because it was replaced by - Heap::reportAbandonedObjectGraph. - (JSC): - * runtime/GCActivityCallback.h: - (JSC::GCActivityCallback::willCollect): - (DefaultGCActivityCallback): - * runtime/GCActivityCallbackCF.cpp: Refactored the GC timer code so that we now schedule the - timer based on how much we have allocated since the last collection up to a certain amount. - We use the length of the previous GC to try to keep our total cost of opportunistic timer-triggered - collections around 1% of the CPU per MB of garbage we expect to reclaim up to a maximum of 5 MB. - (DefaultGCActivityCallbackPlatformData): - (JSC): - (JSC::DefaultGCActivityCallback::~DefaultGCActivityCallback): - (JSC::DefaultGCActivityCallback::commonConstructor): - (JSC::scheduleTimer): - (JSC::cancelTimer): - (JSC::DefaultGCActivityCallback::didAllocate): - -2012-04-24 Michael Saboff - - objectProtoFuncToString creates new string every invocation - https://bugs.webkit.org/show_bug.cgi?id=84781 + Reviewed by Mark Hahnenberg. - Reviewed by Geoffrey Garen. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::boolify): - Cache the results of object toString() in the attached Structure. +2013-12-06 Roger Fong and Brent Fulgham - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncToString): - * runtime/Structure.cpp: - (JSC::Structure::visitChildren): visit new m_hasObjectToStringValue. - * runtime/Structure.h: Added new member m_hasObjectToStringValue - (JSC): - (JSC::Structure::objectToStringValue): - (Structure): - (JSC::Structure::setObjectToStringValue): + [Win] Support compiling with VS2013 + https://bugs.webkit.org/show_bug.cgi?id=125353 -2012-04-24 Thouraya ANDOLSI + Reviewed by Anders Carlsson. - Reviewed by Oliver Hunt. + * API/tests/testapi.c: Use C99 defines if available. + * jit/JITOperations.cpp: Don't attempt to define C linkage when + returning a C++ object. - https://bugs.webkit.org/show_bug.cgi?id=84727. - Fix build when ENABLE_JIT_CONSTANT_BLINDING enabled. +2013-12-06 Filip Pizlo - * assembler/MacroAssemblerSH4.h: - (JSC::MacroAssemblerSH4::or32): - (JSC::MacroAssemblerSH4::and32): - (JSC::MacroAssemblerSH4::lshift32): - (JSC::MacroAssemblerSH4::xor32): - (JSC::MacroAssemblerSH4::branchSub32): - (JSC::MacroAssemblerSH4::urshift32): + FTL should support generic ByVal accesses + https://bugs.webkit.org/show_bug.cgi?id=125368 -2012-04-24 Gavin Barraclough + Reviewed by Mark Hahnenberg. - Add explicit patchableBranchPtrWithPatch/patchableJump methods - https://bugs.webkit.org/show_bug.cgi?id=84498 + * dfg/DFGGraph.h: + (JSC::DFG::Graph::isStrictModeFor): + (JSC::DFG::Graph::ecmaModeFor): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): - Reviewed by Filip Pizlo. +2013-12-06 Filip Pizlo - Don't rely on inUninterruptedSequence to distinguish which jumps we need to be able to repatch. + FTL should support hole/OOB array accesses + https://bugs.webkit.org/show_bug.cgi?id=118077 - * assembler/AbstractMacroAssembler.h: - (JSC::AbstractMacroAssembler::PatchableJump::PatchableJump): - (PatchableJump): - (JSC::AbstractMacroAssembler::PatchableJump::operator Jump&): - (AbstractMacroAssembler): - (JSC::AbstractMacroAssembler::AbstractMacroAssembler): - - Added PatchableJump type, removed inUninterruptedSequence. - * assembler/LinkBuffer.h: - (LinkBuffer): - (JSC::LinkBuffer::locationOf): - - Only allow the location to be taken of patchable branches - * assembler/MacroAssembler.h: - (MacroAssembler): - (JSC::MacroAssembler::patchableBranchPtrWithPatch): - (JSC::MacroAssembler::patchableJump): - (JSC::MacroAssembler::shouldBlind): - - Added default implementation of patchableBranchPtrWithPatch, patchableJump. - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::MacroAssemblerARMv7): - (MacroAssemblerARMv7): - (JSC::MacroAssemblerARMv7::patchableBranchPtrWithPatch): - (JSC::MacroAssemblerARMv7::patchableJump): - (JSC::MacroAssemblerARMv7::jump): - (JSC::MacroAssemblerARMv7::makeBranch): - - Added ARMv7 implementation of patchableBranchPtrWithPatch, patchableJump. - * dfg/DFGCorrectableJumpPoint.h: - (DFG): - (JSC::DFG::CorrectableJumpPoint::switchToLateJump): - - Late jumps are PatchableJumps. - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::linkOSRExits): - - replace use of inUninterruptedSequence - * dfg/DFGJITCompiler.h: - (JSC::DFG::PropertyAccessRecord::PropertyAccessRecord): - (PropertyAccessRecord): - - replace use of inUninterruptedSequence - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - - replace use of inUninterruptedSequence - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - - replace use of inUninterruptedSequence - * jit/JIT.h: - (PropertyStubCompilationInfo): - - replace use of inUninterruptedSequence - * jit/JITInlineMethods.h: - (JSC::JIT::beginUninterruptedSequence): - (JSC::JIT::endUninterruptedSequence): - - replace use of inUninterruptedSequence - * jit/JITPropertyAccess.cpp: - (JSC::JIT::compileGetByIdHotPath): - - replace use of inUninterruptedSequence - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::compileGetByIdHotPath): - - replace use of inUninterruptedSequence + Reviewed by Oliver Hunt and Mark Hahnenberg. -2012-04-24 Benjamin Poulain + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::baseIndex): - Generalize the single character optimization of r114072 - https://bugs.webkit.org/show_bug.cgi?id=83961 +2013-12-06 Michael Saboff - Reviewed by Eric Seidel. + Split sizing of VarArgs frames from loading arguments for the frame + https://bugs.webkit.org/show_bug.cgi?id=125331 - Use the regular String::find(StringImpl*) in all cases now that it has been made faster. + Reviewed by Filip Pizlo. - * runtime/StringPrototype.cpp: - (JSC::replaceUsingStringSearch): + Split loadVarargs into sizeAndAllocFrameForVarargs() and loadVarargs() in + preparation for moving onto the C stack. sizeAndAllocFrameForVarargs() will + compute the size of the callee frame and allocate it, while loadVarargs() + actually loads the argument values. -2012-04-24 Filip Pizlo + As part of moving onto the C stack, sizeAndAllocFrameForVarargs() will be + changed to a function that just computes the size. The caller will use that + size to allocate the new frame on the stack before calling loadVargs() and + actually making the call. - Unreviewed, 32-bit build fix. - - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - -2012-04-24 Filip Pizlo - - DFG performs incorrect DCE on (some?) intrinsics - https://bugs.webkit.org/show_bug.cgi?id=84746 - - - Reviewed by Oliver Hunt. + * interpreter/Interpreter.cpp: + (JSC::sizeAndAllocFrameForVarargs): + (JSC::loadVarargs): + * interpreter/Interpreter.h: + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileLoadVarargs): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileLoadVarargs): + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/VM.h: - * dfg/DFGAbstractState.cpp: - (JSC::DFG::AbstractState::execute): - * dfg/DFGByteCodeParser.cpp: - (ByteCodeParser): - (JSC::DFG::ByteCodeParser::setIntrinsicResult): - (JSC::DFG::ByteCodeParser::handleMinMax): - (JSC::DFG::ByteCodeParser::handleIntrinsic): - * dfg/DFGNodeType.h: - (DFG): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): +2013-12-06 Filip Pizlo -2012-04-24 Mark Hahnenberg + FTL should support all of ValueToInt32 + https://bugs.webkit.org/show_bug.cgi?id=125283 - Failure to allocate ArrayStorage in emit_op_new_array leads to poisonous JSArray - https://bugs.webkit.org/show_bug.cgi?id=84648 + Reviewed by Mark Hahnenberg. - Reviewed by Geoffrey Garen. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::lowCell): + (JSC::FTL::LowerDFGToLLVM::isCell): - When emit_op_new_array successfully allocates a new JSArray but fails to allocate - the corresponding ArrayStorage for it, it falls back to the out-of-line stub call - to constructArray, which constructs and entirely new JSArray/ArrayStorage pair. - This leaves us with a JSArray hanging around on the stack or in a register that - did not go through its own constructor, thus giving it uninitialized memory in the - two fields that are checked in JSArray::visitChildren. +2013-12-06 Filip Pizlo - * jit/JITInlineMethods.h: - (JSC::JIT::emitAllocateJSArray): We try to allocate the ArrayStorage first, so that - if we fail we haven't generated the poisonous JSArray that can cause a GC crash. - * jit/JITOpcodes.cpp: - (JSC::JIT::emitSlow_op_new_array): + FTL shouldn't have a doubleToUInt32 path + https://bugs.webkit.org/show_bug.cgi?id=125360 -2012-04-23 Filip Pizlo + Reviewed by Mark Hahnenberg. + + This code existed because I incorrectly thought it was necessary. It's now basically + dead. - DFG on ARMv7 should not OSR exit on every integer division - https://bugs.webkit.org/show_bug.cgi?id=84661 + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): - Reviewed by Oliver Hunt. - - On ARMv7, ArithDiv no longer has to know whether or not to speculate integer (since - that was broken with the introduction of Int32ToDouble) nor does it have to know - whether or not to convert its result to integer. This is now taken care of for free - with the addition of the DoubleAsInt32 node, which represents a double-is-really-int - speculation. - - * dfg/DFGAbstractState.cpp: - (JSC::DFG::AbstractState::execute): - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::performNodeCSE): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNodeType.h: - (DFG): - * dfg/DFGOSRExit.cpp: - (JSC::DFG::OSRExit::OSRExit): - (JSC::DFG::OSRExit::considerAddingAsFrequentExitSiteSlow): - * dfg/DFGOSRExit.h: - (OSRExit): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): - (JSC::DFG::SpeculativeJIT::compileDoubleAsInt32): - (DFG): - * dfg/DFGSpeculativeJIT.h: - (SpeculativeJIT): - (JSC::DFG::SpeculativeJIT::speculationCheck): - (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): +2013-12-06 Laszlo Vidacs -2012-04-24 Geoffrey Garen + Define SHA1 hash size in SHA1.h and use it at various places. + https://bugs.webkit.org/show_bug.cgi?id=125345 - "GlobalHandle" HandleHeap (now WeakSet) allocations grow but do not shrink - https://bugs.webkit.org/show_bug.cgi?id=84740 - + Reviewed by Darin Adler. - Reviewed by Gavin Barraclough. + Use SHA1::hashSize instead of local variables. - Shrink! + * bytecode/CodeBlockHash.cpp: + (JSC::CodeBlockHash::CodeBlockHash): use SHA1::hashSize - * heap/Heap.cpp: - (JSC::Heap::destroy): Be more specific about what's shrinking, since we - can also shrink the WeakSet, but we don't do so here. +2013-12-05 Michael Saboff - (JSC::Heap::collect): If we're going to shrink the heap, shrink the - WeakSet too. Otherwise, its footprint is permanent. + REGRESSION(r160213): Crash in js/dom/JSON-parse.html + https://bugs.webkit.org/show_bug.cgi?id=125335 - * heap/Heap.h: - (Heap): Removed shrink() as a public interface, since it's vague about - which parts of the heap it affects, and it's really an internal detail. + Reviewed by Mark Lam. - * heap/WeakSet.cpp: - (JSC::WeakSet::shrink): Nix any free blocks. We assume that sweep() has - already taken place, since that's the convention for shrink() in the heap. + Changed _llint_op_catch to materialize the VM via the scope chain instead of + the CodeBlock. CallFrames always have a scope chain, but may have a null CodeBlock. - * heap/WeakSet.h: - (WeakSet): New function! + * llint/LowLevelInterpreter32_64.asm: + (_llint_op_catch): + * llint/LowLevelInterpreter64.asm: + (_llint_op_catch): -2012-04-24 Adam Klein +2013-12-05 Michael Saboff - Fix includes in StrongInlines.h and ScriptValue.h - https://bugs.webkit.org/show_bug.cgi?id=84659 + JSC: Simplify interface between throw and catch handler + https://bugs.webkit.org/show_bug.cgi?id=125328 Reviewed by Geoffrey Garen. - * heap/StrongInlines.h: Include JSGlobalData.h, since JSGlobalData's - definiition is required here. + Simplified the throw - catch interface. The throw side is only responsible for + jumping to the appropriate op_catch handler or returnFromJavaScript for uncaught + exceptions. The handler uses the exception values like VM.callFrameForThrow + as appropriate and no longer relies on the throw side putting anything in + registers. -2012-04-23 Filip Pizlo + * jit/CCallHelpers.h: + (JSC::CCallHelpers::jumpToExceptionHandler): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_catch): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_catch): + * llint/LowLevelInterpreter32_64.asm: + (_llint_op_catch): + (_llint_throw_from_slow_path_trampoline): + * llint/LowLevelInterpreter64.asm: + (_llint_op_catch): + (_llint_throw_from_slow_path_trampoline): - DFG OSR exit should ensure that all variables have been initialized - https://bugs.webkit.org/show_bug.cgi?id=84653 - +2013-12-04 Oliver Hunt - Reviewed by Gavin Barraclough. - - Initialize all uncaptured dead variables to undefined on OSR exit. + Refactor static getter function prototype to include thisValue in addition to the base object + https://bugs.webkit.org/show_bug.cgi?id=124461 - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::ValueSource::dump): - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): - * dfg/DFGSpeculativeJIT.h: + Reviewed by Geoffrey Garen. -2012-04-23 Oliver Hunt + Add thisValue parameter to static getter prototype, and switch + from JSValue to EncodedJSValue for parameters and return value. - Call instruction for the baseline JIT stores origin info in wrong callframe - https://bugs.webkit.org/show_bug.cgi?id=84645 + Currently none of the static getters use the thisValue, but + separating out the refactoring will prevent future changes + from getting lost in the noise of refactoring. This means + that this patch does not result in any change in behaviour. - Reviewed by Gavin Barraclough. + * API/JSCallbackObject.h: + * API/JSCallbackObjectFunctions.h: + (JSC::::asCallbackObject): + (JSC::::staticFunctionGetter): + (JSC::::callbackGetter): + * jit/JITOperations.cpp: + * runtime/JSActivation.cpp: + (JSC::JSActivation::argumentsGetter): + * runtime/JSActivation.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::argumentsGetter): + (JSC::JSFunction::callerGetter): + (JSC::JSFunction::lengthGetter): + (JSC::JSFunction::nameGetter): + * runtime/JSFunction.h: + * runtime/JSObject.h: + (JSC::PropertySlot::getValue): + * runtime/NumberConstructor.cpp: + (JSC::numberConstructorNaNValue): + (JSC::numberConstructorNegInfinity): + (JSC::numberConstructorPosInfinity): + (JSC::numberConstructorMaxValue): + (JSC::numberConstructorMinValue): + * runtime/PropertySlot.h: + * runtime/RegExpConstructor.cpp: + (JSC::asRegExpConstructor): + (JSC::regExpConstructorDollar1): + (JSC::regExpConstructorDollar2): + (JSC::regExpConstructorDollar3): + (JSC::regExpConstructorDollar4): + (JSC::regExpConstructorDollar5): + (JSC::regExpConstructorDollar6): + (JSC::regExpConstructorDollar7): + (JSC::regExpConstructorDollar8): + (JSC::regExpConstructorDollar9): + (JSC::regExpConstructorInput): + (JSC::regExpConstructorMultiline): + (JSC::regExpConstructorLastMatch): + (JSC::regExpConstructorLastParen): + (JSC::regExpConstructorLeftContext): + (JSC::regExpConstructorRightContext): + * runtime/RegExpObject.cpp: + (JSC::asRegExpObject): + (JSC::regExpObjectGlobal): + (JSC::regExpObjectIgnoreCase): + (JSC::regExpObjectMultiline): + (JSC::regExpObjectSource): - The baseline JIT was updating the wrong callframe when making a call. If the - call failed during dispatch (unable to perform codegen, calling a non-object) - we would attempt to use this information, but it would be completely wrong. +2013-12-04 Filip Pizlo - * jit/JITCall.cpp: - (JSC::JIT::compileOpCall): - * jit/JITCall32_64.cpp: - (JSC::JIT::compileOpCall): + FTL should use cvttsd2si directly for double-to-int32 conversions + https://bugs.webkit.org/show_bug.cgi?id=125275 -2012-04-23 Filip Pizlo + Reviewed by Michael Saboff. + + Wow. This was an ordeal. Using cvttsd2si was actually easy, but I learned, and + sometimes even fixed, some interesting things: + + - The llvm.x86.sse2.cvttsd2si intrinsic can actually result in LLVM emitting a + vcvttsd2si. I guess the intrinsic doesn't actually imply the instruction. + + - That whole thing about branchTruncateDoubleToUint32? Yeah we don't need that. It's + better to use branchTruncateDoubleToInt32 instead. It has the right semantics for + all of its callers (err, its one-and-only caller), and it's more likely to take + fast path. This patch kills branchTruncateDoubleToUint32. + + - "a[i] = v; v = a[i]". Does this change v? OK, assume that 'a[i]' is a pure-ish + operation - like an array access with 'i' being an integer index and we're not + having a bad time. Now does this change v? CSE assumes that it doesn't. That's + wrong. If 'a' is a typed array - the most sensible and pure kind of array - then + this can be a truncating cast. For example 'v' could be a double and 'a' could be + an integer array. + + - "v1 = a[i]; v2 = a[i]". Is v1 === v2 assuming that 'a[i]' is pure-ish? The answer + is no. You could have a different arrayMode in each access. I know this sounds + weird, but with concurrent JIT that might happen. + + This patch adds tests for all of this stuff, except for the first issue (it's weird + but probably doesn't matter) and the last issue (it's too much of a freakshow). - DFG must keep alive values that it will perform speculations on - https://bugs.webkit.org/show_bug.cgi?id=84638 - + * assembler/MacroAssemblerARM64.h: + * assembler/MacroAssemblerARMv7.h: + * assembler/MacroAssemblerX86Common.h: + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::getByValLoadElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + * ftl/FTLAbbreviations.h: + (JSC::FTL::vectorType): + (JSC::FTL::getUndef): + (JSC::FTL::buildInsertElement): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::doubleToInt32): + (JSC::FTL::LowerDFGToLLVM::doubleToUInt32): + (JSC::FTL::LowerDFGToLLVM::sensibleDoubleToInt32): + * ftl/FTLOutput.h: + (JSC::FTL::Output::insertElement): + (JSC::FTL::Output::hasSensibleDoubleToInt): + (JSC::FTL::Output::sensibleDoubleToInt): + +2013-12-05 Commit Queue + + Unreviewed, rolling out r160133. + http://trac.webkit.org/changeset/160133 + https://bugs.webkit.org/show_bug.cgi?id=125325 + + broke bindings tests on all the bots (Requested by thorton on + #webkit). - Reviewed by Oliver Hunt. + * API/JSCallbackObject.h: + * API/JSCallbackObjectFunctions.h: + (JSC::::staticFunctionGetter): + (JSC::::callbackGetter): + * jit/JITOperations.cpp: + * runtime/JSActivation.cpp: + (JSC::JSActivation::argumentsGetter): + * runtime/JSActivation.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::argumentsGetter): + (JSC::JSFunction::callerGetter): + (JSC::JSFunction::lengthGetter): + (JSC::JSFunction::nameGetter): + * runtime/JSFunction.h: + * runtime/JSObject.h: + (JSC::PropertySlot::getValue): + * runtime/NumberConstructor.cpp: + (JSC::numberConstructorNaNValue): + (JSC::numberConstructorNegInfinity): + (JSC::numberConstructorPosInfinity): + (JSC::numberConstructorMaxValue): + (JSC::numberConstructorMinValue): + * runtime/PropertySlot.h: + * runtime/RegExpConstructor.cpp: + (JSC::regExpConstructorDollar1): + (JSC::regExpConstructorDollar2): + (JSC::regExpConstructorDollar3): + (JSC::regExpConstructorDollar4): + (JSC::regExpConstructorDollar5): + (JSC::regExpConstructorDollar6): + (JSC::regExpConstructorDollar7): + (JSC::regExpConstructorDollar8): + (JSC::regExpConstructorDollar9): + (JSC::regExpConstructorInput): + (JSC::regExpConstructorMultiline): + (JSC::regExpConstructorLastMatch): + (JSC::regExpConstructorLastParen): + (JSC::regExpConstructorLeftContext): + (JSC::regExpConstructorRightContext): + * runtime/RegExpObject.cpp: + (JSC::regExpObjectGlobal): + (JSC::regExpObjectIgnoreCase): + (JSC::regExpObjectMultiline): + (JSC::regExpObjectSource): - * dfg/DFGNodeType.h: - (DFG): +2013-12-05 Mark Lam -2012-04-23 Oliver Hunt + Make the C Loop LLINT work with callToJavaScript. + https://bugs.webkit.org/show_bug.cgi?id=125294. - Fix non-LLInt builds by temporarily removing an over-enthusiastic assertion + Reviewed by Michael Saboff. + + 1. Changed the C Loop LLINT to dispatch to an Executable via its JITCode + instance which is consistent with how the ASM LLINT works. + 2. Changed CLoop::execute() to take an Opcode instead of an OpcodeID. + This makes it play nice with the use of JITCode for dispatching. + 3. Introduce a callToJavaScript and callToNativeFunction for the C Loop + LLINT. These will call JSStack::pushFrame() and popFrame() to setup + and teardown the CallFrame. + 4. Also introduced a C Loop returnFromJavaScript which is just a + replacement for ctiOpThrowNotCaught which had the same function. + 5. Remove a lot of #if ENABLE(LLINT_C_LOOP) code now that the dispatch + mechanism is consistent. + + This patch has been tested with both configurations of COMPUTED_GOTOs + on and off. + * interpreter/CachedCall.h: + (JSC::CachedCall::CachedCall): + (JSC::CachedCall::call): + (JSC::CachedCall::setArgument): + * interpreter/CallFrameClosure.h: + (JSC::CallFrameClosure::setThis): + (JSC::CallFrameClosure::setArgument): + (JSC::CallFrameClosure::resetCallFrame): * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::prepareForRepeatCall): + * interpreter/Interpreter.h: + * interpreter/JSStack.h: + * interpreter/JSStackInlines.h: + (JSC::JSStack::pushFrame): + * interpreter/ProtoCallFrame.h: + (JSC::ProtoCallFrame::scope): + (JSC::ProtoCallFrame::callee): + (JSC::ProtoCallFrame::thisValue): + (JSC::ProtoCallFrame::argument): + (JSC::ProtoCallFrame::setArgument): + * jit/JITCode.cpp: + (JSC::JITCode::execute): + * jit/JITCode.h: + * jit/JITExceptions.cpp: + (JSC::genericUnwind): + * llint/LLIntCLoop.cpp: + (JSC::LLInt::CLoop::initialize): + * llint/LLIntCLoop.h: + * llint/LLIntEntrypoint.cpp: + (JSC::LLInt::setFunctionEntrypoint): + (JSC::LLInt::setEvalEntrypoint): + (JSC::LLInt::setProgramEntrypoint): + - Inverted the check for vm.canUseJIT(). This allows the JIT case to be + #if'd out nicely when building the C Loop LLINT. + * llint/LLIntOpcode.h: + * llint/LLIntThunks.cpp: + (JSC::doCallToJavaScript): + (JSC::executeJS): + (JSC::callToJavaScript): + (JSC::executeNative): + (JSC::callToNativeFunction): + * llint/LLIntThunks.h: + * llint/LowLevelInterpreter.cpp: + (JSC::CLoop::execute): + * runtime/Executable.h: + (JSC::ExecutableBase::offsetOfNumParametersFor): + (JSC::ExecutableBase::hostCodeEntryFor): + (JSC::ExecutableBase::jsCodeEntryFor): + (JSC::ExecutableBase::jsCodeWithArityCheckEntryFor): + (JSC::NativeExecutable::create): + (JSC::NativeExecutable::finishCreation): + (JSC::ProgramExecutable::generatedJITCode): + * runtime/JSArray.cpp: + (JSC::AVLTreeAbstractorForArrayCompare::compare_key_key): + * runtime/StringPrototype.cpp: + (JSC::replaceUsingRegExpSearch): + * runtime/VM.cpp: + (JSC::VM::getHostFunction): -2012-04-22 Jon Lee - - Remove notifications support on Mac Lion. - https://bugs.webkit.org/show_bug.cgi?id=84554 - - - Reviewed by Sam Weinig. - - * Configurations/FeatureDefines.xcconfig: - -2012-04-21 Darin Adler - - Change JavaScript lexer to use 0 instead of -1 for sentinel, eliminating the need to put characters into ints - https://bugs.webkit.org/show_bug.cgi?id=84523 - - Reviewed by Oliver Hunt. - - Profiles showed that checks against -1 were costly, and I saw they could be eliminated. - Streamlined this code to use standard character types and 0 rather than -1. One benefit - of this is that there's no widening and narrowing. Another is that there are many cases - where we already have the correct behavior for 0, so can eliminate a branch that was - used to test for -1 before. Also eliminates typecasts in the code. +2013-12-05 Laszlo Vidacs - * parser/Lexer.cpp: - (JSC::Lexer::invalidCharacterMessage): Updated use of String::format since m_current is now a - character type, not an int. - (JSC::Lexer::setCode): Use 0 rather than -1 when past the end. - (JSC::Lexer::shift): Ditto. Also spruced up the comment a bit. - (JSC::Lexer::atEnd): Added. New function that distinguishes an actual 0 character from the end - of the code. This can be used places we used to cheeck for -1. - (JSC::Lexer::peek): Updated to use -1 instead of 0. Removed meaningless comment. - (JSC::Lexer::parseFourDigitUnicodeHex): Changed to use character types instead of int. - (JSC::Lexer::shiftLineTerminator): Removed now-unneeded type casts. Changed local variable that - had a data-member-style name. - (JSC::Lexer::parseIdentifier): Removed now-unneeded explicit checks for -1, since the isIdentPart - function already returns false for the 0 character. Updated types in a couple other places. Used - the atEnd function where needed. - (JSC::Lexer::parseIdentifierSlowCase): More of the same. - (JSC::characterRequiresParseStringSlowCase): Added overloaded helper function for parseString. - (JSC::Lexer::parseString): Ditto. - (JSC::Lexer::parseStringSlowCase): Ditto. - (JSC::Lexer::parseMultilineComment): Ditto. - (JSC::Lexer::lex): More of the same. Also changed code to set the startOffset directly in - the tokenInfo instead of putting it in a local variable first, saving some memory access. - (JSC::Lexer::scanRegExp): Ditto. - (JSC::Lexer::skipRegExp): Ditto. - - * parser/Lexer.h: Changed return type of the peek function and type of m_current from int to - the character type. Added atEnd function. - (JSC::Lexer::setOffset): Used 0 instead of -1 and removed an overzealous attempt to optimize. - (JSC::Lexer::lexExpectIdentifier): Used 0 instead of -1. - -2012-04-21 Darin Adler - - Change JavaScript lexer to use 0 instead of -1 for sentinel, eliminating the need to put characters into ints - https://bugs.webkit.org/show_bug.cgi?id=84523 + Fix JavaScriptCore build if cloop is enabled after r160094 + https://bugs.webkit.org/show_bug.cgi?id=125292 - Reviewed by Oliver Hunt. + Reviewed by Michael Saboff. - Separate preparation step of copyright dates, renaming, and other small tweaks. + Move ProtoCallFrame outside the JIT guard. - * parser/Lexer.cpp: - (JSC::Lexer::invalidCharacterMessage): Removed "get" from name to match WebKit naming conventions. - (JSC::Lexer::peek): Removed meaningless comment. - (JSC::Lexer::parseFourDigitUnicodeHex): Renamed from getUnicodeCharacter to be more precise about - what this function does. - (JSC::Lexer::shiftLineTerminator): Renamed local variable that had a data-member-style name. - (JSC::Lexer::parseStringSlowCase): Updated for new name of parseFourDigitUnicodeHex. - (JSC::Lexer::lex): Updated for new name of invalidCharacterMessage. + * jit/JITCode.h: - * parser/Lexer.h: Removed an unneeded forward declaration of the RegExp class. - Renamed getInvalidCharMessage to invalidCharacterMessage and made it const. Renamed - getUnicodeCharacter to parseFourDigitUnicodeHex. +2013-12-04 Filip Pizlo -2012-04-20 Filip Pizlo + Fold constant typed arrays + https://bugs.webkit.org/show_bug.cgi?id=125205 - DFG should optimize int8 and int16 arrays on ARMv7 - https://bugs.webkit.org/show_bug.cgi?id=84503 + Reviewed by Oliver Hunt and Mark Hahnenberg. + + If by some other mechanism we have a typed array access on a compile-time constant + typed array pointer, then fold: + + - Array bounds checks. Specifically, fold the load of length. + + - Loading the vector. + + This needs to install a watchpoint on the array itself because of the possibility of + neutering. Neutering is ridiculous. We do this without bloating the size of + ArrayBuffer or JSArrayBufferView in the common case (i.e. the case where you + allocated an array that didn't end up becoming a compile-time constant). To install + the watchpoint, we slowDownAndWasteMemory and then create an incoming reference to + the ArrayBuffer, where that incoming reference is from a watchpoint object. The + ArrayBuffer already knows about such incoming references and can fire the + watchpoints that way. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGDesiredWatchpoints.cpp: + (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): + (JSC::DFG::DesiredWatchpoints::addLazily): + * dfg/DFGDesiredWatchpoints.h: + (JSC::DFG::GenericSetAdaptor::add): + (JSC::DFG::GenericSetAdaptor::hasBeenInvalidated): + (JSC::DFG::ArrayBufferViewWatchpointAdaptor::hasBeenInvalidated): + (JSC::DFG::GenericDesiredWatchpoints::reallyAdd): + (JSC::DFG::GenericDesiredWatchpoints::areStillValid): + (JSC::DFG::GenericDesiredWatchpoints::isStillValid): + (JSC::DFG::GenericDesiredWatchpoints::shouldAssumeMixedState): + (JSC::DFG::DesiredWatchpoints::isStillValid): + (JSC::DFG::DesiredWatchpoints::shouldAssumeMixedState): + (JSC::DFG::DesiredWatchpoints::isValidOrMixed): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetFoldableView): + * dfg/DFGGraph.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds): + (JSC::DFG::SpeculativeJIT::emitTypedArrayBoundsCheck): + (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compileConstantIndexedPropertyStorage): + (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + (JSC::DFG::WatchpointCollectionPhase::addLazily): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetIndexedPropertyStorage): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::typedArrayLength): + * runtime/ArrayBuffer.cpp: + (JSC::ArrayBuffer::transfer): + * runtime/ArrayBufferNeuteringWatchpoint.cpp: Added. + (JSC::ArrayBufferNeuteringWatchpoint::ArrayBufferNeuteringWatchpoint): + (JSC::ArrayBufferNeuteringWatchpoint::~ArrayBufferNeuteringWatchpoint): + (JSC::ArrayBufferNeuteringWatchpoint::finishCreation): + (JSC::ArrayBufferNeuteringWatchpoint::destroy): + (JSC::ArrayBufferNeuteringWatchpoint::create): + (JSC::ArrayBufferNeuteringWatchpoint::createStructure): + * runtime/ArrayBufferNeuteringWatchpoint.h: Added. + (JSC::ArrayBufferNeuteringWatchpoint::set): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2013-12-04 Commit Queue + + Unreviewed, rolling out r160116. + http://trac.webkit.org/changeset/160116 + https://bugs.webkit.org/show_bug.cgi?id=125264 + + Change doesn't work as intended. See bug comments for details. + (Requested by bfulgham on #webkit). - Reviewed by Oliver Hunt. + * runtime/InitializeThreading.cpp: + (JSC::initializeThreading): - * assembler/ARMv7Assembler.h: - (ARMv7Assembler): - (JSC::ARMv7Assembler::ldrsb): - (JSC::ARMv7Assembler::ldrsh): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::load16Signed): - (JSC::MacroAssemblerARMv7::load8Signed): - * bytecode/PredictedType.h: - (JSC::isActionableIntMutableArrayPrediction): - * dfg/DFGNode.h: - (JSC::DFG::Node::shouldSpeculateInt8Array): - (JSC::DFG::Node::shouldSpeculateInt16Array): +2013-12-04 Oliver Hunt -2012-04-20 Oliver Hunt + Refactor static getter function prototype to include thisValue in addition to the base object + https://bugs.webkit.org/show_bug.cgi?id=124461 - Add an ability to find the extent of a callframe - https://bugs.webkit.org/show_bug.cgi?id=84513 + Reviewed by Geoffrey Garen. - Reviewed by Filip Pizlo. + Add thisValue parameter to static getter prototype, and switch + from JSValue to EncodedJSValue for parameters and return value. - Add a function to get the extent of a callframe and - use that function for a new assertion to make sure the - RegisterFile makes sense using that information. + Currently none of the static getters use the thisValue, but + separating out the refactoring will prevent future changes + from getting lost in the noise of refactoring. This means + that this patch does not result in any change in behaviour. - * interpreter/CallFrame.cpp: - (JSC::CallFrame::frameExtentInternal): - (JSC): - * interpreter/CallFrame.h: - (JSC::ExecState::frameExtent): - (ExecState): - * interpreter/Interpreter.cpp: - (JSC::Interpreter::executeCall): + * API/JSCallbackObject.h: + * API/JSCallbackObjectFunctions.h: + (JSC::::asCallbackObject): + (JSC::::staticFunctionGetter): + (JSC::::callbackGetter): + * jit/JITOperations.cpp: + * runtime/JSActivation.cpp: + (JSC::JSActivation::argumentsGetter): + * runtime/JSActivation.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::argumentsGetter): + (JSC::JSFunction::callerGetter): + (JSC::JSFunction::lengthGetter): + (JSC::JSFunction::nameGetter): + * runtime/JSFunction.h: + * runtime/JSObject.h: + (JSC::PropertySlot::getValue): + * runtime/NumberConstructor.cpp: + (JSC::numberConstructorNaNValue): + (JSC::numberConstructorNegInfinity): + (JSC::numberConstructorPosInfinity): + (JSC::numberConstructorMaxValue): + (JSC::numberConstructorMinValue): + * runtime/PropertySlot.h: + * runtime/RegExpConstructor.cpp: + (JSC::asRegExpConstructor): + (JSC::regExpConstructorDollar1): + (JSC::regExpConstructorDollar2): + (JSC::regExpConstructorDollar3): + (JSC::regExpConstructorDollar4): + (JSC::regExpConstructorDollar5): + (JSC::regExpConstructorDollar6): + (JSC::regExpConstructorDollar7): + (JSC::regExpConstructorDollar8): + (JSC::regExpConstructorDollar9): + (JSC::regExpConstructorInput): + (JSC::regExpConstructorMultiline): + (JSC::regExpConstructorLastMatch): + (JSC::regExpConstructorLastParen): + (JSC::regExpConstructorLeftContext): + (JSC::regExpConstructorRightContext): + * runtime/RegExpObject.cpp: + (JSC::asRegExpObject): + (JSC::regExpObjectGlobal): + (JSC::regExpObjectIgnoreCase): + (JSC::regExpObjectMultiline): + (JSC::regExpObjectSource): -2012-04-20 Benjamin Poulain +2013-12-04 Daniel Bates - Inline the JSArray constructor - https://bugs.webkit.org/show_bug.cgi?id=84416 + [iOS] Enable Objective-C ARC when building JSC tools for iOS simulator + https://bugs.webkit.org/show_bug.cgi?id=125170 Reviewed by Geoffrey Garen. - The constructor is trivial, no reason to jump for it. + * API/tests/testapi.mm: + * Configurations/ToolExecutable.xcconfig: - This makes the creation of array ~5% faster (on non-trivial cases, no empty arrays). +2013-12-04 peavo@outlook.com - * runtime/JSArray.cpp: - (JSC): - * runtime/JSArray.h: - (JSC::JSArray::JSArray): - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + Use ThreadingOnce class to encapsulate pthread_once functionality. + https://bugs.webkit.org/show_bug.cgi?id=125228 -2012-04-20 Mark Hahnenberg + Reviewed by Brent Fulgham. - Heap should cancel GC timer at the start of the collection - https://bugs.webkit.org/show_bug.cgi?id=84477 + * runtime/InitializeThreading.cpp: + (JSC::initializeThreading): - Reviewed by Geoffrey Garen. +2013-12-04 Mark Lam - Currently the Heap cancels the GC timer at the conclusion of a collection. - We should change this to be at the beginning because something (e.g. a finalizer) - could call didAbandonObjectGraph(), which will schedule the timer, but then - we'll immediately unschedule the timer at the conclusion of the collection, - thus potentially preventing large swaths of memory from being reclaimed in a timely manner. + Remove unneeded semicolons. + https://bugs.webkit.org/show_bug.cgi?id=125083. - * API/JSBase.cpp: - (JSGarbageCollect): Remove outdated fix-me and remove check for whether the Heap is - busy or not, since we're just scheduling a timer to run a GC in the future. - * heap/Heap.cpp: - (JSC::Heap::collect): Rename didCollect to willCollect and move the call to the - top of Heap::collect. - * runtime/GCActivityCallback.cpp: Renamed didCollect to willCollect. - (JSC::DefaultGCActivityCallback::willCollect): - * runtime/GCActivityCallback.h: Ditto. - (JSC::GCActivityCallback::willCollect): - (DefaultGCActivityCallback): - * runtime/GCActivityCallbackCF.cpp: Ditto. - (JSC::DefaultGCActivityCallback::willCollect): + Rubber-stamped by Filip Pizlo. -2012-04-20 Mark Hahnenberg + * debugger/Debugger.h: + (JSC::Debugger::detach): + (JSC::Debugger::sourceParsed): + (JSC::Debugger::exception): + (JSC::Debugger::atStatement): + (JSC::Debugger::callEvent): + (JSC::Debugger::returnEvent): + (JSC::Debugger::willExecuteProgram): + (JSC::Debugger::didExecuteProgram): + (JSC::Debugger::didReachBreakpoint): - JSGarbageCollect should not call collectAllGarbage() - https://bugs.webkit.org/show_bug.cgi?id=84476 +2013-12-04 Andy Estes - Reviewed by Geoffrey Garen. + [iOS] Build projects with $(ARCHS_STANDARD_32_64_BIT) + https://bugs.webkit.org/show_bug.cgi?id=125236 - * API/JSBase.cpp: - (JSGarbageCollect): Notify the Heap's GCActivityCallback using didAbandonObjectGraph. + Reviewed by Sam Weinig. -2012-04-19 Oliver Hunt + $(ARCHS_STANDARD_32_64_BIT) is what we want for both device and simulator builds. - Exception stack traces aren't complete when the exception starts in native code - https://bugs.webkit.org/show_bug.cgi?id=84073 + * Configurations/DebugRelease.xcconfig: - Reviewed by Filip Pizlo. +2013-12-03 Filip Pizlo - Refactored building the stack trace to so that we can construct - it earlier, and don't rely on any prior work performed in the - exception handling machinery. Also updated LLInt and the DFG to - completely initialise the callframes of host function calls. + Infer constant closure variables + https://bugs.webkit.org/show_bug.cgi?id=124630 - Also fixed a few LLInt paths that failed to correctly update the - topCallFrame. + Reviewed by Geoffrey Garen. + + Captured variables that are assigned once (not counting op_enter's Undefined + initialization) and that are contained within a function that has thus far only been + entered once are now constant folded. It's pretty awesome. + + This involves a watchpoint on the assignment to variables and a watchpoint on entry + into the function. The former is reused from global variable constant inference and the + latter is reused from one-time closure inference. - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: - * dfg/DFGJITCompiler.h: - * dfg/DFGOperations.cpp: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::emitCall): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::emitCall): - * interpreter/Interpreter.cpp: - (JSC::eval): - (JSC::Interpreter::getStackTrace): - (JSC::Interpreter::addStackTraceIfNecessary): - (JSC): - (JSC::Interpreter::throwException): - * interpreter/Interpreter.h: - (Interpreter): - * jit/JITCall.cpp: - (JSC::JIT::compileOpCall): - * jit/JITCall32_64.cpp: - (JSC::JIT::compileOpCall): - * jit/JITOpcodes.cpp: - (JSC::JIT::privateCompileCTINativeCall): + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + * bytecode/Instruction.h: + (JSC::Instruction::Instruction): + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedInstruction::UnlinkedInstruction): + * bytecode/VariableWatchpointSet.h: + (JSC::VariableWatchpointSet::invalidate): + * bytecode/Watchpoint.h: + (JSC::WatchpointSet::invalidate): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::addVar): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitInitLazyRegister): + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + (JSC::BytecodeGenerator::createArgumentsIfNecessary): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::addVar): + (JSC::BytecodeGenerator::watchableVariable): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getLocal): + (JSC::DFG::ByteCodeParser::inferredConstant): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::parse): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetActivation): + (JSC::DFG::Graph::tryGetRegisters): + * dfg/DFGGraph.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_mov): + (JSC::JIT::emit_op_captured_mov): + (JSC::JIT::emit_op_new_captured_func): + (JSC::JIT::emitSlow_op_captured_mov): * jit/JITOpcodes32_64.cpp: - (JSC::JIT::privateCompileCTINativeCall): - * jsc.cpp: - (functionJSCStack): - * llint/LLIntExceptions.cpp: - (JSC::LLInt::interpreterThrowInCaller): - (JSC::LLInt::returnToThrow): - (JSC::LLInt::callToThrow): - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::handleHostCall): + (JSC::JIT::emit_op_mov): + (JSC::JIT::emit_op_captured_mov): * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: - * parser/Parser.h: - (JSC::::parse): - * runtime/Error.cpp: - (JSC::addErrorInfo): - (JSC::throwError): - * runtime/Error.h: - (JSC): - -2012-04-19 Mark Hahnenberg - - We're collecting pathologically due to small allocations - https://bugs.webkit.org/show_bug.cgi?id=84404 + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/ConstantMode.h: Added. + * runtime/JSGlobalObject.h: + * runtime/JSScope.cpp: + (JSC::abstractAccess): + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::prepareToWatch): - Reviewed by Geoffrey Garen. +2013-12-04 Brent Fulgham - No change in performance on run-jsc-benchmarks. - - * dfg/DFGSpeculativeJIT.h: Replacing m_firstFreeCell with m_freeList. - (JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject): - * heap/CopiedSpace.cpp: Getting rid of any water mark related stuff, since it's no - longer useful. - (JSC::CopiedSpace::CopiedSpace): - (JSC::CopiedSpace::tryAllocateSlowCase): We now only call didAllocate here rather than - carrying out a somewhat complicated accounting job for our old water mark throughout CopiedSpace. - (JSC::CopiedSpace::tryAllocateOversize): Call the new didAllocate to notify the Heap of - newly allocated stuff. - (JSC::CopiedSpace::tryReallocateOversize): - (JSC::CopiedSpace::doneFillingBlock): - (JSC::CopiedSpace::doneCopying): - (JSC::CopiedSpace::destroy): - * heap/CopiedSpace.h: - (CopiedSpace): - * heap/CopiedSpaceInlineMethods.h: - (JSC::CopiedSpace::startedCopying): - * heap/Heap.cpp: Removed water mark related stuff, replaced with new bytesAllocated and - bytesAllocatedLimit to track how much memory has been allocated since the last collection. - (JSC::Heap::Heap): - (JSC::Heap::reportExtraMemoryCostSlowCase): - (JSC::Heap::collect): We now set the new limit of bytes that we can allocate before triggering - a collection to be the size of the Heap after the previous collection. Thus, we still have our - 2x allocation amount. - (JSC::Heap::didAllocate): Notifies the GC activity timer of how many bytes have been allocated - thus far and then adds the new number of bytes to the current total. - (JSC): - * heap/Heap.h: Removed water mark related stuff. - (JSC::Heap::notifyIsSafeToCollect): - (Heap): - (JSC::Heap::shouldCollect): - (JSC): - * heap/MarkedAllocator.cpp: - (JSC::MarkedAllocator::tryAllocateHelper): Refactored to use MarkedBlock's new FreeList struct. - (JSC::MarkedAllocator::allocateSlowCase): - (JSC::MarkedAllocator::addBlock): - * heap/MarkedAllocator.h: - (MarkedAllocator): - (JSC::MarkedAllocator::MarkedAllocator): - (JSC::MarkedAllocator::allocate): - (JSC::MarkedAllocator::zapFreeList): Refactored to take in a FreeList instead of a FreeCell. - * heap/MarkedBlock.cpp: - (JSC::MarkedBlock::specializedSweep): - (JSC::MarkedBlock::sweep): - (JSC::MarkedBlock::sweepHelper): - (JSC::MarkedBlock::zapFreeList): - * heap/MarkedBlock.h: - (FreeList): Added a new struct that keeps track of the current MarkedAllocator's - free list including the number of bytes of stuff in the free list so that when the free list is - exhausted, the correct amount can be reported to Heap. - (MarkedBlock): - (JSC::MarkedBlock::FreeList::FreeList): - (JSC): - * heap/MarkedSpace.cpp: Removing all water mark related stuff. - (JSC::MarkedSpace::MarkedSpace): - (JSC::MarkedSpace::resetAllocators): - * heap/MarkedSpace.h: - (MarkedSpace): - (JSC): - * heap/WeakSet.cpp: - (JSC::WeakSet::findAllocator): Refactored to use the didAllocate interface with the Heap. This - function still needs work though now that the Heap knows how many bytes have been allocated - since the last collection. - * jit/JITInlineMethods.h: Refactored to use MarkedBlock's new FreeList struct. - (JSC::JIT::emitAllocateBasicJSObject): Ditto. - * llint/LowLevelInterpreter.asm: Ditto. - * runtime/GCActivityCallback.cpp: - (JSC::DefaultGCActivityCallback::didAllocate): - * runtime/GCActivityCallback.h: - (JSC::GCActivityCallback::didAllocate): Renamed willAllocate to didAllocate to indicate that - the allocation that is being reported has already taken place. - (DefaultGCActivityCallback): - * runtime/GCActivityCallbackCF.cpp: - (JSC): - (JSC::DefaultGCActivityCallback::didAllocate): Refactored to return early if the amount of - allocation since the last collection is not above a threshold (initially arbitrarily chosen to - be 128KB). + [Win] Unreviewed project file gardening. -2012-04-19 Filip Pizlo + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Remove deleted files from project. + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Put files in proper directory + folders to match the directory structure of the source code. - MacroAssemblerARMv7::branchTruncateDoubleToUint32 should obey the overflow signal - https://bugs.webkit.org/show_bug.cgi?id=84401 +2013-12-04 Joseph Pecoraro - Reviewed by Gavin Barraclough. + Unreviewed Windows Build Fix attempt after r160099. - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::branchTruncateDoubleToUint32): + * JavaScriptCore.vcxproj/copy-files.cmd: -2012-04-19 Don Olmstead +2013-12-04 Julien Brianceau - KeywordLookupGenerator.py should take an output file as an argument - https://bugs.webkit.org/show_bug.cgi?id=84292 + REGRESSION (r160094): Fix lots of crashes for sh4 architecture. + https://bugs.webkit.org/show_bug.cgi?id=125227 - Reviewed by Eric Seidel. + Reviewed by Michael Saboff. - Extended KeywordLookupGenerator to accept an additional argument specifying an output file. If this argument is found stdout is redirected to a file for the duration of the script. + * llint/LowLevelInterpreter32_64.asm: Do not use t4 and t5 as they match a0 and a1. + * offlineasm/registers.rb: Add t7, t8 and t9 in register list for sh4 port. + * offlineasm/sh4.rb: Rearrange RegisterID list and add the missing ones. - * KeywordLookupGenerator.py: +2013-12-03 Joseph Pecoraro -2012-04-19 Filip Pizlo + Web Inspector: Push Remote Inspector debugging connection management into JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=124613 - It should be possible to perform debugCall on ARMv7 - https://bugs.webkit.org/show_bug.cgi?id=84381 + Reviewed by Timothy Hatcher. - Reviewed by Oliver Hunt. - - debugCall() was clobbering the argument to the call it was making, leading to a - corrupt ExecState*. This change fixes that issue by using a scratch register that - does not clobber arguments, and it also introduces more assertions that we have - a valid call frame. - - * dfg/DFGAssemblyHelpers.cpp: - (DFG): - (JSC::DFG::AssemblyHelpers::jitAssertHasValidCallFrame): - * dfg/DFGAssemblyHelpers.h: - (JSC::DFG::AssemblyHelpers::selectScratchGPR): - (AssemblyHelpers): - (JSC::DFG::AssemblyHelpers::debugCall): - (JSC::DFG::AssemblyHelpers::jitAssertHasValidCallFrame): - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::linkOSRExits): - * dfg/DFGOSRExitCompiler.cpp: - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::selectScratchGPR): + Move the ENABLE(REMOTE_INSPECTOR) remote debugger connection management + into JavaScriptCore (originally from WebKit/mac). Include enhancements: + + * allow for different types of remote debuggable targets, + eventually at least a JSContext, WebView, WKView. + * allow debuggables to be registered and debugged on any thread. Unlike + WebViews, JSContexts may be run entirely off of the main thread. + * move the remote connection (XPC connection) itself off of the main thread, + it doesn't need to be on the main thread. + + Make JSContext @class and JavaScriptCore::JSContextRef + "JavaScript" Remote Debuggables. + + * inspector/remote/RemoteInspectorDebuggable.h: Added. + * inspector/remote/RemoteInspectorDebuggable.cpp: Added. + (Inspector::RemoteInspectorDebuggable::RemoteInspectorDebuggable): + (Inspector::RemoteInspectorDebuggable::~RemoteInspectorDebuggable): + (Inspector::RemoteInspectorDebuggable::init): + (Inspector::RemoteInspectorDebuggable::update): + (Inspector::RemoteInspectorDebuggable::setRemoteDebuggingAllowed): + (Inspector::RemoteInspectorDebuggable::info): + RemoteInspectorDebuggable defines a debuggable target. As long as + something creates a debuggable and is set to allow remote inspection + it will be listed in remote debuggers. For the different types of + debuggables (JavaScript and Web) there is different basic information + that may be listed. + + * inspector/InspectorFrontendChannel.h: Added. + (Inspector::InspectorFrontendChannel::~InspectorFrontendChannel): + The only thing a debuggable needs for remote debugging is an + InspectorFrontendChannel a way to send messages to a remote frontend. + This class provides that method, and is vended to the + RemoteInspectorDebuggable when a remote connection is setup. + + * inspector/remote/RemoteInspector.h: Added. + * inspector/remote/RemoteInspector.mm: Added. + Singleton, created at least when the first Debuggable is created. + This class manages the list of debuggables, any connection to a + remote debugger proxy (XPC service "com.apple.webinspector"). + + (Inspector::dispatchAsyncOnQueueSafeForAnyDebuggable): + (Inspector::RemoteInspector::shared): + (Inspector::RemoteInspector::RemoteInspector): + (Inspector::RemoteInspector::nextAvailableIdentifier): + (Inspector::RemoteInspector::registerDebuggable): + (Inspector::RemoteInspector::unregisterDebuggable): + (Inspector::RemoteInspector::updateDebuggable): + Debuggable management. When debuggables are added, removed, or updated + we stash a copy of the debuggable information and push an update to + debuggers. Stashing a copy of the information in the RemoteInspector + is a thread safe way to avoid walking over all debuggables to gather + the information when it is needed. + + (Inspector::RemoteInspector::start): + (Inspector::RemoteInspector::stop): + Runtime API to enable / disable the feature. + + (Inspector::RemoteInspector::listingForDebuggable): + (Inspector::RemoteInspector::pushListingNow): + (Inspector::RemoteInspector::pushListingSoon): + Pushing a listing to remote debuggers. + + (Inspector::RemoteInspector::sendMessageToRemoteFrontend): + (Inspector::RemoteInspector::setupXPCConnectionIfNeeded): + (Inspector::RemoteInspector::xpcConnectionReceivedMessage): + (Inspector::RemoteInspector::xpcConnectionFailed): + (Inspector::RemoteInspector::xpcConnectionUnhandledMessage): + XPC setup, send, and receive handling. + + (Inspector::RemoteInspector::updateHasActiveDebugSession): + Applications being debugged may want to know when a debug + session is active. This provides that notification. + + (Inspector::RemoteInspector::receivedSetupMessage): + (Inspector::RemoteInspector::receivedDataMessage): + (Inspector::RemoteInspector::receivedDidCloseMessage): + (Inspector::RemoteInspector::receivedGetListingMessage): + (Inspector::RemoteInspector::receivedIndicateMessage): + (Inspector::RemoteInspector::receivedConnectionDiedMessage): + Dispatching incoming remote debugging protocol messages. + These are wrapping above the inspector protocol messages. + + * inspector/remote/RemoteInspectorConstants.h: Added. + Protocol messages and dictionary keys inside the messages. + + (Inspector::RemoteInspectorDebuggableInfo::RemoteInspectorDebuggableInfo): + * inspector/remote/RemoteInspectorDebuggableConnection.h: Added. + * inspector/remote/RemoteInspectorDebuggableConnection.mm: Added. + This is a connection between the RemoteInspector singleton and a RemoteInspectorDebuggable. + + (Inspector::RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection): + (Inspector::RemoteInspectorDebuggableConnection::~RemoteInspectorDebuggableConnection): + Allow for dispatching messages on JavaScript debuggables on a dispatch_queue + instead of the main queue. + + (Inspector::RemoteInspectorDebuggableConnection::destination): + (Inspector::RemoteInspectorDebuggableConnection::connectionIdentifier): + Needed in the remote debugging protocol to identify the remote debugger. + + (Inspector::RemoteInspectorDebuggableConnection::dispatchSyncOnDebuggable): + (Inspector::RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable): + (Inspector::RemoteInspectorDebuggableConnection::setup): + (Inspector::RemoteInspectorDebuggableConnection::closeFromDebuggable): + (Inspector::RemoteInspectorDebuggableConnection::close): + (Inspector::RemoteInspectorDebuggableConnection::sendMessageToBackend): + (Inspector::RemoteInspectorDebuggableConnection::sendMessageToFrontend): + The connection is a thin channel between the two sides that can be closed + from either side, so there is some logic around multi-threaded access. + + * inspector/remote/RemoteInspectorXPCConnection.h: Added. + (Inspector::RemoteInspectorXPCConnection::Client::~Client): + * inspector/remote/RemoteInspectorXPCConnection.mm: Added. + (Inspector::RemoteInspectorXPCConnection::RemoteInspectorXPCConnection): + (Inspector::RemoteInspectorXPCConnection::~RemoteInspectorXPCConnection): + (Inspector::RemoteInspectorXPCConnection::close): + (Inspector::RemoteInspectorXPCConnection::deserializeMessage): + (Inspector::RemoteInspectorXPCConnection::handleEvent): + (Inspector::RemoteInspectorXPCConnection::sendMessage): + This is a connection between the RemoteInspector singleton and an XPC service + named "com.apple.webinspector". This handles serialization of the dictionary + messages to and from the service. The receiving is done on a non-main queue. + + * API/JSContext.h: + * API/JSContext.mm: + (-[JSContext name]): + (-[JSContext setName:]): + ObjC API to enable/disable JSContext remote inspection and give a name. + + * API/JSContextRef.h: + * API/JSContextRef.cpp: + (JSGlobalContextGetName): + (JSGlobalContextSetName): + C API to give a JSContext a name. -2012-04-19 Filip Pizlo + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::setName): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::name): + Shared handling of the APIs above. + + * runtime/JSGlobalObjectDebuggable.cpp: Added. + (JSC::JSGlobalObjectDebuggable::JSGlobalObjectDebuggable): + (JSC::JSGlobalObjectDebuggable::name): + (JSC::JSGlobalObjectDebuggable::connect): + (JSC::JSGlobalObjectDebuggable::disconnect): + (JSC::JSGlobalObjectDebuggable::dispatchMessageFromRemoteFrontend): + * runtime/JSGlobalObjectDebuggable.h: Added. + Stub for the actual remote debugging implementation. We will push + down the appropriate WebCore/inspector peices suitable for debugging + just a JavaScript context. - LLInt no-JIT fallback native call trampoline's exception handler incorrectly assumes that - the PB/PC has been preserved - https://bugs.webkit.org/show_bug.cgi?id=84367 + * CMakeLists.txt: + * JavaScriptCore.xcodeproj/project.pbxproj: + * GNUmakefile.am: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + Update build files. - Reviewed by Oliver Hunt. +2013-12-04 Michael Saboff - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: + Move the setting up of callee's callFrame from pushFrame to callToJavaScript thunk + https://bugs.webkit.org/show_bug.cgi?id=123999 -2012-04-19 Filip Pizlo + Reviewed by Filip Pizlo. - It should be possible to load from Float64 arrays on ARMv7 without crashing - https://bugs.webkit.org/show_bug.cgi?id=84361 + Changed LLInt and/or JIT enabled ports to allocate the stack frame in the + callToJavaScript stub. Added an additional stub, callToNativeFunction that + allocates a stack frame in a similar way for calling native entry points + that take a single ExecState* argument. These stubs are implemented + using common macros in LowLevelInterpreter{32_64,64}.asm. There are also + Windows X86 and X86-64 versions in the corresponding JitStubsXX.h. + The stubs allocate and create a sentinel frame, then create the callee's + frame, populating the header and arguments from the passed in ProtoCallFrame*. + It is assumed that the caller of either stub does a check for enough stack space + via JSStack::entryCheck(). - Reviewed by Oliver Hunt. + For ports using the C-Loop interpreter, the prior method for allocating stack + frame and invoking functions is used, namely with JSStack::pushFrame() and + ::popFrame(). - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::loadDouble): - (JSC::MacroAssemblerARMv7::storeDouble): + Made spelling changes "sentinal" -> "sentinel". -2012-04-19 Dominik Röttsches + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * interpreter/CachedCall.h: + (JSC::CachedCall::CachedCall): + (JSC::CachedCall::setThis): + (JSC::CachedCall::setArgument): + * interpreter/CallFrameClosure.h: + (JSC::CallFrameClosure::resetCallFrame): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::prepareForRepeatCall): + * interpreter/Interpreter.h: + * interpreter/JSStack.h: + * interpreter/JSStackInlines.h: + (JSC::JSStack::entryCheck): + (JSC::JSStack::pushFrame): + (JSC::JSStack::popFrame): + * interpreter/ProtoCallFrame.cpp: Added. + (JSC::ProtoCallFrame::init): + * interpreter/ProtoCallFrame.h: Added. + (JSC::ProtoCallFrame::codeBlock): + (JSC::ProtoCallFrame::setCodeBlock): + (JSC::ProtoCallFrame::setScope): + (JSC::ProtoCallFrame::setCallee): + (JSC::ProtoCallFrame::argumentCountIncludingThis): + (JSC::ProtoCallFrame::argumentCount): + (JSC::ProtoCallFrame::setArgumentCountIncludingThis): + (JSC::ProtoCallFrame::setPaddedArgsCount): + (JSC::ProtoCallFrame::clearCurrentVPC): + (JSC::ProtoCallFrame::setThisValue): + (JSC::ProtoCallFrame::setArgument): + * jit/JITCode.cpp: + (JSC::JITCode::execute): + * jit/JITCode.h: + * jit/JITOperations.cpp: + * jit/JITStubs.h: + * jit/JITStubsMSVC64.asm: + * jit/JITStubsX86.h: + * llint/LLIntOffsetsExtractor.cpp: + * llint/LLIntThunks.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/ArgList.h: + (JSC::ArgList::data): + * runtime/JSArray.cpp: + (JSC::AVLTreeAbstractorForArrayCompare::compare_key_key): + * runtime/StringPrototype.cpp: + (JSC::replaceUsingRegExpSearch): - [CMake] Build fix after r114575 - https://bugs.webkit.org/show_bug.cgi?id=84322 +2013-12-04 László Langó - Reviewed by Simon Hausmann. + Remove stdio.h from JSC files. + https://bugs.webkit.org/show_bug.cgi?id=125220 - Build fix, adding WTF when linking jsc shell. + Reviewed by Michael Saboff. - * shell/CMakeLists.txt: + * interpreter/VMInspector.cpp: + * jit/JITArithmetic.cpp: + * jit/JITArithmetic32_64.cpp: + * jit/JITCall.cpp: + * jit/JITCall32_64.cpp: + * jit/JITPropertyAccess.cpp: + * jit/JITPropertyAccess32_64.cpp: + * runtime/Completion.cpp: + * runtime/IndexingType.cpp: + * runtime/Lookup.h: + * runtime/Operations.cpp: + * runtime/Options.cpp: + * runtime/RegExp.cpp: -2012-04-18 Filip Pizlo +2013-12-04 László Langó - JSC testing should have complete coverage over typed array types - https://bugs.webkit.org/show_bug.cgi?id=84302 + Avoid to add zero offset in BaseIndex. + https://bugs.webkit.org/show_bug.cgi?id=125215 - Reviewed by Geoff Garen. - - Added Uint8ClampedArray to the set of typed arrays that are supported by jsc - command-line. + Reviewed by Michael Saboff. - * JSCTypedArrayStubs.h: - (JSC): - * jsc.cpp: - (GlobalObject::finishCreation): + When using cloop do not generate offsets additions for BaseIndex if the offset is zero. -2012-04-18 Filip Pizlo + * offlineasm/cloop.rb: - jsc command line should support typed arrays by default - https://bugs.webkit.org/show_bug.cgi?id=84298 +2013-12-04 Peter Molnar - Rubber stamped by Gavin Barraclough. + Fix !ENABLE(JAVASCRIPT_DEBUGGER) build. + https://bugs.webkit.org/show_bug.cgi?id=125083 - * JSCTypedArrayStubs.h: - (JSC): - * jsc.cpp: - (GlobalObject::finishCreation): + Reviewed by Mark Lam. -2012-04-18 Filip Pizlo + * debugger/Debugger.cpp: + * debugger/Debugger.h: + (JSC::Debugger::Debugger): + (JSC::Debugger::needsOpDebugCallbacks): + (JSC::Debugger::needsExceptionCallbacks): + (JSC::Debugger::detach): + (JSC::Debugger::sourceParsed): + (JSC::Debugger::exception): + (JSC::Debugger::atStatement): + (JSC::Debugger::callEvent): + (JSC::Debugger::returnEvent): + (JSC::Debugger::willExecuteProgram): + (JSC::Debugger::didExecuteProgram): + (JSC::Debugger::didReachBreakpoint): + * debugger/DebuggerPrimitives.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_debug): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_debug): + * llint/LLIntOfflineAsmConfig.h: + * llint/LowLevelInterpreter.asm: - JSVALUE32_64 should be able to perform division on ARM without crashing, and variables - forced double should not be scrambled when performing OSR entry - https://bugs.webkit.org/show_bug.cgi?id=84272 +2013-12-03 Mark Lam - Reviewed by Geoff Garen. + testapi test crashes on Windows in WTF::Vector::size(). + https://bugs.webkit.org/show_bug.cgi?id=121972. - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGOSREntry.cpp: - (JSC::DFG::prepareOSREntry): + Reviewed by Brent Fulgham. -2012-04-18 Don Olmstead + * interpreter/JSStack.cpp: + (JSC::JSStack::~JSStack): + - Reverting the change from r160004 since it's better to fix OSAllocatorWin + to be consistent with OSAllocatorPosix. - JavaScriptCore.gypi not current - https://bugs.webkit.org/show_bug.cgi?id=84224 +2013-12-03 Mark Lam - Reviewed by Eric Seidel. + Fix LLINT_C_LOOP build for Win64. + https://bugs.webkit.org/show_bug.cgi?id=125186. - Updated JavaScriptCore.gypi to contain the latest sources. Removed os-win32 as it wasn't used. Also removed references to ICU files in the gypi file as ICU is most likely specified by the port itself. + Reviewed by Michael Saboff. - Private and public header files were determined by looking at copy-files.cmd within Apple's Visual Studio directory. + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * jit/JITOperationsMSVC64.cpp: Added. + (JSC::getHostCallReturnValueWithExecState): + - Win64 will build JITStubMSVC64.asm even when !ENABLE(JIT). This results + in a linkage error due to a missing getHostCallReturnValueWithExecState(). + So, we add a stub getHostCallReturnValueWithExecState() here to satisfy + that linkage. This function will never be called. + The alternative to providing such a stub is to make the MSVC project + recognize if the JIT is enabled or not, and exclude JITStubMSVC64.asm + if it's not enabled. We don't currently set ENABLE(JIT) via the MSVC + project and the work to do that is too much trouble for what we're trying + to achieve here. So, we're opting for this simpler workaround instead. - * JavaScriptCore.gypi: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter.cpp: + (JSC::CLoop::execute): + - Don't build callToJavaScript if we're building the C loop. Otherwise, + the C loop won't build if !ENABLE(COMPUTE_GOTO_OPCODES). -2012-04-18 Benjamin Poulain +2013-12-03 Michael Saboff - Remove m_subclassData from JSArray, move the attribute to subclass as needed - https://bugs.webkit.org/show_bug.cgi?id=84249 + ARM64: Crash in JIT code due to improper reuse of cached memory temp register + https://bugs.webkit.org/show_bug.cgi?id=125181 Reviewed by Geoffrey Garen. - JSArray's m_subclassData is only used by WebCore's RuntimeArray. This patch moves - the attribute to RuntimeArray to avoid allocating memory for the pointer in the common - case. + Changed load8() and load() to invalidate the memory temp CachedTempRegister when the + destination of an absolute load is the memory temp register since the source address + is also the memory temp register. Change branch{8,32,64} of an AbsoluteAddress with + a register to use the dataTempRegister as the destinate of the absolute load to + reduce the chance that we need to invalidate the memory temp register cache. + In the process, found and fixed an outright bug in branch8() where we'd load into + the data temp register and then compare and branch on the memory temp register. - This gives ~1% improvement in JSArray creation microbenchmark thanks to fewer allocations - of CopiedSpace. + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::load8): + (JSC::MacroAssemblerARM64::branch32): + (JSC::MacroAssemblerARM64::branch64): + (JSC::MacroAssemblerARM64::branch8): + (JSC::MacroAssemblerARM64::load): - * jit/JITInlineMethods.h: - (JSC::JIT::emitAllocateJSArray): - * runtime/JSArray.cpp: - (JSC::JSArray::JSArray): - * runtime/JSArray.h: +2013-12-03 Michael Saboff -2012-04-18 Benjamin Poulain + jit/JITArithmetic.cpp doesn't build for non-X86 ports + https://bugs.webkit.org/show_bug.cgi?id=125185 - replaceUsingStringSearch: delay the creation of the replace string until needed - https://bugs.webkit.org/show_bug.cgi?id=83841 + Rubber stamped by Mark Hahnenberg. - Reviewed by Geoffrey Garen. + Removed unused declarations and related UNUSED_PARAM(). - We do not need to obtain the replaceValue until we have a match. By moving the intialization - of replaceValue when needed, we save a few instructions when there is no match. + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_mod): - * runtime/StringPrototype.cpp: - (JSC::replaceUsingRegExpSearch): - (JSC::replaceUsingStringSearch): - (JSC::stringProtoFuncReplace): +2013-12-03 Filip Pizlo -2012-04-18 Mark Hahnenberg + ObjectAllocationProfile is racy and the DFG should be cool with that + https://bugs.webkit.org/show_bug.cgi?id=125172 + - GC activity timer should be tied to allocation, not collection - https://bugs.webkit.org/show_bug.cgi?id=83919 + Reviewed by Mark Hahnenberg. + + We would previously sometimes get a null Structure because checking if the profile is non-null and loading + the structure from it were two separate operations. - Reviewed by Geoffrey Garen. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::setFuturePossibleStructure): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * runtime/JSFunction.h: + (JSC::JSFunction::allocationProfile): + (JSC::JSFunction::allocationStructure): - * API/JSContextRef.cpp: Used the new didAbandonObjectGraph callback to indicate that now that we've - released a global object, we're abandoning a potentially large number of objects that JSC might want - to collect. - * heap/CopiedSpace.cpp: - (JSC::CopiedSpace::tryAllocateSlowCase): Added the call to timer's willAllocate function to indicate - that we've hit a slow path and are allocating now, so schedule the timer. - * heap/Heap.cpp: - (JSC::Heap::Heap): - (JSC::Heap::collectAllGarbage): Removed the call to discardAllCompiledCode because it was causing us to - throw away too much code during our benchmarks (especially vp8, which is very large and thus has large - amounts of compiled code). - (JSC::Heap::collect): Added the new call to didCollect at the conclusion of a collection so that we - can cancel the timer if we no longer need to run a collection. Also added a check at the beginning of a - collection to see if we should throw away our compiled code. Currently this is set to happen about once - every minute. - * heap/Heap.h: Added field to keep track of the last time we threw away our compiled code. - * heap/MarkedAllocator.cpp: - (JSC::MarkedAllocator::allocateSlowCase): Added call to willAllocate on the allocation slow path, just like - in CopiedSpace. - * runtime/GCActivityCallback.cpp: Added default stubs for non-CF platforms. - (JSC::DefaultGCActivityCallback::willAllocate): - (JSC): - (JSC::DefaultGCActivityCallback::didCollect): - (JSC::DefaultGCActivityCallback::didAbandonObjectGraph): - * runtime/GCActivityCallback.h: Added new functions to make JSC's GC timer less arcane. This includes replacing - the operator () with willAllocate() and adding an explicit didCollect() to cancel the timer after a collection - occurs rather than relying on the way the timer is invoked to cancel itself. Also added a callback for - when somebody else (e.g. WebCore or the JSC API) to notify JSC that they have just abandoned an entire graph of - objects and that JSC might want to clean them up. - (JSC::GCActivityCallback::~GCActivityCallback): - (JSC::GCActivityCallback::willAllocate): - (JSC::GCActivityCallback::didCollect): - (JSC::GCActivityCallback::didAbandonObjectGraph): - (JSC::GCActivityCallback::synchronize): - (DefaultGCActivityCallback): - * runtime/GCActivityCallbackCF.cpp: Re-wired all the run loop stuff to implement the aforementioned functions. - We added a flag to check whether the timer was active because the call to CFRunLoopTimerSetNextFireDate actually - turned out to be quite expensive (although Instruments couldn't tell us this). - (DefaultGCActivityCallbackPlatformData): - (JSC): - (JSC::DefaultGCActivityCallbackPlatformData::timerDidFire): - (JSC::DefaultGCActivityCallback::commonConstructor): - (JSC::scheduleTimer): - (JSC::cancelTimer): - (JSC::DefaultGCActivityCallback::willAllocate): - (JSC::DefaultGCActivityCallback::didCollect): - (JSC::DefaultGCActivityCallback::didAbandonObjectGraph): - -2012-04-17 Filip Pizlo - - DFG should not attempt to get rare case counts for op_mod on ARM - https://bugs.webkit.org/show_bug.cgi?id=84218 +2013-12-03 peavo@outlook.com - Reviewed by Geoff Garen. + testapi test crashes on Windows in WTF::Vector::size() + https://bugs.webkit.org/show_bug.cgi?id=121972 - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::makeSafe): - * dfg/DFGCommon.h: - (JSC::DFG::isX86): - (DFG): + Reviewed by Michael Saboff. -2012-04-17 Myles Maxfield + The reason for the crash is that the wrong memory block is decommitted. + This can happen if no memory has been committed in the reserved block before the JSStack object is destroyed. + In the JSStack destructor, the pointer to decommit then points to the end of the block (or the start of the next), and the decommit size is zero. + If there is a block just after the block we are trying to decommit, this block will be decommitted, since Windows will decommit the whole block, + if the decommit size is zero (see VirtualFree). When somebody tries to read/write to this block later, we crash. - BumpPointerAllocator assumes page size is less than MINIMUM_BUMP_POOL_SIZE - https://bugs.webkit.org/show_bug.cgi?id=80912 + * interpreter/JSStack.cpp: + (JSC::JSStack::~JSStack): Don't decommit memory if nothing has been committed. - Reviewed by Hajime Morita. +2013-12-03 László Langó - * wtf/BumpPointerAllocator.h: - (WTF::BumpPointerPool::create): + Guard JIT include. + https://bugs.webkit.org/show_bug.cgi?id=125063 -2012-04-17 Filip Pizlo + Reviewed by Filip Pizlo. - Attempt to fix Windows build. + * llint/LLIntThunks.cpp: - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: +2013-12-03 Julien Brianceau -2012-04-17 Filip Pizlo + Merge mips and arm/sh4 paths in nativeForGenerator and privateCompileCTINativeCall functions. + https://bugs.webkit.org/show_bug.cgi?id=125067 - It should be possible to create an inheritorID for the global this object without crashing - https://bugs.webkit.org/show_bug.cgi?id=84200 - + Reviewed by Michael Saboff. - Reviewed by Oliver Hunt. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTINativeCall): + * jit/ThunkGenerators.cpp: + (JSC::nativeForGenerator): + +2013-12-02 Mark Lam + + Build failure when disabling JIT, YARR_JIT, and ASSEMBLER. + https://bugs.webkit.org/show_bug.cgi?id=123809. + + Reviewed by Geoffrey Garen. + + Also fixed build when disabling the DISASSEMBLER. + Added some needed #if's and some comments. + + * assembler/LinkBuffer.cpp: + (JSC::LinkBuffer::finalizeCodeWithDisassembly): + * dfg/DFGDisassembler.cpp: + * dfg/DFGDisassembler.h: + (JSC::DFG::Disassembler::Disassembler): + (JSC::DFG::Disassembler::setStartOfCode): + (JSC::DFG::Disassembler::setForBlockIndex): + (JSC::DFG::Disassembler::setForNode): + (JSC::DFG::Disassembler::setEndOfMainPath): + (JSC::DFG::Disassembler::setEndOfCode): + (JSC::DFG::Disassembler::dump): + (JSC::DFG::Disassembler::reportToProfiler): + * disassembler/Disassembler.cpp: + * disassembler/X86Disassembler.cpp: + * jit/FPRInfo.h: + * jit/GPRInfo.h: + * jit/JITDisassembler.cpp: + * jit/JITDisassembler.h: + (JSC::JITDisassembler::JITDisassembler): + (JSC::JITDisassembler::setStartOfCode): + (JSC::JITDisassembler::setForBytecodeMainPath): + (JSC::JITDisassembler::setForBytecodeSlowPath): + (JSC::JITDisassembler::setEndOfSlowPath): + (JSC::JITDisassembler::setEndOfCode): + (JSC::JITDisassembler::dump): + (JSC::JITDisassembler::reportToProfiler): + +2013-12-02 Filip Pizlo + + Baseline JIT calls to CommonSlowPaths shouldn't restore the last result + https://bugs.webkit.org/show_bug.cgi?id=125107 + + Reviewed by Mark Hahnenberg. + + Just killing dead code. - * runtime/JSGlobalThis.cpp: - (JSC::JSGlobalThis::setUnwrappedObject): - * runtime/JSGlobalThis.h: - (JSC::JSGlobalThis::unwrappedObject): - (JSGlobalThis): - * runtime/JSObject.cpp: - (JSC::JSObject::createInheritorID): - * runtime/JSObject.h: - (JSObject): - (JSC::JSObject::resetInheritorID): + * jit/JITArithmetic.cpp: + (JSC::JIT::emitSlow_op_negate): + (JSC::JIT::emitSlow_op_lshift): + (JSC::JIT::emitSlow_op_rshift): + (JSC::JIT::emitSlow_op_urshift): + (JSC::JIT::emitSlow_op_bitand): + (JSC::JIT::emitSlow_op_inc): + (JSC::JIT::emitSlow_op_dec): + (JSC::JIT::emitSlow_op_mod): + (JSC::JIT::emit_op_mod): + (JSC::JIT::compileBinaryArithOpSlowCase): + (JSC::JIT::emitSlow_op_div): + * jit/JITArithmetic32_64.cpp: + (JSC::JIT::emitSlow_op_negate): + (JSC::JIT::emitSlow_op_lshift): + (JSC::JIT::emitRightShiftSlowCase): + (JSC::JIT::emitSlow_op_bitand): + (JSC::JIT::emitSlow_op_bitor): + (JSC::JIT::emitSlow_op_bitxor): + (JSC::JIT::emitSlow_op_inc): + (JSC::JIT::emitSlow_op_dec): + (JSC::JIT::emitSlow_op_add): + (JSC::JIT::emitSlow_op_sub): + (JSC::JIT::emitSlow_op_mul): + (JSC::JIT::emitSlow_op_div): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_strcat): + (JSC::JIT::emitSlow_op_get_callee): + (JSC::JIT::emitSlow_op_create_this): + (JSC::JIT::emitSlow_op_to_this): + (JSC::JIT::emitSlow_op_to_primitive): + (JSC::JIT::emitSlow_op_not): + (JSC::JIT::emitSlow_op_bitxor): + (JSC::JIT::emitSlow_op_bitor): + (JSC::JIT::emitSlow_op_stricteq): + (JSC::JIT::emitSlow_op_nstricteq): + (JSC::JIT::emitSlow_op_to_number): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emitSlow_op_to_primitive): + (JSC::JIT::emitSlow_op_not): + (JSC::JIT::emitSlow_op_stricteq): + (JSC::JIT::emitSlow_op_nstricteq): + (JSC::JIT::emitSlow_op_to_number): + (JSC::JIT::emitSlow_op_get_callee): + (JSC::JIT::emitSlow_op_create_this): + (JSC::JIT::emitSlow_op_to_this): -2012-04-17 Filip Pizlo +2013-12-01 Filip Pizlo - DFG and LLInt should not clobber the frame pointer on ARMv7 - https://bugs.webkit.org/show_bug.cgi?id=84185 - + Stores to local captured variables should be intercepted + https://bugs.webkit.org/show_bug.cgi?id=124883 - Reviewed by Gavin Barraclough. + Reviewed by Mark Hahnenberg. + + Previously, in bytecode, you could assign to a captured variable just as you would + assign to any other kind of variable. This complicates closure variable constant + inference because we don't have any place where we can intercept stores to captured + variables in the LLInt. + + This patch institutes a policy that only certain instructions can store to captured + variables. If you interpret those instructions and you are required to notifyWrite() + then you need to check if the relevant variable is captured. Those instructions are + tracked in CodeBlock.cpp's VerifyCapturedDef. The main one is simply op_captured_mov. + In the future, we'll probably modify those instructions to have a pointer directly to + the VariableWatchpointSet; but for now we just introduce the captured instructions as + placeholders. + + In order to validate that the placeholders are inserted correctly, this patch improves + the CodeBlock validation to be able to inspect every def in the bytecode. To do that, + this patch refactors the liveness analysis' use/def calculator to be reusable; it now + takes a functor for each use or def. - Changed LLInt to use a different register. Changed DFG to use one fewer - registers. We should revisit this and switch the DFG to use a different - register instead of r7, but we can do that in a subsequent step since - the performance effect is tiny. + In the process of refactoring the liveness analysis, I noticed that op_enter was + claiming to def all callee registers. That's wrong; it only defs the non-temporary + variables. Making that change revealed preexisting bugs in the liveness analysis, since + now the validator would pick up cases where the bytecode claimed to use a temporary and + the def calculator never noticed the definition (or the converse - where the bytecode + was actually not using a temporary but the liveness analysis thought that it was a + use). This patch fixes a few of those bugs. - * dfg/DFGGPRInfo.h: - (GPRInfo): - (JSC::DFG::GPRInfo::toRegister): - (JSC::DFG::GPRInfo::toIndex): - * offlineasm/armv7.rb: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeLivenessAnalysis.cpp: + (JSC::stepOverInstruction): + * bytecode/BytecodeUseDef.h: Added. + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::isCaptured): + (JSC::CodeBlock::validate): + * bytecode/CodeBlock.h: + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::resolveCallee): + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::isCaptured): + (JSC::BytecodeGenerator::local): + (JSC::BytecodeGenerator::constLocal): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitLazyNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + * bytecompiler/BytecodeGenerator.h: + (JSC::Local::Local): + (JSC::Local::isCaptured): + (JSC::Local::captureMode): + (JSC::BytecodeGenerator::captureMode): + (JSC::BytecodeGenerator::emitNode): + (JSC::BytecodeGenerator::pushOptimisedForIn): + * bytecompiler/NodesCodegen.cpp: + (JSC::PostfixNode::emitResolve): + (JSC::PrefixNode::emitResolve): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::ForInNode::emitBytecode): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/SymbolTable.h: + (JSC::SymbolTable::isCaptured): -2012-04-17 Filip Pizlo +2013-12-02 Filip Pizlo - use after free in JSC::DFG::Node::op / JSC::DFG::ByteCodeParser::flushArgument - https://bugs.webkit.org/show_bug.cgi?id=83942 - + Instead of watchpointing activation allocation, we should watchpoint entry into functions that have captured variables + https://bugs.webkit.org/show_bug.cgi?id=125052 - Reviewed by Gavin Barraclough. + Reviewed by Mark Hahnenberg. - Don't use references to the graph after resizing the graph. + This makes us watch function entry rather than activation creation. We only incur the + costs of doing so for functions that have captured variables, and only on the first two + entries into the function. This means that closure variable constant inference will + naturally work even for local uses of the captured variable, like: + + (function(){ + var blah = 42; + ... // stuff + function () { ... blah /* we can fold this to 42 */ } + ... blah // we can also fold this to 42. + })(); + + Previously, only the nested use would have been foldable. + * bytecode/BytecodeLivenessAnalysis.cpp: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecode/Watchpoint.h: + (JSC::WatchpointSet::touch): + (JSC::InlineWatchpointSet::touch): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::flushArgument): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasSymbolTable): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_touch_entry): + * llint/LowLevelInterpreter.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/JSActivation.h: + (JSC::JSActivation::create): + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::SymbolTable): + * runtime/SymbolTable.h: -2012-04-16 Gavin Barraclough +2013-12-02 Nick Diego Yamane - Array.prototype.toString should be generic - https://bugs.webkit.org/show_bug.cgi?id=81588 + [JSC] Get rid of some unused parameters in LLIntSlowPaths.cpp macros + https://bugs.webkit.org/show_bug.cgi?id=125075 - Reviewed by Sam Weinig. + Reviewed by Michael Saboff. - * runtime/ArrayPrototype.cpp: - (JSC::arrayProtoFuncToString): - - check for join function, use fast case if base object is array & join is present & default. - * runtime/CommonIdentifiers.h: - - added 'join'. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::handleHostCall): added UNUSED_PARAM(pc). + (JSC::LLInt::setUpCall): Doesn't pass 'pc' to LLINT_CALL macros. + (JSC::LLInt::LLINT_SLOW_PATH_DECL): Ditto. -2012-04-16 Carlos Garcia Campos +2013-12-02 László Langó - Unreviewed. Fix make distcheck issues. + Remove stdio.h from JSC files. + https://bugs.webkit.org/show_bug.cgi?id=125066 - * GNUmakefile.list.am: Add missing files. + Reviewed by Michael Saboff. -2012-04-16 Sheriff Bot + Remove stdio.h, when it is not necessary to be included. - Unreviewed, rolling out r114309. - http://trac.webkit.org/changeset/114309 - https://bugs.webkit.org/show_bug.cgi?id=84097 + * bytecode/CodeBlock.cpp: + * bytecode/StructureSet.h: + * profiler/LegacyProfiler.cpp: + * profiler/Profile.cpp: + * profiler/ProfileNode.cpp: + * yarr/YarrInterpreter.cpp: - it broke everything (Requested by olliej on #webkit). +2013-12-02 László Langó - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: - * bytecode/CodeBlock.h: - * dfg/DFGOperations.cpp: - * interpreter/Interpreter.cpp: - (JSC::Interpreter::getStackTrace): - (JSC::Interpreter::throwException): - * interpreter/Interpreter.h: - (Interpreter): - * jit/JITStubs.cpp: - (JSC::DEFINE_STUB_FUNCTION): - * jsc.cpp: - (functionJSCStack): - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::handleHostCall): - * parser/Parser.h: - (JSC::::parse): - * runtime/Error.cpp: - (JSC::addErrorInfo): - (JSC::throwError): - * runtime/Error.h: - (JSC): - -2012-04-16 Oliver Hunt - - Exception stack traces aren't complete when the exception starts in native code - https://bugs.webkit.org/show_bug.cgi?id=84073 - - Reviewed by Gavin Barraclough. - - Refactored building the stack trace to so that we can construct - it earlier, and don't rely on any prior work performed in the - exception handling machinery. Also updated LLInt and the DFG to - completely initialise the callframes of host function calls. - - * bytecode/CodeBlock.h: - (JSC::CodeBlock::codeOriginIndexForReturn): - (CodeBlock): - * dfg/DFGOperations.cpp: - * interpreter/Interpreter.cpp: - (JSC::Interpreter::getStackTrace): - (JSC::Interpreter::addStackTraceIfNecessary): - (JSC): - (JSC::Interpreter::throwException): - * interpreter/Interpreter.h: - (Interpreter): - * jit/JITStubs.cpp: - (JSC::DEFINE_STUB_FUNCTION): - * jsc.cpp: - (functionJSCStack): - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::handleHostCall): - * parser/Parser.h: - (JSC::::parse): - * runtime/Error.cpp: - (JSC::addErrorInfo): - (JSC::throwError): - * runtime/Error.h: - (JSC): - -2012-04-16 Oliver Hunt - - Fix COMMANDLINE_TYPEDARRAYS build - https://bugs.webkit.org/show_bug.cgi?id=84051 - - Reviewed by Gavin Barraclough. - - Update for new putByIndex API and wtf changes. + Unused include files when building without JIT. + https://bugs.webkit.org/show_bug.cgi?id=125062 - * JSCTypedArrayStubs.h: - (JSC): - -2012-04-16 Mark Hahnenberg + Reviewed by Michael Saboff. - GC in the middle of JSObject::allocatePropertyStorage can cause badness - https://bugs.webkit.org/show_bug.cgi?id=83839 + We should organize the includes, and guard JIT methods + in ValueRecovery. - Reviewed by Geoffrey Garen. + * bytecode/ValueRecovery.cpp: Guard include files. + * bytecode/ValueRecovery.h: Guard JIT methods. - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: - * jit/JITStubs.cpp: Making changes to use the new return value of growPropertyStorage. - (JSC::DEFINE_STUB_FUNCTION): - * runtime/JSObject.cpp: - (JSC::JSObject::growPropertyStorage): Renamed to more accurately reflect that we're - growing our already-existing PropertyStorage. - * runtime/JSObject.h: - (JSObject): - (JSC::JSObject::setPropertyStorage): "Atomically" sets the new property storage - and the new structure so that we can be sure a GC never occurs when our Structure - info is out of sync with our PropertyStorage. - (JSC): - (JSC::JSObject::putDirectInternal): Moved the check to see if we should - allocate more backing store before the actual property insertion into - the structure. - (JSC::JSObject::putDirectWithoutTransition): Ditto. - (JSC::JSObject::transitionTo): Ditto. - * runtime/Structure.cpp: - (JSC::Structure::suggestedNewPropertyStorageSize): Added to keep the resize policy - for property backing stores contained within the Structure class. - (JSC): - * runtime/Structure.h: - (JSC::Structure::shouldGrowPropertyStorage): Lets clients know if another insertion - into the Structure would require resizing the property backing store so that they can - preallocate the required storage. - (Structure): +2013-12-02 Balazs Kilvady -2012-04-13 Sheriff Bot + [MIPS] Small stack frame causes regressions. + https://bugs.webkit.org/show_bug.cgi?id=124945 - Unreviewed, rolling out r114185. - http://trac.webkit.org/changeset/114185 - https://bugs.webkit.org/show_bug.cgi?id=83967 + Reviewed by Michael Saboff. - Broke a bunch of JavaScript related tests (Requested by - andersca on #webkit). + Fix stack space for LLInt on MIPS. - * runtime/ArrayPrototype.cpp: - (JSC::arrayProtoFuncToString): - (JSC::arrayProtoFuncToLocaleString): - * runtime/CommonIdentifiers.h: - * tests/mozilla/ecma/Array/15.4.4.2.js: - (getTestCases): + * llint/LowLevelInterpreter32_64.asm: -2012-04-13 Gavin Barraclough +2013-12-02 Brian J. Burg - Don't rely on fixed offsets to patch calls - https://bugs.webkit.org/show_bug.cgi?id=83966 + jsc: implement a native readFile function + https://bugs.webkit.org/show_bug.cgi?id=125059 - Rubber stamped by Oliver Hunt. + Reviewed by Filip Pizlo. - These aren't being used anywhere! + This adds a native readFile() function to jsc, used to slurp + an entire file into a JavaScript string. - * jit/JIT.h: - * jit/JITCall.cpp: - (JSC::JIT::compileOpCall): - * jit/JITCall32_64.cpp: - (JSC::JIT::compileOpCall): + * jsc.cpp: + (GlobalObject::finishCreation): Add readFile() to globals. + (functionReadFile): Added. -2012-04-13 Hojong Han +2013-12-02 László Langó - Array.prototype.toString and Array.prototype.toLocaleString should be generic - https://bugs.webkit.org/show_bug.cgi?id=81588 + JSC does not build if OPCODE_STATS is enabled. + https://bugs.webkit.org/show_bug.cgi?id=125011 - Reviewed by Gavin Barraclough. + Reviewed by Filip Pizlo. - * runtime/ArrayPrototype.cpp: - (JSC::arrayProtoFuncToString): - (JSC::arrayProtoFuncToLocaleString): - * runtime/CommonIdentifiers.h: - * tests/mozilla/ecma/Array/15.4.4.2.js: - (getTestCases.array.item.new.TestCase): - (getTestCases): + * bytecode/Opcode.cpp: -2012-04-13 Gavin Barraclough +2013-11-29 Filip Pizlo - Don't rely on fixed offsets to patch method checks - https://bugs.webkit.org/show_bug.cgi?id=83958 + Finally remove those DFG_ENABLE things + https://bugs.webkit.org/show_bug.cgi?id=125025 - Reviewed by Oliver Hunt. + Rubber stamped by Sam Weinig. + + This removes a bunch of unused and untested insanity. - * bytecode/StructureStubInfo.h: - - Add fields for the method check info. + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::tallyFrequentExitSites): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation): + (JSC::DFG::ByteCodeParser::getArrayModeConsideringSlowPath): + (JSC::DFG::ByteCodeParser::makeSafe): + (JSC::DFG::ByteCodeParser::makeDivSafe): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::linkBlock): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + (JSC::DFG::ByteCodeParser::parse): + (JSC::DFG::parse): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::run): + (JSC::DFG::CFGSimplificationPhase::convertToJump): + (JSC::DFG::CFGSimplificationPhase::fixJettisonedPredecessors): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::endIndexForPureCSE): + (JSC::DFG::CSEPhase::eliminateIrrelevantPhantomChildren): + (JSC::DFG::CSEPhase::setReplacement): + (JSC::DFG::CSEPhase::eliminate): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGCommon.h: + (JSC::DFG::verboseCompilationEnabled): + (JSC::DFG::logCompilationChanges): + (JSC::DFG::shouldDumpGraphAtEachPhase): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::injectInt32ToDoubleNode): + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + (JSC::DFG::InPlaceAbstractState::endBasicBlock): + (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): + (JSC::DFG::InPlaceAbstractState::mergeToSuccessors): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compileBody): + (JSC::DFG::JITCompiler::link): + * dfg/DFGOSRExitCompiler.cpp: + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::adjustAndJumpToTarget): + * dfg/DFGPredictionInjectionPhase.cpp: + (JSC::DFG::PredictionInjectionPhase::run): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::run): + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::propagateForward): + (JSC::DFG::PredictionPropagationPhase::propagateBackward): + (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): + * dfg/DFGScoreBoard.h: + (JSC::DFG::ScoreBoard::use): + * dfg/DFGSlowPathGenerator.h: + (JSC::DFG::SlowPathGenerator::generate): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::terminateSpeculativeExecution): + (JSC::DFG::SpeculativeJIT::runSlowPathGenerators): + (JSC::DFG::SpeculativeJIT::dump): + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + (JSC::DFG::SpeculativeJIT::checkGeneratedTypeForToInt32): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGVariableEventStream.cpp: + (JSC::DFG::VariableEventStream::reconstruct): + * dfg/DFGVariableEventStream.h: + (JSC::DFG::VariableEventStream::appendAndLog): + * dfg/DFGVirtualRegisterAllocationPhase.cpp: + (JSC::DFG::VirtualRegisterAllocationPhase::run): * jit/JIT.cpp: - (JSC::PropertyStubCompilationInfo::copyToStubInfo): - - Store the offsets on the stub info, instead of asserting. - * jit/JIT.h: - - Delete all the method check related offsets. - * jit/JITPropertyAccess.cpp: - (JSC::JIT::patchMethodCallProto): - - Use the offset from the stubInfo. - * jit/JITStubs.cpp: - (JSC::DEFINE_STUB_FUNCTION): - - Pass the stubInfo to patchMethodCallProto. + (JSC::JIT::privateCompile): -2012-04-13 Gavin Barraclough +2013-11-29 Filip Pizlo - Don't rely on fixed offsets to patch get_by_id/put_by_id - https://bugs.webkit.org/show_bug.cgi?id=83924 + FTL IC should nop-fill to make up the difference between the actual IC size and the requested patchpoint size + https://bugs.webkit.org/show_bug.cgi?id=124960 - Reviewed by Oliver Hunt. + Reviewed by Sam Weinig. - Store offsets in the structure stub info, as we do for the DFG JIT. + * assembler/LinkBuffer.h: + (JSC::LinkBuffer::size): + * assembler/X86Assembler.h: + (JSC::X86Assembler::fillNops): + * dfg/DFGDisassembler.cpp: + (JSC::DFG::Disassembler::dumpHeader): + * ftl/FTLCompile.cpp: + (JSC::FTL::generateICFastPath): + * jit/JITDisassembler.cpp: + (JSC::JITDisassembler::dumpHeader): - * assembler/AbstractMacroAssembler.h: - (JSC::AbstractMacroAssembler::differenceBetween): - - this method can be static (now used from PropertyStubCompilationInfo::copyToStubInfo, will be removed soon!) - * bytecode/StructureStubInfo.h: - - added new fields for baseline JIT offsets. - * jit/JIT.cpp: - (JSC::PropertyStubCompilationInfo::copyToStubInfo): - - moved out from JIT::privateCompile. - (JSC::JIT::privateCompile): - - moved out code to PropertyStubCompilationInfo::copyToStubInfo. - * jit/JIT.h: - (PropertyStubCompilationInfo): - - added helper functions to initializae PropertyStubCompilationInfo, state to store more offset info. - - removed many offsets. - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emit_op_method_check): - (JSC::JIT::compileGetByIdHotPath): - (JSC::JIT::compileGetByIdSlowCase): - (JSC::JIT::emit_op_put_by_id): - (JSC::JIT::emitSlow_op_put_by_id): - (JSC::JIT::patchGetByIdSelf): - (JSC::JIT::patchPutByIdReplace): - (JSC::JIT::privateCompilePatchGetArrayLength): - (JSC::JIT::privateCompileGetByIdProto): - (JSC::JIT::privateCompileGetByIdSelfList): - (JSC::JIT::privateCompileGetByIdProtoList): - (JSC::JIT::privateCompileGetByIdChainList): - (JSC::JIT::privateCompileGetByIdChain): - (JSC::JIT::resetPatchGetById): - (JSC::JIT::resetPatchPutById): - - changed code generation to use new interface to store info on PropertyStubCompilationInfo. - - changed repatch functions to read offsets from the structure stub info. - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::emit_op_method_check): - (JSC::JIT::compileGetByIdHotPath): - (JSC::JIT::compileGetByIdSlowCase): - (JSC::JIT::emit_op_put_by_id): - (JSC::JIT::emitSlow_op_put_by_id): - (JSC::JIT::patchGetByIdSelf): - (JSC::JIT::patchPutByIdReplace): - (JSC::JIT::privateCompilePatchGetArrayLength): - (JSC::JIT::privateCompileGetByIdProto): - (JSC::JIT::privateCompileGetByIdSelfList): - (JSC::JIT::privateCompileGetByIdProtoList): - (JSC::JIT::privateCompileGetByIdChainList): - (JSC::JIT::privateCompileGetByIdChain): - (JSC::JIT::resetPatchGetById): - (JSC::JIT::resetPatchPutById): - - changed code generation to use new interface to store info on PropertyStubCompilationInfo. - - changed repatch functions to read offsets from the structure stub info. +2013-11-29 Julien Brianceau -2012-04-13 Rob Buis + Use moveDoubleToInts in SpecializedThunkJIT::returnDouble for non-X86 JSVALUE32_64 ports. + https://bugs.webkit.org/show_bug.cgi?id=124936 - Fix some compiler warnings (miscellaneous) - https://bugs.webkit.org/show_bug.cgi?id=80790 + Reviewed by Zoltan Herczeg. - Reviewed by Antonio Gomes. + The moveDoubleToInts implementations in ARM, MIPS and SH4 macro assemblers do not clobber + src FPRegister and are likely to be more efficient than the current generic implementation + using the stack. - Fix signed/unsigned comparison warning. + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::returnDouble): - * parser/Lexer.cpp: - (JSC::::record16): +2013-11-29 Julien Brianceau -2012-04-12 Benjamin Poulain + Merge arm and sh4 paths in nativeForGenerator and privateCompileCTINativeCall functions. + https://bugs.webkit.org/show_bug.cgi?id=124892 - Improve replaceUsingStringSearch() for case of a single character searchValue - https://bugs.webkit.org/show_bug.cgi?id=83738 + Reviewed by Zoltan Herczeg. - Reviewed by Geoffrey Garen. + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::call): Pick a scratch register instead of getting it as a + parameter. The sh4 port was the only one to have this call(Address, RegisterID) prototype. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTINativeCall): Use argumentGPRx and merge arm and sh4 paths. + * jit/ThunkGenerators.cpp: + (JSC::nativeForGenerator): Use argumentGPRx and merge arm and sh4 paths. - This patch improves replaceUsingStringSearch() with the following: - -Add a special case for single character search, taking advantage of the faster WTF::find(). - -Inline replaceUsingStringSearch(). - -Use StringImpl::create() instead of UString::substringSharingImpl() since we know we are in the bounds - by definition. +2013-11-28 Nadav Rotem - This gives less than 1% improvement for the multicharacter replace. - The single character search show about 9% improvement. + Revert the X86 assembler peephole changes + https://bugs.webkit.org/show_bug.cgi?id=124988 - * runtime/StringPrototype.cpp: - (JSC::replaceUsingStringSearch): + Reviewed by Csaba Osztrogonác. + + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::add32): + (JSC::MacroAssemblerX86::add64): + (JSC::MacroAssemblerX86::or32): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::add32): + (JSC::MacroAssemblerX86Common::or32): + (JSC::MacroAssemblerX86Common::branchAdd32): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::add32): + (JSC::MacroAssemblerX86_64::or32): + (JSC::MacroAssemblerX86_64::add64): + (JSC::MacroAssemblerX86_64::or64): + (JSC::MacroAssemblerX86_64::xor64): -2012-04-12 Michael Saboff +2013-11-28 Antti Koivisto - StructureStubInfo::reset() causes leaks of PolymorphicAccessStructureList and ExecutableMemoryHandle objects - https://bugs.webkit.org/show_bug.cgi?id=83823 + Remove feature: CSS variables + https://bugs.webkit.org/show_bug.cgi?id=114119 - Reviewed by Gavin Barraclough. + Reviewed by Andreas Kling. - Put the clearing of the accessType to after the call to deref() so that - deref() can use the accessType to delete referenced objects as needed. + * Configurations/FeatureDefines.xcconfig: - * bytecode/StructureStubInfo.h: - (JSC::StructureStubInfo::reset): +2013-11-28 Peter Gal -2012-04-12 Balazs Kelemen + Typo fix after r159834 to fix 32 bit builds. - [Qt] Fix WebKit1 build with V8 - https://bugs.webkit.org/show_bug.cgi?id=83322 + Reviewed by Csaba Osztrogonác. - Reviewed by Adam Barth. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): - * yarr/yarr.pri: +2013-11-27 Nadav Rotem -2012-04-12 Gavin Barraclough + Add a bunch of early exits and local optimizations to the x86 assembler. + https://bugs.webkit.org/show_bug.cgi?id=124904 - https://bugs.webkit.org/show_bug.cgi?id=83821 - Move dfg repatching properties of structure stub info into a union + Reviewed by Filip Pizlo. - Reviewed by Oliver Hunt. + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::add32): + (JSC::MacroAssemblerX86::add64): + (JSC::MacroAssemblerX86::or32): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::add32): + (JSC::MacroAssemblerX86Common::or32): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::add32): + (JSC::MacroAssemblerX86_64::or32): + (JSC::MacroAssemblerX86_64::add64): + (JSC::MacroAssemblerX86_64::or64): + (JSC::MacroAssemblerX86_64::xor64): - We want to be able to have similar properties for the baseline JIT, some restructuring to prepare for this. +2013-11-27 Filip Pizlo - * bytecode/StructureStubInfo.h: - (StructureStubInfo): - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::link): - * dfg/DFGRepatch.cpp: - (JSC::DFG::dfgRepatchByIdSelfAccess): - (JSC::DFG::linkRestoreScratch): - (JSC::DFG::generateProtoChainAccessStub): - (JSC::DFG::tryCacheGetByID): - (JSC::DFG::tryBuildGetByIDList): - (JSC::DFG::tryBuildGetByIDProtoList): - (JSC::DFG::emitPutReplaceStub): - (JSC::DFG::emitPutTransitionStub): - (JSC::DFG::tryCachePutByID): - (JSC::DFG::tryBuildPutByIdList): - (JSC::DFG::dfgResetGetByID): - (JSC::DFG::dfgResetPutByID): - -2012-04-12 Gavin Barraclough - - Delete a bunch of unused, copy & pasted values in JIT.h - https://bugs.webkit.org/show_bug.cgi?id=83822 + Infer one-time scopes + https://bugs.webkit.org/show_bug.cgi?id=124812 Reviewed by Oliver Hunt. - The only architecture we support the JSVALUE64 JIT on is x86-64, all the patch offsets for other architectures are just nonsense. + This detects JSActivations that are created only once. The JSActivation pointer is then + baked into the machine code. + + This takes advantage of the one-time scope inference to reduce the number of + indirections needed to get to a closure variable in case where the scope is only + allocated once. This isn't really a speed-up since in the common case the total number + of instruction bytes needed to load the scope from the stack is about equal to the + number of instruction bytes needed to materialize the absolute address of a scoped + variable. But, this is a necessary prerequisite to + https://bugs.webkit.org/show_bug.cgi?id=124630, so it's probably a good idea anyway. - * jit/JIT.h: - (JIT): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + * bytecode/Instruction.h: + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecode/Watchpoint.h: + (JSC::WatchpointSet::notifyWrite): + (JSC::InlineWatchpointSet::notifyWrite): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitResolveScope): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::scopedVarLoadElimination): + (JSC::DFG::CSEPhase::scopedVarStoreElimination): + (JSC::DFG::CSEPhase::getLocalLoadElimination): + (JSC::DFG::CSEPhase::setLocalStoreElimination): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetRegisters): + * dfg/DFGGraph.h: + * dfg/DFGNode.h: + (JSC::DFG::Node::varNumber): + (JSC::DFG::Node::hasSymbolTable): + (JSC::DFG::Node::symbolTable): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetClosureRegisters): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSActivation.h: + (JSC::JSActivation::create): + * runtime/JSScope.cpp: + (JSC::abstractAccess): + (JSC::JSScope::abstractResolve): + * runtime/JSScope.h: + (JSC::ResolveOp::ResolveOp): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::registers): + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::SymbolTable): + * runtime/SymbolTable.h: -2012-04-12 Csaba Osztrogonác +2013-11-27 Filip Pizlo - [Qt][ARM] Buildfix after r113934. + Finally fix some obvious Bartlett bugs + https://bugs.webkit.org/show_bug.cgi?id=124951 - Reviewed by Zoltan Herczeg. + Reviewed by Mark Hahnenberg. + + Sanitize the stack (i.e. zero parts of it known to be dead) at three key points: + + - GC. + + - At beginning of OSR entry. + + - Just as we finish preparing OSR entry. This clears those slots on the stack that + could have been live in baseline but that are known to be dead in DFG. + + This is as much as a 2x speed-up on splay if you run it in certain modes, and run it + for a long enough interval. It appears to fix all instances of the dreaded exponential + heap growth that splay gets into when some stale pointer stays around. + + This doesn't have much of an effect on real-world programs. This bug has only ever + manifested in splay and for that reason we thus far opted against fixing it. But splay + is, for what it's worth, the premiere GC stress test in JavaScript - so making sure we + can run it without pathologies - even when you tweak its configuration - is probably + fairly important. - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::compare8): - (MacroAssemblerARM): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::noticeOSREntry): + * dfg/DFGOSREntry.cpp: + (JSC::DFG::prepareOSREntry): + * dfg/DFGOSREntry.h: + * heap/Heap.cpp: + (JSC::Heap::markRoots): + * interpreter/JSStack.cpp: + (JSC::JSStack::JSStack): + (JSC::JSStack::sanitizeStack): + * interpreter/JSStack.h: -2012-04-11 Filip Pizlo +2013-11-26 Filip Pizlo - It is incorrect to short-circuit Branch(LogicalNot(@a)) if boolean speculations on @a may fail - https://bugs.webkit.org/show_bug.cgi?id=83744 - + Do bytecode validation as part of testing + https://bugs.webkit.org/show_bug.cgi?id=124913 - Reviewed by Andy Estes. + Reviewed by Oliver Hunt. - This does the conservative thing: it only short-circuits Branch(LogicalNot(@a)) if @a is a node - that is statically known to return boolean results. + Also fix some small bugs in the bytecode liveness analysis that I found by doing + this validation thingy. - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): + * bytecode/BytecodeLivenessAnalysis.cpp: + (JSC::isValidRegisterForLiveness): + (JSC::BytecodeLivenessAnalysis::runLivenessFixpoint): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::validate): + (JSC::CodeBlock::beginValidationDidFail): + (JSC::CodeBlock::endValidationDidFail): + * bytecode/CodeBlock.h: + * runtime/Executable.cpp: + (JSC::ScriptExecutable::prepareForExecutionImpl): + * runtime/Options.h: -2012-04-11 Michael Saboff +2013-11-27 Andreas Kling - Invalid Union Reference in StructureStubInfo.{cpp.h} - https://bugs.webkit.org/show_bug.cgi?id=83735 + Structure::m_staticFunctionReified should be a single bit. + - Reviewed by Filip Pizlo. + Shave 8 bytes off of JSC::Structure by jamming m_staticFunctionReified + into the bitfield just above. - Changed the references to u.getByIdProtoList and u.getByIdSelfList - to be consistent. + Reviewed by Antti Koivisto. - * bytecode/StructureStubInfo.cpp: - (JSC::StructureStubInfo::visitWeakReferences): - * bytecode/StructureStubInfo.h: - (JSC::StructureStubInfo::initGetByIdSelfList): +2013-11-27 Andreas Kling -2012-04-11 Filip Pizlo + JSActivation constructor should use NotNull placement new. + - Unreviewed attempting to make Qt's eccentric hardware work. + Knock a null check outta the storage initialization loop. - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::compare8): - (MacroAssemblerARM): - * assembler/MacroAssemblerMIPS.h: - (JSC::MacroAssemblerMIPS::compare8): - (MacroAssemblerMIPS): - * assembler/MacroAssemblerSH4.h: - (JSC::MacroAssemblerSH4::compare8): - (MacroAssemblerSH4): + Reviewed by Antti Koivisto. -2012-04-11 Filip Pizlo +2013-11-26 Filip Pizlo - op_is_foo should be optimized - https://bugs.webkit.org/show_bug.cgi?id=83666 + Restructure global variable constant inference so that it could work for any kind of symbol table variable + https://bugs.webkit.org/show_bug.cgi?id=124760 - Reviewed by Gavin Barraclough. + Reviewed by Oliver Hunt. - This implements inlining of op_is_undefined, op_is_string, op_is_number, - and op_is_boolean in LLInt and the baseline JIT. op_is_object and - op_is_function are not inlined because they are quite a bit more complex. + This changes the way global variable constant inference works so that it can be reused + for closure variable constant inference. Some of the premises that originally motivated + this patch are somewhat wrong, but it led to some simplifications anyway and I suspect + that we'll be able to fix those premises in the future. The main point of this patch is + to make it easy to reuse global variable constant inference for closure variable + constant inference, and this will be possible provided we can also either (a) infer + one-shot closures (easy) or (b) infer closure variables that are always assigned prior + to first use. - This also implements all of the op_is_foo opcodes in the DFG, but it does - not do any type profiling based optimizations, yet. + One of the things that this patch is meant to enable is constant inference for closure + variables that may be part of a multi-shot closure. Closure variables may be + instantiated multiple times, like: + + function foo() { + var WIDTH = 45; + function bar() { + ... use WIDTH ... + } + ... + } + + Even if foo() is called many times and WIDTH is assigned to multiple times, that + doesn't change the fact that it's a constant. The goal of closure variable constant + inference is to catch any case where a closure variable has been assigned at least once + and its value has never changed. This patch doesn't implement that, but it does change + global variable constant inference to have most of the powers needed to do that. Note + that most likely we will use this functionality only to implement constant inference + for one-shot closures, but the resulting machinery is still simpler than what we had + before. + + This involves three changes: + + - The watchpoint object now contains the inferred value. This involves creating a + new kind of watchpoint set, the VariableWatchpointSet. We will reuse this object + for closure variables. + + - Writing to a variable that is watchpointed still involves these three states that + we proceed through monotonically (Uninitialized->Initialized->Invalidated) but + now, the Initialized->Invalidated state transition only happens if we change the + variable's value, rather than store to the variable. Repeatedly storing the same + value won't change the variable's state. + + - On 64-bit systems (the only systems on which we do concurrent JIT), you no longer + need fancy fencing to get a consistent view of the watchpoint in the JIT. The + state of the VariableWatchpointSet for the purposes of constant folding is + entirely encapsulated in the VariableWatchpointSet::m_inferredValue. If that is + JSValue() then you cannot fold (either because the set is uninitialized or + because it's invalidated - doesn't matter which); on the other hand if the value + is anything other than JSValue() then you can fold, and that's the value you fold + to. Simple! + + This also changes the way that DFG IR deals with variable watchpoints. It's now + oblivious to global variables. You install a watchpoint using VariableWatchpoint and + you notify write using NotifyWrite. Easy! + + Note that this will requires some more tweaks because of the fact that op_enter will + store Undefined into every captured variable. Hence it won't even work for one-shot + closures. One-shot closures are easily fixed by introducing another state (so we'll + have Uninitialized->Undefined->Initialized->Invalidated). Multi-shot closures will + require static analysis. One-shot closures are clearly a higher priority. - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::compare8): - (MacroAssemblerARMv7): - * assembler/MacroAssemblerX86Common.h: - (JSC::MacroAssemblerX86Common::compare8): - (MacroAssemblerX86Common): - * assembler/MacroAssemblerX86_64.h: - (MacroAssemblerX86_64): - (JSC::MacroAssemblerX86_64::testPtr): - * dfg/DFGAbstractState.cpp: - (JSC::DFG::AbstractState::execute): + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/Instruction.h: + * bytecode/VariableWatchpointSet.h: Added. + (JSC::VariableWatchpointSet::VariableWatchpointSet): + (JSC::VariableWatchpointSet::~VariableWatchpointSet): + (JSC::VariableWatchpointSet::inferredValue): + (JSC::VariableWatchpointSet::notifyWrite): + (JSC::VariableWatchpointSet::invalidate): + (JSC::VariableWatchpointSet::finalizeUnconditionally): + (JSC::VariableWatchpointSet::addressOfInferredValue): + * bytecode/Watchpoint.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGCCallHelpers.h: - (JSC::DFG::CCallHelpers::setupArguments): - (CCallHelpers): * dfg/DFGCSEPhase.cpp: (JSC::DFG::CSEPhase::performNodeCSE): - * dfg/DFGCapabilities.h: - (JSC::DFG::canCompileOpcode): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasRegisterPointer): + (JSC::DFG::Node::hasVariableWatchpointSet): + (JSC::DFG::Node::variableWatchpointSet): * dfg/DFGNodeType.h: - (DFG): * dfg/DFGOperations.cpp: * dfg/DFGOperations.h: * dfg/DFGPredictionPropagationPhase.cpp: (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithMod): * dfg/DFGSpeculativeJIT.h: (JSC::DFG::SpeculativeJIT::callOperation): - (JSC::DFG::SpeculativeJIT::appendCallSetResult): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): - * jit/JIT.cpp: - (JSC::JIT::privateCompileMainPass): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileNotifyWrite): * jit/JIT.h: - (JIT): - * jit/JITOpcodes.cpp: - (JSC::JIT::emit_op_is_undefined): - (JSC): - (JSC::JIT::emit_op_is_boolean): - (JSC::JIT::emit_op_is_number): - (JSC::JIT::emit_op_is_string): - * jit/JITOpcodes32_64.cpp: - (JSC::JIT::emit_op_is_undefined): - (JSC): - (JSC::JIT::emit_op_is_boolean): - (JSC::JIT::emit_op_is_number): - (JSC::JIT::emit_op_is_string): - * jit/JITStubs.cpp: - (JSC): - * llint/LLIntSlowPaths.cpp: - (LLInt): - * llint/LLIntSlowPaths.h: - (LLInt): - * llint/LowLevelInterpreter.asm: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitNotifyWrite): + (JSC::JIT::emitPutGlobalVar): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitNotifyWrite): + (JSC::JIT::emitPutGlobalVar): * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: - * offlineasm/armv7.rb: - * offlineasm/instructions.rb: - * offlineasm/x86.rb: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + * runtime/JSGlobalObject.h: + * runtime/JSScope.h: + (JSC::ResolveOp::ResolveOp): + * runtime/JSSymbolTableObject.h: + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::inferredValue): + (JSC::SymbolTableEntry::prepareToWatch): + (JSC::SymbolTableEntry::addWatchpoint): + (JSC::SymbolTableEntry::notifyWriteSlow): + (JSC::SymbolTable::visitChildren): + (JSC::SymbolTable::WatchpointCleanup::WatchpointCleanup): + (JSC::SymbolTable::WatchpointCleanup::~WatchpointCleanup): + (JSC::SymbolTable::WatchpointCleanup::finalizeUnconditionally): + * runtime/SymbolTable.h: + (JSC::SymbolTableEntry::watchpointSet): + (JSC::SymbolTableEntry::notifyWrite): -2012-04-11 Filip Pizlo +2013-11-24 Filip Pizlo - If you use an IntegerOperand and want to return it with integerResult, you need to - zero extend to get rid of the box - https://bugs.webkit.org/show_bug.cgi?id=83734 - + Create a new SymbolTable every time code is loaded so that the watchpoints don't get reused + https://bugs.webkit.org/show_bug.cgi?id=124824 Reviewed by Oliver Hunt. - - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::fillInteger): - (JSC::DFG::SpeculativeJIT::nonSpeculativeValueToInt32): - -2012-04-11 Filip Pizlo - - SpeculativeJIT::fillStorage() should work with all the states that a cell may be in - https://bugs.webkit.org/show_bug.cgi?id=83722 - - Reviewed by Gavin Barraclough. - - It's now possible to do StorageOperand on a cell, in the case that the storage is - inline. But this means that fillStorage() must be able to handle all of the states - that a cell might be in. Previously it didn't. - With this change, it now does handle all of the states, and moreover, it does so - by preserving the DataFormat of cells and performing all of the cell speculations - that should be performed if you're using a cell as storage. But if you use this on - something that is known to be storage already then it behaves as it did before. + This helps with one shot closure inference as well as closure variable constant + inference, since without this, if code was reloaded from the cache then we would + think that the first run was actually an Nth run. This would cause us to think that + the watchpoint(s) should all be invalidated. - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::fillStorage): - -2012-04-11 Filip Pizlo + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::stronglyVisitStrongReferences): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::symbolTable): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::symbolTable): + * runtime/Executable.h: + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::clone): + * runtime/SymbolTable.h: - Global variable predictions should not be coalesced unnecessarily - https://bugs.webkit.org/show_bug.cgi?id=83678 +2013-11-26 Oliver Hunt - Reviewed by Geoff Garen. - - Removed the PredictionTracker and everyone who used it. Converted GetGlobalVar - to have a heapPrediction like a civilized DFG opcode ought to. - - No performance effect. + Crash in JSC::ASTBuilder::Expression JSC::Parser >::parseUnaryExpression(JSC::ASTBuilder&) + https://bugs.webkit.org/show_bug.cgi?id=124886 - * GNUmakefile.list.am: - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/CodeBlock.h: - * bytecode/PredictionTracker.h: Removed. - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGGenerationInfo.h: - * dfg/DFGGraph.cpp: - (JSC::DFG::Graph::dump): - * dfg/DFGGraph.h: - (Graph): - * dfg/DFGNode.h: - (JSC::DFG::Node::hasHeapPrediction): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): + Reviewed by Sam Weinig. -2012-04-11 Benjamin Poulain + Make sure the error macros propagate an existing error before + trying to create a new error message. We need to do this as + the parser state may not be safe for any specific error message + if we are already unwinding due to an error. - Optimize String.split() for 1 character separator - https://bugs.webkit.org/show_bug.cgi?id=83546 + * parser/Parser.cpp: - Reviewed by Gavin Barraclough. +2013-11-26 Nadav Rotem - This patch adds a serie of optimizations to make stringProtoFuncSplit() faster in the common case - where the separator is a single character. + Optimize away OR with zero - a common ASM.js pattern. + https://bugs.webkit.org/show_bug.cgi?id=124869 - The two main gains are: - -Use of the find() function with a single character instead of doing a full string matching. - -Use of WTF::find() instead of UString::find() to avoid branching on is8Bit() and have a simpler inline - function. + Reviewed by Filip Pizlo. - The code is also changed to avoid making unnecessary allocations by converting the 8bit string to 16bits. + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): - This makes String.split() faster by about 13% in that particular case. +2013-11-25 Julien Brianceau - * runtime/StringPrototype.cpp: - (JSC): - (JSC::splitStringByOneCharacterImpl): - (JSC::stringProtoFuncSplit): + [arm][mips] Fix crash in dfg-arrayify-elimination layout jsc test. + https://bugs.webkit.org/show_bug.cgi?id=124839 -2012-04-10 Carlos Garcia Campos + Reviewed by Michael Saboff. - Unreviewed. Fix make distcheck issues. + In ARM EABI and MIPS, 64-bit values have to be aligned on stack too. - * GNUmakefile.list.am: Ad missing files. + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JITInlines.h: + (JSC::JIT::callOperation): Add missing EABI_32BIT_DUMMY_ARG. -2012-04-10 Mark Rowe +2013-11-23 Filip Pizlo - Attempt to fix the Windows build. + Fix more fallout from failed attempts at div/mod DFG strength reductions + https://bugs.webkit.org/show_bug.cgi?id=124813 - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + Reviewed by Geoffrey Garen. -2012-04-10 Patrick Gansterer + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithMod): - Cleanup wtf/Platform.h and config.h files - https://bugs.webkit.org/show_bug.cgi?id=83431 +2013-11-22 Mark Hahnenberg - Reviewed by Eric Seidel. + JSC Obj-C API should have real documentation + https://bugs.webkit.org/show_bug.cgi?id=124805 - The ENABLE() and USE() macros take care about the case when the flag - isn't defined. So there is no need to define anything with 0. + Reviewed by Geoffrey Garen. - Also move duplicated code from the config.h files to Platform.h and - merge a few preprocessor commands to make the file more readable. + Massaging the header comments into proper headerdocs. - * config.h: + * API/JSContext.h: + * API/JSExport.h: + * API/JSManagedValue.h: + * API/JSValue.h: + * API/JSVirtualMachine.h: -2012-04-10 Filip Pizlo +2013-11-22 Filip Pizlo - DFG should flush SetLocals to arguments - https://bugs.webkit.org/show_bug.cgi?id=83554 + CodeBlock::m_numCalleeRegisters shouldn't also mean frame size, frame size needed for exit, or any other unrelated things + https://bugs.webkit.org/show_bug.cgi?id=124793 - Reviewed by Gavin Barraclough. + Reviewed by Mark Hahnenberg. - This is necessary to match baseline JIT argument capture behavior. + Now m_numCalleeRegisters always refers to the number of locals that the attached + bytecode uses. It never means anything else. - But to make this work right we need to have a story for arguments into - which we store values of different formats. This patch introduces the - notion of an ArgumentPosition - i.e. an argument in a particular inline - call frame - and forces unification of all data pertinent to selecting - the argument's data format. + For frame size, we now have it lazily computed from m_numCalleeRegisters for the + baseline engines and we have it stored in DFG::CommonData for the optimizing JITs. - Also fixed an amusing bug in the handling of OSR on SetLocals if there - was any insertion/deletion of nodes in the basic block. This is benign - for now but won't be eventually since the DFG is getting smarter. So - better fix it now. + For frame-size-needed-at-exit, we store that in DFG::CommonData, too. - Also fixed an amusing bug in the handling of OSR on SetLocals if they - are immediately followed by a Flush. I think this bug might have always - been there but now it'll happen more commonly, and it's covered by the - run-javascriptcore-tests. + The code no longer implies that there is any arithmetic relationship between + m_numCalleeRegisters and frameSize. Previously it implied that the latter is greater + than the former. + + The code no longer implies that there is any arithmetic relationship between the + frame Size and the frame-size-needed-at-exit. Previously it implied that the latter + is greater that the former. - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGAbstractState.cpp: - (JSC::DFG::AbstractState::execute): - * dfg/DFGArgumentPosition.h: Added. - (DFG): - (ArgumentPosition): - (JSC::DFG::ArgumentPosition::ArgumentPosition): - (JSC::DFG::ArgumentPosition::addVariable): - (JSC::DFG::ArgumentPosition::mergeArgumentAwareness): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::setLocal): - (JSC::DFG::ByteCodeParser::setArgument): - (InlineStackEntry): - (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): - * dfg/DFGDoubleFormatState.h: Added. - (DFG): - (JSC::DFG::mergeDoubleFormatStates): - (JSC::DFG::mergeDoubleFormatState): - (JSC::DFG::doubleFormatStateToString): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::frameRegisterCount): + * bytecode/CodeBlock.h: + * dfg/DFGCommonData.h: + (JSC::DFG::CommonData::CommonData): + (JSC::DFG::CommonData::requiredRegisterCountForExecutionAndExit): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::frameRegisterCount): + (JSC::DFG::Graph::requiredRegisterCountForExit): + (JSC::DFG::Graph::requiredRegisterCountForExecutionAndExit): * dfg/DFGGraph.h: - (Graph): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGVariableAccessData.h: - (JSC::DFG::VariableAccessData::VariableAccessData): - (JSC::DFG::VariableAccessData::predict): - (JSC::DFG::VariableAccessData::argumentAwarePrediction): - (VariableAccessData): - (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): - (JSC::DFG::VariableAccessData::doubleFormatState): - (JSC::DFG::VariableAccessData::shouldUseDoubleFormat): - (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat): - (JSC::DFG::VariableAccessData::mergeDoubleFormatState): - (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + (JSC::DFG::JITCompiler::compileFunction): + * dfg/DFGOSREntry.cpp: + (JSC::DFG::prepareOSREntry): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::SpeculativeJIT): + * dfg/DFGVirtualRegisterAllocationPhase.cpp: + (JSC::DFG::VirtualRegisterAllocationPhase::run): + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct): + * ftl/FTLOSREntry.cpp: + (JSC::FTL::prepareOSREntry): + * interpreter/CallFrame.cpp: + (JSC::CallFrame::frameExtentInternal): + * interpreter/JSStackInlines.h: + (JSC::JSStack::pushFrame): + * jit/JIT.h: + (JSC::JIT::frameRegisterCountFor): + * jit/JITOperations.cpp: + * llint/LLIntEntrypoint.cpp: + (JSC::LLInt::frameRegisterCountFor): + * llint/LLIntEntrypoint.h: -2012-04-10 Adam Klein +2013-11-21 Filip Pizlo - Remove unused NonNullPassRefPtr from WTF - https://bugs.webkit.org/show_bug.cgi?id=82389 + Combine SymbolTable and SharedSymbolTable + https://bugs.webkit.org/show_bug.cgi?id=124761 - Reviewed by Kentaro Hara. + Reviewed by Geoffrey Garen. + + SymbolTable was never used directly; we now always used SharedSymbolTable. So, this + gets rid of SymbolTable and renames SharedSymbolTable to SymbolTable. - * JavaScriptCore.order: Remove nonexistent symbols referencing NonNullPassRefPtr. + * bytecode/CodeBlock.h: + (JSC::CodeBlock::symbolTable): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::symbolTable): + (JSC::UnlinkedCodeBlock::symbolTable): + (JSC::UnlinkedCodeBlock::finishCreation): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::symbolTable): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::symbolTableFor): + * runtime/Arguments.h: + (JSC::Arguments::finishCreation): + * runtime/Executable.h: + (JSC::FunctionExecutable::symbolTable): + * runtime/JSActivation.h: + (JSC::JSActivation::create): + (JSC::JSActivation::JSActivation): + (JSC::JSActivation::registersOffset): + (JSC::JSActivation::allocationSize): + * runtime/JSSymbolTableObject.h: + (JSC::JSSymbolTableObject::symbolTable): + (JSC::JSSymbolTableObject::JSSymbolTableObject): + (JSC::JSSymbolTableObject::finishCreation): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::JSVariableObject): + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::destroy): + (JSC::SymbolTable::SymbolTable): + * runtime/SymbolTable.h: + (JSC::SymbolTable::create): + (JSC::SymbolTable::createStructure): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: -2012-04-10 Darin Adler +2013-11-22 Mark Lam - Remove unused data member from Lexer class - https://bugs.webkit.org/show_bug.cgi?id=83429 + Remove residual references to "dynamicGlobalObject". + https://bugs.webkit.org/show_bug.cgi?id=124787. - Reviewed by Kentaro Hara. + Reviewed by Filip Pizlo. - I noticed that m_delimited was "write-only", so I deleted it. + * JavaScriptCore.order: + * interpreter/CallFrame.h: - * parser/Lexer.cpp: - (JSC::Lexer::setCode): Removed code to set m_delimited. - (JSC::Lexer::parseIdentifier): Ditto. - (JSC::Lexer::parseIdentifierSlowCase): Ditto. - (JSC::Lexer::lex): Ditto. - * parser/Lexer.h: Deleted m_delimited. +2013-11-22 Mark Lam -2012-04-10 Patrick Gansterer + Ensure that arity fixups honor stack alignment requirements. + https://bugs.webkit.org/show_bug.cgi?id=124756. - [CMake] Enable USE_FOLDERS property - https://bugs.webkit.org/show_bug.cgi?id=83571 + Reviewed by Geoffrey Garen. - Reviewed by Daniel Bates. + The LLINT and all the JITs rely on CommonSlowPaths::arityCheckFor() to + compute the arg count adjustment for the arity fixup. We take advantage + of this choke point and introduce the stack alignment padding there in + the guise of additional args. - Setting the FOLDER property on targets gives more structure - to the generated Visual Studio solutions. - This does not affect other CMake generators. + The only cost of this approach is that the padding will also be + initialized to undefined values as if they were args. Since arity fixups + are considered a slow path that is rarely taken, this cost is not a + concern. - * CMakeLists.txt: - * shell/CMakeLists.txt: + * runtime/CommonSlowPaths.h: + (JSC::CommonSlowPaths::arityCheckFor): + * runtime/VM.h: + (JSC::VM::isSafeToRecurse): -2012-04-10 Filip Pizlo +2013-11-21 Filip Pizlo - It should be possible to see why a code block was not compiled by the DFG - https://bugs.webkit.org/show_bug.cgi?id=83553 + BytecodeGenerator should align the stack according to native conventions + https://bugs.webkit.org/show_bug.cgi?id=124735 - Reviewed by Geoff Garen. + Reviewed by Mark Lam. - If DFG_ENABLE(DEBUG_VERBOSE) and a code block is rejected, then print the - opcode that caused the rejection. - - * dfg/DFGCapabilities.cpp: - (JSC::DFG::debugFail): - (DFG): - (JSC::DFG::canHandleOpcodes): - -2012-04-09 Gavin Barraclough - - If a callback constructor returns a C++ null, throw a type error. - https://bugs.webkit.org/show_bug.cgi?id=83537 + Rolling this back in because it actually fixed fast/dom/gc-attribute-node.html, but + our infrastructure misleads peole into thinking that fixing a test constitutes + breaking it. - Rubber Stamped by Geoff Garen. - - * API/JSCallbackConstructor.cpp: - (JSC::constructJSCallback): - - If a callback constructor returns a C++ null, throw a type error. - * API/tests/testapi.c: - (Base_returnHardNull): - * API/tests/testapi.js: - - Add a test case for callback constructors that return a C++ null. - -2012-04-09 Gavin Barraclough - - If a callback function returns a C++ null, convert to undefined. - https://bugs.webkit.org/show_bug.cgi?id=83534 - - Reviewed by Geoff Garen. - - * API/JSCallbackFunction.cpp: - - If a callback function returns a C++ null, convert to undefined. - (JSC::JSCallbackFunction::call): - * API/tests/testapi.c: - (Base_returnHardNull): - * API/tests/testapi.js: - - Add a test case for callback functions that return a C++ null. + * bytecompiler/BytecodeGenerator.h: + (JSC::CallArguments::registerOffset): + (JSC::CallArguments::argumentCountIncludingThis): + * bytecompiler/NodesCodegen.cpp: + (JSC::CallArguments::CallArguments): -2012-04-09 Filip Pizlo +2013-11-21 Filip Pizlo - Classic interpreter's GC hooks shouldn't attempt to scan instructions for code blocks that - are currently being generated - https://bugs.webkit.org/show_bug.cgi?id=83531 - + Get rid of CodeBlock::dumpStatistics() + https://bugs.webkit.org/show_bug.cgi?id=124762 - Reviewed by Gavin Barraclough. + Reviewed by Mark Hahnenberg. * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::stronglyVisitStrongReferences): - -2012-04-09 Filip Pizlo - - Unreviewed, modernize and clean up uses of ARM assembly mnemonics in inline asm blocks. - - * dfg/DFGOperations.cpp: - (JSC): - * offlineasm/armv7.rb: - -2012-04-09 Patrick Gansterer + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::~CodeBlock): + * bytecode/CodeBlock.h: - Remove HAVE_STDINT_H - https://bugs.webkit.org/show_bug.cgi?id=83434 +2013-11-22 Commit Queue - Reviewed by Kentaro Hara. + Unreviewed, rolling out r159652. + http://trac.webkit.org/changeset/159652 + https://bugs.webkit.org/show_bug.cgi?id=124778 - HAVE_STDINT_H is defined with 1 all the time and we us stdint.h without HAVE(STDINT_H) already. + broke fast/dom/gc-attribute-node.html (Requested by ap on + #webkit). - * config.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitConstruct): + * bytecompiler/BytecodeGenerator.h: + (JSC::CallArguments::registerOffset): + (JSC::CallArguments::argumentCountIncludingThis): + * bytecompiler/NodesCodegen.cpp: + (JSC::CallArguments::CallArguments): + (JSC::CallArguments::newArgument): -2012-04-08 Filip Pizlo +2013-11-21 Filip Pizlo - DFG should not load the property storage if it is inline. - https://bugs.webkit.org/show_bug.cgi?id=83455 + Fix a typo (requriements->requirements). - Reviewed by Gavin Barraclough. - - We had previously decided to have all property storage accesses go through - the property storage pointer even if they don't "really" have to, because - we were thinking this would help GC barriers somehow. Well, we never ended - up doing anything with that. Hence, doing these wasted loads of the - property storage pointer when the storage is inline is just a waste of CPU - cycles. - - This change makes the DFG's inline property accesses (GetByOffset and - PutByOffset) go directly to the inline property storage if the structure(s) - tell us that it's OK. - - This looks like an across-the-board 1% win. + * runtime/StackAlignment.h: - * bytecode/StructureSet.h: - (JSC): - (JSC::StructureSet::allAreUsingInlinePropertyStorage): - (StructureSet): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::fillStorage): +2013-11-21 Mark Lam -2012-04-08 Filip Pizlo + CodeBlock::m_numCalleeRegisters need to honor native stack alignment. + https://bugs.webkit.org/show_bug.cgi?id=124754. - Command-line jsc's exception handling should be rationalized - https://bugs.webkit.org/show_bug.cgi?id=83437 + Reviewed by Filip Pizlo. - Reviewed by Dan Bernstein. - - - If an exception is thrown during run() execution, it is now propagated, - so that it will terminate program execution unless it is caught. - - - If program execution terminates with an exception, the exception is now - always printed. - - - When printing the exception, the backtrace is now also printed if one is - available. It will only not be available if you use something akin to my - favorite line of code, 'throw "error"', since primitives don't have - properties and hence we cannot attach a "stack" property to them. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::newRegister): + * dfg/DFGVirtualRegisterAllocationPhase.cpp: + (JSC::DFG::VirtualRegisterAllocationPhase::run): - * jsc.cpp: - (functionRun): - (runWithScripts): +2013-11-21 Mark Rowe -2012-04-04 Filip Pizlo + Stop overriding VALID_ARCHS. - Forced OSR exits should lead to recompilation based on count, not rate - https://bugs.webkit.org/show_bug.cgi?id=83247 - + All modern versions of Xcode set it appropriately for our needs. - Reviewed by Geoff Garen. - - Track which OSR exits happen because of inadequate coverage. Count them - separately. If the count reaches a threshold, immediately trigger - reoptimization. - - This is in contrast to the recompilation trigger for all other OSR exits. - Normally recomp is triggered when the exit rate exceeds a certain ratio. - - Looks like a slight V8 speedup (sub 1%). + Reviewed by Alexey Proskuryakov. - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::CodeBlock): - * bytecode/CodeBlock.h: - (JSC::CodeBlock::forcedOSRExitCounter): - (JSC::CodeBlock::addressOfForcedOSRExitCounter): - (JSC::CodeBlock::offsetOfForcedOSRExitCounter): - (JSC::CodeBlock::shouldReoptimizeNow): - (JSC::CodeBlock::shouldReoptimizeFromLoopNow): - (CodeBlock): - * bytecode/DFGExitProfile.h: - (JSC::DFG::exitKindToString): - * dfg/DFGOSRExitCompiler.cpp: - (JSC::DFG::OSRExitCompiler::handleExitCounts): - (DFG): - * dfg/DFGOSRExitCompiler.h: - (OSRExitCompiler): - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOperations.cpp: - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * runtime/Options.cpp: - (Options): - (JSC::Options::initializeOptions): - * runtime/Options.h: - (Options): + * Configurations/Base.xcconfig: -2012-04-06 Benjamin Poulain +2013-11-21 Mark Rowe - Do not abuse ArrayStorage's m_length for testing array consistency - https://bugs.webkit.org/show_bug.cgi?id=83403 + Fix an error in a few Xcode configuration setting files. - Reviewed by Geoffrey Garen. + Reviewed by Alexey Proskuryakov. - Array creation from a list of values is a 3 steps process: - -JSArray::tryCreateUninitialized() - -JSArray::initializeIndex() for each values - -JSArray::completeInitialization() + * Configurations/Base.xcconfig: - Previously, the attribute m_length was not set to the final size - JSArray::tryCreateUninitialized() because it was used to test the array - consistency JSArray::initializeIndex(). +2013-11-21 Michael Saboff - This caused the initialization loop using JSArray::initializeIndex() maintain - two counters: - -index of the loop - -storage->m_length++ + ARM64: Implement push/pop equivalents in LLInt + https://bugs.webkit.org/show_bug.cgi?id=124721 - This patch fixes this by using the index of the initialization loop for the indinces of - JSArray::initializeIndex(). For testing consistency, the variable m_initializationIndex - is introduced if CHECK_ARRAY_CONSISTENCY is defined. + Reviewed by Filip Pizlo. - The patch also fixes minor unrelated build issue when CHECK_ARRAY_CONSISTENCY is defined. + Added pushLRAndFP and popLRAndFP that push and pop the link register and frame pointer register. + These ops emit code just like what the compiler emits in the prologue and epilogue. Also changed + pushCalleeSaves and popCalleeSaves to use the same store pair and load pair instructions to do + the actually pushing and popping. Finally changed the implementation of push and pop to raise + an exception since we don't have (or need) a single register push or pop. - This improves the performance of JSArray creation from literals by 8%. + * llint/LowLevelInterpreter64.asm: + * offlineasm/arm64.rb: + * offlineasm/instructions.rb: - * runtime/JSArray.cpp: - (JSC::JSArray::tryFinishCreationUninitialized): - (JSC::JSArray::checkConsistency): - * runtime/JSArray.h: - (ArrayStorage): - (JSC::JSArray::initializeIndex): - (JSC::JSArray::completeInitialization): +2013-11-21 Michael Saboff -2012-04-06 Jon Lee + JSC: Removed unused opcodes from offline assembler + https://bugs.webkit.org/show_bug.cgi?id=124749 - Build fix for Windows bots. + Reviewed by Mark Hahnenberg. - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: export missing symbol. + Removed the unused, X86 only peekq and pokeq. -2012-04-06 Geoffrey Garen + * offlineasm/instructions.rb: + * offlineasm/x86.rb: - Renamed +2013-11-21 Michael Saboff - WeakHeap => WeakSet - HandleHeap => HandleSet + REGRESSION(159395) Fix branch8(…, AbsoluteAddress, …) in ARM64 MacroAssembler + https://bugs.webkit.org/show_bug.cgi?id=124688 - Reviewed by Sam Weinig. + Reviewed by Geoffrey Garen. - These sets do have internal allocators, but it's confusing to call them - heaps because they're sub-objects of an object called "heap". + Changed handling of the address for the load8() in the branch8(AbsoluteAddress) to be like + the rest of the branchXX(AbsoluteAddress) fucntions. - * heap/HandleHeap.cpp: Removed. - * heap/HandleHeap.h: Removed. - * heap/HandleSet.cpp: Copied from JavaScriptCore/heap/HandleHeap.cpp. - * heap/WeakHeap.cpp: Removed. - * heap/WeakHeap.h: Removed. - * heap/WeakSet.cpp: Copied from JavaScriptCore/heap/WeakHeap.cpp. - * heap/WeakSet.h: Copied from JavaScriptCore/heap/WeakHeap.h. + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::branch8): - Plus global rename using grep. +2013-11-21 Filip Pizlo -2012-04-06 Dan Bernstein + BytecodeGenerator should align the stack according to native conventions + https://bugs.webkit.org/show_bug.cgi?id=124735 - HiDPI: Have canvas use a hidpi backing store, but downsample upon access + Reviewed by Mark Lam. - Reviewed by Sam Weinig. + * bytecompiler/BytecodeGenerator.h: + (JSC::CallArguments::registerOffset): + (JSC::CallArguments::argumentCountIncludingThis): + * bytecompiler/NodesCodegen.cpp: + (JSC::CallArguments::CallArguments): - * Configurations/FeatureDefines.xcconfig: Added ENABLE_HIGH_DPI_CANVAS. +2013-11-21 Filip Pizlo -2012-04-06 Rob Buis + Unreviewed, preemptive build fix. - Fix cast-align warnings in JSC - https://bugs.webkit.org/show_bug.cgi?id=80790 + * runtime/StackAlignment.h: + (JSC::stackAlignmentBytes): + (JSC::stackAlignmentRegisters): - Reviewed by George Staikos. +2013-11-21 Filip Pizlo - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::computeJumpType): - (JSC::ARMv7Assembler::link): - * assembler/LinkBuffer.h: - (JSC::LinkBuffer::linkCode): - * heap/MarkStack.cpp: - (JSC::SlotVisitor::copyAndAppend): - * runtime/JSArray.cpp: - (JSC::JSArray::visitChildren): - * wtf/RefCountedArray.h: - (WTF::RefCountedArray::Header::payload): + JSC should know what the stack alignment conventions are + https://bugs.webkit.org/show_bug.cgi?id=124736 -2012-04-06 Darin Adler + Reviewed by Mark Lam. - Streamline strtod and fix some related problems - https://bugs.webkit.org/show_bug.cgi?id=82857 + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/StackAlignment.h: Added. + (JSC::stackAlignmentBytes): + (JSC::stackAlignmentRegisters): - Reviewed by Geoffrey Garen. +2013-11-21 Balazs Kilvady - * parser/Lexer.cpp: - (JSC::Lexer<>::lex): Use parseDouble. Since we have already scanned the number - and we know it has only correct characters, leading spaces, trailing junk, and - trailing spaces are not a possibility. No need to add a trailing null character. - - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::parseInt): Changed overflow based 10 case to use parseDouble. No need - to allow trailing junk since the code above already allows only numeric digits - in the string. This code path is used only in unusual cases, so it's not - optimized for 8-bit strings, but easily could be. - (JSC::jsStrDecimalLiteral): Removed the allow trailing junk argument to this - function template because all the callers are OK with trailing junk. Use the - parseDouble function. No need to copy the data into a byte buffer, because - parseDouble handles that. - (JSC::toDouble): Got rid of the DisallowTrailingJunk argument to the - jsStrDecimalLiteral function template. That's OK because this function - already checks for trailing junk and handles it appropriately. The old code - path was doing it twice. - (JSC::parseFloat): Got rid of the AllowTrailingJunk argument to the - jsStrDecimalLiteral function template; the template allows junk unconditionally. - - * runtime/LiteralParser.cpp: - (JSC::::Lexer::lexNumber): Use parseDouble. Since we have already scanned the number - and we know it has only correct characters, leading spaces, trailing junk, and - trailing spaces are not a possibility. No need to add a trailing null character. - No need to copy the data into a byte buffer, because parseDouble handles that. - We could optimize the UChar case even more because we know all the characters - are ASCII, but not doing that at this time. - - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Updated. - -2012-04-06 Patrick Gansterer - - Remove JSC dependency from GregorianDateTime - https://bugs.webkit.org/show_bug.cgi?id=83290 + [MIPS] Build fails since r159545. + https://bugs.webkit.org/show_bug.cgi?id=124716 - Reviewed by Geoffrey Garen. + Reviewed by Michael Saboff. - This allows us to move it to WTF later. + Add missing implementations in MacroAssembler and LLInt for MIPS. - * runtime/DateConstructor.cpp: - (JSC::callDate): - * runtime/JSDateMath.h: + * assembler/MIPSAssembler.h: + (JSC::MIPSAssembler::sync): + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::store8): + (JSC::MacroAssemblerMIPS::memoryFence): + * offlineasm/mips.rb: -2012-04-05 Michael Saboff +2013-11-21 Julien Brianceau - Call Heap::discardAllCompiledCode() in low memory situations - https://bugs.webkit.org/show_bug.cgi?id=83335 + Fix sh4 build after r159545. + https://bugs.webkit.org/show_bug.cgi?id=124713 - Reviewed by Geoffrey Garen. + Reviewed by Michael Saboff. - Restructured Heap::discardAllCompiledCode() to do the "Is JavaScriptRunning?" - check inline so that it can be called directly without this check. + Add missing implementations in macro assembler and LLINT for sh4. - * heap/Heap.cpp: - (JSC::Heap::discardAllCompiledCode): - (JSC::Heap::collectAllGarbage): - * heap/Heap.h: Added JS_EXPORT_PRIVATE to discardAllCompiledCode() so it can be - called from WebCore. - (Heap): - * runtime/JSGlobalData.h: Removed unused " void discardAllCompiledCode()" declaration. - (JSGlobalData): + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::load8): + (JSC::MacroAssemblerSH4::store8): + (JSC::MacroAssemblerSH4::memoryFence): + * assembler/SH4Assembler.h: + (JSC::SH4Assembler::synco): + * offlineasm/sh4.rb: Handle "memfence" opcode. -2012-04-05 Benjamin Poulain +2013-11-20 Mark Lam - Speed up the conversion from JSValue to String for bulk operations - https://bugs.webkit.org/show_bug.cgi?id=83243 + Introducing VMEntryScope to update the VM stack limit. + https://bugs.webkit.org/show_bug.cgi?id=124634. Reviewed by Geoffrey Garen. - When making operations on primitive types, we loose some time converting - values to JSString in order to extract the string. - - This patch speeds up some basic Array operations by avoiding the creation - of intermediary JSString when possible. + 1. Introduced USE(SEPARATE_C_AND_JS_STACK) (defined in Platform.h). + Currently, it is hardcoded to use separate C and JS stacks. Once we + switch to using the C stack for JS frames, we'll need to fix this to + only be enabled when ENABLE(LLINT_C_LOOP). - For the cases where we need to convert a lot of JSValue in a tight loop, - an inline conversion is used. + 2. Stack limits are now tracked in the VM. - * runtime/ArrayPrototype.cpp: - (JSC::arrayProtoFuncToString): - (JSC::arrayProtoFuncToLocaleString): - (JSC::arrayProtoFuncJoin): - (JSC::arrayProtoFuncPush): - (JSC::arrayProtoFuncSort): - * runtime/CommonIdentifiers.h: - * runtime/JSArray.cpp: - (JSC::JSArray::sort): - * runtime/JSString.h: - (JSC::JSValue::toUString): - (JSC): - (JSC::inlineJSValueNotStringtoUString): - (JSC::JSValue::toUStringInline): - * runtime/JSValue.cpp: - (JSC::JSValue::toUStringSlowCase): - (JSC): - * runtime/JSValue.h: - (JSValue): - -2012-04-05 Benjamin Poulain - - Use QuickSort when sorting primitive values by string representation - https://bugs.webkit.org/show_bug.cgi?id=83312 - - Reviewed by Gavin Barraclough. - - When the value we are sorting are all primitive values, we do not need to - ensure a stable sort as two values with equal string representation are - indistinguishable from JavaScript. - - This gives about 16% performance increase when sorting primitive values. - - * runtime/JSArray.cpp: - (JSC::JSArray::sort): - -2012-04-05 Oliver Hunt - - SIGILL in JavaScriptCore on a Geode processor - https://bugs.webkit.org/show_bug.cgi?id=82496 - - Reviewed by Gavin Barraclough. - - Don't attempt to use the DFG when SSE2 is not available. + Logically, there are 2 stack limits: + a. m_stackLimit for the native C stack, and + b. m_jsStackLimit for the JS stack. - * dfg/DFGCapabilities.cpp: - (JSC::DFG::canCompileOpcodes): + If USE(SEPARATE_C_AND_JS_STACK), then the 2 limits are the same + value, and are implemented as 2 fields in a union. -2012-04-05 Oliver Hunt + 3. The VM native stackLimit is set as follows: + a. Initially, the VM sets it to the limit of the stack of the thread that + instantiated the VM. This allows the parser and bytecode generator to + run before we enter the VM to execute JS code. - Fix 32-bit build. + b. Upon entry into the VM to execute JS code (via one of the + Interpreter::execute...() functions), we instantiate a VMEntryScope + that sets the VM's stackLimit to the limit of the current thread's + stack. The VMEntryScope will automatically restore the previous + entryScope and stack limit upon destruction. - * API/APICast.h: - (toJS): + If USE(SEPARATE_C_AND_JS_STACK), the JSStack's methods will set the VM's + jsStackLimit whenever it grows or shrinks. -2012-04-05 Oliver Hunt + 4. The VM now provides a isSafeToRecurse() function that compares the + current stack pointer against its native stackLimit. This subsumes and + obsoletes the VMStackBounds class. - Replace static_cast with jsCast when casting JSCell subclasses in JSC - https://bugs.webkit.org/show_bug.cgi?id=83307 + 5. The VMEntryScope class also subsumes DynamicGlobalObjectScope for + tracking the JSGlobalObject that we last entered the VM with. - Reviewed by Gavin Barraclough. + 6. Renamed dynamicGlobalObject() to vmEntryGlobalObject() since that is + the value that the function retrieves. - Replace all usage of static_cast with jsCast<> in JavaScriptCore. - This results in assertions when unsafe casts are performed, but simply leaves - a static_cast<> in release builds. + 7. Changed JIT and LLINT code to do stack checks against the jsStackLimit + in the VM class instead of the JSStack. - * API/APICast.h: - (toJS): - * API/JSCallbackConstructor.cpp: - (JSC::constructJSCallback): - * API/JSCallbackFunction.cpp: - (JSC::JSCallbackFunction::call): - * API/JSCallbackObjectFunctions.h: - (JSC::::asCallbackObject): - (JSC::::finishCreation): - (JSC::::construct): - (JSC::::call): - * API/JSObjectRef.cpp: - (JSObjectGetPrivate): - (JSObjectSetPrivate): - (JSObjectGetPrivateProperty): - (JSObjectSetPrivateProperty): - (JSObjectDeletePrivateProperty): - * API/JSValueRef.cpp: - (JSValueIsObjectOfClass): - * API/JSWeakObjectMapRefPrivate.cpp: + * API/JSBase.cpp: + (JSEvaluateScript): + (JSCheckScriptSyntax): + * API/JSContextRef.cpp: + (JSGlobalContextRetain): + (JSGlobalContextRelease): + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::resolve): - (JSC::BytecodeGenerator::resolveConstDecl): - * debugger/DebuggerActivation.cpp: - (JSC::DebuggerActivation::finishCreation): - * dfg/DFGOperations.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitNode): + (JSC::BytecodeGenerator::emitNodeInConditionContext): + * debugger/Debugger.cpp: + (JSC::Debugger::detach): + (JSC::Debugger::recompileAllJSFunctions): + (JSC::Debugger::pauseIfNeeded): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::vmEntryGlobalObject): + * debugger/DebuggerCallFrame.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compileFunction): + * dfg/DFGOSREntry.cpp: + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLOSREntry.cpp: + * heap/Heap.cpp: + (JSC::Heap::lastChanceToFinalize): + (JSC::Heap::deleteAllCompiledCode): + * interpreter/CachedCall.h: + (JSC::CachedCall::CachedCall): + * interpreter/CallFrame.cpp: + (JSC::CallFrame::vmEntryGlobalObject): + * interpreter/CallFrame.h: * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + (JSC::Interpreter::unwind): (JSC::Interpreter::execute): - (JSC::Interpreter::privateExecute): - * jit/JITStubs.cpp: - (JSC::DEFINE_STUB_FUNCTION): - * runtime/Executable.h: - (JSC::isHostFunction): - * runtime/JSActivation.h: - (JSC::asActivation): - * runtime/JSArray.cpp: - (JSC::JSArray::defineOwnProperty): - * runtime/JSArray.h: - (JSC::asArray): - * runtime/JSBoundFunction.cpp: - (JSC::boundFunctionCall): - (JSC::boundFunctionConstruct): - * runtime/JSByteArray.h: - (JSC::asByteArray): - * runtime/JSCell.cpp: - (JSC::JSCell::toObject): - * runtime/JSCell.h: - (JSC::jsCast): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::prepareForRepeatCall): + (JSC::Interpreter::debug): + * interpreter/JSStack.cpp: + (JSC::JSStack::JSStack): + (JSC::JSStack::growSlowCase): + * interpreter/JSStack.h: + * interpreter/JSStackInlines.h: + (JSC::JSStack::shrink): + (JSC::JSStack::grow): + - Moved these inlined functions here from JSStack.h. It reduces some + #include dependencies of JSSTack.h which had previously resulted + in some EWS bots' unhappiness with this patch. + (JSC::JSStack::updateStackLimit): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JITCall.cpp: + (JSC::JIT::compileLoadVarargs): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileLoadVarargs): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + * llint/LowLevelInterpreter.asm: + * parser/Parser.cpp: + (JSC::::Parser): + * parser/Parser.h: + (JSC::Parser::canRecurse): + * runtime/CommonSlowPaths.h: + * runtime/Completion.cpp: + (JSC::evaluate): + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): + * runtime/JSGlobalObject.cpp: * runtime/JSGlobalObject.h: - (JSC::asGlobalObject): - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::globalFuncEval): - * runtime/JSObject.cpp: - (JSC::JSObject::setPrototypeWithCycleCheck): - (JSC::JSObject::allowsAccessFrom): - (JSC::JSObject::toThisObject): - (JSC::JSObject::unwrappedObject): - * runtime/JSObject.h: - (JSC::asObject): - * runtime/JSPropertyNameIterator.h: - (JSC::Register::propertyNameIterator): - * runtime/JSString.h: - (JSC::asString): - (JSC::JSValue::toString): - * runtime/StringPrototype.cpp: - (JSC::stringProtoFuncSubstr): + * runtime/StringRecursionChecker.h: + (JSC::StringRecursionChecker::performCheck): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::releaseExecutableMemory): + (JSC::VM::throwException): + * runtime/VM.h: + (JSC::VM::addressOfJSStackLimit): + (JSC::VM::jsStackLimit): + (JSC::VM::setJSStackLimit): + (JSC::VM::stackLimit): + (JSC::VM::setStackLimit): + (JSC::VM::isSafeToRecurse): + * runtime/VMEntryScope.cpp: Added. + (JSC::VMEntryScope::VMEntryScope): + (JSC::VMEntryScope::~VMEntryScope): + (JSC::VMEntryScope::requiredCapacity): + * runtime/VMEntryScope.h: Added. + (JSC::VMEntryScope::globalObject): + * runtime/VMStackBounds.h: Removed. + +2013-11-20 Michael Saboff + + [Win] JavaScript JIT crash (with DFG enabled). + https://bugs.webkit.org/show_bug.cgi?id=124675 + + Reviewed by Geoffrey Garen. + + Similar to the change in r159427, changed linkClosureCall to use regT0/regT1 (payload/tag) for the callee. + linkForThunkGenerator already expected the callee in regT0/regT1, but changed the comment to reflect that. + + * jit/Repatch.cpp: + (JSC::linkClosureCall): + * jit/ThunkGenerators.cpp: + (JSC::linkForThunkGenerator): -2012-04-05 Benjamin Poulain +2013-11-20 Michael Saboff - Make something faster than JSStringBuilder for joining an array of JSValue - https://bugs.webkit.org/show_bug.cgi?id=83180 + ARMv7: Crash due to use after free of AssemblerBuffer + https://bugs.webkit.org/show_bug.cgi?id=124611 Reviewed by Geoffrey Garen. - This patch add the class JSStringJoiner optimized for join() operations. + Changed JITFinalizer constructor to take a MacroAssemblerCodePtr instead of a Label. + In finalizeFunction(), we use that value instead of calculating it from the label. - This class makes stricter constraints than JSStringBuilder in order avoid - memory allocations. + * assembler/MacroAssembler.cpp: + * dfg/DFGJITFinalizer.cpp: + (JSC::DFG::JITFinalizer::JITFinalizer): + (JSC::DFG::JITFinalizer::finalizeFunction): + * dfg/DFGJITFinalizer.h: - In the best case, the class allocate memory only twice: - -Allocate an array to keep a list of UString to join. - -Allocate the final string. +2013-11-20 Julien Brianceau - We also avoid the conversion from 8bits strings to 16bits strings since - they are costly and unlikly to help for subsequent calls. + Fix CPU(ARM_TRADITIONAL) build after r159545. + https://bugs.webkit.org/show_bug.cgi?id=124649 - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.gypi: - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * Target.pri: - * runtime/ArrayPrototype.cpp: - (JSC::arrayProtoFuncToLocaleString): - (JSC::arrayProtoFuncJoin): - * runtime/JSStringJoiner.cpp: Added. - (JSC): - (JSC::appendStringToData): - (JSC::joinStrings): - (JSC::JSStringJoiner::build): - * runtime/JSStringJoiner.h: Added. - (JSC): - (JSStringJoiner): - (JSC::JSStringJoiner::JSStringJoiner): - (JSC::JSStringJoiner::append): + Reviewed by Michael Saboff. -2012-04-05 Gavin Barraclough + Add missing memoryFence, load8 and store8 implementations in macro assembler. - https://bugs.webkit.org/show_bug.cgi?id=77293 - [Un]Reserve 'let' + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::dmbSY): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::load8): + (JSC::MacroAssemblerARM::store8): + (JSC::MacroAssemblerARM::memoryFence): - Rubber stamped by Oliver Hunt. +2013-11-20 Julien Brianceau - Revert r106198. - This does break the web - e.g. https://bvi.bnc.ca/index/bnc/indexen.html - If we're going to reserve let, we're going to have to do so in a more - circumspect fashion. + [armv7][arm64] Speculative build fix after r159545. + https://bugs.webkit.org/show_bug.cgi?id=124646 - * parser/Keywords.table: + Reviewed by Filip Pizlo. -2012-04-05 Michael Saboff + * assembler/ARMv7Assembler.h: + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::memoryFence): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::memoryFence): - Rolling out http://trac.webkit.org/changeset/113262. - Original code was fine. +2013-11-19 Ryosuke Niwa - Rubber-stamped by Oliver Hunt. + Enable HTMLTemplateElement on Mac port + https://bugs.webkit.org/show_bug.cgi?id=124637 - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::additionBlindedConstant): + Reviewed by Tim Horton. -2012-04-05 Patrick Gansterer + * Configurations/FeatureDefines.xcconfig: - [WinCE] Remove unnecessary function decleration - https://bugs.webkit.org/show_bug.cgi?id=83155 +2013-11-19 Filip Pizlo - Reviewed by Kentaro Hara. + Unreviewed, remove completely bogus assertion. - * runtime/JSDateMath.cpp: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addFunction): -2012-04-04 Patrick Gansterer +2013-11-19 Filip Pizlo - Add WTF::getCurrentLocalTime() - https://bugs.webkit.org/show_bug.cgi?id=83164 + Unreviewed, debug build fix. - Reviewed by Alexey Proskuryakov. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addFunction): - Replace the calls to WTF::getLocalTime() with time(0) with the new function. - This allows us to use Win32 API on windows to get the same result in a next step. +2013-11-19 Filip Pizlo - * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: - * runtime/DateConstructor.cpp: - (JSC::callDate): + Infer constant global variables + https://bugs.webkit.org/show_bug.cgi?id=124464 -2012-04-04 Oliver Hunt + Reviewed by Sam Weinig. + + All global variables that are candidates for watchpoint-based constant inference (i.e. + not 'const' variables) will now have WatchpointSet's associated with them and those + are used to drive the inference by tracking three states of each variable: + + Uninitialized: the variable's value is Undefined and the WatchpointSet state is + ClearWatchpoint. + + Initialized: the variable's value was set to something (could even be explicitly set + to Undefined) and the WatchpointSet state is IsWatching. + + Invalidated: the variable's value was set to something else (could even be the same + thing as before but the point is that a put operation did execute again) and the + WatchpointSet is IsInvalidated. + + If the compiler tries to compile a GetGlobalVar and the WatchpointSet state is + IsWatching, then the current value of the variable can be folded in place of the get, + and a watchpoint on the variable can be registered. + + We handle race conditions between the mutator and compiler by mandating that: + + - The mutator changes the WatchpointSet state after executing the put. + + - There is no opportunity to install code or call functions between when the mutator + executes a put and changes the WatchpointSet state. + + - The compiler checks the WatchpointSet state prior to reading the value. + + The concrete algorithm used by the mutator is: + + 1. Store the new value into the variable. + --- Execute a store-store fence. + 2. Bump the state (ClearWatchpoing becomes IsWatching, IsWatching becomes + IsInvalidated); the IsWatching->IsInvalidated transition may end up firing + watchpoints. + + The concrete algorithm that the compiler uses is: + + 1. Load the state. If it's *not* IsWatching, then give up on constant inference. + --- Execute a load-load fence. + 2. Load the value of the variable and use that for folding, while also registering + a DesiredWatchpoint. The various parts of this step can be done in any order. + + The desired watchpoint registration will fail if the watchpoint set is already + invalidated. Now consider the following interesting interleavings: + + Uninitialized->M1->M2->C1->C2: Compiler sees IsWatching because of the mutator's store + operation, and the variable is folded. The fencing ensures that C2 sees the value + stored in M1 - i.e. we fold on the value that will actually be watchpointed. If + before the compilation is installed the mutator executes another store then we + will be sure that it will be a complete sequence of M1+M2 since compilations get + installed at safepoints and never "in the middle" of a put_to_scope. Hence that + compilation installation will be invalidated. If the M1+M2 sequence happens after + the code is installed, then the code will be invalidated by triggering a jettison. + + Uninitialized->M1->C1->C2->M2: Compiler sees Uninitialized and will not fold. This is + a sensible outcome since if the compiler read the variable's value, it would have + seen Undefined. + + Uninitialized->C1->C2->M1->M2: Compiler sees Uninitialized and will not fold. + Uninitialized->C1->M1->C2->M2: Compiler sees Uninitialized and will not fold. + Uninitialized->C1->M1->M2->C2: Compiler sees Uninitialized and will not fold. + Uninitialized->M1->C1->M2->C2: Compiler sees Uninitialized and will not fold. + + IsWatched->M1->M2->C1->C2: Compiler sees IsInvalidated and will not fold. + + IsWatched->M1->C1->C2->M2: Compiler will fold, but will also register a desired + watchpoint, and that watchpoint will get invalidated before the code is installed. + + IsWatched->M1->C1->M2->C2: As above, will fold but the code will get invalidated. + IsWatched->C1->C2->M1->M2: As above, will fold but the code will get invalidated. + IsWatched->C1->M1->C2->M2: As above, will fold but the code will get invalidated. + IsWatched->C1->M1->M2->C2: As above, will fold but the code will get invalidated. + + Note that this kind of reasoning shows why having the mutator first bump the state and + then store the new value would be wrong. If we had done that (M1 = bump state, M2 = + execute put) then we could have the following deadly interleavings: + + Uninitialized->M1->C1->C2->M2: + Uninitialized->M1->C1->M2->C2: Mutator bumps the state to IsWatched and then the + compiler folds Undefined, since M2 hasn't executed yet. Although C2 will set the + watchpoint, M1 didn't notify it - it mearly initiated watching. M2 then stores a + value other than Undefined, and you're toast. + + You could fix this sort of thing by making the Desired Watchpoints machinery more + sophisticated, for example having it track the value that was folded; if the global + variable's value was later found to be different then we could invalidate the + compilation. You could also fix it by having the compiler also check that the value of + the variable is not Undefined before folding. While those all sound great, I decided + to instead just use the right interleaving since that results in less code and feels + more intuitive. + + This is a 0.5% speed-up on SunSpider, mostly due to a 20% speed-up on math-cordic. + It's a 0.6% slow-down on LongSpider, mostly due to a 25% slow-down on 3d-cube. This is + because 3d-cube takes global variable assignment slow paths very often. Note that this + 3d-cube slow-down doesn't manifest as much in SunSpider (only 6% there). This patch is + also a 1.5% speed-up on V8v7 and a 2.8% speed-up on Octane v1, mostly due to deltablue + (3.7%), richards (4%), and mandreel (26%). This is a 2% speed-up on Kraken, mostly due + to a 17.5% speed-up on imaging-gaussian-blur. Something that really illustrates the + slam-dunk-itude of this patch is the wide range of speed-ups on JSRegress. Casual JS + programming often leads to global-var-based idioms and those variables tend to be + assigned once, leading to excellent constant folding opportunities in an optimizing + JIT. This is very evident in the speed-ups on JSRegress. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::dmbSY): + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::dmbSY): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::memfence): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::load8): + (JSC::MacroAssemblerARMv7::memfence): + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::load8): + (JSC::MacroAssemblerX86::store8): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::getUnusedRegister): + (JSC::MacroAssemblerX86Common::store8): + (JSC::MacroAssemblerX86Common::memoryFence): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::load8): + (JSC::MacroAssemblerX86_64::store8): + * assembler/X86Assembler.h: + (JSC::X86Assembler::movb_rm): + (JSC::X86Assembler::movzbl_mr): + (JSC::X86Assembler::mfence): + (JSC::X86Assembler::X86InstructionFormatter::threeByteOp): + (JSC::X86Assembler::X86InstructionFormatter::oneByteOp8): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/Watchpoint.cpp: + (JSC::WatchpointSet::WatchpointSet): + (JSC::WatchpointSet::add): + (JSC::WatchpointSet::notifyWriteSlow): + * bytecode/Watchpoint.h: + (JSC::WatchpointSet::state): + (JSC::WatchpointSet::isStillValid): + (JSC::WatchpointSet::addressOfSetIsNotEmpty): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getJSConstantForValue): + (JSC::DFG::ByteCodeParser::getJSConstant): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::isStronglyProvedConstantIn): + (JSC::DFG::Node::hasIdentifierNumberForCheck): + (JSC::DFG::Node::hasRegisterPointer): + * dfg/DFGNodeFlags.h: + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileNotifyPutGlobalVar): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLAbbreviatedTypes.h: + * ftl/FTLAbbreviations.h: + (JSC::FTL::buildFence): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileNotifyPutGlobalVar): + * ftl/FTLOutput.h: + (JSC::FTL::Output::fence): + * jit/JIT.h: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitPutGlobalVar): + (JSC::JIT::emit_op_put_to_scope): + (JSC::JIT::emitSlow_op_put_to_scope): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitPutGlobalVar): + (JSC::JIT::emit_op_put_to_scope): + (JSC::JIT::emitSlow_op_put_to_scope): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * llvm/LLVMAPIFunctions.h: + * offlineasm/arm.rb: + * offlineasm/arm64.rb: + * offlineasm/cloop.rb: + * offlineasm/instructions.rb: + * offlineasm/x86.rb: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::addVar): + (JSC::JSGlobalObject::addConst): + * runtime/JSScope.cpp: + (JSC::abstractAccess): + * runtime/JSSymbolTableObject.h: + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::couldBeWatched): + (JSC::SymbolTableEntry::prepareToWatch): + (JSC::SymbolTableEntry::notifyWriteSlow): + * runtime/SymbolTable.h: - Parser fails to revert some state after parsing expression and object literals. - https://bugs.webkit.org/show_bug.cgi?id=83236 +2013-11-19 Michael Saboff - Reviewed by Gavin Barraclough. + REGRESSION(158384) ARMv7 point checks too restrictive for native calls to traditional ARM code + https://bugs.webkit.org/show_bug.cgi?id=124612 - Reset left hand side counter after parsing the literals. + Reviewed by Geoffrey Garen. - * parser/Parser.cpp: - (JSC::::parseObjectLiteral): - (JSC::::parseStrictObjectLiteral): - (JSC::::parseArrayLiteral): + Removed ASSERT checks (i.e. lower bit set) for ARM Thumb2 destination addresses related to + calls since we are calling native ARM traditional functions like sin() and cos(). -2012-04-04 Filip Pizlo + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::linkCall): + (JSC::ARMv7Assembler::relinkCall): + * assembler/MacroAssemblerCodeRef.h: - DFG InstanceOf should not uselessly speculate cell - https://bugs.webkit.org/show_bug.cgi?id=83234 +2013-11-19 Commit Queue - Reviewed by Oliver Hunt. - - If InstanceOf is the only user of its child then don't speculate cell, since - the not-cell case is super easy to handle. + Unreviewed, rolling out r159459. + http://trac.webkit.org/changeset/159459 + https://bugs.webkit.org/show_bug.cgi?id=124616 - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileInstanceOf): + tons of assertions on launch (Requested by thorton on + #webkit). -2012-04-04 Michael Saboff + * API/JSContext.mm: + (-[JSContext setException:]): + (-[JSContext wrapperForObjCObject:]): + (-[JSContext wrapperForJSObject:]): + * API/JSContextRef.cpp: + (JSContextGroupRelease): + (JSGlobalContextRelease): + * API/JSManagedValue.mm: + (-[JSManagedValue initWithValue:]): + (-[JSManagedValue value]): + * API/JSObjectRef.cpp: + (JSObjectIsFunction): + (JSObjectCopyPropertyNames): + * API/JSValue.mm: + (containerValueToObject): + * API/JSWrapperMap.mm: + (tryUnwrapObjcObject): - Fixed minor error: "& 3" should be "& 2". +2013-11-19 Filip Pizlo - Rubber-stamped by Oliver Hunt. + Rename WatchpointSet::notifyWrite() should be renamed to WatchpointSet::fireAll() + https://bugs.webkit.org/show_bug.cgi?id=124609 - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::additionBlindedConstant): + Rubber stamped by Mark Lam. + + notifyWrite() is a thing that SymbolTable does. WatchpointSet uses that terminology + because it was original designed to match exactly SymbolTable's semantics. But now + it's a confusing term. -2012-04-04 Michael Saboff + * bytecode/Watchpoint.cpp: + (JSC::WatchpointSet::fireAllSlow): + * bytecode/Watchpoint.h: + (JSC::WatchpointSet::fireAll): + (JSC::InlineWatchpointSet::fireAll): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * runtime/JSFunction.cpp: + (JSC::JSFunction::put): + (JSC::JSFunction::defineOwnProperty): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::haveABadTime): + * runtime/Structure.h: + (JSC::Structure::notifyTransitionFromThisStructure): + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::notifyWriteSlow): - Constant Blinding for add/sub immediate crashes in ArmV7 when dest is SP - https://bugs.webkit.org/show_bug.cgi?id=83191 +2013-11-18 Michael Saboff - Reviewed by Oliver Hunt. + REGRESSION (r159395): Error compiling for ARMv7 + https://bugs.webkit.org/show_bug.cgi?id=124552 - Make are that blinded constant pairs are similarly aligned to the - original immediate values so that instructions that expect that - alignment work correctly. One example is ARMv7 add/sub imm to SP. + Reviewed by Geoffrey Garen. - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::add): Added ASSERT that immediate is word aligned. - (JSC::ARMv7Assembler::sub): Added ASSERT that immediate is word aligned. - (JSC::ARMv7Assembler::sub_S): Added ASSERT that immediate is word aligned. - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::additionBlindedConstant): + Fixed the implementation of branch8(RelationalCondition cond, AbsoluteAddress address, TrustedImm32 right) + to materialize and use address similar to other ARMv7 branchXX() functions. -2012-04-04 Filip Pizlo + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::branch8): - DFG should short-circuit Branch(LogicalNot(...)) - https://bugs.webkit.org/show_bug.cgi?id=83181 +2013-11-19 Mark Lam - Reviewed by Geoff Garen. - - Slight (sub 1%) speed-up on V8. + Add tracking of endColumn for Executables. + https://bugs.webkit.org/show_bug.cgi?id=124245. - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): + Reviewed by Geoffrey Garen. -2012-04-04 Geoffrey Garen + 1. Fixed computation of columns to take into account the startColumn from +