diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-30 12:48:17 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-30 12:48:17 +0200 |
commit | 881da28418d380042aa95a97f0cbd42560a64f7c (patch) | |
tree | a794dff3274695e99c651902dde93d934ea7a5af /Source/JavaScriptCore/API | |
parent | 7e104c57a70fdf551bb3d22a5d637cdcbc69dbea (diff) | |
parent | 0fcedcd17cc00d3dd44c718b3cb36c1033319671 (diff) | |
download | qtwebkit-881da28418d380042aa95a97f0cbd42560a64f7c.tar.gz |
Merge 'wip/next' into dev
Change-Id: Iff9ee5e23bb326c4371ec8ed81d56f2f05d680e9
Diffstat (limited to 'Source/JavaScriptCore/API')
96 files changed, 4123 insertions, 6366 deletions
diff --git a/Source/JavaScriptCore/API/APICallbackFunction.h b/Source/JavaScriptCore/API/APICallbackFunction.h new file mode 100644 index 000000000..94b10c420 --- /dev/null +++ b/Source/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 "Error.h" +#include "JSCallbackConstructor.h" +#include "JSLock.h" +#include <wtf/Vector.h> + +namespace JSC { + +struct APICallbackFunction { + +template <typename T> static EncodedJSValue JSC_HOST_CALL call(ExecState*); +template <typename T> static EncodedJSValue JSC_HOST_CALL construct(ExecState*); + +}; + +template <typename T> +EncodedJSValue JSC_HOST_CALL APICallbackFunction::call(ExecState* exec) +{ + JSContextRef execRef = toRef(exec); + JSObjectRef functionRef = toRef(exec->callee()); + JSObjectRef thisObjRef = toRef(jsCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode))); + + int argumentCount = static_cast<int>(exec->argumentCount()); + Vector<JSValueRef, 16> arguments; + arguments.reserveInitialCapacity(argumentCount); + for (int i = 0; i < argumentCount; i++) + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); + + JSValueRef exception = 0; + JSValueRef result; + { + JSLock::DropAllLocks dropAllLocks(exec); + result = jsCast<T*>(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 <typename T> +EncodedJSValue JSC_HOST_CALL APICallbackFunction::construct(ExecState* exec) +{ + JSObject* constructor = exec->callee(); + JSContextRef ctx = toRef(exec); + JSObjectRef constructorRef = toRef(constructor); + + JSObjectCallAsConstructorCallback callback = jsCast<T*>(constructor)->constructCallback(); + if (callback) { + size_t argumentCount = exec->argumentCount(); + Vector<JSValueRef, 16> arguments; + arguments.reserveInitialCapacity(argumentCount); + for (size_t i = 0; i < argumentCount; ++i) + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); + + JSValueRef exception = 0; + JSObjectRef result; + { + JSLock::DropAllLocks dropAllLocks(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<JSCallbackConstructor*>(constructor)->classRef(), 0))); +} + +} // namespace JSC + +#endif // APICallbackFunction_h diff --git a/Source/JavaScriptCore/API/APICast.h b/Source/JavaScriptCore/API/APICast.h index fc5d71b2e..8fe8d6034 100644 --- a/Source/JavaScriptCore/API/APICast.h +++ b/Source/JavaScriptCore/API/APICast.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -28,6 +28,7 @@ #include "JSAPIValueWrapper.h" #include "JSCJSValue.h" +#include "JSCJSValueInlines.h" #include "JSGlobalObject.h" namespace JSC { @@ -123,6 +124,7 @@ inline JSC::VM* toJS(JSContextGroupRef g) inline JSValueRef toRef(JSC::ExecState* exec, JSC::JSValue v) { + ASSERT(exec->vm().currentThreadIsHoldingAPILock()); #if USE(JSVALUE32_64) if (!v) return 0; diff --git a/Source/JavaScriptCore/API/APIShims.h b/Source/JavaScriptCore/API/APIShims.h deleted file mode 100644 index d8e1fb790..000000000 --- a/Source/JavaScriptCore/API/APIShims.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef APIShims_h -#define APIShims_h - -#include "CallFrame.h" -#include "GCActivityCallback.h" -#include "IncrementalSweeper.h" -#include "JSLock.h" -#include <wtf/WTFThreadData.h> - -namespace JSC { - -class APIEntryShimWithoutLock { -protected: - APIEntryShimWithoutLock(VM* vm, bool registerThread) - : m_vm(vm) - , m_entryIdentifierTable(wtfThreadData().setCurrentIdentifierTable(vm->identifierTable)) - { - if (registerThread) - vm->heap.machineThreads().addCurrentThread(); - } - - ~APIEntryShimWithoutLock() - { - wtfThreadData().setCurrentIdentifierTable(m_entryIdentifierTable); - } - -protected: - RefPtr<VM> m_vm; - IdentifierTable* m_entryIdentifierTable; -}; - -class APIEntryShim : public APIEntryShimWithoutLock { -public: - // Normal API entry - APIEntryShim(ExecState* exec, bool registerThread = true) - : APIEntryShimWithoutLock(&exec->vm(), registerThread) - , m_lockHolder(exec) - { - } - - // JSPropertyNameAccumulator only has a vm. - APIEntryShim(VM* vm, bool registerThread = true) - : APIEntryShimWithoutLock(vm, registerThread) - , m_lockHolder(vm) - { - } - - ~APIEntryShim() - { - // Destroying our JSLockHolder should also destroy the VM. - m_vm.clear(); - } - -private: - JSLockHolder m_lockHolder; -}; - -class APICallbackShim { -public: - APICallbackShim(ExecState* exec) - : m_dropAllLocks(exec) - , m_vm(&exec->vm()) - { - wtfThreadData().resetCurrentIdentifierTable(); - } - - ~APICallbackShim() - { - wtfThreadData().setCurrentIdentifierTable(m_vm->identifierTable); - } - -private: - JSLock::DropAllLocks m_dropAllLocks; - VM* m_vm; -}; - -} - -#endif diff --git a/Source/JavaScriptCore/API/JSAPIWrapperObject.h b/Source/JavaScriptCore/API/JSAPIWrapperObject.h index 909039771..14194b6f9 100644 --- a/Source/JavaScriptCore/API/JSAPIWrapperObject.h +++ b/Source/JavaScriptCore/API/JSAPIWrapperObject.h @@ -45,8 +45,6 @@ public: void setWrappedObject(void*); protected: - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - JSAPIWrapperObject(VM&, Structure*); private: diff --git a/Source/JavaScriptCore/API/JSAPIWrapperObject.mm b/Source/JavaScriptCore/API/JSAPIWrapperObject.mm deleted file mode 100644 index c06de3978..000000000 --- a/Source/JavaScriptCore/API/JSAPIWrapperObject.mm +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 "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<JSC::Unknown>, void*); - virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&); -}; - -static JSAPIWrapperObjectHandleOwner* jsAPIWrapperObjectHandleOwner() -{ - DEFINE_STATIC_LOCAL(JSAPIWrapperObjectHandleOwner, jsWrapperObjectHandleOwner, ()); - return &jsWrapperObjectHandleOwner; -} - -void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void*) -{ - JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell()); - if (!wrapperObject->wrappedObject()) - return; - [static_cast<id>(wrapperObject->wrappedObject()) release]; - JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot())); -} - -bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor) -{ - JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(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<JSAPIWrapperObject>::s_info = { "JSAPIWrapperObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; - -template<> const bool JSCallbackObject<JSAPIWrapperObject>::needsDestruction = true; - -template <> -Structure* JSCallbackObject<JSAPIWrapperObject>::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<id>(wrappedObject) retain]; -} - -void JSAPIWrapperObject::visitChildren(JSCell* cell, JSC::SlotVisitor& visitor) -{ - JSAPIWrapperObject* thisObject = JSC::jsCast<JSAPIWrapperObject*>(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/Source/JavaScriptCore/API/JSBase.cpp b/Source/JavaScriptCore/API/JSBase.cpp index 7669ff1a9..6b2a907f1 100644 --- a/Source/JavaScriptCore/API/JSBase.cpp +++ b/Source/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 @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -28,18 +28,23 @@ #include "JSBasePrivate.h" #include "APICast.h" -#include "APIShims.h" #include "CallFrame.h" #include "Completion.h" +#include "Exception.h" +#include "GCActivityCallback.h" #include "InitializeThreading.h" #include "JSGlobalObject.h" #include "JSLock.h" #include "JSObject.h" #include "OpaqueJSString.h" -#include "Operations.h" +#include "JSCInlines.h" #include "SourceCode.h" #include <wtf/text/StringHash.h> +#if ENABLE(REMOTE_INSPECTOR) +#include "JSGlobalObjectInspectorController.h" +#endif + using namespace JSC; JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) @@ -49,20 +54,30 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsThisObject = toJS(thisObject); + startingLineNumber = std::max(1, startingLineNumber); + // evaluate sets "this" to the global object if it is NULL - JSGlobalObject* globalObject = exec->dynamicGlobalObject(); - SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + JSGlobalObject* globalObject = exec->vmEntryGlobalObject(); + SourceCode source = makeSource(script->string(), sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); - JSValue evaluationException; - JSValue returnValue = evaluate(globalObject->globalExec(), source, jsThisObject, &evaluationException); + NakedPtr<Exception> evaluationException; + JSValue returnValue = profiledEvaluate(globalObject->globalExec(), ProfilingReason::API, source, jsThisObject, evaluationException); if (evaluationException) { if (exception) - *exception = toRef(exec, evaluationException); + *exception = toRef(exec, evaluationException->value()); +#if ENABLE(REMOTE_INSPECTOR) + // FIXME: If we have a debugger attached we could learn about ParseError exceptions through + // ScriptDebugServer::sourceParsed and this path could produce a duplicate warning. The + // Debugger path is currently ignored by inspector. + // NOTE: If we don't have a debugger, this SourceCode will be forever lost to the inspector. + // We could stash it in the inspector in case an inspector is ever opened. + globalObject->inspectorController().reportAPIException(exec, evaluationException); +#endif return 0; } @@ -80,16 +95,22 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + startingLineNumber = std::max(1, startingLineNumber); + + SourceCode source = makeSource(script->string(), sourceURL ? sourceURL->string() : 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) *exception = toRef(exec, syntaxException); +#if ENABLE(REMOTE_INSPECTOR) + Exception* exception = Exception::create(exec->vm(), syntaxException); + exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); +#endif return false; } @@ -107,7 +128,7 @@ void JSGarbageCollect(JSContextRef ctx) return; ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec, false); + JSLockHolder locker(exec); exec->vm().heap.reportAbandonedObjectGraph(); } @@ -119,11 +140,13 @@ void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) return; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); - exec->vm().heap.reportExtraMemoryCost(size); + JSLockHolder locker(exec); + + exec->vm().heap.deprecatedReportExtraMemory(size); } extern "C" JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef); +extern "C" JS_EXPORT void JSSynchronousEdenCollectForDebugging(JSContextRef); void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx) { @@ -131,6 +154,38 @@ void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx) return; ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); exec->vm().heap.collectAllGarbage(); } + +void JSSynchronousEdenCollectForDebugging(JSContextRef ctx) +{ + if (!ctx) + return; + + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + exec->vm().heap.collect(EdenCollection); +} + +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 <rdar://problem/13696872> 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/Source/JavaScriptCore/API/JSBase.h b/Source/JavaScriptCore/API/JSBase.h index 50e8f1e64..f15271353 100644 --- a/Source/JavaScriptCore/API/JSBase.h +++ b/Source/JavaScriptCore/API/JSBase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,17 +10,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef JSBase_h @@ -84,11 +84,6 @@ typedef struct OpaqueJSValue* JSObjectRef; #define JS_EXPORT #endif /* defined(JS_NO_EXPORT) */ -/* JS tests uses WTF but has no config.h, so we need to set the export defines here. */ -#ifndef WTF_EXPORT_PRIVATE -#define WTF_EXPORT_PRIVATE JS_EXPORT -#endif - #ifdef __cplusplus extern "C" { #endif @@ -101,8 +96,8 @@ extern "C" { @param ctx The execution context to use. @param script A JSString containing the script to evaluate. @param thisObject The object to use as "this," or NULL to use the global object as "this." -@param sourceURL A JSString containing a URL for the script's source file. This is only used when reporting exceptions. Pass NULL if you do not care to include source file information in 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 sourceURL A JSString containing a URL for the script's source file. This is used by debuggers and when reporting exceptions. Pass NULL if you do not care to include source file information. +@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. The value is one-based, so the first line is line 1 and invalid values are clamped to 1. @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. */ @@ -114,7 +109,7 @@ JS_EXPORT JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSOb @param ctx The execution context to use. @param script A JSString containing the script to check for syntax errors. @param sourceURL A JSString containing a URL for the script's source file. This is only used when reporting exceptions. Pass NULL if you do not care to include source file information in 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 startingLineNumber An integer value specifying the script's starting line number in the file located at sourceURL. This is only used when reporting exceptions. The value is one-based, so the first line is line 1 and invalid values are clamped to 1. @param exception A pointer to a JSValueRef in which to store a syntax error exception, if any. Pass NULL if you do not care to store a syntax error exception. @result true if the script is syntactically correct, otherwise false. */ @@ -122,13 +117,13 @@ JS_EXPORT bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStrin /*! @function JSGarbageCollect -@abstract Performs a JavaScript garbage collection. +@abstract Performs a JavaScript garbage collection. @param ctx The execution context to use. -@discussion JavaScript values that are on the machine stack, in a register, - protected by JSValueProtect, set as the global object of an execution context, +@discussion JavaScript values that are on the machine stack, in a register, + protected by JSValueProtect, set as the global object of an execution context, or reachable from any such value will not be collected. - During JavaScript execution, you are not required to call this function; the + During JavaScript execution, you are not required to call this function; the JavaScript engine will garbage collect as needed. JavaScript values created within a context group are automatically destroyed when the last reference to the context group is released. @@ -141,7 +136,7 @@ JS_EXPORT void JSGarbageCollect(JSContextRef ctx); /* Enable the Objective-C API for platforms with a modern runtime. */ #if !defined(JSC_OBJC_API_ENABLED) -#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__)) +#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && !defined(__i386__)) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE))) #endif #endif /* JSBase_h */ diff --git a/Source/JavaScriptCore/API/JSBasePrivate.h b/Source/JavaScriptCore/API/JSBasePrivate.h index befa31643..137594972 100644 --- a/Source/JavaScriptCore/API/JSBasePrivate.h +++ b/Source/JavaScriptCore/API/JSBasePrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -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/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp b/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp index 394246711..d314c5d48 100644 --- a/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp +++ b/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp @@ -27,45 +27,38 @@ #include "JSCTestRunnerUtils.h" #include "APICast.h" -#include "CodeBlock.h" -#include "Operations.h" +#include "JSCInlines.h" +#include "TestRunnerUtils.h" namespace JSC { -static FunctionExecutable* getExecutable(JSContextRef context, JSValueRef theFunctionValueRef) + +JSValueRef failNextNewCodeBlock(JSContextRef context) { - ExecState* exec = toJS(context); - JSValue theFunctionValue = toJS(exec, theFunctionValueRef); - - JSFunction* theFunction = jsDynamicCast<JSFunction*>(theFunctionValue); - if (!theFunction) - return 0; - - FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>( - theFunction->executable()); - return executable; + ExecState* exec= toJS(context); + JSLockHolder holder(exec); + return toRef(exec, failNextNewCodeBlock(exec)); } JSValueRef numberOfDFGCompiles(JSContextRef context, JSValueRef theFunctionValueRef) { - if (FunctionExecutable* executable = getExecutable(context, theFunctionValueRef)) { - CodeBlock* baselineCodeBlock = executable->baselineCodeBlockFor(CodeForCall); - - if (!baselineCodeBlock) - return JSValueMakeNumber(context, 0); - - return JSValueMakeNumber(context, baselineCodeBlock->numberOfDFGCompiles()); - } - - return JSValueMakeUndefined(context); + ExecState* exec= toJS(context); + JSLockHolder holder(exec); + return toRef(exec, numberOfDFGCompiles(toJS(exec, theFunctionValueRef))); } JSValueRef setNeverInline(JSContextRef context, JSValueRef theFunctionValueRef) { - if (FunctionExecutable* executable = getExecutable(context, theFunctionValueRef)) - executable->setNeverInline(true); - - return JSValueMakeUndefined(context); + ExecState* exec= toJS(context); + JSLockHolder holder(exec); + return toRef(exec, setNeverInline(toJS(exec, theFunctionValueRef))); +} + +JSValueRef setNeverOptimize(JSContextRef context, JSValueRef theFunctionValueRef) +{ + ExecState* exec= toJS(context); + JSLockHolder holder(exec); + return toRef(exec, setNeverOptimize(toJS(exec, theFunctionValueRef))); } } // namespace JSC diff --git a/Source/JavaScriptCore/API/JSCTestRunnerUtils.h b/Source/JavaScriptCore/API/JSCTestRunnerUtils.h index aaecdd5c9..c52da524b 100644 --- a/Source/JavaScriptCore/API/JSCTestRunnerUtils.h +++ b/Source/JavaScriptCore/API/JSCTestRunnerUtils.h @@ -31,8 +31,10 @@ namespace JSC { +JS_EXPORT_PRIVATE JSValueRef failNextNewCodeBlock(JSContextRef); JS_EXPORT_PRIVATE JSValueRef numberOfDFGCompiles(JSContextRef, JSValueRef theFunction); JS_EXPORT_PRIVATE JSValueRef setNeverInline(JSContextRef, JSValueRef theFunction); +JS_EXPORT_PRIVATE JSValueRef setNeverOptimize(JSContextRef, JSValueRef theFunction); } // namespace JSC diff --git a/Source/JavaScriptCore/API/JSCallbackConstructor.cpp b/Source/JavaScriptCore/API/JSCallbackConstructor.cpp index 8340c10b4..65e66dc13 100644 --- a/Source/JavaScriptCore/API/JSCallbackConstructor.cpp +++ b/Source/JavaScriptCore/API/JSCallbackConstructor.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -26,18 +26,18 @@ #include "config.h" #include "JSCallbackConstructor.h" -#include "APIShims.h" +#include "APICallbackFunction.h" #include "APICast.h" #include "Error.h" #include "JSGlobalObject.h" #include "JSLock.h" #include "ObjectPrototype.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/Vector.h> namespace JSC { -const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) }; +const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) }; JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback) : JSDestructibleObject(globalObject->vm(), structure) @@ -49,7 +49,7 @@ JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Struc void JSCallbackConstructor::finishCreation(JSGlobalObject* globalObject, JSClassRef jsClass) { Base::finishCreation(globalObject->vm()); - ASSERT(inherits(&s_info)); + ASSERT(inherits(info())); if (m_class) JSClassRetain(jsClass); } @@ -65,40 +65,9 @@ void JSCallbackConstructor::destroy(JSCell* cell) static_cast<JSCallbackConstructor*>(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<JSCallbackConstructor*>(constructor)->callback(); - if (callback) { - size_t argumentCount = exec->argumentCount(); - Vector<JSValueRef, 16> arguments; - arguments.reserveInitialCapacity(argumentCount); - for (size_t i = 0; i < argumentCount; ++i) - arguments.uncheckedAppend(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<JSCallbackConstructor*>(constructor)->classRef(), 0))); -} - ConstructType JSCallbackConstructor::getConstructData(JSCell*, ConstructData& constructData) { - constructData.native.function = constructJSCallback; + constructData.native.function = APICallbackFunction::construct<JSCallbackConstructor>; return ConstructTypeHost; } diff --git a/Source/JavaScriptCore/API/JSCallbackConstructor.h b/Source/JavaScriptCore/API/JSCallbackConstructor.h index 72100e672..d730ad779 100644 --- a/Source/JavaScriptCore/API/JSCallbackConstructor.h +++ b/Source/JavaScriptCore/API/JSCallbackConstructor.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -34,6 +34,7 @@ namespace JSC { class JSCallbackConstructor : public JSDestructibleObject { public: typedef JSDestructibleObject Base; + static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | ImplementsDefaultHasInstance; static JSCallbackConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, JSObjectCallAsConstructorCallback callback) { @@ -46,21 +47,24 @@ public: 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(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); } protected: JSCallbackConstructor(JSGlobalObject*, Structure*, JSClassRef, JSObjectCallAsConstructorCallback); void finishCreation(JSGlobalObject*, JSClassRef); - 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/Source/JavaScriptCore/API/JSCallbackFunction.cpp b/Source/JavaScriptCore/API/JSCallbackFunction.cpp index c29b9077c..047fcd01c 100644 --- a/Source/JavaScriptCore/API/JSCallbackFunction.cpp +++ b/Source/JavaScriptCore/API/JSCallbackFunction.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -26,7 +26,7 @@ #include "config.h" #include "JSCallbackFunction.h" -#include "APIShims.h" +#include "APICallbackFunction.h" #include "APICast.h" #include "CodeBlock.h" #include "Error.h" @@ -35,17 +35,17 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSLock.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/Vector.h> namespace JSC { -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) }; +const ClassInfo JSCallbackFunction::s_info = { "CallbackFunction", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(JSCallbackFunction) }; -JSCallbackFunction::JSCallbackFunction(JSGlobalObject* globalObject, Structure* structure, JSObjectCallAsFunctionCallback callback) - : InternalFunction(globalObject, structure) +JSCallbackFunction::JSCallbackFunction(VM& vm, Structure* structure, JSObjectCallAsFunctionCallback callback) + : InternalFunction(vm, structure) , m_callback(callback) { } @@ -53,47 +53,19 @@ JSCallbackFunction::JSCallbackFunction(JSGlobalObject* globalObject, Structure* void JSCallbackFunction::finishCreation(VM& vm, const String& name) { Base::finishCreation(vm, name); - ASSERT(inherits(&s_info)); + ASSERT(inherits(info())); } -JSCallbackFunction* JSCallbackFunction::create(ExecState* exec, JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback callback, const String& name) +JSCallbackFunction* JSCallbackFunction::create(VM& vm, JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback callback, const String& name) { - JSCallbackFunction* function = new (NotNull, allocateCell<JSCallbackFunction>(*exec->heap())) JSCallbackFunction(globalObject, globalObject->callbackFunctionStructure(), callback); - function->finishCreation(exec->vm(), name); + JSCallbackFunction* function = new (NotNull, allocateCell<JSCallbackFunction>(vm.heap)) JSCallbackFunction(vm, globalObject->callbackFunctionStructure(), callback); + function->finishCreation(vm, name); return function; } -EncodedJSValue JSCallbackFunction::call(ExecState* exec) -{ - JSContextRef execRef = toRef(exec); - JSObjectRef functionRef = toRef(exec->callee()); - JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec)); - - size_t argumentCount = exec->argumentCount(); - Vector<JSValueRef, 16> arguments; - arguments.reserveInitialCapacity(argumentCount); - for (size_t i = 0; i < argumentCount; ++i) - arguments.uncheckedAppend(toRef(exec, exec->argument(i))); - - JSValueRef exception = 0; - JSValueRef result; - { - APICallbackShim callbackShim(exec); - result = jsCast<JSCallbackFunction*>(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)); -} - CallType JSCallbackFunction::getCallData(JSCell*, CallData& callData) { - callData.native.function = call; + callData.native.function = APICallbackFunction::call<JSCallbackFunction>; return CallTypeHost; } diff --git a/Source/JavaScriptCore/API/JSCallbackFunction.h b/Source/JavaScriptCore/API/JSCallbackFunction.h index 885ef949d..a4fdd068f 100644 --- a/Source/JavaScriptCore/API/JSCallbackFunction.h +++ b/Source/JavaScriptCore/API/JSCallbackFunction.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -32,29 +32,28 @@ namespace JSC { class JSCallbackFunction : public InternalFunction { -protected: - JSCallbackFunction(JSGlobalObject*, Structure*, JSObjectCallAsFunctionCallback); - void finishCreation(VM&, const String& name); - + friend struct APICallbackFunction; public: typedef InternalFunction Base; - static JSCallbackFunction* create(ExecState*, JSGlobalObject*, JSObjectCallAsFunctionCallback, const String& name); + 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(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); } -protected: +private: + JSCallbackFunction(VM&, Structure*, JSObjectCallAsFunctionCallback); + void finishCreation(VM&, const String& name); + static CallType getCallData(JSCell*, CallData&); -private: - static EncodedJSValue JSC_HOST_CALL call(ExecState*); + JSObjectCallAsFunctionCallback functionCallback() { return m_callback; } JSObjectCallAsFunctionCallback m_callback; }; diff --git a/Source/JavaScriptCore/API/JSCallbackObject.cpp b/Source/JavaScriptCore/API/JSCallbackObject.cpp index 7436e71f7..02b38fde7 100644 --- a/Source/JavaScriptCore/API/JSCallbackObject.cpp +++ b/Source/JavaScriptCore/API/JSCallbackObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * Copyright (C) 2007 Eric Seidel <eric@webkit.org> * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -28,14 +28,14 @@ #include "JSCallbackObject.h" #include "Heap.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/text/StringHash.h> namespace JSC { // Define the two types of JSCallbackObjects we support. -template <> const ClassInfo JSCallbackObject<JSDestructibleObject>::s_info = { "CallbackObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; -template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; +template <> const ClassInfo JSCallbackObject<JSDestructibleObject>::s_info = { "CallbackObject", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; +template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; template<> const bool JSCallbackObject<JSDestructibleObject>::needsDestruction = true; template<> const bool JSCallbackObject<JSGlobalObject>::needsDestruction = false; @@ -43,7 +43,7 @@ template<> const bool JSCallbackObject<JSGlobalObject>::needsDestruction = false template<> JSCallbackObject<JSGlobalObject>* JSCallbackObject<JSGlobalObject>::create(VM& vm, JSClassRef classRef, Structure* structure) { - JSCallbackObject<JSGlobalObject>* callbackObject = new (NotNull, allocateCell<JSCallbackObject<JSGlobalObject> >(vm.heap)) JSCallbackObject(vm, classRef, structure); + JSCallbackObject<JSGlobalObject>* callbackObject = new (NotNull, allocateCell<JSCallbackObject<JSGlobalObject>>(vm.heap)) JSCallbackObject(vm, classRef, structure); callbackObject->finishCreation(vm); vm.heap.addFinalizer(callbackObject, destroy); return callbackObject; @@ -52,24 +52,13 @@ JSCallbackObject<JSGlobalObject>* JSCallbackObject<JSGlobalObject>::create(VM& v template <> Structure* JSCallbackObject<JSDestructibleObject>::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); } template <> Structure* JSCallbackObject<JSGlobalObject>::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { - return Structure::create(vm, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), info()); } -void JSCallbackObjectData::finalize(Handle<Unknown> handle, void* context) -{ - JSClassRef jsClass = static_cast<JSClassRef>(context); - JSObjectRef thisRef = toRef(static_cast<JSObject*>(handle.get().asCell())); - - for (; jsClass; jsClass = jsClass->parentClass) - if (JSObjectFinalizeCallback finalize = jsClass->finalize) - finalize(thisRef); - WeakSet::deallocate(WeakImpl::asWeakImpl(handle.slot())); -} - } // namespace JSC diff --git a/Source/JavaScriptCore/API/JSCallbackObject.h b/Source/JavaScriptCore/API/JSCallbackObject.h index 16d8aa2c6..8356e704d 100644 --- a/Source/JavaScriptCore/API/JSCallbackObject.h +++ b/Source/JavaScriptCore/API/JSCallbackObject.h @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -30,11 +30,12 @@ #include "JSObjectRef.h" #include "JSValueRef.h" #include "JSObject.h" -#include <wtf/PassOwnPtr.h> namespace JSC { -struct JSCallbackObjectData : WeakHandleOwner { +struct JSCallbackObjectData { + WTF_MAKE_FAST_ALLOCATED; +public: JSCallbackObjectData(void* privateData, JSClassRef jsClass) : privateData(privateData) , jsClass(jsClass) @@ -57,7 +58,7 @@ struct JSCallbackObjectData : WeakHandleOwner { void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value) { if (!m_privateProperties) - m_privateProperties = adoptPtr(new JSPrivatePropertyMap); + m_privateProperties = std::make_unique<JSPrivatePropertyMap>(); m_privateProperties->setPrivateProperty(vm, owner, propertyName, value); } @@ -78,6 +79,8 @@ struct JSCallbackObjectData : WeakHandleOwner { void* privateData; JSClassRef jsClass; struct JSPrivatePropertyMap { + WTF_MAKE_FAST_ALLOCATED; + public: JSValue getPrivateProperty(const Identifier& propertyName) const { PrivatePropertyMap::const_iterator location = m_propertyMap.find(propertyName.impl()); @@ -106,11 +109,10 @@ struct JSCallbackObjectData : WeakHandleOwner { } private: - typedef HashMap<RefPtr<StringImpl>, WriteBarrier<Unknown>, IdentifierRepHash> PrivatePropertyMap; + typedef HashMap<RefPtr<UniquedStringImpl>, WriteBarrier<Unknown>, IdentifierRepHash> PrivatePropertyMap; PrivatePropertyMap m_propertyMap; }; - OwnPtr<JSPrivatePropertyMap> m_privateProperties; - virtual void finalize(Handle<Unknown>, void*); + std::unique_ptr<JSPrivatePropertyMap> m_privateProperties; }; @@ -125,6 +127,9 @@ protected: public: typedef Parent Base; + static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesGetPropertyNames | TypeOfShouldCallGetCallData; + + ~JSCallbackObject(); static JSCallbackObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data) { @@ -144,7 +149,19 @@ public: void setPrivate(void* data); void* getPrivate(); - static const ClassInfo s_info; + // FIXME: We should fix the warnings for extern-template in JSObject template classes: https://bugs.webkit.org/show_bug.cgi?id=161979 +#if COMPILER(CLANG) +#if __has_warning("-Wundefined-var-template") +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-var-template" +#endif +#endif + DECLARE_INFO; +#if COMPILER(CLANG) +#if __has_warning("-Wundefined-var-template") +#pragma clang diagnostic pop +#endif +#endif JSClassRef classRef() const { return m_callbackObjectData->jsClass; } bool inherits(JSClassRef) const; @@ -168,17 +185,13 @@ public: using Parent::methodTable; -protected: - static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Parent::StructureFlags; - private: static String className(const JSObject*); static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); static void putByIndex(JSCell*, ExecState*, unsigned, JSValue, bool shouldThrow); @@ -196,9 +209,7 @@ private: static void visitChildren(JSCell* cell, SlotVisitor& visitor) { JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); - ASSERT_GC_OBJECT_INHERITS((static_cast<Parent*>(thisObject)), &JSCallbackObject<Parent>::s_info); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->Parent::structure()->typeInfo().overridesVisitChildren()); + ASSERT_GC_OBJECT_INHERITS((static_cast<Parent*>(thisObject)), JSCallbackObject<Parent>::info()); Parent::visitChildren(thisObject, visitor); thisObject->m_callbackObjectData->visitChildren(visitor); } @@ -206,15 +217,16 @@ private: 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*, PropertyName); - static JSValue staticFunctionGetter(ExecState*, JSValue, PropertyName); - static JSValue callbackGetter(ExecState*, JSValue, PropertyName); + static EncodedJSValue staticFunctionGetter(ExecState*, EncodedJSValue, PropertyName); + static EncodedJSValue callbackGetter(ExecState*, EncodedJSValue, PropertyName); - OwnPtr<JSCallbackObjectData> m_callbackObjectData; + std::unique_ptr<JSCallbackObjectData> m_callbackObjectData; }; } // namespace JSC diff --git a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h index b92e3161e..6e0a6ceb4 100644 --- a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h +++ b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -24,7 +24,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "APIShims.h" #include "APICast.h" #include "Error.h" #include "ExceptionHelpers.h" @@ -45,14 +44,21 @@ namespace JSC { template <class Parent> inline JSCallbackObject<Parent>* JSCallbackObject<Parent>::asCallbackObject(JSValue value) { - ASSERT(asObject(value)->inherits(&s_info)); + ASSERT(asObject(value)->inherits(info())); return jsCast<JSCallbackObject*>(asObject(value)); } template <class Parent> +inline JSCallbackObject<Parent>* JSCallbackObject<Parent>::asCallbackObject(EncodedJSValue value) +{ + ASSERT(asObject(JSValue::decode(value))->inherits(info())); + return jsCast<JSCallbackObject*>(asObject(JSValue::decode(value))); +} + +template <class Parent> JSCallbackObject<Parent>::JSCallbackObject(ExecState* exec, Structure* structure, JSClassRef jsClass, void* data) : Parent(exec->vm(), structure) - , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass))) + , m_callbackObjectData(std::make_unique<JSCallbackObjectData>(data, jsClass)) { } @@ -61,15 +67,25 @@ JSCallbackObject<Parent>::JSCallbackObject(ExecState* exec, Structure* structure template <class Parent> JSCallbackObject<Parent>::JSCallbackObject(VM& vm, JSClassRef jsClass, Structure* structure) : Parent(vm, structure) - , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass))) + , m_callbackObjectData(std::make_unique<JSCallbackObjectData>(nullptr, jsClass)) { } template <class Parent> +JSCallbackObject<Parent>::~JSCallbackObject() +{ + JSObjectRef thisRef = toRef(static_cast<JSObject*>(this)); + for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { + if (JSObjectFinalizeCallback finalize = jsClass->finalize) + finalize(thisRef); + } +} + +template <class Parent> void JSCallbackObject<Parent>::finishCreation(ExecState* exec) { Base::finishCreation(exec->vm()); - ASSERT(Parent::inherits(&s_info)); + ASSERT(Parent::inherits(info())); init(exec); } @@ -77,7 +93,7 @@ void JSCallbackObject<Parent>::finishCreation(ExecState* exec) template <class Parent> void JSCallbackObject<Parent>::finishCreation(VM& vm) { - ASSERT(Parent::inherits(&s_info)); + ASSERT(Parent::inherits(info())); ASSERT(Parent::isGlobalObject()); Base::finishCreation(vm); init(jsCast<JSGlobalObject*>(this)->globalExec()); @@ -97,17 +113,10 @@ void JSCallbackObject<Parent>::init(ExecState* exec) // initialize from base to derived for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); JSObjectInitializeCallback initialize = initRoutines[i]; initialize(toRef(exec), toRef(this)); } - - for (JSClassRef jsClassPtr = classRef(); jsClassPtr; jsClassPtr = jsClassPtr->parentClass) { - if (jsClassPtr->finalize) { - WeakSet::allocate(this, m_callbackObjectData.get(), classRef()); - break; - } - } } template <class Parent> @@ -122,22 +131,22 @@ String JSCallbackObject<Parent>::className(const JSObject* object) } template <class Parent> -bool JSCallbackObject<Parent>::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); + JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); JSContextRef ctx = toRef(exec); JSObjectRef thisRef = toRef(thisObject); RefPtr<OpaqueJSString> propertyNameRef; - if (StringImpl* name = propertyName.publicName()) { + if (StringImpl* name = propertyName.uid()) { 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); + JSLock::DropAllLocks dropAllLocks(exec); if (hasProperty(ctx, thisRef, propertyNameRef.get())) { - slot.setCustom(thisObject, callbackGetter); + slot.setCustom(thisObject, ReadOnly | DontEnum, callbackGetter); return true; } } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { @@ -146,16 +155,16 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSCell* cell, ExecState* exec, JSValueRef exception = 0; JSValueRef value; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); } if (exception) { - throwError(exec, toJS(exec, exception)); - slot.setValue(jsUndefined()); + exec->vm().throwException(exec, toJS(exec, exception)); + slot.setValue(thisObject, ReadOnly | DontEnum, jsUndefined()); return true; } if (value) { - slot.setValue(toJS(exec, value)); + slot.setValue(thisObject, ReadOnly | DontEnum, toJS(exec, value)); return true; } } @@ -164,7 +173,7 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSCell* cell, ExecState* exec, if (staticValues->contains(name)) { JSValue value = thisObject->getStaticValue(exec, propertyName); if (value) { - slot.setValue(value); + slot.setValue(thisObject, ReadOnly | DontEnum, value); return true; } } @@ -172,7 +181,7 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSCell* cell, ExecState* exec, if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { if (staticFunctions->contains(name)) { - slot.setCustom(thisObject, staticFunctionGetter); + slot.setCustom(thisObject, ReadOnly | DontEnum, staticFunctionGetter); return true; } } @@ -183,9 +192,9 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSCell* cell, ExecState* exec, } template <class Parent> -bool JSCallbackObject<Parent>::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot) +bool JSCallbackObject<Parent>::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot) { - return cell->methodTable()->getOwnPropertySlot(cell, exec, Identifier::from(exec, propertyName), slot); + return object->methodTable()->getOwnPropertySlot(object, exec, Identifier::from(exec, propertyName), slot); } template <class Parent> @@ -201,7 +210,7 @@ JSValue JSCallbackObject<Parent>::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) @@ -213,26 +222,6 @@ JSValue JSCallbackObject<Parent>::defaultValue(const JSObject* object, ExecState } template <class Parent> -bool JSCallbackObject<Parent>::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) -{ - JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); - PropertySlot slot(thisObject); - 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; - } - - return Parent::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); -} - -template <class Parent> void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); @@ -241,7 +230,7 @@ void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName p RefPtr<OpaqueJSString> propertyNameRef; JSValueRef valueRef = toRef(exec, value); - if (StringImpl* name = propertyName.publicName()) { + if (StringImpl* name = propertyName.uid()) { for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { if (!propertyNameRef) @@ -249,11 +238,11 @@ void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName p JSValueRef exception = 0; bool result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); 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; } @@ -263,16 +252,14 @@ void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName p if (entry->attributes & kJSPropertyAttributeReadOnly) return; if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(name); JSValueRef exception = 0; bool result; { - APICallbackShim callbackShim(exec); - result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); + JSLock::DropAllLocks dropAllLocks(exec); + 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; } @@ -281,6 +268,9 @@ void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName p if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { if (StaticFunctionEntry* entry = staticFunctions->get(name)) { + PropertySlot getSlot(thisObject, PropertySlot::InternalMethodType::VMInquiry); + if (Parent::getOwnPropertySlot(thisObject, exec, propertyName, getSlot)) + return Parent::put(thisObject, exec, propertyName, value, slot); if (entry->attributes & kJSPropertyAttributeReadOnly) return; thisObject->JSCallbackObject<Parent>::putDirect(exec->vm(), propertyName, value); // put as override property @@ -301,7 +291,7 @@ void JSCallbackObject<Parent>::putByIndex(JSCell* cell, ExecState* exec, unsigne JSObjectRef thisRef = toRef(thisObject); RefPtr<OpaqueJSString> propertyNameRef; JSValueRef valueRef = toRef(exec, value); - Identifier propertyName = Identifier(exec, String::number(propertyIndex)); + Identifier propertyName = Identifier::from(exec, propertyIndex); for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { @@ -310,11 +300,11 @@ void JSCallbackObject<Parent>::putByIndex(JSCell* cell, ExecState* exec, unsigne JSValueRef exception = 0; bool result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); 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; } @@ -324,16 +314,14 @@ void JSCallbackObject<Parent>::putByIndex(JSCell* cell, ExecState* exec, unsigne if (entry->attributes & kJSPropertyAttributeReadOnly) return; if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(propertyName.impl()); JSValueRef exception = 0; bool result; { - APICallbackShim callbackShim(exec); - result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); + JSLock::DropAllLocks dropAllLocks(exec); + 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; } @@ -360,7 +348,7 @@ bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, ExecState* exec, Pro JSObjectRef thisRef = toRef(thisObject); RefPtr<OpaqueJSString> propertyNameRef; - if (StringImpl* name = propertyName.publicName()) { + if (StringImpl* name = propertyName.uid()) { for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { if (!propertyNameRef) @@ -368,11 +356,11 @@ bool JSCallbackObject<Parent>::deleteProperty(JSCell* cell, ExecState* exec, Pro JSValueRef exception = 0; bool result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); } if (exception) - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); if (result || exception) return true; } @@ -431,15 +419,15 @@ EncodedJSValue JSCallbackObject<Parent>::construct(ExecState* exec) Vector<JSValueRef, 16> arguments; arguments.reserveInitialCapacity(argumentCount); for (size_t i = 0; i < argumentCount; ++i) - arguments.uncheckedAppend(toRef(exec, exec->argument(i))); + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); JSValueRef exception = 0; JSObject* result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(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); } } @@ -461,11 +449,11 @@ bool JSCallbackObject<Parent>::customHasInstance(JSObject* object, ExecState* ex JSValueRef exception = 0; bool result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); result = hasInstance(execRef, thisRef, valueRef, &exception); } if (exception) - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); return result; } } @@ -490,7 +478,7 @@ EncodedJSValue JSCallbackObject<Parent>::call(ExecState* exec) { JSContextRef execRef = toRef(exec); JSObjectRef functionRef = toRef(exec->callee()); - JSObjectRef thisObjRef = toRef(exec->hostThisValue().toThisObject(exec)); + JSObjectRef thisObjRef = toRef(jsCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode))); for (JSClassRef jsClass = jsCast<JSCallbackObject<Parent>*>(toJS(functionRef))->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { @@ -498,15 +486,15 @@ EncodedJSValue JSCallbackObject<Parent>::call(ExecState* exec) Vector<JSValueRef, 16> arguments; arguments.reserveInitialCapacity(argumentCount); for (size_t i = 0; i < argumentCount; ++i) - arguments.uncheckedAppend(toRef(exec, exec->argument(i))); + arguments.uncheckedAppend(toRef(exec, exec->uncheckedArgument(i))); JSValueRef exception = 0; JSValue result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(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); } } @@ -524,7 +512,7 @@ void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, Exe for (JSClassRef jsClass = thisObject->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); getPropertyNames(execRef, thisRef, toRef(&propertyNames)); } @@ -534,8 +522,10 @@ void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, Exe for (iterator it = staticValues->begin(); it != end; ++it) { StringImpl* name = it->key.get(); StaticValueEntry* entry = it->value.get(); - if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) - propertyNames.add(Identifier(exec, name)); + if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || mode.includeDontEnumProperties())) { + ASSERT(!name->isSymbol()); + propertyNames.add(Identifier::fromString(exec, String(name))); + } } } @@ -545,8 +535,10 @@ void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, Exe for (iterator it = staticFunctions->begin(); it != end; ++it) { StringImpl* name = it->key.get(); StaticFunctionEntry* entry = it->value.get(); - if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) - propertyNames.add(Identifier(exec, name)); + if (!(entry->attributes & kJSPropertyAttributeDontEnum) || mode.includeDontEnumProperties()) { + ASSERT(!name->isSymbol()); + propertyNames.add(Identifier::fromString(exec, String(name))); + } } } } @@ -580,23 +572,20 @@ template <class Parent> JSValue JSCallbackObject<Parent>::getStaticValue(ExecState* exec, PropertyName propertyName) { JSObjectRef thisRef = toRef(this); - RefPtr<OpaqueJSString> propertyNameRef; - if (StringImpl* name = propertyName.publicName()) { + if (StringImpl* name = propertyName.uid()) { 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) { - if (!propertyNameRef) - propertyNameRef = OpaqueJSString::create(name); JSValueRef exception = 0; JSValueRef value; { - APICallbackShim callbackShim(exec); - value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); + JSLock::DropAllLocks dropAllLocks(exec); + value = getProperty(toRef(exec), thisRef, entry->propertyNameRef.get(), &exception); } if (exception) { - throwError(exec, toJS(exec, exception)); + exec->vm().throwException(exec, toJS(exec, exception)); return jsUndefined(); } if (value) @@ -611,42 +600,42 @@ JSValue JSCallbackObject<Parent>::getStaticValue(ExecState* exec, PropertyName p } template <class Parent> -JSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, JSValue slotParent, PropertyName propertyName) +EncodedJSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName) { - JSCallbackObject* thisObj = asCallbackObject(slotParent); + JSCallbackObject* thisObj = asCallbackObject(thisValue); // Check for cached or override property. - PropertySlot slot2(thisObj); + PropertySlot slot2(thisObj, PropertySlot::InternalMethodType::VMInquiry); if (Parent::getOwnPropertySlot(thisObj, exec, propertyName, slot2)) - return slot2.getValue(exec, propertyName); - - if (StringImpl* name = propertyName.publicName()) { + return JSValue::encode(slot2.getValue(exec, propertyName)); + + if (StringImpl* name = propertyName.uid()) { 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) { - - JSObject* o = JSCallbackFunction::create(exec, thisObj->globalObject(), callAsFunction, name); - thisObj->putDirect(exec->vm(), propertyName, o, entry->attributes); - return o; + 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, ASCIILiteral("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 <class Parent> -JSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, JSValue slotParent, PropertyName propertyName) +EncodedJSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName) { - JSCallbackObject* thisObj = asCallbackObject(slotParent); + JSCallbackObject* thisObj = asCallbackObject(thisValue); JSObjectRef thisRef = toRef(thisObj); RefPtr<OpaqueJSString> propertyNameRef; - if (StringImpl* name = propertyName.publicName()) { + if (StringImpl* name = propertyName.uid()) { for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { if (!propertyNameRef) @@ -654,20 +643,20 @@ JSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, JSValue slotPa JSValueRef exception = 0; JSValueRef value; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); } if (exception) { - throwError(exec, toJS(exec, exception)); - return jsUndefined(); + exec->vm().throwException(exec, toJS(exec, exception)); + return JSValue::encode(jsUndefined()); } if (value) - return toJS(exec, value); + return JSValue::encode(toJS(exec, value)); } } } - return throwError(exec, createReferenceError(exec, ASCIILiteral("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/Source/JavaScriptCore/API/JSClassRef.cpp b/Source/JavaScriptCore/API/JSClassRef.cpp index c77f63cf9..e0dbe6043 100644 --- a/Source/JavaScriptCore/API/JSClassRef.cpp +++ b/Source/JavaScriptCore/API/JSClassRef.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -33,7 +33,7 @@ #include "JSGlobalObject.h" #include "JSObjectRef.h" #include "ObjectPrototype.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/text/StringHash.h> #include <wtf/unicode/UTF8.h> @@ -62,21 +62,21 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* initializeThreading(); if (const JSStaticValue* staticValue = definition->staticValues) { - m_staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable); + m_staticValues = std::make_unique<OpaqueJSClassStaticValuesTable>(); while (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<StaticValueEntry>(staticValue->getProperty, staticValue->setProperty, staticValue->attributes, valueName)); ++staticValue; } } if (const JSStaticFunction* staticFunction = definition->staticFunctions) { - m_staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable); + m_staticFunctions = std::make_unique<OpaqueJSClassStaticFunctionsTable>(); while (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<StaticFunctionEntry>(staticFunction->callAsFunction, staticFunction->attributes)); ++staticFunction; } } @@ -88,19 +88,19 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* OpaqueJSClass::~OpaqueJSClass() { // The empty string is shared across threads & is an identifier, in all other cases we should have done a deep copy in className(), below. - ASSERT(!m_className.length() || !m_className.impl()->isIdentifier()); + ASSERT(!m_className.length() || !m_className.impl()->isAtomic()); #ifndef NDEBUG if (m_staticValues) { OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end(); for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it) - ASSERT(!it->key->isIdentifier()); + ASSERT(!it->key->isAtomic()); } if (m_staticFunctions) { OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end(); for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it) - ASSERT(!it->key->isIdentifier()); + ASSERT(!it->key->isAtomic()); } #endif @@ -108,12 +108,12 @@ OpaqueJSClass::~OpaqueJSClass() JSClassRelease(prototypeClass); } -PassRefPtr<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition) +Ref<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition) { - return adoptRef(new OpaqueJSClass(definition, 0)); + return adoptRef(*new OpaqueJSClass(definition, 0)); } -PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition) +Ref<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition) { JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy. @@ -124,42 +124,43 @@ PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientD // We are supposed to use JSClassRetain/Release but since we know that we currently have // the only reference to this class object we cheat and use a RefPtr instead. RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0)); - return adoptRef(new OpaqueJSClass(&definition, protoClass.get())); + return adoptRef(*new OpaqueJSClass(&definition, protoClass.get())); } OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsClass) : m_class(jsClass) { if (jsClass->m_staticValues) { - staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable); + staticValues = std::make_unique<OpaqueJSClassStaticValuesTable>(); OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end(); for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) { - ASSERT(!it->key->isIdentifier()); - staticValues->add(it->key->isolatedCopy(), adoptPtr(new StaticValueEntry(it->value->getProperty, it->value->setProperty, it->value->attributes))); + ASSERT(!it->key->isAtomic()); + String valueName = it->key->isolatedCopy(); + staticValues->add(valueName.impl(), std::make_unique<StaticValueEntry>(it->value->getProperty, it->value->setProperty, it->value->attributes, valueName)); } } if (jsClass->m_staticFunctions) { - staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable); + staticFunctions = std::make_unique<OpaqueJSClassStaticFunctionsTable>(); OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end(); for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) { - ASSERT(!it->key->isIdentifier()); - staticFunctions->add(it->key->isolatedCopy(), adoptPtr(new StaticFunctionEntry(it->value->callAsFunction, it->value->attributes))); + ASSERT(!it->key->isAtomic()); + staticFunctions->add(it->key->isolatedCopy(), std::make_unique<StaticFunctionEntry>(it->value->callAsFunction, it->value->attributes)); } } } OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec) { - OwnPtr<OpaqueJSClassContextData>& contextData = exec->lexicalGlobalObject()->opaqueJSClassData().add(this, nullptr).iterator->value; + std::unique_ptr<OpaqueJSClassContextData>& contextData = exec->lexicalGlobalObject()->opaqueJSClassData().add(this, nullptr).iterator->value; if (!contextData) - contextData = adoptPtr(new OpaqueJSClassContextData(exec->vm(), this)); + contextData = std::make_unique<OpaqueJSClassContextData>(exec->vm(), this); return *contextData; } String OpaqueJSClass::className() { - // Make a deep copy, so that the caller has no chance to put the original into IdentifierTable. + // Make a deep copy, so that the caller has no chance to put the original into AtomicStringTable. return m_className.isolatedCopy(); } @@ -206,6 +207,6 @@ JSObject* OpaqueJSClass::prototype(ExecState* exec) prototype->setPrototype(exec->vm(), parentPrototype); } - jsClassData.cachedPrototype = PassWeak<JSObject>(prototype); + jsClassData.cachedPrototype = Weak<JSObject>(prototype); return prototype; } diff --git a/Source/JavaScriptCore/API/JSClassRef.h b/Source/JavaScriptCore/API/JSClassRef.h index 7bf18e758..fa024d344 100644 --- a/Source/JavaScriptCore/API/JSClassRef.h +++ b/Source/JavaScriptCore/API/JSClassRef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -26,24 +26,25 @@ #ifndef JSClassRef_h #define JSClassRef_h -#include <JavaScriptCore/JSObjectRef.h> - -#include "Weak.h" +#include "OpaqueJSString.h" #include "Protect.h" +#include "Weak.h" +#include <JavaScriptCore/JSObjectRef.h> #include <wtf/HashMap.h> #include <wtf/text/WTFString.h> 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<OpaqueJSString> propertyNameRef; }; struct StaticFunctionEntry { @@ -58,8 +59,8 @@ public: JSPropertyAttributes attributes; }; -typedef HashMap<RefPtr<StringImpl>, OwnPtr<StaticValueEntry> > OpaqueJSClassStaticValuesTable; -typedef HashMap<RefPtr<StringImpl>, OwnPtr<StaticFunctionEntry> > OpaqueJSClassStaticFunctionsTable; +typedef HashMap<RefPtr<StringImpl>, std::unique_ptr<StaticValueEntry>> OpaqueJSClassStaticValuesTable; +typedef HashMap<RefPtr<StringImpl>, std::unique_ptr<StaticFunctionEntry>> OpaqueJSClassStaticFunctionsTable; struct OpaqueJSClass; @@ -78,14 +79,14 @@ public: // 4. When it is used, the old context data is found in VM and used. RefPtr<OpaqueJSClass> m_class; - OwnPtr<OpaqueJSClassStaticValuesTable> staticValues; - OwnPtr<OpaqueJSClassStaticFunctionsTable> staticFunctions; + std::unique_ptr<OpaqueJSClassStaticValuesTable> staticValues; + std::unique_ptr<OpaqueJSClassStaticFunctionsTable> staticFunctions; JSC::Weak<JSC::JSObject> cachedPrototype; }; struct OpaqueJSClass : public ThreadSafeRefCounted<OpaqueJSClass> { - static PassRefPtr<OpaqueJSClass> create(const JSClassDefinition*); - static PassRefPtr<OpaqueJSClass> createNoAutomaticPrototype(const JSClassDefinition*); + static Ref<OpaqueJSClass> create(const JSClassDefinition*); + static Ref<OpaqueJSClass> createNoAutomaticPrototype(const JSClassDefinition*); JS_EXPORT_PRIVATE ~OpaqueJSClass(); String className(); @@ -117,10 +118,10 @@ private: OpaqueJSClassContextData& contextData(JSC::ExecState*); - // Strings in these data members should not be put into any IdentifierTable. + // Strings in these data members should not be put into any AtomicStringTable. String m_className; - OwnPtr<OpaqueJSClassStaticValuesTable> m_staticValues; - OwnPtr<OpaqueJSClassStaticFunctionsTable> m_staticFunctions; + std::unique_ptr<OpaqueJSClassStaticValuesTable> m_staticValues; + std::unique_ptr<OpaqueJSClassStaticFunctionsTable> m_staticFunctions; }; #endif // JSClassRef_h diff --git a/Source/JavaScriptCore/API/JSContext.h b/Source/JavaScriptCore/API/JSContext.h index ef3e51f17..ddb51adfe 100644 --- a/Source/JavaScriptCore/API/JSContext.h +++ b/Source/JavaScriptCore/API/JSContext.h @@ -20,108 +20,220 @@ * 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 JSContext_h #define JSContext_h #include <JavaScriptCore/JavaScript.h> +#include <JavaScriptCore/WebKitAvailability.h> #if JSC_OBJC_API_ENABLED @class JSVirtualMachine, JSValue; -// 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. - -NS_CLASS_AVAILABLE(10_9, NA) +/*! +@interface +@discussion A JSContext is a JavaScript execution environment. All + JavaScript execution takes place within a context, and all JavaScript values + are tied to a context. +*/ +NS_CLASS_AVAILABLE(10_9, 7_0) @interface JSContext : NSObject -// Create a JSContext. -- (id)init; -// Create a JSContext in the specified virtual machine. -- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine; - -// Evaluate a string of JavaScript code. +/*! +@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; -// 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. -- (JSValue *)globalObject; - -// 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. +/*! +@method +@abstract Evaluate a string of JavaScript code, with a URL for the script's source file. +@param script A string containing the JavaScript code to evaluate. +@param sourceURL A URL for the script's source file. Used by debuggers and when reporting exceptions. This parameter is informative only: it does not change the behavior of the script. +@result The last value generated by the script. +*/ +- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL NS_AVAILABLE(10_10, 8_0); + +/*! +@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; -// 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. + +/*! +@method +@abstract Get the JavaScript function 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 JavaScript function or nil if there isn't one. +*/ ++ (JSValue *)currentCallee NS_AVAILABLE(10_10, 8_0); + +/*! +@method +@abstract Get the <code>this</code> 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 <code>this</code> value or nil if there isn't one. +*/ + (JSValue *)currentThis; -// 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. + +/*! +@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; -// 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(retain) JSValue *exception; - -// 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); - -// All instances of JSContext are associated with a single JSVirtualMachine. The -// virtual machine provides an "object space" or set of execution resources. -@property(readonly, retain) JSVirtualMachine *virtualMachine; +/*! +@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 <code>exception</code> 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 <code>exceptionHandler</code> is to + assign an uncaught exception to this property). +*/ +@property (strong) JSValue *exception; + +/*! +@property +@discussion If a call to an API function results in an uncaught JavaScript exception, the + <code>exceptionHandler</code> 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 uncaught exceptions + occurring within a callback from JavaScript to be rethrown upon return. + Setting this value to nil will cause all exceptions occurring + within a callback from JavaScript to be silently caught. +*/ +@property (copy) void(^exceptionHandler)(JSContext *context, JSValue *exception); + +/*! +@property +@discussion All instances of JSContext are associated with a JSVirtualMachine. +*/ +@property (readonly, strong) JSVirtualMachine *virtualMachine; + +/*! +@property +@discussion Name of the JSContext. Exposed when remote debugging the context. +*/ +@property (copy) NSString *name NS_AVAILABLE(10_10, 8_0); @end -// Instances of JSContext implement the following methods in order to enable -// support for subscript access by key and index, for example: -// -// 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. -// -// 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) - +/*! +@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 <NSCopying> *)key; @end -// These functions are for bridging between the C API and the Objective-C API. -@interface JSContext(JSContextRefSupport) -// Creates a JSContext, wrapping its C API counterpart. +/*! +@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; -// Returns the C API counterpart wrapped by a JSContext. -- (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 diff --git a/Source/JavaScriptCore/API/JSContext.mm b/Source/JavaScriptCore/API/JSContext.mm deleted file mode 100644 index 58754b38c..000000000 --- a/Source/JavaScriptCore/API/JSContext.mm +++ /dev/null @@ -1,289 +0,0 @@ -/* - * 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 <wtf/HashSet.h> - -#if JSC_OBJC_API_ENABLED - -@implementation JSContext { - JSVirtualMachine *m_virtualMachine; - JSGlobalContextRef m_context; - JSWrapperMap *m_wrapperMap; - JSC::Strong<JSC::JSObject> m_exception; -} - -@synthesize exceptionHandler; - -- (JSGlobalContextRef)JSGlobalContextRef -{ - return m_context; -} - -- (id)init -{ - return [self initWithVirtualMachine:[[[JSVirtualMachine alloc] init] autorelease]]; -} - -- (id)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->currentThis) - entry->currentThis = [[JSValue alloc] initWithValue:entry->thisValue inContext:[JSContext currentContext]]; - - return entry->currentThis; -} - -+ (NSArray *)currentArguments -{ - WTFThreadData& threadData = wtfThreadData(); - CallbackData *entry = (CallbackData *)threadData.m_apiData; - - 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; -} - -@end - -@implementation JSContext(SubscriptSupport) - -- (JSValue *)objectForKeyedSubscript:(id)key -{ - return [self globalObject][key]; -} - -- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key -{ - [self globalObject][key] = object; -} - -@end - -@implementation JSContext(Internal) - -- (id)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, nil, 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->currentThis 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/Source/JavaScriptCore/API/JSContextInternal.h b/Source/JavaScriptCore/API/JSContextInternal.h index d08e97d93..5308fbb92 100644 --- a/Source/JavaScriptCore/API/JSContextInternal.h +++ b/Source/JavaScriptCore/API/JSContextInternal.h @@ -36,8 +36,8 @@ struct CallbackData { CallbackData *next; JSContext *context; JSValue *preservedException; + JSValueRef calleeValue; JSValueRef thisValue; - JSValue *currentThis; size_t argumentCount; const JSValueRef *arguments; NSArray *currentArguments; @@ -65,7 +65,7 @@ private: - (JSValue *)valueFromNotifyException:(JSValueRef)exception; - (BOOL)boolFromNotifyException:(JSValueRef)exception; -- (void)beginCallbackWithData:(CallbackData *)callbackData thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments; +- (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments; - (void)endCallbackWithData:(CallbackData *)callbackData; - (JSValue *)wrapperForObjCObject:(id)object; diff --git a/Source/JavaScriptCore/API/JSContextPrivate.h b/Source/JavaScriptCore/API/JSContextPrivate.h new file mode 100644 index 000000000..7d1d0cbdb --- /dev/null +++ b/Source/JavaScriptCore/API/JSContextPrivate.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 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 JSContextPrivate_h +#define JSContextPrivate_h + +#if JSC_OBJC_API_ENABLED + +#import <JavaScriptCore/JSContext.h> + +@interface JSContext(Private) + +/*! +@property +@discussion Remote inspection setting of the JSContext. Default value is YES. +*/ +@property (setter=_setRemoteInspectionEnabled:) BOOL _remoteInspectionEnabled NS_AVAILABLE(10_10, 8_0); + +/*! +@property +@discussion Set whether or not the native call stack is included when reporting exceptions. Default value is YES. +*/ +@property (setter=_setIncludesNativeCallStackWhenReportingExceptions:) BOOL _includesNativeCallStackWhenReportingExceptions NS_AVAILABLE(10_10, 8_0); + +/*! +@property +@discussion Set the run loop the Web Inspector debugger should use when evaluating JavaScript in the JSContext. +*/ +@property (setter=_setDebuggerRunLoop:) CFRunLoopRef _debuggerRunLoop NS_AVAILABLE(10_10, 8_0); + +@end + +#endif + +#endif // JSContextInternal_h diff --git a/Source/JavaScriptCore/API/JSContextRef.cpp b/Source/JavaScriptCore/API/JSContextRef.cpp index 3869e87bf..98cd8b030 100644 --- a/Source/JavaScriptCore/API/JSContextRef.cpp +++ b/Source/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 @@ -10,36 +10,47 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "JSContextRef.h" -#include "JSContextRefPrivate.h" +#include "JSContextRefInternal.h" #include "APICast.h" +#include "CallFrame.h" #include "InitializeThreading.h" -#include <interpreter/CallFrame.h> -#include <interpreter/Interpreter.h> #include "JSCallbackObject.h" #include "JSClassRef.h" #include "JSGlobalObject.h" #include "JSObject.h" -#include "Operations.h" +#include "JSCInlines.h" #include "SourceProvider.h" +#include "StackVisitor.h" +#include "Watchdog.h" #include <wtf/text/StringBuilder.h> #include <wtf/text/StringHash.h> +#if ENABLE(REMOTE_INSPECTOR) +#include "JSGlobalObjectDebuggable.h" +#include "JSGlobalObjectInspectorController.h" +#include "JSRemoteInspector.h" +#endif + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "JSContextRefInspectorSupport.h" +#endif + #if OS(DARWIN) #include <mach-o/dyld.h> @@ -56,7 +67,7 @@ using namespace JSC; JSContextGroupRef JSContextGroupCreate() { initializeThreading(); - return toRef(VM::createContextGroup().leakRef()); + return toRef(&VM::createContextGroup().leakRef()); } JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) @@ -67,16 +78,10 @@ JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) void JSContextGroupRelease(JSContextGroupRef group) { - IdentifierTable* savedIdentifierTable; VM& vm = *toJS(group); - { - JSLockHolder lock(vm); - savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable); - vm.deref(); - } - - wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable); + JSLockHolder locker(&vm); + vm.deref(); } static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData) @@ -90,21 +95,21 @@ static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, vo void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData) { VM& vm = *toJS(group); - APIEntryShim entryShim(&vm); - Watchdog& watchdog = vm.watchdog; + JSLockHolder locker(&vm); + Watchdog& watchdog = vm.ensureWatchdog(); if (callback) { void* callbackPtr = reinterpret_cast<void*>(callback); - watchdog.setTimeLimit(vm, limit, internalScriptTimeoutCallback, callbackPtr, callbackData); + watchdog.setTimeLimit(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit)), internalScriptTimeoutCallback, callbackPtr, callbackData); } else - watchdog.setTimeLimit(vm, limit); + watchdog.setTimeLimit(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit))); } void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) { VM& vm = *toJS(group); - APIEntryShim entryShim(&vm); - Watchdog& watchdog = vm.watchdog; - watchdog.setTimeLimit(vm, std::numeric_limits<double>::infinity()); + JSLockHolder locker(&vm); + if (vm.watchdog()) + vm.watchdog()->setTimeLimit(Watchdog::noTimeLimit); } // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained. @@ -130,11 +135,14 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup(); - APIEntryShim entryShim(vm.get(), false); - vm->makeUsableFromMultipleThreads(); + JSLockHolder locker(vm.get()); if (!globalObjectClass) { JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull())); +#if ENABLE(REMOTE_INSPECTOR) + if (JSRemoteInspectorGetInspectionEnabledByDefault()) + globalObject->setRemoteDebuggingEnabled(true); +#endif return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec())); } @@ -144,37 +152,34 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass if (!prototype) prototype = jsNull(); globalObject->resetPrototype(*vm, prototype); +#if ENABLE(REMOTE_INSPECTOR) + if (JSRemoteInspectorGetInspectionEnabledByDefault()) + globalObject->setRemoteDebuggingEnabled(true); +#endif return JSGlobalContextRetain(toGlobalRef(exec)); } JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx) { ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); VM& vm = exec->vm(); - gcProtect(exec->dynamicGlobalObject()); + gcProtect(exec->vmEntryGlobalObject()); vm.ref(); return ctx; } void JSGlobalContextRelease(JSGlobalContextRef ctx) { - IdentifierTable* savedIdentifierTable; ExecState* exec = toJS(ctx); - { - JSLockHolder lock(exec); - - VM& vm = exec->vm(); - savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable); - - bool protectCountIsZero = Heap::heap(exec->dynamicGlobalObject())->unprotect(exec->dynamicGlobalObject()); - if (protectCountIsZero) - vm.heap.reportAbandonedObjectGraph(); - vm.deref(); - } + JSLockHolder locker(exec); - wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable); + VM& vm = exec->vm(); + bool protectCountIsZero = Heap::heap(exec->vmEntryGlobalObject())->unprotect(exec->vmEntryGlobalObject()); + if (protectCountIsZero) + vm.heap.reportAbandonedObjectGraph(); + vm.deref(); } JSObjectRef JSContextGetGlobalObject(JSContextRef ctx) @@ -184,10 +189,9 @@ JSObjectRef JSContextGetGlobalObject(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(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<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode))); } JSContextGroupRef JSContextGetGroup(JSContextRef ctx) @@ -207,11 +211,90 @@ JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toGlobalRef(exec->lexicalGlobalObject()->globalExec()); } - + +JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + 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); + JSLockHolder locker(exec); + + exec->vmEntryGlobalObject()->setName(name ? name->string() : String()); +} + + +class BacktraceFunctor { +public: + BacktraceFunctor(StringBuilder& builder, unsigned remainingCapacityForFrameCapture) + : m_builder(builder) + , m_remainingCapacityForFrameCapture(remainingCapacityForFrameCapture) + { + } + + 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; + } + return StackVisitor::Done; + } + +private: + StringBuilder& m_builder; + unsigned m_remainingCapacityForFrameCapture; +}; + JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) { if (!ctx) { @@ -221,41 +304,128 @@ JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) ExecState* exec = toJS(ctx); JSLockHolder lock(exec); StringBuilder builder; - Vector<StackFrame> stackTrace; - Interpreter::getStackTrace(&exec->vm(), stackTrace, maxStackSize); - - for (size_t i = 0; i < stackTrace.size(); i++) { - String urlString; - String functionName; - StackFrame& frame = stackTrace[i]; - JSValue function = frame.callee.get(); - if (frame.callee) - functionName = frame.friendlyFunctionName(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 (i) - break; - } - unsigned lineNumber; - unsigned column; - frame.computeLineAndColumn(lineNumber, column); - if (!builder.isEmpty()) - builder.append('\n'); - builder.append('#'); - builder.appendNumber(i); - builder.append(' '); - builder.append(functionName); - builder.appendLiteral("() at "); - builder.append(urlString); - if (frame.codeType != StackFrameNativeCode) { - builder.append(':'); - builder.appendNumber(lineNumber); - } - if (!function) - break; - } + CallFrame* frame = exec->vm().topCallFrame; + + ASSERT(maxStackSize); + BacktraceFunctor functor(builder, maxStackSize); + frame->iterate(functor); + return OpaqueJSString::create(builder.toString()).leakRef(); } +bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + return exec->vmEntryGlobalObject()->remoteDebuggingEnabled(); +} + +void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } + + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + exec->vmEntryGlobalObject()->setRemoteDebuggingEnabled(enabled); +} + +bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) +{ +#if ENABLE(REMOTE_INSPECTOR) + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + JSGlobalObject* globalObject = exec->vmEntryGlobalObject(); + return globalObject->inspectorController().includesNativeCallStackWhenReportingExceptions(); +#else + UNUSED_PARAM(ctx); + return false; +#endif +} + +void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) +{ +#if ENABLE(REMOTE_INSPECTOR) + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } + + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + JSGlobalObject* globalObject = exec->vmEntryGlobalObject(); + globalObject->inspectorController().setIncludesNativeCallStackWhenReportingExceptions(includesNativeCallStack); +#else + UNUSED_PARAM(ctx); + UNUSED_PARAM(includesNativeCallStack); +#endif +} + +#if USE(CF) +CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx) +{ +#if ENABLE(REMOTE_INSPECTOR) + if (!ctx) { + ASSERT_NOT_REACHED(); + return nullptr; + } + + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + return exec->vmEntryGlobalObject()->inspectorDebuggable().targetRunLoop(); +#else + UNUSED_PARAM(ctx); + return nullptr; +#endif +} + +void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runLoop) +{ +#if ENABLE(REMOTE_INSPECTOR) + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } + + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + exec->vmEntryGlobalObject()->inspectorDebuggable().setTargetRunLoop(runLoop); +#else + UNUSED_PARAM(ctx); + UNUSED_PARAM(runLoop); +#endif +} +#endif // USE(CF) + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +Inspector::AugmentableInspectorController* JSGlobalContextGetAugmentableInspectorController(JSGlobalContextRef ctx) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return nullptr; + } + + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + return &exec->vmEntryGlobalObject()->inspectorController(); +} +#endif diff --git a/Source/JavaScriptCore/API/JSContextRef.h b/Source/JavaScriptCore/API/JSContextRef.h index c5c8a71e6..0c800bced 100644 --- a/Source/JavaScriptCore/API/JSContextRef.h +++ b/Source/JavaScriptCore/API/JSContextRef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,17 +10,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * 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(void) 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) CF_AVAILABLE(10_10, 8_0); + +/*! +@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) CF_AVAILABLE(10_10, 8_0); #ifdef __cplusplus } diff --git a/Source/JavaScriptCore/API/JSContextRefInspectorSupport.h b/Source/JavaScriptCore/API/JSContextRefInspectorSupport.h new file mode 100644 index 000000000..a09d828bd --- /dev/null +++ b/Source/JavaScriptCore/API/JSContextRefInspectorSupport.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 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 JSContextRefInspectorSupport_h +#define JSContextRefInspectorSupport_h + +#ifndef __cplusplus +#error Requires C++ Support. +#endif + +#include <JavaScriptCore/JSContextRefPrivate.h> + +namespace Inspector { +class AugmentableInspectorController; +} + +extern "C" { +JS_EXPORT Inspector::AugmentableInspectorController* JSGlobalContextGetAugmentableInspectorController(JSGlobalContextRef); +} + +#endif // JSContextRefInspectorSupport_h diff --git a/Source/JavaScriptCore/API/JSContextRefInternal.h b/Source/JavaScriptCore/API/JSContextRefInternal.h new file mode 100644 index 000000000..85632b8c7 --- /dev/null +++ b/Source/JavaScriptCore/API/JSContextRefInternal.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 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 JSContextRefInternal_h +#define JSContextRefInternal_h + +#include "JSContextRefPrivate.h" + +#if USE(CF) +#include <CoreFoundation/CFRunLoop.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if USE(CF) +/*! +@function +@abstract Gets the run loop used by the Web Inspector debugger when evaluating JavaScript in this context. +@param ctx The JSGlobalContext whose setting you want to get. +*/ +JS_EXPORT CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0); + +/*! +@function +@abstract Sets the run loop used by the Web Inspector debugger when evaluating JavaScript in this context. +@param ctx The JSGlobalContext that you want to change. +@param runLoop The new value of the setting for the context. +*/ +JS_EXPORT void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef) CF_AVAILABLE(10_10, 8_0); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // JSContextRefInternal_h diff --git a/Source/JavaScriptCore/API/JSContextRefPrivate.h b/Source/JavaScriptCore/API/JSContextRefPrivate.h index 8d7684ac0..5a5bebd42 100644 --- a/Source/JavaScriptCore/API/JSContextRefPrivate.h +++ b/Source/JavaScriptCore/API/JSContextRefPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,17 +10,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef JSContextRefPrivate_h @@ -40,20 +40,11 @@ extern "C" { /*! @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); /*! @@ -94,14 +85,48 @@ typedef bool need to call JSContextGroupSetExecutionTimeLimit before you start executing any scripts. */ -JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef, double limit, JSShouldTerminateCallback, void* context) AVAILABLE_IN_WEBKIT_VERSION_4_0; +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) AVAILABLE_IN_WEBKIT_VERSION_4_0; +JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef) CF_AVAILABLE(10_6, 7_0); + +/*! +@function +@abstract Gets a whether or not remote inspection is enabled on the context. +@param ctx The JSGlobalContext whose setting you want to get. +@result The value of the setting, true if remote inspection is enabled, otherwise false. +@discussion Remote inspection is true by default. +*/ +JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0); + +/*! +@function +@abstract Sets the remote inspection setting for a context. +@param ctx The JSGlobalContext that you want to change. +@param enabled The new remote inspection enabled setting for the context. +*/ +JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled) CF_AVAILABLE(10_10, 8_0); + +/*! +@function +@abstract Gets the include native call stack when reporting exceptions setting for a context. +@param ctx The JSGlobalContext whose setting you want to get. +@result The value of the setting, true if remote inspection is enabled, otherwise false. +@discussion This setting is true by default. +*/ +JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0); + +/*! +@function +@abstract Sets the include native call stack when reporting exceptions setting for a context. +@param ctx The JSGlobalContext that you want to change. +@param includeNativeCallStack The new value of the setting for the context. +*/ +JS_EXPORT void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) CF_AVAILABLE(10_10, 8_0); #ifdef __cplusplus } diff --git a/Source/JavaScriptCore/API/JSExport.h b/Source/JavaScriptCore/API/JSExport.h index 96e9fec35..b8a484909 100644 --- a/Source/JavaScriptCore/API/JSExport.h +++ b/Source/JavaScriptCore/API/JSExport.h @@ -27,103 +27,119 @@ #if JSC_OBJC_API_ENABLED -// 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, and for each class method exported a JavaScript function will be -// created on the Constructor object. For example: -// -// @protocol MyClassJavaScriptMethods <JSExport> -// - (void)foo; -// @end -// -// @interface MyClass : NSObject <MyClassJavaScriptMethods> -// - (void)foo; -// - (void)bar; -// @end -// -// 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: In addition to support provided by valueWithObject/toObject for -// block types, if a JavaScript Function is passed as an argument, where the -// type required is a block with a void return value (and where the block's -// arguments are all of supported types), then a special adaptor block -// will be created, allowing the JavaScript function to be used in the place -// of a block. -// -// 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 +@abstract JSExport provides a declarative way to export Objective-C objects and + classes -- including properties, instance methods, class methods, and + initializers -- to JavaScript. + +@discussion When an Objective-C object is exported to JavaScript, a JavaScript + wrapper object is created. + + In JavaScript, inheritance works via a chain of prototype objects. + For each Objective-C class in each JSContext, an object appropriate for use + as a prototype will be provided. For the class NSObject the prototype + will be the Object prototype. For all other Objective-C + classes a prototype will be created. The prototype for a given + Objective-C class will have its internal [Prototype] property set to point to + the prototype created for 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. + + JavaScriptCore also produces a constructor for each Objective-C class. The + constructor has a property named 'prototype' that references the prototype, + and the prototype has a property named 'constructor' that references the + constructor. + + By default JavaScriptCore does not export any methods or properties from an + Objective-C class to JavaScript; however methods and properties may be exported + explicitly using JSExport. For each protocol that a class conforms to, if the + protocol incorporates the protocol JSExport, JavaScriptCore exports the methods + and properties in that protocol to JavaScript + + For each exported instance method JavaScriptCore will assign a corresponding + JavaScript function to the prototype. For each exported Objective-C property + JavaScriptCore will assign a corresponding JavaScript accessor to the prototype. + For each exported class method JavaScriptCore will assign a corresponding + JavaScript function to the constructor. For example: + +<pre> +@textblock + @protocol MyClassJavaScriptMethods <JSExport> + - (void)foo; + @end + + @interface MyClass : NSObject <MyClassJavaScriptMethods> + - (void)foo; + - (void)bar; + @end +@/textblock +</pre> + + Data properties that are created on the prototype or constructor objects have + the attributes: <code>writable:true</code>, <code>enumerable:false</code>, <code>configurable:true</code>. + Accessor properties have the attributes: <code>enumerable:false</code> and <code>configurable:true</code>. + + If an instance of <code>MyClass</code> is converted to a JavaScript value, the resulting + wrapper object will (via its prototype) export the method <code>foo</code> to JavaScript, + since the class conforms to the <code>MyClassJavaScriptMethods</code> protocol, and this + protocol incorporates <code>JSExport</code>. <code>bar</code> will not be exported. + + JSExport supports properties, arguments, and return values of the following types: + + Primitive numbers: signed values up to 32-bits convert using JSValue's + valueWithInt32/toInt32. Unsigned values up to 32-bits convert using JSValue's + valueWithUInt32/toUInt32. All other numeric values convert using JSValue's + valueWithDouble/toDouble. + + BOOL: values convert using JSValue's valueWithBool/toBool. + + id: values convert using JSValue's valueWithObject/toObject. + + Objective-C instance pointers: Pointers convert using JSValue's + valueWithObjectOfClass/toObject. + + C structs: C structs for CGPoint, NSRange, CGRect, and CGSize convert using + JSValue's appropriate methods. Other C structs are not supported. + + Blocks: Blocks convert using JSValue's valueWithObject/toObject. + + All objects that conform to JSExport convert to JavaScript wrapper objects, + even if they subclass classes that would otherwise behave differently. For + example, if a subclass of NSString conforms to JSExport, it converts to + JavaScript as a wrapper object rather than a JavaScript string. +*/ @protocol JSExport @end -// 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": -// -// @protocol MyClassJavaScriptMethods <JSExport> -// JSExportAs(doFoo, -// - (void)doFoo:(id)foo withBar:(id)bar -// ); -// @end -// -// Note that the JSExport macro may only be applied to a selector that takes one -// or more argument. +/*! +@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 <code>doFoo:withBar:</code> will be exported as + <code>doFooWithBar</code>. The default conversion may be overriden using the JSExportAs + macro, for example to export a method <code>doFoo:withBar:</code> as <code>doFoo</code>: + +<pre> +@textblock + @protocol MyClassJavaScriptMethods <JSExport> + JSExportAs(doFoo, + - (void)doFoo:(id)foo withBar:(id)bar + ); + @end +@/textblock +</pre> + + 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 diff --git a/Source/JavaScriptCore/API/JSManagedValue.h b/Source/JavaScriptCore/API/JSManagedValue.h index 5ff3f83cb..d13733d08 100644 --- a/Source/JavaScriptCore/API/JSManagedValue.h +++ b/Source/JavaScriptCore/API/JSManagedValue.h @@ -27,37 +27,54 @@ #define JSManagedValue_h #import <JavaScriptCore/JSBase.h> +#import <JavaScriptCore/WebKitAvailability.h> #if JSC_OBJC_API_ENABLED @class JSValue; @class JSContext; -// JSManagedValue represents a "conditionally retained" JSValue. -// "Conditionally retained" means that as long as either the JSManagedValue -// 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. -NS_CLASS_AVAILABLE(10_9, NA) +/*! +@interface +@discussion JSManagedValue represents a "conditionally retained" JSValue. + "Conditionally retained" means that as long as the JSManagedValue's + JSValue is reachable through the JavaScript object graph, + or through the Objective-C object graph reported to the JSVirtualMachine using + addManagedReference:withOwner:, the corresponding JSValue will + be retained. However, if neither graph reaches the JSManagedValue, the + corresponding JSValue will be released and set to nil. + +The primary use for a JSManagedValue is to store a JSValue in an Objective-C +or Swift object that is exported to JavaScript. It is incorrect to store a JSValue +in an object that is exported to JavaScript, since doing so creates a retain cycle. +*/ +NS_CLASS_AVAILABLE(10_9, 7_0) @interface JSManagedValue : NSObject -// Convenience method for creating JSManagedValues from JSValues. +/*! +@method +@abstract Create a JSManagedValue from a JSValue. +@param value +@result The new JSManagedValue. +*/ + (JSManagedValue *)managedValueWithValue:(JSValue *)value; ++ (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner NS_AVAILABLE(10_10, 8_0); -// Create a JSManagedValue. -- (id)initWithValue:(JSValue *)value; +/*! +@method +@abstract Create a JSManagedValue. +@param value +@result The new JSManagedValue. +*/ +- (instancetype)initWithValue:(JSValue *)value; -// Get the JSValue to which this JSManagedValue refers. If the JavaScript value has been collected, -// this method returns nil. -- (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 diff --git a/Source/JavaScriptCore/API/JSManagedValue.mm b/Source/JavaScriptCore/API/JSManagedValue.mm deleted file mode 100644 index f336ba662..000000000 --- a/Source/JavaScriptCore/API/JSManagedValue.mm +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 "JSCJSValueInlines.h" -#import "JSContextInternal.h" -#import "JSValueInternal.h" -#import "Weak.h" -#import "WeakHandleOwner.h" -#import "ObjcRuntimeExtras.h" - -class JSManagedValueHandleOwner : public JSC::WeakHandleOwner { -public: - virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); - virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&); -}; - -static JSManagedValueHandleOwner* managedValueHandleOwner() -{ - DEFINE_STATIC_LOCAL(JSManagedValueHandleOwner, jsManagedValueHandleOwner, ()); - return &jsManagedValueHandleOwner; -} - -@implementation JSManagedValue { - JSC::Weak<JSC::JSObject> m_value; -} - -+ (JSManagedValue *)managedValueWithValue:(JSValue *)value -{ - return [[[self alloc] initWithValue:value] autorelease]; -} - -- (id)init -{ - return [self initWithValue:nil]; -} - -- (id)initWithValue:(JSValue *)value -{ - self = [super init]; - if (!self) - return nil; - - if (!value || !JSValueIsObject([value.context JSGlobalContextRef], [value JSValueRef])) { - JSC::Weak<JSC::JSObject> weak; - m_value.swap(weak); - } else { - JSC::JSObject* object = toJS(const_cast<OpaqueJSValue*>([value JSValueRef])); - JSC::Weak<JSC::JSObject> weak(object, managedValueHandleOwner(), self); - m_value.swap(weak); - } - - return self; -} - -- (JSValue *)value -{ - if (!m_value) - return nil; - JSC::JSObject* object = m_value.get(); - JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(object->structure()->globalObject()->globalExec())]; - return [JSValue valueWithJSValueRef:toRef(object) inContext:context]; -} - -- (void)disconnectValue -{ - m_value.clear(); -} - -@end - -@interface JSManagedValue (PrivateMethods) -- (void)disconnectValue; -@end - -bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor& visitor) -{ - JSManagedValue *managedValue = static_cast<JSManagedValue *>(context); - return visitor.containsOpaqueRoot(managedValue); -} - -void JSManagedValueHandleOwner::finalize(JSC::Handle<JSC::Unknown>, void* context) -{ - JSManagedValue *managedValue = static_cast<JSManagedValue *>(context); - [managedValue disconnectValue]; -} - -#endif // JSC_OBJC_API_ENABLED diff --git a/Source/JavaScriptCore/API/JSManagedValueInternal.h b/Source/JavaScriptCore/API/JSManagedValueInternal.h new file mode 100644 index 000000000..2443fe5a9 --- /dev/null +++ b/Source/JavaScriptCore/API/JSManagedValueInternal.h @@ -0,0 +1,42 @@ +/* + * 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 JSManagedValueInternal_h +#define JSManagedValueInternal_h + +#import <JavaScriptCore/JSBase.h> + +#if JSC_OBJC_API_ENABLED + +@interface JSManagedValue(Internal) + +- (void)didAddOwner:(id)owner; +- (void)didRemoveOwner:(id)owner; + +@end + +#endif // JSC_OBJC_API_ENABLED + +#endif // JSManagedValueInternal_h diff --git a/Source/JavaScriptCore/API/JSObjectRef.cpp b/Source/JavaScriptCore/API/JSObjectRef.cpp index 5ba446513..78efc2461 100644 --- a/Source/JavaScriptCore/API/JSObjectRef.cpp +++ b/Source/JavaScriptCore/API/JSObjectRef.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2016 Apple Inc. All rights reserved. * Copyright (C) 2008 Kelvin W Sherlock (ksherlock@gmail.com) * * Redistribution and use in source and binary forms, with or without @@ -11,17 +11,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -34,6 +34,7 @@ #include "CopiedSpaceInlines.h" #include "DateConstructor.h" #include "ErrorConstructor.h" +#include "Exception.h" #include "FunctionConstructor.h" #include "Identifier.h" #include "InitializeThreading.h" @@ -51,12 +52,36 @@ #include "JSValueRef.h" #include "ObjectConstructor.h" #include "ObjectPrototype.h" -#include "Operations.h" +#include "JSCInlines.h" #include "PropertyNameArray.h" #include "RegExpConstructor.h" +#if ENABLE(REMOTE_INSPECTOR) +#include "JSGlobalObjectInspectorController.h" +#endif + using namespace JSC; +enum class ExceptionStatus { + DidThrow, + DidNotThrow +}; + +static ExceptionStatus handleExceptionIfNeeded(ExecState* exec, JSValueRef* returnedExceptionRef) +{ + if (exec->hadException()) { + Exception* exception = exec->exception(); + if (returnedExceptionRef) + *returnedExceptionRef = toRef(exec, exception->value()); + exec->clearException(); +#if ENABLE(REMOTE_INSPECTOR) + exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); +#endif + return ExceptionStatus::DidThrow; + } + return ExceptionStatus::DidNotThrow; +} + JSClassRef JSClassCreate(const JSClassDefinition* definition) { initializeThreading(); @@ -85,7 +110,7 @@ JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); if (!jsClass) return toRef(constructEmptyObject(exec)); @@ -104,8 +129,8 @@ JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); - return toRef(JSCallbackFunction::create(exec, exec->lexicalGlobalObject(), callAsFunction, name ? name->string() : ASCIILiteral("anonymous"))); + JSLockHolder locker(exec); + return toRef(JSCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), callAsFunction, name ? name->string() : ASCIILiteral("anonymous"))); } JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor) @@ -115,7 +140,7 @@ JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObje return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsPrototype = jsClass ? jsClass->prototype(exec) : 0; if (!jsPrototype) @@ -133,22 +158,19 @@ JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned pa return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier(exec, "anonymous"); + startingLineNumber = std::max(1, startingLineNumber); + Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier::fromString(exec, "anonymous"); MarkedArgumentBuffer args; for (unsigned i = 0; i < parameterCount; i++) args.append(jsString(exec, parameterNames[i]->string())); args.append(jsString(exec, body->string())); - 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()); - exec->clearException(); + JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -159,7 +181,7 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* result; if (argumentCount) { @@ -171,12 +193,8 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa } else result = constructEmptyArray(exec, 0); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -188,19 +206,15 @@ JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSVal return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; ++i) argList.append(toJS(exec, arguments[i])); - JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), argList); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), JSValue(), argList); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -212,18 +226,14 @@ JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSVa return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue message = argumentCount ? toJS(exec, arguments[0]) : jsUndefined(); Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure(); JSObject* result = ErrorInstance::create(exec, errorStructure, message); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -235,19 +245,15 @@ JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSV return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; ++i) argList.append(toJS(exec, arguments[i])); - JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(), argList); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(), argList); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -259,7 +265,7 @@ JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); return toRef(exec, jsObject->prototype()); @@ -272,12 +278,20 @@ void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value return; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); JSValue jsValue = toJS(exec, value); - jsObject->setPrototypeWithCycleCheck(exec->vm(), jsValue.isObject() ? jsValue : jsNull()); + if (JSProxy* proxy = jsDynamicCast<JSProxy*>(jsObject)) { + if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(proxy->target())) { + globalObject->resetPrototype(exec->vm(), jsValue.isObject() ? jsValue : jsNull()); + return; + } + // Someday we might use proxies for something other than JSGlobalObjects, but today is not that day. + RELEASE_ASSERT_NOT_REACHED(); + } + jsObject->setPrototypeWithCycleCheck(exec, jsValue.isObject() ? jsValue : jsNull()); } bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) @@ -287,7 +301,7 @@ bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); @@ -301,16 +315,12 @@ JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->vm())); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - } + handleExceptionIfNeeded(exec, exception); return toRef(exec, jsValue); } @@ -321,24 +331,21 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope return; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); 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); } - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - } + handleExceptionIfNeeded(exec, exception); } JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception) @@ -348,16 +355,12 @@ JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsi return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); JSValue jsValue = jsObject->get(exec, propertyIndex); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - } + handleExceptionIfNeeded(exec, exception); return toRef(exec, jsValue); } @@ -369,17 +372,13 @@ void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned p return; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); JSValue jsValue = toJS(exec, value); jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue, false); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - } + handleExceptionIfNeeded(exec, exception); } bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) @@ -389,29 +388,29 @@ bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->vm())); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - } + handleExceptionIfNeeded(exec, exception); return result; } void* JSObjectGetPrivate(JSObjectRef object) { JSObject* jsObject = uncheckedToJS(object); - - if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) + + // Get wrapped object if proxied + if (jsObject->inherits(JSProxy::info())) + jsObject = jsCast<JSProxy*>(jsObject)->target(); + + if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) return jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate(); - if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) + if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) return jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivate(); #if JSC_OBJC_API_ENABLED - if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) + if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivate(); #endif @@ -421,17 +420,21 @@ void* JSObjectGetPrivate(JSObjectRef object) bool JSObjectSetPrivate(JSObjectRef object, void* data) { JSObject* jsObject = uncheckedToJS(object); - - if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) { + + // Get wrapped object if proxied + if (jsObject->inherits(JSProxy::info())) + jsObject = jsCast<JSProxy*>(jsObject)->target(); + + if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) { jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data); return true; } - if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) { + if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) { jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivate(data); return true; } #if JSC_OBJC_API_ENABLED - if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) { + if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) { jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivate(data); return true; } @@ -443,16 +446,21 @@ bool JSObjectSetPrivate(JSObjectRef object, void* data) JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) { ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); JSValue result; Identifier name(propertyName->identifier(&exec->vm())); - if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) + + // Get wrapped object if proxied + if (jsObject->inherits(JSProxy::info())) + jsObject = jsCast<JSProxy*>(jsObject)->target(); + + if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name); - else if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) + else if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) result = jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivateProperty(name); #if JSC_OBJC_API_ENABLED - else if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) + else if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) result = jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivateProperty(name); #endif return toRef(exec, result); @@ -461,20 +469,25 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value) { ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); JSValue jsValue = value ? toJS(exec, value) : JSValue(); Identifier name(propertyName->identifier(&exec->vm())); - if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) { + + // Get wrapped object if proxied + if (jsObject->inherits(JSProxy::info())) + jsObject = jsCast<JSProxy*>(jsObject)->target(); + + if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) { jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue); return true; } - if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) { + if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) { jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue); return true; } #if JSC_OBJC_API_ENABLED - if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) { + if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) { jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue); return true; } @@ -485,19 +498,24 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) { ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsObject = toJS(object); Identifier name(propertyName->identifier(&exec->vm())); - if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) { + + // Get wrapped object if proxied + if (jsObject->inherits(JSProxy::info())) + jsObject = jsCast<JSProxy*>(jsObject)->target(); + + if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) { jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name); return true; } - if (jsObject->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) { + if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) { jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name); return true; } #if JSC_OBJC_API_ENABLED - if (jsObject->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) { + if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) { jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->deletePrivateProperty(name); return true; } @@ -505,10 +523,11 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin return false; } -bool JSObjectIsFunction(JSContextRef, JSObjectRef object) +bool JSObjectIsFunction(JSContextRef ctx, JSObjectRef object) { if (!object) return false; + JSLockHolder locker(toJS(ctx)); CallData callData; JSCell* cell = toJS(object); return cell->methodTable()->getCallData(cell, callData) != CallTypeNone; @@ -517,7 +536,7 @@ bool JSObjectIsFunction(JSContextRef, JSObjectRef object) JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); if (!object) return 0; @@ -528,8 +547,6 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject if (!jsThisObject) jsThisObject = exec->globalThisValue(); - jsThisObject = jsThisObject->methodTable()->toThisObject(jsThisObject, exec); - MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(exec, arguments[i])); @@ -539,13 +556,9 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject if (callType == CallTypeNone) return 0; - JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList)); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + JSValueRef result = toRef(exec, profiledCall(exec, ProfilingReason::API, jsObject, callType, callData, jsThisObject, argList)); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return result; } @@ -561,7 +574,7 @@ bool JSObjectIsConstructor(JSContextRef, JSObjectRef object) JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); if (!object) return 0; @@ -576,13 +589,10 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size MarkedArgumentBuffer argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(exec, arguments[i])); - JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList)); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + + JSObjectRef result = toRef(profiledConstruct(exec, ProfilingReason::API, jsObject, constructType, constructData, argList)); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return result; } @@ -597,7 +607,7 @@ public: unsigned refCount; VM* vm; - Vector<JSRetainPtr<JSStringRef> > array; + Vector<JSRetainPtr<JSStringRef>> array; }; JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object) @@ -606,15 +616,15 @@ JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef o ASSERT_NOT_REACHED(); return 0; } - JSObject* jsObject = toJS(object); ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); VM* vm = &exec->vm(); + JSObject* jsObject = toJS(object); JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(vm); - PropertyNameArray array(vm); - jsObject->methodTable()->getPropertyNames(jsObject, exec, array, ExcludeDontEnumProperties); + PropertyNameArray array(vm, PropertyNameMode::Strings); + jsObject->methodTable()->getPropertyNames(jsObject, exec, array, EnumerationMode()); size_t size = array.size(); propertyNames->array.reserveInitialCapacity(size); @@ -633,7 +643,7 @@ JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array) void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array) { if (--array->refCount == 0) { - APIEntryShim entryShim(array->vm, false); + JSLockHolder locker(array->vm); delete array; } } @@ -651,6 +661,6 @@ JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName) { PropertyNameArray* propertyNames = toJS(array); - APIEntryShim entryShim(propertyNames->vm()); + JSLockHolder locker(propertyNames->vm()); propertyNames->add(propertyName->identifier(propertyNames->vm())); } diff --git a/Source/JavaScriptCore/API/JSObjectRef.h b/Source/JavaScriptCore/API/JSObjectRef.h index 5014726bc..754dff363 100644 --- a/Source/JavaScriptCore/API/JSObjectRef.h +++ b/Source/JavaScriptCore/API/JSObjectRef.h @@ -11,17 +11,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef 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 @@ -485,7 +485,7 @@ JS_EXPORT JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, @param parameterNames A JSString array containing the names of the function's parameters. Pass NULL if parameterCount is 0. @param body A JSString containing the script to use as the function's body. @param sourceURL A JSString containing a URL for the script's source file. This is only used when reporting exceptions. Pass NULL if you do not care to include source file information in 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 startingLineNumber An integer value specifying the script's starting line number in the file located at sourceURL. This is only used when reporting exceptions. The value is one-based, so the first line is line 1 and invalid values are clamped to 1. @param exception A pointer to a JSValueRef in which to store a syntax error exception, if any. Pass NULL if you do not care to store a syntax error exception. @result A JSObject that is a function, or NULL if either body or parameterNames contains a syntax error. The object's prototype will be the default function prototype. @discussion Use this method when you want to execute a script repeatedly, to avoid the cost of re-parsing the script before each execution. diff --git a/Source/JavaScriptCore/API/JSProfilerPrivate.cpp b/Source/JavaScriptCore/API/JSProfilerPrivate.cpp index 0405b4b26..ac112ae6e 100644 --- a/Source/JavaScriptCore/API/JSProfilerPrivate.cpp +++ b/Source/JavaScriptCore/API/JSProfilerPrivate.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -34,7 +34,11 @@ using namespace JSC; void JSStartProfiling(JSContextRef ctx, JSStringRef title) { - LegacyProfiler::profiler()->startProfiling(toJS(ctx), title->string()); + // Use an independent stopwatch for API-initiated profiling, since the user will expect it + // to be relative to when their command was issued. + RefPtr<Stopwatch> stopwatch = Stopwatch::create(); + stopwatch->start(); + LegacyProfiler::profiler()->startProfiling(toJS(ctx), title->string(), stopwatch.release()); } void JSEndProfiling(JSContextRef ctx, JSStringRef title) diff --git a/Source/JavaScriptCore/API/JSProfilerPrivate.h b/Source/JavaScriptCore/API/JSProfilerPrivate.h index b3fe533a3..34f26a202 100644 --- a/Source/JavaScriptCore/API/JSProfilerPrivate.h +++ b/Source/JavaScriptCore/API/JSProfilerPrivate.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/JSRemoteInspector.cpp b/Source/JavaScriptCore/API/JSRemoteInspector.cpp new file mode 100644 index 000000000..faebc5de3 --- /dev/null +++ b/Source/JavaScriptCore/API/JSRemoteInspector.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 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 "JSRemoteInspector.h" + +#include "JSGlobalObjectConsoleClient.h" + +#if ENABLE(REMOTE_INSPECTOR) +#include "RemoteInspector.h" +#endif + +using namespace Inspector; + +static bool remoteInspectionEnabledByDefault = true; + +void JSRemoteInspectorDisableAutoStart(void) +{ +#if ENABLE(REMOTE_INSPECTOR) + RemoteInspector::startDisabled(); +#endif +} + +void JSRemoteInspectorStart(void) +{ +#if ENABLE(REMOTE_INSPECTOR) + RemoteInspector::singleton(); +#endif +} + +void JSRemoteInspectorSetParentProcessInformation(pid_t pid, const UInt8* auditData, size_t auditLength) +{ +#if ENABLE(REMOTE_INSPECTOR) + RetainPtr<CFDataRef> auditDataRef = adoptCF(CFDataCreate(kCFAllocatorDefault, auditData, auditLength)); + RemoteInspector::singleton().setParentProcessInformation(pid, auditDataRef); +#else + UNUSED_PARAM(pid); + UNUSED_PARAM(auditData); + UNUSED_PARAM(auditLength); +#endif +} + +void JSRemoteInspectorSetLogToSystemConsole(bool logToSystemConsole) +{ + JSGlobalObjectConsoleClient::setLogToSystemConsole(logToSystemConsole); +} + +bool JSRemoteInspectorGetInspectionEnabledByDefault(void) +{ + return remoteInspectionEnabledByDefault; +} + +void JSRemoteInspectorSetInspectionEnabledByDefault(bool enabledByDefault) +{ + remoteInspectionEnabledByDefault = enabledByDefault; +} diff --git a/Source/JavaScriptCore/API/JSRemoteInspector.h b/Source/JavaScriptCore/API/JSRemoteInspector.h new file mode 100644 index 000000000..2bde47949 --- /dev/null +++ b/Source/JavaScriptCore/API/JSRemoteInspector.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 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 JSRemoteInspector_h +#define JSRemoteInspector_h + +#include <JavaScriptCore/JSBase.h> +#include <JavaScriptCore/WebKitAvailability.h> + +#ifdef __cplusplus +extern "C" { +#endif + +JS_EXPORT void JSRemoteInspectorDisableAutoStart(void) CF_AVAILABLE(10_11, 9_0); +JS_EXPORT void JSRemoteInspectorStart(void) CF_AVAILABLE(10_11, 9_0); +JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(pid_t, const uint8_t* auditData, size_t auditLength) CF_AVAILABLE(10_11, 9_0); + +JS_EXPORT void JSRemoteInspectorSetLogToSystemConsole(bool) CF_AVAILABLE(10_11, 9_0); + +JS_EXPORT bool JSRemoteInspectorGetInspectionEnabledByDefault(void) CF_AVAILABLE(10_11, 9_0); +JS_EXPORT void JSRemoteInspectorSetInspectionEnabledByDefault(bool) CF_AVAILABLE(10_11, 9_0); + +#ifdef __cplusplus +} +#endif + +#endif /* JSRemoteInspector_h */ diff --git a/Source/JavaScriptCore/API/JSRetainPtr.h b/Source/JavaScriptCore/API/JSRetainPtr.h index 574f7aaf1..e40084080 100644 --- a/Source/JavaScriptCore/API/JSRetainPtr.h +++ b/Source/JavaScriptCore/API/JSRetainPtr.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -57,11 +57,8 @@ public: T operator->() const { return m_ptr; } bool operator!() const { return !m_ptr; } + explicit operator bool() const { return m_ptr; } - // This conversion operator allows implicit conversion to bool but not to other integer types. - typedef T JSRetainPtr::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return m_ptr ? &JSRetainPtr::m_ptr : 0; } - JSRetainPtr& operator=(const JSRetainPtr&); template<typename U> JSRetainPtr& operator=(const JSRetainPtr<U>&); JSRetainPtr& operator=(T); @@ -75,6 +72,16 @@ private: T m_ptr; }; +inline JSRetainPtr<JSStringRef> adopt(JSStringRef o) +{ + return JSRetainPtr<JSStringRef>(Adopt, o); +} + +inline JSRetainPtr<JSGlobalContextRef> adopt(JSGlobalContextRef o) +{ + return JSRetainPtr<JSGlobalContextRef>(Adopt, o); +} + template<typename T> inline JSRetainPtr<T>::JSRetainPtr(const JSRetainPtr& o) : m_ptr(o.m_ptr) { diff --git a/Source/JavaScriptCore/API/JSScriptRef.cpp b/Source/JavaScriptCore/API/JSScriptRef.cpp index 8a5f3caf3..60bde604e 100644 --- a/Source/JavaScriptCore/API/JSScriptRef.cpp +++ b/Source/JavaScriptCore/API/JSScriptRef.cpp @@ -26,13 +26,13 @@ #include "config.h" #include "APICast.h" -#include "APIShims.h" #include "Completion.h" +#include "Exception.h" #include "JSBasePrivate.h" #include "VM.h" #include "JSScriptRefPrivate.h" #include "OpaqueJSString.h" -#include "Operations.h" +#include "JSCInlines.h" #include "Parser.h" #include "SourceCode.h" #include "SourceProvider.h" @@ -41,14 +41,19 @@ using namespace JSC; struct OpaqueJSScript : public SourceProvider { public: - static WTF::PassRefPtr<OpaqueJSScript> create(VM* vm, const String& url, int startingLineNumber, const String& source) + static WTF::RefPtr<OpaqueJSScript> create(VM* vm, const String& url, int startingLineNumber, const String& source) { - return WTF::adoptRef(new OpaqueJSScript(vm, url, startingLineNumber, source)); + return WTF::adoptRef(*new OpaqueJSScript(vm, url, startingLineNumber, source)); } - const String& source() const OVERRIDE + unsigned hash() const override { - return m_source; + return m_source.get().hash(); + } + + StringView source() const override + { + return m_source.get(); } VM* vm() const { return m_vm; } @@ -57,19 +62,22 @@ 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) + , m_source(source.isNull() ? *StringImpl::empty() : *source.impl()) { } - ~OpaqueJSScript() { } + virtual ~OpaqueJSScript() { } VM* m_vm; - String m_source; + Ref<StringImpl> m_source; }; static bool parseScript(VM* vm, const SourceCode& source, ParserError& error) { - return JSC::parse<JSC::ProgramNode>(vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); + return !!JSC::parse<JSC::ProgramNode>( + vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, + JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, + error); } extern "C" { @@ -77,21 +85,23 @@ 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); + JSLockHolder locker(vm); for (size_t i = 0; i < length; i++) { if (!isASCII(source[i])) return 0; } - RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url->string(), startingLineNumber, String(StringImpl::createFromLiteral(source, length))); + startingLineNumber = std::max(1, startingLineNumber); + + RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url ? url->string() : String(), startingLineNumber, String(StringImpl::createFromLiteral(source, length))); ParserError error; if (!parseScript(vm, SourceCode(result), error)) { if (errorMessage) - *errorMessage = OpaqueJSString::create(error.m_message).leakRef(); + *errorMessage = OpaqueJSString::create(error.message()).leakRef(); if (errorLine) - *errorLine = error.m_line; - return 0; + *errorLine = error.line(); + return nullptr; } return result.release().leakRef(); @@ -100,17 +110,19 @@ JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupRef context JSScriptRef JSScriptCreateFromString(JSContextGroupRef contextGroup, JSStringRef url, int startingLineNumber, JSStringRef source, JSStringRef* errorMessage, int* errorLine) { VM* vm = toJS(contextGroup); - APIEntryShim entryShim(vm); + JSLockHolder locker(vm); + + startingLineNumber = std::max(1, startingLineNumber); - RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url->string(), startingLineNumber, source->string()); + RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url ? url->string() : String(), startingLineNumber, source->string()); ParserError error; if (!parseScript(vm, SourceCode(result), error)) { if (errorMessage) - *errorMessage = OpaqueJSString::create(error.m_message).leakRef(); + *errorMessage = OpaqueJSString::create(error.message()).leakRef(); if (errorLine) - *errorLine = error.m_line; - return 0; + *errorLine = error.line(); + return nullptr; } return result.release().leakRef(); @@ -118,30 +130,30 @@ JSScriptRef JSScriptCreateFromString(JSContextGroupRef contextGroup, JSStringRef void JSScriptRetain(JSScriptRef script) { - APIEntryShim entryShim(script->vm()); + JSLockHolder locker(script->vm()); script->ref(); } void JSScriptRelease(JSScriptRef script) { - APIEntryShim entryShim(script->vm()); + JSLockHolder locker(script->vm()); script->deref(); } JSValueRef JSScriptEvaluate(JSContextRef context, JSScriptRef script, JSValueRef thisValueRef, JSValueRef* exception) { ExecState* exec = toJS(context); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); if (script->vm() != &exec->vm()) { RELEASE_ASSERT_NOT_REACHED(); return 0; } - JSValue internalException; + NakedPtr<Exception> internalException; JSValue thisValue = thisValueRef ? toJS(exec, thisValueRef) : jsUndefined(); - JSValue result = evaluate(exec, SourceCode(script), thisValue, &internalException); + JSValue result = evaluate(exec, SourceCode(script), thisValue, internalException); if (internalException) { if (exception) - *exception = toRef(exec, internalException); + *exception = toRef(exec, internalException->value()); return 0; } ASSERT(result); diff --git a/Source/JavaScriptCore/API/JSScriptRefPrivate.h b/Source/JavaScriptCore/API/JSScriptRefPrivate.h index e1992052a..e6224ce37 100644 --- a/Source/JavaScriptCore/API/JSScriptRefPrivate.h +++ b/Source/JavaScriptCore/API/JSScriptRefPrivate.h @@ -42,7 +42,7 @@ extern "C" { @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 startingLineNumber An integer value specifying the script's starting line number in the file located at sourceURL. This is only used when reporting exceptions. The value is one-based, so the first line is line 1 and invalid values are clamped to 1. @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. @@ -58,7 +58,7 @@ JS_EXPORT JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupR @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 startingLineNumber An integer value specifying the script's starting line number in the file located at sourceURL. This is only used when reporting exceptions. The value is one-based, so the first line is line 1 and invalid values are clamped to 1. @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. diff --git a/Source/JavaScriptCore/API/JSStringRef.cpp b/Source/JavaScriptCore/API/JSStringRef.cpp index 812f3d413..909540481 100644 --- a/Source/JavaScriptCore/API/JSStringRef.cpp +++ b/Source/JavaScriptCore/API/JSStringRef.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -37,7 +37,7 @@ using namespace WTF::Unicode; JSStringRef JSStringCreateWithCharacters(const JSChar* chars, size_t numChars) { initializeThreading(); - return OpaqueJSString::create(chars, numChars).leakRef(); + return &OpaqueJSString::create(reinterpret_cast<const UChar*>(chars), numChars).leakRef(); } JSStringRef JSStringCreateWithUTF8CString(const char* string) @@ -51,18 +51,18 @@ JSStringRef JSStringCreateWithUTF8CString(const char* string) const LChar* stringStart = reinterpret_cast<const LChar*>(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(); + return &OpaqueJSString::create(stringStart, length).leakRef(); + return &OpaqueJSString::create(buffer.data(), p - buffer.data()).leakRef(); } } - return OpaqueJSString::create().leakRef(); + return &OpaqueJSString::create().leakRef(); } JSStringRef JSStringCreateWithCharactersNoCopy(const JSChar* chars, size_t numChars) { initializeThreading(); - return OpaqueJSString::create(StringImpl::createWithoutCopying(chars, numChars, WTF::DoesNotHaveTerminatingNullCharacter)).leakRef(); + return OpaqueJSString::create(StringImpl::createWithoutCopying(reinterpret_cast<const UChar*>(chars), numChars)).leakRef(); } JSStringRef JSStringRetain(JSStringRef string) @@ -78,12 +78,16 @@ void JSStringRelease(JSStringRef string) size_t JSStringGetLength(JSStringRef string) { + if (!string) + return 0; return string->length(); } const JSChar* JSStringGetCharactersPtr(JSStringRef string) { - return string->characters(); + if (!string) + return nullptr; + return reinterpret_cast<const JSChar*>(string->characters()); } size_t JSStringGetMaximumUTF8CStringSize(JSStringRef string) @@ -94,23 +98,29 @@ size_t JSStringGetMaximumUTF8CStringSize(JSStringRef string) size_t JSStringGetUTF8CString(JSStringRef string, char* buffer, size_t bufferSize) { - if (!bufferSize) + if (!string || !buffer || !bufferSize) return 0; - char* p = buffer; - const UChar* d = string->characters(); - ConversionResult result = convertUTF16ToUTF8(&d, d + string->length(), &p, p + bufferSize - 1, true); - *p++ = '\0'; + char* destination = buffer; + ConversionResult result; + if (string->is8Bit()) { + const LChar* source = string->characters8(); + result = convertLatin1ToUTF8(&source, source + string->length(), &destination, destination + bufferSize - 1); + } else { + const UChar* source = string->characters16(); + result = convertUTF16ToUTF8(&source, source + string->length(), &destination, destination + bufferSize - 1, true); + } + + *destination++ = '\0'; if (result != conversionOK && result != targetExhausted) return 0; - return p - buffer; + return destination - buffer; } bool JSStringIsEqual(JSStringRef a, JSStringRef b) { - unsigned len = a->length(); - return len == b->length() && 0 == memcmp(a->characters(), b->characters(), len * sizeof(UChar)); + return OpaqueJSString::equal(a, b); } bool JSStringIsEqualToUTF8CString(JSStringRef a, const char* b) diff --git a/Source/JavaScriptCore/API/JSStringRef.h b/Source/JavaScriptCore/API/JSStringRef.h index 75d73c919..6f45fcbd8 100644 --- a/Source/JavaScriptCore/API/JSStringRef.h +++ b/Source/JavaScriptCore/API/JSStringRef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,17 +10,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef JSStringRef_h diff --git a/Source/JavaScriptCore/API/JSStringRefBSTR.cpp b/Source/JavaScriptCore/API/JSStringRefBSTR.cpp index 70f42540b..e900d24d8 100644 --- a/Source/JavaScriptCore/API/JSStringRefBSTR.cpp +++ b/Source/JavaScriptCore/API/JSStringRefBSTR.cpp @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * diff --git a/Source/JavaScriptCore/API/JSStringRefBSTR.h b/Source/JavaScriptCore/API/JSStringRefBSTR.h index 59f19b763..066c68d53 100644 --- a/Source/JavaScriptCore/API/JSStringRefBSTR.h +++ b/Source/JavaScriptCore/API/JSStringRefBSTR.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * diff --git a/Source/JavaScriptCore/API/JSStringRefCF.cpp b/Source/JavaScriptCore/API/JSStringRefCF.cpp index 64d2d6251..05872593f 100644 --- a/Source/JavaScriptCore/API/JSStringRefCF.cpp +++ b/Source/JavaScriptCore/API/JSStringRefCF.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -28,10 +28,10 @@ #include "APICast.h" #include "InitializeThreading.h" +#include "JSCJSValue.h" #include "JSStringRef.h" #include "OpaqueJSString.h" -#include <runtime/JSCJSValue.h> -#include <wtf/OwnArrayPtr.h> +#include <wtf/StdLibExtras.h> JSStringRef JSStringCreateWithCFString(CFStringRef string) { @@ -40,23 +40,28 @@ JSStringRef JSStringCreateWithCFString(CFStringRef string) // We cannot use CFIndex here since CFStringGetLength can return values larger than // it can hold. (<rdar://problem/6806478>) size_t length = CFStringGetLength(string); - if (length) { - Vector<LChar, 1024> lcharBuffer(length); - CFIndex usedBufferLength; - CFIndex convertedSize = CFStringGetBytes(string, CFRangeMake(0, length), kCFStringEncodingISOLatin1, 0, false, lcharBuffer.data(), length, &usedBufferLength); - if (static_cast<size_t>(convertedSize) == length && static_cast<size_t>(usedBufferLength) == length) - return OpaqueJSString::create(lcharBuffer.data(), length).leakRef(); - - OwnArrayPtr<UniChar> buffer = adoptArrayPtr(new UniChar[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<UChar*>(buffer.get()), length).leakRef(); - } - - return OpaqueJSString::create(reinterpret_cast<const LChar*>(""), 0).leakRef(); + if (!length) + return &OpaqueJSString::create(reinterpret_cast<const LChar*>(""), 0).leakRef(); + + Vector<LChar, 1024> lcharBuffer(length); + CFIndex usedBufferLength; + CFIndex convertedSize = CFStringGetBytes(string, CFRangeMake(0, length), kCFStringEncodingISOLatin1, 0, false, lcharBuffer.data(), length, &usedBufferLength); + if (static_cast<size_t>(convertedSize) == length && static_cast<size_t>(usedBufferLength) == length) + return &OpaqueJSString::create(lcharBuffer.data(), length).leakRef(); + + auto buffer = std::make_unique<UniChar[]>(length); + CFStringGetCharacters(string, CFRangeMake(0, length), buffer.get()); + static_assert(sizeof(UniChar) == sizeof(UChar), "UniChar and UChar must be same size"); + return &OpaqueJSString::create(reinterpret_cast<UChar*>(buffer.get()), length).leakRef(); } -CFStringRef JSStringCopyCFString(CFAllocatorRef alloc, JSStringRef string) +CFStringRef JSStringCopyCFString(CFAllocatorRef allocator, JSStringRef string) { - return CFStringCreateWithCharacters(alloc, reinterpret_cast<const UniChar*>(string->characters()), string->length()); + if (!string || !string->length()) + return CFSTR(""); + + if (string->is8Bit()) + return CFStringCreateWithBytes(allocator, reinterpret_cast<const UInt8*>(string->characters8()), string->length(), kCFStringEncodingISOLatin1, false); + + return CFStringCreateWithCharacters(allocator, reinterpret_cast<const UniChar*>(string->characters16()), string->length()); } diff --git a/Source/JavaScriptCore/API/JSStringRefCF.h b/Source/JavaScriptCore/API/JSStringRefCF.h index a42476561..1e210c7a9 100644 --- a/Source/JavaScriptCore/API/JSStringRefCF.h +++ b/Source/JavaScriptCore/API/JSStringRefCF.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -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/Source/JavaScriptCore/API/JSStringRefQt.cpp b/Source/JavaScriptCore/API/JSStringRefQt.cpp index c1ce761f7..2d5792e21 100644 --- a/Source/JavaScriptCore/API/JSStringRefQt.cpp +++ b/Source/JavaScriptCore/API/JSStringRefQt.cpp @@ -32,7 +32,6 @@ #include "JSStringRef.h" #include "OpaqueJSString.h" #include <runtime/JSCJSValue.h> -#include <wtf/OwnArrayPtr.h> QString JSStringCopyQString(JSStringRef string) { @@ -46,5 +45,5 @@ JSRetainPtr<JSStringRef> JSStringCreateWithQString(const QString& qString) if (jsString) return JSRetainPtr<JSStringRef>(Adopt, jsString.release().leakRef()); - return JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create().leakRef()); + return JSRetainPtr<JSStringRef>(Adopt, &OpaqueJSString::create().leakRef()); } diff --git a/Source/JavaScriptCore/API/JSStringRefQt.h b/Source/JavaScriptCore/API/JSStringRefQt.h index b4f934a3b..6a3963209 100644 --- a/Source/JavaScriptCore/API/JSStringRefQt.h +++ b/Source/JavaScriptCore/API/JSStringRefQt.h @@ -39,7 +39,7 @@ @param string The JSString to copy into the new QString. @result A QString containing string. */ -JS_EXPORT QString JSStringCopyQString(JSStringRef string); +JS_EXPORT QString JSStringCopyQString(JSStringRef); JS_EXPORT JSRetainPtr<JSStringRef> JSStringCreateWithQString(const QString&); #endif /* JSStringRefQt_h */ diff --git a/Source/JavaScriptCore/API/JSValue.h b/Source/JavaScriptCore/API/JSValue.h index c77707538..37d759407 100644 --- a/Source/JavaScriptCore/API/JSValue.h +++ b/Source/JavaScriptCore/API/JSValue.h @@ -28,225 +28,553 @@ #if JSC_OBJC_API_ENABLED +#import <CoreGraphics/CGGeometry.h> + @class JSContext; -// 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. -// -// For all methods taking arguments of type id, arguments will be converted -// into a JavaScript value according to the conversion specified below. -// 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. -// -// Conversion between Objective-C and JavaScript types. -// -// 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. -// -// Objective-C type | JavaScript type -// --------------------+--------------------- -// nil | undefined -// NSNull | null -// NSString | string -// NSNumber | number, boolean -// NSDictionary | Object object -// NSArray | Array object -// NSDate | Date object -// NSBlock * | Function object * -// id ** | Wrapper object ** -// Class *** | Constructor object *** -// -// * 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. -// -// ** 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. -// -// *** For Objective-C Class objects a constructor object containing exported -// class methods will be returned. See JSExport.h for more information on -// constructor objects. - -NS_CLASS_AVAILABLE(10_9, NA) +/*! +@interface +@discussion A JSValue is a reference to a JavaScript value. Every JSValue + originates from a JSContext and holds a strong reference to it. + When a JSValue instance method creates a new JSValue, the new value + originates from the same JSContext. + + All JSValues values also originate from a JSVirtualMachine + (available indirectly via the context property). It is an error to pass a + JSValue to a method or property of a JSValue or JSContext originating from a + different JSVirtualMachine. Doing so will raise an Objective-C exception. +*/ +NS_CLASS_AVAILABLE(10_9, 7_0) @interface JSValue : NSObject -// Create a JSValue by converting an Objective-C object. +/*! +@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; -// Create a JavaScript value from an Objective-C primitive type. + +/*! +@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 <code>int32_t</code> 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 <code>uint32_t</code> 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; -// Create a JavaScript value in this 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 <code>null</code>. +@param context The JSContext to which the resulting JSValue belongs. +@result The JSValue representing the JavaScript value <code>null</code>. +*/ + (JSValue *)valueWithNullInContext:(JSContext *)context; + +/*! +@method +@abstract Create the JavaScript value <code>undefined</code>. +@param context The JSContext to which the resulting JSValue belongs. +@result The JSValue representing the JavaScript value <code>undefined</code>. +*/ + (JSValue *)valueWithUndefinedInContext:(JSContext *)context; -// Convert this value to a corresponding Objective-C object, according to the -// conversion specified above. +/*! +@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. + +<pre> +@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 +</pre> + + (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; -// Convert this value to a corresponding Objective-C object, if the result is -// not of the specified class then nil will be returned. + +/*! +@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 <code>nil</code> will be returned. +@result An Objective-C object of the specified Class or <code>nil</code>. +*/ - (id)toObjectOfClass:(Class)expectedClass; -// The value is copied to a boolean according to the conversion specified by the -// JavaScript language. + +/*! +@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; -// The value is copied to a number according to the conversion specified by the -// JavaScript language. + +/*! +@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; -// The value is copied to an integer according to the conversion specified by -// the JavaScript language. + +/*! +@method +@abstract Convert a JSValue to an <code>int32_t</code>. +@discussion The JSValue is converted to an integer according to the rules specified + by the JavaScript language. +@result The <code>int32_t</code> result of the conversion. +*/ - (int32_t)toInt32; -// The value is copied to an integer according to the conversion specified by -// the JavaScript language. + +/*! +@method +@abstract Convert a JSValue to a <code>uint32_t</code>. +@discussion The JSValue is converted to an integer according to the rules specified + by the JavaScript language. +@result The <code>uint32_t</code> result of the conversion. +*/ - (uint32_t)toUInt32; -// If the value is a boolean, a NSNumber value of @YES or @NO will be returned. -// For all other types the value will be copied to a number according to the -// conversion specified by the JavaScript language. + +/*! +@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; -// The value is copied to a string according to the conversion specified by the -// JavaScript language. + +/*! +@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; -// The value is converted to a number representing a time interval since 1970, -// and a new NSDate instance is returned. + +/*! +@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; -// 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 -// Objective-C objects converted to equivalent JSValues as specified. + +/*! +@method +@abstract Convert a JSValue to a NSArray. +@discussion If the value is <code>null</code> or <code>undefined</code> then <code>nil</code> is returned. + If the value is not an object then a JavaScript TypeError will be thrown. + The property <code>length</code> 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; -// 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 -// Objective-C objects converted to equivalent JSValues as specified. + +/*! +@method +@abstract Convert a JSValue to a NSDictionary. +@discussion If the value is <code>null</code> or <code>undefined</code> then <code>nil</code> 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; -// Access a property from the value. This method will return the JavaScript value -// 'undefined' if the property does not exist. +/*! +@methodgroup Accessing Properties +*/ +/*! +@method +@abstract Access a property of a JSValue. +@result The JSValue for the requested property or the JSValue <code>undefined</code> + if the property does not exist. +*/ - (JSValue *)valueForProperty:(NSString *)property; -// Set a property on the value. + +/*! +@method +@abstract Set a property on a JSValue. +*/ - (void)setValue:(id)value forProperty:(NSString *)property; -// Delete a property from the value, returns YES if deletion is successful. + +/*! +@method +@abstract Delete a property from a JSValue. +@result YES if deletion is successful, NO otherwise. +*/ - (BOOL)deleteProperty:(NSString *)property; -// Returns YES if property is present on the value. -// This method has the same function as the JavaScript operator "in". + +/*! +@method +@abstract Check if a JSValue has a property. +@discussion This method has the same function as the JavaScript operator <code>in</code>. +@result Returns YES if property is present on the value. +*/ - (BOOL)hasProperty:(NSString *)property; -// 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. + +/*! +@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; -// Access an indexed property from the value. This method will return the -// JavaScript value 'undefined' if no property exists at that index. +/*! +@method +@abstract Access an indexed (numerical) property on a JSValue. +@result The JSValue for the property at the specified index. + Returns the JavaScript value <code>undefined</code> if no property exists at that index. +*/ - (JSValue *)valueAtIndex:(NSUInteger)index; -// Set an indexed property on the value. For JSValues that are JavaScript arrays, -// indices greater than UINT_MAX - 1 will not affect the length of the array. + +/*! +@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; -// All JavaScript values are precisely one of these types. -- (BOOL)isUndefined; -- (BOOL)isNull; -- (BOOL)isBoolean; -- (BOOL)isNumber; -- (BOOL)isString; -- (BOOL)isObject; +/*! +@methodgroup Checking JavaScript Types +*/ +/*! +@method +@abstract Check if a JSValue corresponds to the JavaScript value <code>undefined</code>. +*/ +@property (readonly) BOOL isUndefined; + +/*! +@method +@abstract Check if a JSValue corresponds to the JavaScript value <code>null</code>. +*/ +@property (readonly) BOOL isNull; + +/*! +@method +@abstract Check if a JSValue is a boolean. +*/ +@property (readonly) 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. +*/ +@property (readonly) BOOL isNumber; + +/*! +@method +@abstract Check if a JSValue is a string. +*/ +@property (readonly) BOOL isString; + +/*! +@method +@abstract Check if a JSValue is an object. +*/ +@property (readonly) BOOL isObject; -// This method has the same function as the JavaScript operator "===". +/*! +@method +@abstract Check if a JSValue is an array. +*/ +@property (readonly) BOOL isArray NS_AVAILABLE(10_11, 9_0); + +/*! +@method +@abstract Check if a JSValue is a date. +*/ +@property (readonly) BOOL isDate NS_AVAILABLE(10_11, 9_0); + +/*! +@method +@abstract Compare two JSValues using JavaScript's <code>===</code> operator. +*/ - (BOOL)isEqualToObject:(id)value; -// This method has the same function as the JavaScript operator "==". + +/*! +@method +@abstract Compare two JSValues using JavaScript's <code>==</code> operator. +*/ - (BOOL)isEqualWithTypeCoercionToObject:(id)value; -// This method has the same function as the JavaScript operator "instanceof". + +/*! +@method +@abstract Check if a JSValue is an instance of another object. +@discussion This method has the same function as the JavaScript operator <code>instanceof</code>. + If an object other than a JSValue is passed, it will first be converted according to + the aforementioned rules. +*/ - (BOOL)isInstanceOf:(id)value; -// Call this value as a function passing the specified arguments. +/*! +@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 <code>undefined</code>. +@param arguments The arguments to pass to the function. +@result The return value of the function call. +*/ - (JSValue *)callWithArguments:(NSArray *)arguments; -// Call this value as a constructor passing the specified arguments. + +/*! +@method +@abstract Invoke a JSValue as a constructor. +@discussion This is equivalent to using the <code>new</code> syntax in JavaScript. +@param arguments The arguments to pass to the constructor. +@result The return value of the constructor call. +*/ - (JSValue *)constructWithArguments:(NSArray *)arguments; -// Access the property named "method" from this value; call the value resulting -// from the property access as a function, passing this value as the "this" -// value, and the specified arguments. -- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments; -// The JSContext that this value originates from. -@property(readonly, retain) JSContext *context; +/*! +@method +@abstract Invoke a method on a JSValue. +@discussion Accesses the property named <code>method</code> from this value and + calls the resulting value as a function, passing this JSValue as the <code>this</code> + 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 -// 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<Type>:inContext:", and and instance -// method "to<Type>" - where the string "<Type>" 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) - -// This method returns a newly allocated JavaScript object containing properties -// named "x" and "y", with values from the CGPoint. +/*! +@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 <code>valueWith<Type>:inContext:</code>, and and instance + method <code>to<Type></code>- where the string <code><Type></code> 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 <code>x</code> and <code>y</code>, with values from the CGPoint. +*/ + (JSValue *)valueWithPoint:(CGPoint)point inContext:(JSContext *)context; -// This method returns a newly allocated JavaScript object containing properties -// named "location" and "length", with values from the NSRange. + +/*! +@method +@abstract Create a JSValue from a NSRange. +@result A newly allocated JavaScript object containing properties + named <code>location</code> and <code>length</code>, with values from the NSRange. +*/ + (JSValue *)valueWithRange:(NSRange)range inContext:(JSContext *)context; -// This method returns a newly allocated JavaScript object containing properties -// named "x", "y", "width", and "height", with values from the CGRect. + +/*! +@method +@abstract +Create a JSValue from a CGRect. +@result A newly allocated JavaScript object containing properties + named <code>x</code>, <code>y</code>, <code>width</code>, and <code>height</code>, with values from the CGRect. +*/ + (JSValue *)valueWithRect:(CGRect)rect inContext:(JSContext *)context; -// This method returns a newly allocated JavaScript object containing properties -// named "width" and "height", with values from the CGSize. + +/*! +@method +@abstract Create a JSValue from a CGSize. +@result A newly allocated JavaScript object containing properties + named <code>width</code> and <code>height</code>, with values from the CGSize. +*/ + (JSValue *)valueWithSize:(CGSize)size inContext:(JSContext *)context; -// Convert a value to type CGPoint by reading properties named "x" and "y" from -// this value, and converting the results to double. +/*! +@method +@abstract Convert a JSValue to a CGPoint. +@discussion Reads the properties named <code>x</code> and <code>y</code> from + this JSValue, and converts the results to double. +@result The new CGPoint. +*/ - (CGPoint)toPoint; -// Convert a value to type NSRange by accessing properties named "location" and -// "length" from this value converting the results to double. + +/*! +@method +@abstract Convert a JSValue to an NSRange. +@discussion Reads the properties named <code>location</code> and + <code>length</code> from this JSValue and converts the results to double. +@result The new NSRange. +*/ - (NSRange)toRange; -// Convert a value to type CGRect by reading properties named "x", "y", "width", -// and "height" from this value, and converting the results to double. + +/*! +@method +@abstract Convert a JSValue to a CGRect. +@discussion Reads the properties named <code>x</code>, <code>y</code>, + <code>width</code>, and <code>height</code> from this JSValue and converts the results to double. +@result The new CGRect. +*/ - (CGRect)toRect; -// Convert a value to type CGSize by accessing properties named "width" and -// "height" from this value converting the results to double. + +/*! +@method +@abstract Convert a JSValue to a CGSize. +@discussion Reads the properties named <code>width</code> and + <code>height</code> from this JSValue and converts the results to double. +@result The new CGSize. +*/ - (CGSize)toSize; @end -// Instances of JSValue implement the following methods in order to enable -// support for subscript access by key and index, for example: -// -// 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'. -// -// 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) +/*! +@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; @@ -255,46 +583,85 @@ NS_CLASS_AVAILABLE(10_9, NA) @end -// These functions are for bridging between the C API and the Objective-C API. -@interface JSValue(JSValueRefSupport) -// Creates a JSValue, wrapping its C API counterpart. +/*! +@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; -// Returns the C API counterpart wrapped by a JSContext. -- (JSValueRef)JSValueRef; + +/*! +@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 -// 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. +/*! +@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 <code>value</code> and <code>writable</code>, + and optionally containing one or both of the keys <code>enumerable</code> and + <code>configurable</code>. A data descriptor may not contain either the <code>get</code> or + <code>set</code> 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 <code>get</code> and <code>set</code>, and + optionally containing one or both of the keys <code>enumerable</code> and + <code>configurable</code>. An accessor descriptor may not contain either the <code>value</code> + or <code>writable</code> 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 <code>enumerable</code> and + <code>configurable</code>. A generic descriptor may not contain any of the keys + <code>value</code>, <code>writable</code>, <code>get</code>, or <code>set</code>. + 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 diff --git a/Source/JavaScriptCore/API/JSValue.mm b/Source/JavaScriptCore/API/JSValue.mm deleted file mode 100644 index e708cc674..000000000 --- a/Source/JavaScriptCore/API/JSValue.mm +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * 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 <wtf/HashMap.h> -#import <wtf/HashSet.h> -#import <wtf/Vector.h> -#import <wtf/TCSpinLock.h> -#import <wtf/text/WTFString.h> -#import <wtf/text/StringHash.h> - -#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<double>::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){ - [self[@"x"] toDouble], - [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){ - [self[@"width"] toDouble], - [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 <NSCopying> *)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::s_info); -} - -inline bool isArray(JSObjectRef object, JSGlobalContextRef context) -{ - JSC::APIEntryShim entryShim(toJS(context)); - return toJS(object)->inherits(&JSC::JSArray::s_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<JSValueRef, id> m_objectMap; - Vector<Task> m_worklist; -}; - -inline id JSContainerConvertor::convert(JSValueRef value) -{ - HashMap<JSValueRef, id>::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<double>::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 = [(NSString *)JSStringCopyCFString(kCFAllocatorDefault, jsstring) autorelease]; - 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<id, JSValueRef> m_objectMap; - Vector<Task> 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<JSManagedValue *>(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<String, StructTagHandler> StructHandlers; - -static StructHandlers* createStructHandlerMap() -{ - StructHandlers* structHandlers = new StructHandlers(); - - size_t valueWithXinContextLength = strlen("valueWithX:inContext:"); - size_t toXLength = strlen("toX"); - - // Step 1: find all valueWith<Foo>: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<Foo>:context: - if (nameLength < valueWithXinContextLength || memcmp(name, "valueWith", 9) || memcmp(name + nameLength - 11, ":inContext:", 11)) - return; - // Check for [ id, SEL, <type>, <contextType> ] - 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<Foo> 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<Foo> - if (nameLength < toXLength || memcmp(name, "to", 2)) - return; - // Check for [ id, SEL ] - if (method_getNumberOfArguments(method) != 2) - return; - // Try to find a matching valueWith<Foo>: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(<foo>) == strlen(<Foo>) - const char* valueWithName = sel_getName(handler.typeToValueSEL); - size_t valueWithLength = strlen(valueWithName); - if (valueWithLength - valueWithXinContextLength != nameLength - toXLength) - return; - // Check that <Foo> == <Foo> - if (memcmp(valueWithName + 9, name + 2, nameLength - toXLength - 1)) - return; - handler.valueToTypeSEL = selector; - }); - - // Step 3: clean up - remove entries where we found prospective valueWith<Foo>:inContext: conversions, but no matching to<Foo> methods. - typedef HashSet<String> 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/Source/JavaScriptCore/API/JSValueRef.cpp b/Source/JavaScriptCore/API/JSValueRef.cpp index 81a2db7b7..54405e2af 100644 --- a/Source/JavaScriptCore/API/JSValueRef.cpp +++ b/Source/JavaScriptCore/API/JSValueRef.cpp @@ -10,47 +10,69 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "JSValueRef.h" #include "APICast.h" -#include "APIShims.h" +#include "DateInstance.h" +#include "Exception.h" #include "JSAPIWrapperObject.h" +#include "JSCInlines.h" +#include "JSCJSValue.h" #include "JSCallbackObject.h" - -#include <runtime/JSCJSValue.h> -#include <runtime/JSGlobalObject.h> -#include <runtime/JSONObject.h> -#include <runtime/JSString.h> -#include <runtime/LiteralParser.h> -#include <runtime/Operations.h> -#include <runtime/Protect.h> - +#include "JSGlobalObject.h" +#include "JSONObject.h" +#include "JSString.h" +#include "LiteralParser.h" +#include "Protect.h" +#include <algorithm> #include <wtf/Assertions.h> #include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> -#include <algorithm> // for std::min - #if PLATFORM(MAC) #include <mach-o/dyld.h> #endif +#if ENABLE(REMOTE_INSPECTOR) +#include "JSGlobalObjectInspectorController.h" +#endif + using namespace JSC; +enum class ExceptionStatus { + DidThrow, + DidNotThrow +}; + +static ExceptionStatus handleExceptionIfNeeded(ExecState* exec, JSValueRef* returnedExceptionRef) +{ + if (exec->hadException()) { + Exception* exception = exec->exception(); + if (returnedExceptionRef) + *returnedExceptionRef = toRef(exec, exception->value()); + exec->clearException(); +#if ENABLE(REMOTE_INSPECTOR) + exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); +#endif + return ExceptionStatus::DidThrow; + } + return ExceptionStatus::DidNotThrow; +} + #if PLATFORM(MAC) static bool evernoteHackNeeded() { @@ -69,7 +91,7 @@ static bool evernoteHackNeeded() return kJSTypeUndefined; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); @@ -94,10 +116,9 @@ bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isUndefined(); + return toJS(exec, value).isUndefined(); } bool JSValueIsNull(JSContextRef ctx, JSValueRef value) @@ -107,10 +128,9 @@ bool JSValueIsNull(JSContextRef ctx, JSValueRef value) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isNull(); + return toJS(exec, value).isNull(); } bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) @@ -120,10 +140,9 @@ bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isBoolean(); + return toJS(exec, value).isBoolean(); } bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) @@ -133,10 +152,9 @@ bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isNumber(); + return toJS(exec, value).isNumber(); } bool JSValueIsString(JSContextRef ctx, JSValueRef value) @@ -146,10 +164,9 @@ bool JSValueIsString(JSContextRef ctx, JSValueRef value) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isString(); + return toJS(exec, value).isString(); } bool JSValueIsObject(JSContextRef ctx, JSValueRef value) @@ -159,10 +176,33 @@ bool JSValueIsObject(JSContextRef ctx, JSValueRef value) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isObject(); + return toJS(exec, value).isObject(); +} + +bool JSValueIsArray(JSContextRef ctx, JSValueRef value) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).inherits(JSArray::info()); +} + +bool JSValueIsDate(JSContextRef ctx, JSValueRef value) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).inherits(DateInstance::info()); } bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) @@ -172,17 +212,20 @@ bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsCla return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); if (JSObject* o = jsValue.getObject()) { - if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) + if (o->inherits(JSProxy::info())) + o = jsCast<JSProxy*>(o)->target(); + + if (o->inherits(JSCallbackObject<JSGlobalObject>::info())) return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass); - if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)) + if (o->inherits(JSCallbackObject<JSDestructibleObject>::info())) return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass); #if JSC_OBJC_API_ENABLED - if (o->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info)) + if (o->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(o)->inherits(jsClass); #endif } @@ -196,17 +239,14 @@ bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* ex return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsA = toJS(exec, a); JSValue jsB = toJS(exec, b); bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - } + handleExceptionIfNeeded(exec, exception); + return result; } @@ -217,7 +257,7 @@ bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsA = toJS(exec, a); JSValue jsB = toJS(exec, b); @@ -232,7 +272,7 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); @@ -240,11 +280,7 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject if (!jsConstructor->structure()->typeInfo().implementsHasInstance()) return false; bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - } + handleExceptionIfNeeded(exec, exception); return result; } @@ -255,7 +291,7 @@ JSValueRef JSValueMakeUndefined(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(exec, jsUndefined()); } @@ -267,7 +303,7 @@ JSValueRef JSValueMakeNull(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(exec, jsNull()); } @@ -279,7 +315,7 @@ JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(exec, jsBoolean(value)); } @@ -291,15 +327,9 @@ JSValueRef JSValueMakeNumber(JSContextRef ctx, double value) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(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 (std::isnan(value)) - value = QNaN; - - return toRef(exec, jsNumber(value)); + return toRef(exec, jsNumber(purifyNaN(value))); } JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string) @@ -309,9 +339,9 @@ JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); - return toRef(exec, jsString(exec, string->string())); + return toRef(exec, jsString(exec, string ? string->string() : String())); } JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) @@ -321,14 +351,14 @@ JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); String str = string->string(); unsigned length = str.length(); - if (length && str.is8Bit()) { + if (!length || str.is8Bit()) { LiteralParser<LChar> parser(exec, str.characters8(), length, StrictJSON); return toRef(exec, parser.tryLiteralParse()); } - LiteralParser<UChar> parser(exec, str.characters(), length, StrictJSON); + LiteralParser<UChar> parser(exec, str.characters16(), length, StrictJSON); return toRef(exec, parser.tryLiteralParse()); } @@ -339,17 +369,13 @@ JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsig return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue value = toJS(exec, apiValue); String result = JSONStringify(exec, value, indent); if (exception) *exception = 0; - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) return 0; - } return OpaqueJSString::create(result).leakRef(); } @@ -360,7 +386,7 @@ bool JSValueToBoolean(JSContextRef ctx, JSValueRef value) return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); return jsValue.toBoolean(exec); @@ -370,20 +396,16 @@ double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception { if (!ctx) { ASSERT_NOT_REACHED(); - return QNaN; + return PNaN; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); double number = jsValue.toNumber(exec); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - number = QNaN; - } + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) + number = PNaN; return number; } @@ -394,17 +416,13 @@ JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec))); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - stringRef.clear(); - } + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) + stringRef = nullptr; return stringRef.release().leakRef(); } @@ -415,19 +433,15 @@ JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exce return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); JSObjectRef objectRef = toRef(jsValue.toObject(exec)); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) objectRef = 0; - } return objectRef; -} +} void JSValueProtect(JSContextRef ctx, JSValueRef value) { @@ -436,7 +450,7 @@ void JSValueProtect(JSContextRef ctx, JSValueRef value) return; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJSForGC(exec, value); gcProtect(jsValue); @@ -450,7 +464,7 @@ void JSValueUnprotect(JSContextRef ctx, JSValueRef value) #endif ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJSForGC(exec, value); gcUnprotect(jsValue); diff --git a/Source/JavaScriptCore/API/JSValueRef.h b/Source/JavaScriptCore/API/JSValueRef.h index 125e4028a..9c4fa58cd 100644 --- a/Source/JavaScriptCore/API/JSValueRef.h +++ b/Source/JavaScriptCore/API/JSValueRef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -129,6 +129,24 @@ JS_EXPORT bool JSValueIsObject(JSContextRef ctx, JSValueRef value); */ JS_EXPORT bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass); +/*! +@function +@abstract Tests whether a JavaScript value is an array. +@param ctx The execution context to use. +@param value The JSValue to test. +@result true if value is an array, otherwise false. +*/ +JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0); + +/*! +@function +@abstract Tests whether a JavaScript value is a date. +@param ctx The execution context to use. +@param value The JSValue to test. +@result true if value is a date, otherwise false. +*/ +JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0); + /* Comparing values */ /*! @@ -218,7 +236,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 +247,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/Source/JavaScriptCore/API/JSVirtualMachine.h b/Source/JavaScriptCore/API/JSVirtualMachine.h index b50616f4c..ccf9264d5 100644 --- a/Source/JavaScriptCore/API/JSVirtualMachine.h +++ b/Source/JavaScriptCore/API/JSVirtualMachine.h @@ -27,30 +27,54 @@ #if JSC_OBJC_API_ENABLED -// 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. - -NS_CLASS_AVAILABLE(10_9, NA) +/*! +@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. +*/ +NS_CLASS_AVAILABLE(10_9, 7_0) @interface JSVirtualMachine : NSObject -// Create a new JSVirtualMachine. -- (id)init; - -// addManagedReference:withOwner and removeManagedReference:withOwner allow -// 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 with -// addManagedReference:withOwner: will be scanned by the garbage collector. -// +/*! +@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 diff --git a/Source/JavaScriptCore/API/JSVirtualMachine.mm b/Source/JavaScriptCore/API/JSVirtualMachine.mm deleted file mode 100644 index 6bada34a6..000000000 --- a/Source/JavaScriptCore/API/JSVirtualMachine.mm +++ /dev/null @@ -1,255 +0,0 @@ -/* - * 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" - -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<JSVirtualMachine *>(NSMapGet(wrapperCache(), group)); -} - -@end - -@implementation JSVirtualMachine { - JSContextGroupRef m_group; - NSMapTable *m_contextCache; - NSMapTable *m_externalObjectGraph; -} - -- (id)init -{ - JSContextGroupRef group = JSContextGroupCreate(); - self = [self initWithContextGroupRef:group]; - // The extra JSContextGroupRetain is balanced here. - JSContextGroupRelease(group); - return self; -} - -- (id)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<JSManagedValue *>(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<JSValue *>(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<void*>(reinterpret_cast<size_t>(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<size_t>(NSMapGet(ownedObjects, object)); - if (count > 1) { - NSMapInsert(ownedObjects, object, reinterpret_cast<void*>(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<JSContext *>(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<void*> 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<id>(nextRoot)]; - id ownedObject; - NSEnumerator *enumerator = [ownedObjects keyEnumerator]; - while ((ownedObject = [enumerator nextObject])) { - ASSERT(reinterpret_cast<size_t>(NSMapGet(ownedObjects, ownedObject)) == 1); - stack.append(static_cast<void*>(ownedObject)); - } - } - } -} - -#endif - diff --git a/Source/JavaScriptCore/API/JSVirtualMachineInternal.h b/Source/JavaScriptCore/API/JSVirtualMachineInternal.h index 729226566..5a4fbefa5 100644 --- a/Source/JavaScriptCore/API/JSVirtualMachineInternal.h +++ b/Source/JavaScriptCore/API/JSVirtualMachineInternal.h @@ -26,16 +26,18 @@ #ifndef JSVirtualMachineInternal_h #define JSVirtualMachineInternal_h -#import <JavaScriptCore/JavaScriptCore.h> - #if JSC_OBJC_API_ENABLED +#import <JavaScriptCore/JavaScriptCore.h> + namespace JSC { class VM; class SlotVisitor; } #if defined(__OBJC__) +@class NSMapTable; + @interface JSVirtualMachine(Internal) JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *); @@ -51,7 +53,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *); #endif // defined(__OBJC__) void scanExternalObjectGraph(JSC::VM&, JSC::SlotVisitor&, void* root); +void scanExternalRememberedSet(JSC::VM&, JSC::SlotVisitor&); -#endif +#endif // JSC_OBJC_API_ENABLED #endif // JSVirtualMachineInternal_h diff --git a/Source/JavaScriptCore/API/JSWeakObjectMapRefInternal.h b/Source/JavaScriptCore/API/JSWeakObjectMapRefInternal.h index f7b91da51..9037947d7 100644 --- a/Source/JavaScriptCore/API/JSWeakObjectMapRefInternal.h +++ b/Source/JavaScriptCore/API/JSWeakObjectMapRefInternal.h @@ -41,9 +41,9 @@ typedef JSC::WeakGCMap<void*, JSC::JSObject> WeakMapType; struct OpaqueJSWeakObjectMap : public RefCounted<OpaqueJSWeakObjectMap> { public: - static PassRefPtr<OpaqueJSWeakObjectMap> create(void* data, JSWeakMapDestroyedCallback callback) + static Ref<OpaqueJSWeakObjectMap> create(JSC::VM& vm, void* data, JSWeakMapDestroyedCallback callback) { - return adoptRef(new OpaqueJSWeakObjectMap(data, callback)); + return adoptRef(*new OpaqueJSWeakObjectMap(vm, data, callback)); } WeakMapType& map() { return m_map; } @@ -54,8 +54,9 @@ public: } private: - OpaqueJSWeakObjectMap(void* data, JSWeakMapDestroyedCallback callback) - : m_data(data) + OpaqueJSWeakObjectMap(JSC::VM& vm, void* data, JSWeakMapDestroyedCallback callback) + : m_map(vm) + , m_data(data) , m_callback(callback) { } diff --git a/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp b/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp index 8cbe263a7..925c00f0b 100644 --- a/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp +++ b/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp @@ -27,12 +27,12 @@ #include "JSWeakObjectMapRefPrivate.h" #include "APICast.h" -#include "APIShims.h" #include "JSCJSValue.h" #include "JSCallbackObject.h" #include "JSWeakObjectMapRefInternal.h" -#include "Operations.h" +#include "JSCInlines.h" #include "Weak.h" +#include "WeakGCMapInlines.h" #include <wtf/HashMap.h> #include <wtf/text/StringHash.h> @@ -46,8 +46,8 @@ extern "C" { JSWeakObjectMapRef JSWeakObjectMapCreate(JSContextRef context, void* privateData, JSWeakMapDestroyedCallback callback) { ExecState* exec = toJS(context); - APIEntryShim entryShim(exec); - RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create(privateData, callback); + JSLockHolder locker(exec); + RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create(exec->vm(), privateData, callback); exec->lexicalGlobalObject()->registerWeakMap(map.get()); return map.get(); } @@ -59,11 +59,13 @@ void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSO return; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* obj = toJS(object); if (!obj) return; - ASSERT(obj->inherits(&JSCallbackObject<JSGlobalObject>::s_info) || obj->inherits(&JSCallbackObject<JSDestructibleObject>::s_info)); + ASSERT(obj->inherits(JSProxy::info()) + || obj->inherits(JSCallbackObject<JSGlobalObject>::info()) + || obj->inherits(JSCallbackObject<JSDestructibleObject>::info())); map->map().set(key, obj); } @@ -74,7 +76,7 @@ JSObjectRef JSWeakObjectMapGet(JSContextRef ctx, JSWeakObjectMapRef map, void* k return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(jsCast<JSObject*>(map->map().get(key))); } @@ -85,7 +87,7 @@ void JSWeakObjectMapRemove(JSContextRef ctx, JSWeakObjectMapRef map, void* key) return; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); map->map().remove(key); } diff --git a/Source/JavaScriptCore/API/JSWrapperMap.h b/Source/JavaScriptCore/API/JSWrapperMap.h index ce74a9c61..c6aa1af13 100644 --- a/Source/JavaScriptCore/API/JSWrapperMap.h +++ b/Source/JavaScriptCore/API/JSWrapperMap.h @@ -41,6 +41,7 @@ id tryUnwrapObjcObject(JSGlobalContextRef, JSValueRef); +bool supportsInitMethodConstructors(); Protocol *getJSExportProtocol(); Class getNSBlockClass(); diff --git a/Source/JavaScriptCore/API/JSWrapperMap.mm b/Source/JavaScriptCore/API/JSWrapperMap.mm deleted file mode 100644 index 4dde1a659..000000000 --- a/Source/JavaScriptCore/API/JSWrapperMap.mm +++ /dev/null @@ -1,521 +0,0 @@ -/* - * 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 <wtf/TCSpinLock.h> -#import <wtf/Vector.h> - -@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<char*>(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<JSC::JSAPIWrapperObject>* object = JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::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 - }]; -} - -// 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 (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<Property> 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<JSC::JSObject> m_prototype; - JSC::Weak<JSC::JSObject> 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]; -} - -- (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 = objectWithCustomBrand(m_context, [NSString stringWithFormat:@"%sConstructor", 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)) - return [JSValue valueWithJSValueRef:method inContext:m_context]; - } - - 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<id, JSC::JSObject> 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<JSValue *>(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<JSC::JSAPIWrapperObject>::s_info)) - return (id)JSC::jsCast<JSC::JSAPIWrapperObject*>(toJS(object))->wrappedObject(); - if (id target = tryUnwrapBlock(object)) - return target; - return nil; -} - -Protocol *getJSExportProtocol() -{ - static Protocol *protocol = objc_getProtocol("JSExport"); - return protocol; -} - -Class getNSBlockClass() -{ - static Class cls = objc_getClass("NSBlock"); - return cls; -} - -#endif diff --git a/Source/JavaScriptCore/API/JavaScript.h b/Source/JavaScriptCore/API/JavaScript.h index f8d92d8f9..ffe7b83fc 100644 --- a/Source/JavaScriptCore/API/JavaScript.h +++ b/Source/JavaScriptCore/API/JavaScript.h @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/JavaScriptCore.h b/Source/JavaScriptCore/API/JavaScriptCore.h index 40bea9c3d..b2fde1dbe 100644 --- a/Source/JavaScriptCore/API/JavaScriptCore.h +++ b/Source/JavaScriptCore/API/JavaScriptCore.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/ObjCCallbackFunction.h b/Source/JavaScriptCore/API/ObjCCallbackFunction.h index 0218cd8b4..adb167c76 100644 --- a/Source/JavaScriptCore/API/ObjCCallbackFunction.h +++ b/Source/JavaScriptCore/API/ObjCCallbackFunction.h @@ -34,36 +34,46 @@ #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 tryUnwrapBlock(JSObjectRef); +id tryUnwrapConstructor(JSObjectRef); #endif namespace JSC { class ObjCCallbackFunctionImpl; -class ObjCCallbackFunction : public JSCallbackFunction { +class ObjCCallbackFunction : public InternalFunction { + friend struct APICallbackFunction; public: - typedef JSCallbackFunction Base; + typedef InternalFunction Base; - static ObjCCallbackFunction* create(ExecState*, JSGlobalObject*, const String& name, PassOwnPtr<ObjCCallbackFunctionImpl>); + static ObjCCallbackFunction* create(VM&, JSGlobalObject*, const String& name, std::unique_ptr<ObjCCallbackFunctionImpl>); static void destroy(JSCell*); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { ASSERT(globalObject); - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } - static JS_EXPORTDATA const ClassInfo s_info; + DECLARE_EXPORT_INFO; - ObjCCallbackFunctionImpl* impl() { return m_impl.get(); } + ObjCCallbackFunctionImpl* impl() const { return m_impl.get(); } protected: - ObjCCallbackFunction(JSGlobalObject*, JSObjectCallAsFunctionCallback, PassOwnPtr<ObjCCallbackFunctionImpl>); + ObjCCallbackFunction(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, JSObjectCallAsConstructorCallback, std::unique_ptr<ObjCCallbackFunctionImpl>); private: - OwnPtr<ObjCCallbackFunctionImpl> m_impl; + 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; + std::unique_ptr<ObjCCallbackFunctionImpl> m_impl; }; } // namespace JSC diff --git a/Source/JavaScriptCore/API/ObjCCallbackFunction.mm b/Source/JavaScriptCore/API/ObjCCallbackFunction.mm deleted file mode 100644 index cc342f59e..000000000 --- a/Source/JavaScriptCore/API/ObjCCallbackFunction.mm +++ /dev/null @@ -1,615 +0,0 @@ -/* - * 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 "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 <objc/runtime.h> -#import <wtf/RetainPtr.h> - -class CallbackArgument { -public: - virtual ~CallbackArgument(); - virtual void set(NSInvocation *, NSInteger, JSContext *, JSValueRef, JSValueRef*) = 0; - - OwnPtr<CallbackArgument> 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<typename T> -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<typename T> -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<NSInvocation> m_conversionInvocation; - StructBuffer m_buffer; -}; - -class ArgumentTypeDelegate { -public: - typedef CallbackArgument* ResultType; - - template<typename T> - static ResultType typeInteger() - { - return new CallbackArgumentInteger<T>; - } - - template<typename T> - static ResultType typeDouble() - { - return new CallbackArgumentDouble<T>; - } - - 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<typename T> -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<NSInvocation> m_conversionInvocation; - StructBuffer m_buffer; -}; - -class ResultTypeDelegate { -public: - typedef CallbackResult* ResultType; - - template<typename T> - static ResultType typeInteger() - { - return new CallbackResultNumeric<T>; - } - - template<typename T> - static ResultType typeDouble() - { - return new CallbackResultNumeric<T>; - } - - 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 { - CallbackInstanceMethod, - CallbackClassMethod, - CallbackBlock -}; - -namespace JSC { - -class ObjCCallbackFunctionImpl { -public: - ObjCCallbackFunctionImpl(JSContext *context, NSInvocation *invocation, CallbackType type, Class instanceClass, PassOwnPtr<CallbackArgument> arguments, PassOwnPtr<CallbackResult> result) - : m_context(context) - , m_type(type) - , m_instanceClass([instanceClass retain]) - , m_invocation(invocation) - , m_arguments(arguments) - , m_result(result) - { - ASSERT(type != CallbackInstanceMethod || instanceClass); - } - - ~ObjCCallbackFunctionImpl() - { - if (m_type != CallbackInstanceMethod) - [[m_invocation.get() target] release]; - [m_instanceClass release]; - } - - JSValueRef call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); - - JSContext *context() - { - return m_context.get(); - } - - void setContext(JSContext *context) - { - ASSERT(!m_context.get()); - m_context.set(context); - } - - id wrappedBlock() - { - return m_type == CallbackBlock ? [m_invocation target] : nil; - } - -private: - WeakContextRef m_context; - CallbackType m_type; - Class m_instanceClass; - RetainPtr<NSInvocation> m_invocation; - OwnPtr<CallbackArgument> m_arguments; - OwnPtr<CallbackResult> 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<ObjCCallbackFunction*>(toJS(function)); - ObjCCallbackFunctionImpl* impl = callback->impl(); - JSContext *context = impl->context(); - if (!context) { - context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(toJS(callerContext)->lexicalGlobalObject()->globalExec())]; - impl->setContext(context); - } - - 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; -} - -const JSC::ClassInfo ObjCCallbackFunction::s_info = { "CallbackFunction", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ObjCCallbackFunction) }; - -ObjCCallbackFunction::ObjCCallbackFunction(JSC::JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback callback, PassOwnPtr<ObjCCallbackFunctionImpl> impl) - : Base(globalObject, globalObject->objcCallbackFunctionStructure(), callback) - , m_impl(impl) -{ -} - -ObjCCallbackFunction* ObjCCallbackFunction::create(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, const String& name, PassOwnPtr<ObjCCallbackFunctionImpl> impl) -{ - ObjCCallbackFunction* function = new (NotNull, allocateCell<ObjCCallbackFunction>(*exec->heap())) ObjCCallbackFunction(globalObject, objCCallbackFunctionCallAsFunction, impl); - function->finishCreation(exec->vm(), name); - return function; -} - -void ObjCCallbackFunction::destroy(JSCell* cell) -{ - static_cast<ObjCCallbackFunction*>(cell)->ObjCCallbackFunction::~ObjCCallbackFunction(); -} - -JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - JSGlobalContextRef contextRef = [context JSGlobalContextRef]; - - size_t firstArgument; - switch (m_type) { - case CallbackInstanceMethod: { - id 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]; - } - // fallthrough - firstArgument for CallbackInstanceMethod is also 2! - 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]; - - return m_result->get(m_invocation.get(), context, exception); -} - -} // 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<CallbackResult> result = adoptPtr(parseObjCType<ResultTypeDelegate>(position)); - if (!result || !skipNumber(position)) - return nil; - - switch (type) { - 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<CallbackArgument> arguments = 0; - OwnPtr<CallbackArgument>* nextArgument = &arguments; - unsigned argumentCount = 0; - while (*position) { - OwnPtr<CallbackArgument> argument = adoptPtr(parseObjCType<ArgumentTypeDelegate>(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<JSC::ObjCCallbackFunctionImpl> impl = adoptPtr(new JSC::ObjCCallbackFunctionImpl(context, invocation, type, instanceClass, arguments.release(), result.release())); - // FIXME: Maybe we could support having the selector as the name of the function to make it a bit more user-friendly from the JS side? - return toRef(JSC::ObjCCallbackFunction::create(exec, exec->lexicalGlobalObject(), "", impl.release())); -} - -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]; - if (!isInstanceMethod) - [invocation setTarget:cls]; - 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]]; - [invocation setTarget:[target copy]]; - return objCCallbackFunctionForInvocation(context, invocation, CallbackBlock, nil, signature); -} - -id tryUnwrapBlock(JSObjectRef object) -{ - if (!toJS(object)->inherits(&JSC::ObjCCallbackFunction::s_info)) - return nil; - return static_cast<JSC::ObjCCallbackFunction*>(toJS(object))->impl()->wrappedBlock(); -} - -#endif diff --git a/Source/JavaScriptCore/API/ObjcRuntimeExtras.h b/Source/JavaScriptCore/API/ObjcRuntimeExtras.h index 48c112093..128df5c90 100644 --- a/Source/JavaScriptCore/API/ObjcRuntimeExtras.h +++ b/Source/JavaScriptCore/API/ObjcRuntimeExtras.h @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#import <objc/Protocol.h> #import <objc/runtime.h> #import <wtf/HashSet.h> #import <wtf/Vector.h> @@ -163,7 +164,7 @@ typename DelegateType::ResultType parseObjCType(const char*& position) case 'l': return DelegateType::template typeInteger<long>(); case 'q': - return DelegateType::template typeDouble<unsigned long long>(); + return DelegateType::template typeDouble<long long>(); case 'C': return DelegateType::template typeInteger<unsigned char>(); case 'I': @@ -192,9 +193,19 @@ typename DelegateType::ResultType parseObjCType(const char*& position) } if (*position == '"') { - const char* begin = ++position; - position = index(position, '"'); - return DelegateType::typeOfClass(begin, position++); + const char* begin = position + 1; + const char* protocolPosition = strchr(begin, '<'); + const char* endOfType = strchr(begin, '"'); + position = endOfType + 1; + + // There's no protocol involved in this type, so just handle the class name. + if (!protocolPosition || protocolPosition > endOfType) + return DelegateType::typeOfClass(begin, endOfType); + // We skipped the class name and went straight to the protocol, so this is an id type. + if (begin == protocolPosition) + return DelegateType::typeId(); + // We have a class name with a protocol. For now, ignore the protocol. + return DelegateType::typeOfClass(begin, protocolPosition); } return DelegateType::typeId(); diff --git a/Source/JavaScriptCore/API/OpaqueJSString.cpp b/Source/JavaScriptCore/API/OpaqueJSString.cpp index a7cef8d9a..07a79ad99 100644 --- a/Source/JavaScriptCore/API/OpaqueJSString.cpp +++ b/Source/JavaScriptCore/API/OpaqueJSString.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -26,38 +26,84 @@ #include "config.h" #include "OpaqueJSString.h" -#include <interpreter/CallFrame.h> -#include <runtime/JSGlobalObject.h> -#include <runtime/Identifier.h> +#include "CallFrame.h" +#include "Identifier.h" +#include "IdentifierInlines.h" +#include "JSGlobalObject.h" +#include <wtf/text/StringView.h> using namespace JSC; -PassRefPtr<OpaqueJSString> OpaqueJSString::create(const String& string) +RefPtr<OpaqueJSString> OpaqueJSString::create(const String& string) { - if (!string.isNull()) - return adoptRef(new OpaqueJSString(string)); - return 0; + if (string.isNull()) + return nullptr; + + return adoptRef(new OpaqueJSString(string)); } -String OpaqueJSString::string() const +OpaqueJSString::~OpaqueJSString() { - if (!this) - return String(); + // m_characters is put in a local here to avoid an extra atomic load. + UChar* characters = m_characters; + if (!characters) + return; + + if (!m_string.is8Bit() && m_string.characters16() == characters) + return; + + fastFree(characters); +} +String OpaqueJSString::string() const +{ // Return a copy of the wrapped string, because the caller may make it an Identifier. return m_string.isolatedCopy(); } Identifier OpaqueJSString::identifier(VM* vm) const { - if (!this || m_string.isNull()) + if (m_string.isNull()) 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::fromString(vm, m_string.characters8(), m_string.length()); + + return Identifier::fromString(vm, m_string.characters16(), m_string.length()); +} + +const UChar* OpaqueJSString::characters() +{ + // m_characters is put in a local here to avoid an extra atomic load. + UChar* characters = m_characters; + if (characters) + return characters; + + if (m_string.isNull()) + return nullptr; + + unsigned length = m_string.length(); + UChar* newCharacters = static_cast<UChar*>(fastMalloc(length * sizeof(UChar))); + StringView(m_string).getCharactersWithUpconvert(newCharacters); + + if (!m_characters.compare_exchange_strong(characters, newCharacters)) { + fastFree(newCharacters); + return characters; + } + + return newCharacters; +} + +bool OpaqueJSString::equal(const OpaqueJSString* a, const OpaqueJSString* b) +{ + if (a == b) + return true; + + if (!a || !b) + return false; - return Identifier(vm, m_string.characters16(), m_string.length()); + return a->m_string == b->m_string; } diff --git a/Source/JavaScriptCore/API/OpaqueJSString.h b/Source/JavaScriptCore/API/OpaqueJSString.h index c374b567a..ec4fd7f6a 100644 --- a/Source/JavaScriptCore/API/OpaqueJSString.h +++ b/Source/JavaScriptCore/API/OpaqueJSString.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -26,6 +26,7 @@ #ifndef OpaqueJSString_h #define OpaqueJSString_h +#include <atomic> #include <wtf/ThreadSafeRefCounted.h> #include <wtf/text/WTFString.h> @@ -35,26 +36,31 @@ namespace JSC { } struct OpaqueJSString : public ThreadSafeRefCounted<OpaqueJSString> { - - static PassRefPtr<OpaqueJSString> create() // null + static Ref<OpaqueJSString> create() { - return adoptRef(new OpaqueJSString); + return adoptRef(*new OpaqueJSString); } - static PassRefPtr<OpaqueJSString> create(const LChar* characters, unsigned length) + static Ref<OpaqueJSString> create(const LChar* characters, unsigned length) { - return adoptRef(new OpaqueJSString(characters, length)); + return adoptRef(*new OpaqueJSString(characters, length)); } - static PassRefPtr<OpaqueJSString> create(const UChar* characters, unsigned length) + static Ref<OpaqueJSString> create(const UChar* characters, unsigned length) { - return adoptRef(new OpaqueJSString(characters, length)); + return adoptRef(*new OpaqueJSString(characters, length)); } - JS_EXPORT_PRIVATE static PassRefPtr<OpaqueJSString> create(const String&); + JS_EXPORT_PRIVATE static RefPtr<OpaqueJSString> create(const String&); + + JS_EXPORT_PRIVATE ~OpaqueJSString(); + + bool is8Bit() { return m_string.is8Bit(); } + const LChar* characters8() { return m_string.characters8(); } + const UChar* characters16() { return m_string.characters16(); } + unsigned length() { return m_string.length(); } - const UChar* characters() { return !!this ? m_string.characters() : 0; } - unsigned length() { return !!this ? m_string.length() : 0; } + const UChar* characters(); JS_EXPORT_PRIVATE String string() const; JSC::Identifier identifier(JSC::VM*) const; @@ -62,29 +68,38 @@ struct OpaqueJSString : public ThreadSafeRefCounted<OpaqueJSString> { QString qString() const { return m_string; } #endif + static bool equal(const OpaqueJSString*, const OpaqueJSString*); + private: friend class WTF::ThreadSafeRefCounted<OpaqueJSString>; OpaqueJSString() + : m_characters(nullptr) { } OpaqueJSString(const String& string) : m_string(string.isolatedCopy()) + , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast<UChar*>(m_string.characters16())) { } OpaqueJSString(const LChar* characters, unsigned length) + : m_string(characters, length) + , m_characters(nullptr) { - m_string = String(characters, length); } OpaqueJSString(const UChar* characters, unsigned length) + : m_string(characters, length) + , m_characters(m_string.impl() && m_string.is8Bit() ? nullptr : const_cast<UChar*>(m_string.characters16())) { - m_string = String(characters, length); } String m_string; + + // This will be initialized on demand when characters() is called if the string needs up-conversion. + std::atomic<UChar*> m_characters; }; #endif diff --git a/Source/JavaScriptCore/API/WebKitAvailability.h b/Source/JavaScriptCore/API/WebKitAvailability.h index 7846058fa..f878beae9 100644 --- a/Source/JavaScriptCore/API/WebKitAvailability.h +++ b/Source/JavaScriptCore/API/WebKitAvailability.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009, 2010, 2014 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,898 +26,51 @@ #ifndef __WebKitAvailability__ #define __WebKitAvailability__ -/* The structure of this header is based on AvailabilityMacros.h. The major difference is that the availability - macros are defined in terms of WebKit version numbers rather than Mac OS X system version numbers, as WebKit - releases span multiple versions of Mac OS X. -*/ - -#define WEBKIT_VERSION_1_0 0x0100 -#define WEBKIT_VERSION_1_1 0x0110 -#define WEBKIT_VERSION_1_2 0x0120 -#define WEBKIT_VERSION_1_3 0x0130 -#define WEBKIT_VERSION_2_0 0x0200 -#define WEBKIT_VERSION_3_0 0x0300 -#define WEBKIT_VERSION_3_1 0x0310 -#define WEBKIT_VERSION_4_0 0x0400 -#define WEBKIT_VERSION_LATEST 0x9999 +#if defined(__APPLE__) -#ifdef __APPLE__ #include <AvailabilityMacros.h> -#else -/* - * For non-Mac platforms, require the newest version. - */ -#define WEBKIT_VERSION_MIN_REQUIRED WEBKIT_VERSION_LATEST -/* - * only certain compilers support __attribute__((deprecated)) - */ -#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) - #define DEPRECATED_ATTRIBUTE __attribute__((deprecated)) -#else - #define DEPRECATED_ATTRIBUTE -#endif -#endif +#include <CoreFoundation/CoreFoundation.h> -/* The versions of GCC that shipped with Xcode prior to 3.0 (GCC build number < 5400) did not support attributes on methods. - If we are building with one of these versions, we need to omit the attribute. We achieve this by wrapping the annotation - in WEBKIT_OBJC_METHOD_ANNOTATION, which will remove the annotation when an old version of GCC is in use and will otherwise - expand to the annotation. The same is needed for protocol methods. +#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100 +/* To support availability macros that mention newer OS X versions when building on older OS X versions, + we provide our own definitions of the underlying macros that the availability macros expand to. We're + free to expand the macros as no-ops since frameworks built on older OS X versions only ship bundled with + an application rather than as part of the system. */ -#if defined(__APPLE_CC__) && __APPLE_CC__ < 5400 - #define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) -#else - #define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION -#endif - - -/* If minimum WebKit version is not specified, assume the version that shipped with the target Mac OS X version */ -#ifndef WEBKIT_VERSION_MIN_REQUIRED - #if !defined(MAC_OS_X_VERSION_10_2) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_2 - #error WebKit was not available prior to Mac OS X 10.2 - #elif !defined(MAC_OS_X_VERSION_10_3) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 - /* WebKit 1.0 is the only version available on Mac OS X 10.2. */ - #define WEBKIT_VERSION_MIN_REQUIRED WEBKIT_VERSION_1_0 - #elif !defined(MAC_OS_X_VERSION_10_4) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4 - /* WebKit 1.1 is the version that shipped on Mac OS X 10.3. */ - #define WEBKIT_VERSION_MIN_REQUIRED WEBKIT_VERSION_1_1 - #elif !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - /* WebKit 2.0 is the version that shipped on Mac OS X 10.4. */ - #define WEBKIT_VERSION_MIN_REQUIRED WEBKIT_VERSION_2_0 - #elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 - /* WebKit 3.0 is the version that shipped on Mac OS X 10.5. */ - #define WEBKIT_VERSION_MIN_REQUIRED WEBKIT_VERSION_3_0 - #elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 - /* WebKit 4.0 is the version that shipped on Mac OS X 10.6. */ - #define WEBKIT_VERSION_MIN_REQUIRED WEBKIT_VERSION_4_0 - #else - #define WEBKIT_VERSION_MIN_REQUIRED WEBKIT_VERSION_LATEST - #endif -#endif - - -/* If maximum WebKit version is not specified, assume largerof(latest, minimum) */ -#ifndef WEBKIT_VERSION_MAX_ALLOWED - #if WEBKIT_VERSION_MIN_REQUIRED > WEBKIT_VERSION_LATEST - #define WEBKIT_VERSION_MAX_ALLOWED WEBKIT_VERSION_MIN_REQUIRED - #else - #define WEBKIT_VERSION_MAX_ALLOWED WEBKIT_VERSION_LATEST - #endif -#endif - - -/* Sanity check the configured values */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_MIN_REQUIRED - #error WEBKIT_VERSION_MAX_ALLOWED must be >= WEBKIT_VERSION_MIN_REQUIRED -#endif -#if WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_1_0 - #error WEBKIT_VERSION_MIN_REQUIRED must be >= WEBKIT_VERSION_1_0 -#endif - - - - - - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER - * - * Used on functions introduced in WebKit 1.0 - */ -#define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED - * - * Used on functions introduced in WebKit 1.0, - * and deprecated in WebKit 1.0 - */ -#define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE - -/* - * DEPRECATED_IN_WEBKIT_VERSION_1_0_AND_LATER - * - * Used on types deprecated in WebKit 1.0 - */ -#define DEPRECATED_IN_WEBKIT_VERSION_1_0_AND_LATER DEPRECATED_ATTRIBUTE - - - - - - -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER - * - * Used on declarations introduced in WebKit 1.1 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_1_1 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_1_1 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED - * - * Used on declarations introduced in WebKit 1.1, - * and deprecated in WebKit 1.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_1 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_1 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated in WebKit 1.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_1 - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_1 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_1 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif - -/* - * DEPRECATED_IN_WEBKIT_VERSION_1_1_AND_LATER - * - * Used on types deprecated in WebKit 1.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_1 - #define DEPRECATED_IN_WEBKIT_VERSION_1_1_AND_LATER DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_IN_WEBKIT_VERSION_1_1_AND_LATER -#endif - - - - - - -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER - * - * Used on declarations introduced in WebKit 1.2 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_1_2 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_1_2 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED - * - * Used on declarations introduced in WebKit 1.2, - * and deprecated in WebKit 1.2 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_2 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_2 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated in WebKit 1.2 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_2 - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_2 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_2 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_2 - * - * Used on declarations introduced in WebKit 1.1, - * but later deprecated in WebKit 1.2 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_2 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_2 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_2 AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER -#endif - -/* - * DEPRECATED_IN_WEBKIT_VERSION_1_2_AND_LATER - * - * Used on types deprecated in WebKit 1.2 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_2 - #define DEPRECATED_IN_WEBKIT_VERSION_1_2_AND_LATER DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_IN_WEBKIT_VERSION_1_2_AND_LATER -#endif - - - - - - -/* - * AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER - * - * Used on declarations introduced in WebKit 1.3 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_1_3 - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_1_3 - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED - * - * Used on declarations introduced in WebKit 1.3, - * and deprecated in WebKit 1.3 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_3 - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated in WebKit 1.3 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_3 - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 - * - * Used on declarations introduced in WebKit 1.1, - * but later deprecated in WebKit 1.3 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_3 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 - * - * Used on declarations introduced in WebKit 1.2, - * but later deprecated in WebKit 1.3 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_3 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_1_3 AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER -#endif - -/* - * DEPRECATED_IN_WEBKIT_VERSION_1_3_AND_LATER - * - * Used on types deprecated in WebKit 1.3 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_1_3 - #define DEPRECATED_IN_WEBKIT_VERSION_1_3_AND_LATER DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_IN_WEBKIT_VERSION_1_3_AND_LATER -#endif - - - - - - -/* - * AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER - * - * Used on declarations introduced in WebKit 2.0 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_2_0 - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_2_0 - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED - * - * Used on declarations introduced in WebKit 2.0, - * and deprecated in WebKit 2.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_2_0 - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated in WebKit 2.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_2_0 - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 - * - * Used on declarations introduced in WebKit 1.1, - * but later deprecated in WebKit 2.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_2_0 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 - * - * Used on declarations introduced in WebKit 1.2, - * but later deprecated in WebKit 2.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_2_0 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 - * - * Used on declarations introduced in WebKit 1.3, - * but later deprecated in WebKit 2.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_2_0 - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_2_0 AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER -#endif - -/* - * DEPRECATED_IN_WEBKIT_VERSION_2_0_AND_LATER - * - * Used on types deprecated in WebKit 2.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_2_0 - #define DEPRECATED_IN_WEBKIT_VERSION_2_0_AND_LATER DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_IN_WEBKIT_VERSION_2_0_AND_LATER -#endif - - - - - - -/* - * AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER - * - * Used on declarations introduced in WebKit 3.0 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED - * - * Used on declarations introduced in WebKit 3.0, - * and deprecated in WebKit 3.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated in WebKit 3.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 - * - * Used on declarations introduced in WebKit 1.1, - * but later deprecated in WebKit 3.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER +#ifndef __NSi_10_10 // Building from trunk rather than SDK. +#define __NSi_10_10 introduced=10.0 // Use 10.0 to indicate that everything is available. #endif -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 - * - * Used on declarations introduced in WebKit 1.2, - * but later deprecated in WebKit 3.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER +#ifndef __NSi_10_11 // Building from trunk rather than SDK. +#define __NSi_10_11 introduced=10.0 // Use 10.0 to indicate that everything is available. #endif -/* - * AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 - * - * Used on declarations introduced in WebKit 1.3, - * but later deprecated in WebKit 3.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER +#ifndef __AVAILABILITY_INTERNAL__MAC_10_9 +#define __AVAILABILITY_INTERNAL__MAC_10_9 #endif -/* - * AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 - * - * Used on declarations introduced in WebKit 2.0, - * but later deprecated in WebKit 3.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_0 - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_0 AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER +#ifndef __AVAILABILITY_INTERNAL__MAC_10_10 +#define __AVAILABILITY_INTERNAL__MAC_10_10 #endif -/* - * DEPRECATED_IN_WEBKIT_VERSION_3_0_AND_LATER - * - * Used on types deprecated in WebKit 3.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_0 - #define DEPRECATED_IN_WEBKIT_VERSION_3_0_AND_LATER DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_IN_WEBKIT_VERSION_3_0_AND_LATER +#ifndef AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER +#define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER #endif - - - - - -/* - * AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER - * - * Used on declarations introduced in WebKit 3.1 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER +#ifndef AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER +#define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER #endif -/* - * AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED - * - * Used on declarations introduced in WebKit 3.1, - * and deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif +#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED <= 101100 */ -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 - * - * Used on declarations introduced in WebKit 1.1, - * but later deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER +#if defined(BUILDING_GTK__) +#undef CF_AVAILABLE +#define CF_AVAILABLE(_mac, _ios) #endif -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 - * - * Used on declarations introduced in WebKit 1.2, - * but later deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 - * - * Used on declarations introduced in WebKit 1.3, - * but later deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 - * - * Used on declarations introduced in WebKit 2.0, - * but later deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 - * - * Used on declarations introduced in WebKit 3.0, - * but later deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_3_1 AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER -#endif - -/* - * DEPRECATED_IN_WEBKIT_VERSION_3_1_AND_LATER - * - * Used on types deprecated in WebKit 3.1 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_3_1 - #define DEPRECATED_IN_WEBKIT_VERSION_3_1_AND_LATER DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_IN_WEBKIT_VERSION_3_1_AND_LATER -#endif - - - - - - -/* - * AVAILABLE_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 4.0 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_4_0 - #define AVAILABLE_IN_WEBKIT_VERSION_4_0 UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_4_0 - #define AVAILABLE_IN_WEBKIT_VERSION_4_0 WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_IN_WEBKIT_VERSION_4_0 -#endif - -/* - * AVAILABLE_IN_WEBKIT_VERSION_4_0_BUT_DEPRECATED - * - * Used on declarations introduced in WebKit 4.0, - * and deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_IN_WEBKIT_VERSION_4_0_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_IN_WEBKIT_VERSION_4_0_BUT_DEPRECATED AVAILABLE_IN_WEBKIT_VERSION_4_0 -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.1, - * but later deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.2, - * but later deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.3, - * but later deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE #else - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER +#define CF_AVAILABLE(_mac, _ios) #endif -/* - * AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 2.0, - * but later deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 3.0, - * but later deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 3.1, - * but later deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED_IN_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER -#endif - -/* - * DEPRECATED_IN_WEBKIT_VERSION_4_0 - * - * Used on types deprecated in WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_4_0 - #define DEPRECATED_IN_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_IN_WEBKIT_VERSION_4_0 -#endif - - - - - - -/* - * AVAILABLE_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced after WebKit 4.0 - */ -#if WEBKIT_VERSION_MAX_ALLOWED < WEBKIT_VERSION_LATEST - #define AVAILABLE_AFTER_WEBKIT_VERSION_4_0 UNAVAILABLE_ATTRIBUTE -#elif WEBKIT_VERSION_MIN_REQUIRED < WEBKIT_VERSION_LATEST - #define AVAILABLE_AFTER_WEBKIT_VERSION_4_0 WEAK_IMPORT_ATTRIBUTE -#else - #define AVAILABLE_AFTER_WEBKIT_VERSION_4_0 -#endif - -/* - * AVAILABLE_AFTER_WEBKIT_VERSION_4_0_BUT_DEPRECATED - * - * Used on declarations introduced after WebKit 4.0, - * and deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_AFTER_WEBKIT_VERSION_4_0_BUT_DEPRECATED DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_AFTER_WEBKIT_VERSION_4_0_BUT_DEPRECATED AVAILABLE_AFTER_WEBKIT_VERSION_4_0 -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.0, - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.1, - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.2, - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_2_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 1.3, - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 2.0, - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_2_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 3.0, - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 3.1, - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_3_1_AND_LATER -#endif - -/* - * AVAILABLE_WEBKIT_VERSION_4_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on declarations introduced in WebKit 4.0 - * but later deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define AVAILABLE_WEBKIT_VERSION_4_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define AVAILABLE_WEBKIT_VERSION_4_0_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_4_0 AVAILABLE_WEBKIT_VERSION_4_0_AND_LATER -#endif - -/* - * DEPRECATED_AFTER_WEBKIT_VERSION_4_0 - * - * Used on types deprecated after WebKit 4.0 - */ -#if WEBKIT_VERSION_MIN_REQUIRED >= WEBKIT_VERSION_LATEST - #define DEPRECATED_AFTER_WEBKIT_VERSION_4_0 DEPRECATED_ATTRIBUTE -#else - #define DEPRECATED_AFTER_WEBKIT_VERSION_4_0 -#endif - - - - - - -/* - * AVAILABLE_AFTER_WEBKIT_VERSION_5_1 - * - * Used on functions introduced after WebKit 5.1 - */ -#define AVAILABLE_AFTER_WEBKIT_VERSION_5_1 - -/* AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_5_1 - * - * Used on declarations introduced in WebKit 1.3, - * but later deprecated after WebKit 5.1 - */ -#define AVAILABLE_WEBKIT_VERSION_1_3_AND_LATER_BUT_DEPRECATED_AFTER_WEBKIT_VERSION_5_1 - - #endif /* __WebKitAvailability__ */ diff --git a/Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp new file mode 100644 index 000000000..525ebc9cc --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 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 "CompareAndSwapTest.h" + +#include <stdio.h> +#include <wtf/Atomics.h> +#include <wtf/Threading.h> + +class Bitmap { +public: + Bitmap() { clearAll(); } + + inline void clearAll(); + inline bool concurrentTestAndSet(size_t n); + inline size_t numBits() const { return words * wordSize; } + +private: + static const size_t Size = 4096*10; + + static const unsigned wordSize = sizeof(uint8_t) * 8; + static const unsigned words = (Size + wordSize - 1) / wordSize; + static const uint8_t one = 1; + + uint8_t bits[words]; +}; + +inline void Bitmap::clearAll() +{ + memset(&bits, 0, sizeof(bits)); +} + +inline bool Bitmap::concurrentTestAndSet(size_t n) +{ + uint8_t mask = one << (n % wordSize); + size_t index = n / wordSize; + uint8_t* wordPtr = &bits[index]; + uint8_t oldValue; + do { + oldValue = *wordPtr; + if (oldValue & mask) + return true; + } while (!WTF::weakCompareAndSwap(wordPtr, oldValue, static_cast<uint8_t>(oldValue | mask))); + return false; +} + +struct Data { + Bitmap* bitmap; + int id; + int numThreads; +}; + +static void setBitThreadFunc(void* p) +{ + Data* data = reinterpret_cast<Data*>(p); + Bitmap* bitmap = data->bitmap; + size_t numBits = bitmap->numBits(); + + // The computed start index here is heuristic that seems to maximize (anecdotally) + // the chance for the CAS issue to manifest. + size_t start = (numBits * (data->numThreads - data->id)) / data->numThreads; + + printf(" started Thread %d\n", data->id); + for (size_t i = start; i < numBits; i++) + while (!bitmap->concurrentTestAndSet(i)) { } + for (size_t i = 0; i < start; i++) + while (!bitmap->concurrentTestAndSet(i)) { } + + printf(" finished Thread %d\n", data->id); +} + +void testCompareAndSwap() +{ + Bitmap bitmap; + const int numThreads = 5; + ThreadIdentifier threadIDs[numThreads]; + Data data[numThreads]; + + WTF::initializeThreading(); + + printf("Starting %d threads for CompareAndSwap test. Test should complete without hanging.\n", numThreads); + for (int i = 0; i < numThreads; i++) { + data[i].bitmap = &bitmap; + data[i].id = i; + data[i].numThreads = numThreads; + std::function<void()> threadFunc = std::bind(setBitThreadFunc, &data[i]); + threadIDs[i] = createThread("setBitThreadFunc", threadFunc); + } + + printf("Waiting for %d threads to join\n", numThreads); + for (int i = 0; i < numThreads; i++) + waitForThreadCompletion(threadIDs[i]); + + printf("PASS: CompareAndSwap test completed without a hang\n"); +} diff --git a/Source/JavaScriptCore/API/tests/CompareAndSwapTest.h b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.h new file mode 100644 index 000000000..73fa0de13 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 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 CompareAndSwapTest_h +#define CompareAndSwapTest_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Regression test for webkit.org/b/142513 */ +void testCompareAndSwap(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* CompareAndSwapTest_h */ diff --git a/Source/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h b/Source/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h new file mode 100644 index 000000000..f228333c4 --- /dev/null +++ b/Source/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 <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void currentThisInsideBlockGetterTest(); + +#endif // JSC_OBJC_API_ENABLED + + +#endif // CurrentThisInsideBlockGetterTest_h diff --git a/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.c b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.c new file mode 100644 index 000000000..62e63978e --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2014 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 "CustomGlobalObjectClassTest.h" + +#include <JavaScriptCore/JSObjectRefPrivate.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <stdio.h> + +extern bool assertTrue(bool value, const char* message); + +static bool executedCallback = false; + +static JSValueRef jsDoSomething(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef args[], JSValueRef* exception) +{ + (void)function; + (void)thisObject; + (void)argc; + (void)args; + (void)exception; + executedCallback = true; + return JSValueMakeNull(ctx); +} + +static JSStaticFunction bridgedFunctions[] = { + {"doSomething", jsDoSomething, kJSPropertyAttributeDontDelete}, + {0, 0, 0}, +}; + +static JSClassRef bridgedObjectClass = NULL; +static JSClassDefinition bridgedClassDef; + +static JSClassRef jsClassRef() +{ + if (!bridgedObjectClass) { + bridgedClassDef = kJSClassDefinitionEmpty; + bridgedClassDef.className = "BridgedObject"; + bridgedClassDef.staticFunctions = bridgedFunctions; + bridgedObjectClass = JSClassCreate(&bridgedClassDef); + } + return bridgedObjectClass; +} + +void customGlobalObjectClassTest() +{ + JSClassRef bridgedObjectJsClassRef = jsClassRef(); + JSGlobalContextRef globalContext = JSGlobalContextCreate(bridgedObjectJsClassRef); + + JSObjectRef globalObj = JSContextGetGlobalObject(globalContext); + + JSPropertyNameArrayRef propertyNames = JSObjectCopyPropertyNames(globalContext, globalObj); + size_t propertyCount = JSPropertyNameArrayGetCount(propertyNames); + assertTrue(propertyCount == 1, "Property count == 1"); + + JSStringRef propertyNameRef = JSPropertyNameArrayGetNameAtIndex(propertyNames, 0); + size_t propertyNameLength = JSStringGetLength(propertyNameRef); + size_t bufferSize = sizeof(char) * (propertyNameLength + 1); + char* buffer = (char*)malloc(bufferSize); + JSStringGetUTF8CString(propertyNameRef, buffer, bufferSize); + buffer[propertyNameLength] = '\0'; + assertTrue(!strncmp(buffer, "doSomething", propertyNameLength), "First property name is doSomething"); + free(buffer); + + bool hasMethod = JSObjectHasProperty(globalContext, globalObj, propertyNameRef); + assertTrue(hasMethod, "Property found by name"); + + JSValueRef doSomethingProperty = + JSObjectGetProperty(globalContext, globalObj, propertyNameRef, NULL); + assertTrue(!JSValueIsUndefined(globalContext, doSomethingProperty), "Property is defined"); + + bool globalObjectClassMatchesClassRef = JSValueIsObjectOfClass(globalContext, globalObj, bridgedObjectJsClassRef); + assertTrue(globalObjectClassMatchesClassRef, "Global object is the right class"); + + JSStringRef script = JSStringCreateWithUTF8CString("doSomething();"); + JSEvaluateScript(globalContext, script, NULL, NULL, 1, NULL); + JSStringRelease(script); + + assertTrue(executedCallback, "Executed custom global object callback"); +} + +void globalObjectSetPrototypeTest() +{ + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.className = "Global"; + JSClassRef global = JSClassCreate(&definition); + JSGlobalContextRef context = JSGlobalContextCreate(global); + JSObjectRef object = JSContextGetGlobalObject(context); + + JSObjectRef above = JSObjectMake(context, 0, 0); + JSStringRef test = JSStringCreateWithUTF8CString("test"); + JSValueRef value = JSValueMakeString(context, test); + JSObjectSetProperty(context, above, test, value, kJSPropertyAttributeDontEnum, 0); + + JSObjectSetPrototype(context, object, above); + JSStringRef script = JSStringCreateWithUTF8CString("test === \"test\""); + JSValueRef result = JSEvaluateScript(context, script, 0, 0, 0, 0); + + assertTrue(JSValueToBoolean(context, result), "test === \"test\""); + + JSStringRelease(test); + JSStringRelease(script); +} + +void globalObjectPrivatePropertyTest() +{ + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.className = "Global"; + JSClassRef global = JSClassCreate(&definition); + JSGlobalContextRef context = JSGlobalContextCreate(global); + JSObjectRef globalObject = JSContextGetGlobalObject(context); + + JSStringRef privateName = JSStringCreateWithUTF8CString("private"); + JSValueRef privateValue = JSValueMakeString(context, privateName); + assertTrue(JSObjectSetPrivateProperty(context, globalObject, privateName, privateValue), "JSObjectSetPrivateProperty succeeded"); + JSValueRef result = JSObjectGetPrivateProperty(context, globalObject, privateName); + assertTrue(JSValueIsStrictEqual(context, privateValue, result), "privateValue === \"private\""); + + assertTrue(JSObjectDeletePrivateProperty(context, globalObject, privateName), "JSObjectDeletePrivateProperty succeeded"); + result = JSObjectGetPrivateProperty(context, globalObject, privateName); + assertTrue(JSValueIsNull(context, result), "Deleted private property is indeed no longer present"); + + JSStringRelease(privateName); +} diff --git a/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.h b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.h new file mode 100644 index 000000000..86914ca6f --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 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 CustomGlobalObjectClassTest_h +#define CustomGlobalObjectClassTest_h + +void customGlobalObjectClassTest(void); +void globalObjectSetPrototypeTest(void); +void globalObjectPrivatePropertyTest(void); + +#endif // CustomGlobalObjectClassTest_h diff --git a/Source/JavaScriptCore/API/tests/DateTests.h b/Source/JavaScriptCore/API/tests/DateTests.h new file mode 100644 index 000000000..eeb47a165 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/DateTests.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 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 <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runDateTests(); + +#endif // JSC_OBJC_API_ENABLED diff --git a/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp new file mode 100644 index 000000000..fc8cc10aa --- /dev/null +++ b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2015 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 "ExecutionTimeLimitTest.h" + +#include "InitializeThreading.h" +#include "JSContextRefPrivate.h" +#include "JavaScriptCore.h" +#include "Options.h" +#include <chrono> +#include <wtf/CurrentTime.h> +#include <wtf/text/StringBuilder.h> + +using namespace std::chrono; +using JSC::Options; + +static JSGlobalContextRef context = nullptr; + +static JSValueRef currentCPUTimeAsJSFunctionCallback(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().count() / 1000000.); +} + +bool shouldTerminateCallbackWasCalled = false; +static bool shouldTerminateCallback(JSContextRef, void*) +{ + shouldTerminateCallbackWasCalled = true; + return true; +} + +bool cancelTerminateCallbackWasCalled = false; +static bool cancelTerminateCallback(JSContextRef, void*) +{ + cancelTerminateCallbackWasCalled = true; + return false; +} + +int extendTerminateCallbackCalled = 0; +static bool extendTerminateCallback(JSContextRef ctx, void*) +{ + extendTerminateCallbackCalled++; + if (extendTerminateCallbackCalled == 1) { + JSContextGroupRef contextGroup = JSContextGetGroup(ctx); + JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); + return false; + } + return true; +} + +struct TierOptions { + const char* tier; + unsigned timeLimitAdjustmentMillis; + const char* optionsStr; +}; + +static void testResetAfterTimeout(bool& failed) +{ + JSValueRef v = nullptr; + JSValueRef exception = nullptr; + const char* reentryScript = "100"; + JSStringRef script = JSStringCreateWithUTF8CString(reentryScript); + v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + if (exception) { + printf("FAIL: Watchdog timeout was not reset.\n"); + failed = true; + } else if (!JSValueIsNumber(context, v) || JSValueToNumber(context, v, nullptr) != 100) { + printf("FAIL: Script result is not as expected.\n"); + failed = true; + } +} + +int testExecutionTimeLimit() +{ + static const TierOptions tierOptionsList[] = { + { "LLINT", 0, "--useConcurrentJIT=false --useLLInt=true --useJIT=false" }, + { "Baseline", 0, "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=false" }, + { "DFG", 0, "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=false" }, + { "FTL", 200, "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=true" }, + }; + + bool failed = false; + + JSC::initializeThreading(); + Options::initialize(); // Ensure options is initialized first. + + for (auto tierOptions : tierOptionsList) { + StringBuilder savedOptionsBuilder; + Options::dumpAllOptionsInALine(savedOptionsBuilder); + + Options::setOptions(tierOptions.optionsStr); + + unsigned tierAdjustmentMillis = tierOptions.timeLimitAdjustmentMillis; + double timeLimit; + + context = JSGlobalContextCreateInGroup(nullptr, nullptr); + + JSContextGroupRef contextGroup = JSContextGetGroup(context); + JSObjectRef globalObject = JSContextGetGlobalObject(context); + ASSERT(JSValueIsObject(context, globalObject)); + + JSValueRef exception = nullptr; + + JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime"); + JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTimeAsJSFunctionCallback); + JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, nullptr); + JSStringRelease(currentCPUTimeStr); + + /* Test script timeout: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && shouldTerminateCallbackWasCalled) + printf("PASS: %s script timed out as expected.\n", tierOptions.tier); + else { + if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) + printf("FAIL: %s script did not time out as expected.\n", tierOptions.tier); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (!exception) { + printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test script timeout with tail calls: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("var startTime = currentCPUTime();" + "function recurse(i) {" + "'use strict';" + "if (i % 1000 === 0) {" + "if (currentCPUTime() - startTime >"); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(" ) { return; }"); + scriptBuilder.append(" }"); + scriptBuilder.append(" return recurse(i + 1); }"); + scriptBuilder.append("recurse(0);"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && shouldTerminateCallbackWasCalled) + printf("PASS: %s script with infinite tail calls timed out as expected .\n", tierOptions.tier); + else { + if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) + printf("FAIL: %s script with infinite tail calls did not time out as expected.\n", tierOptions.tier); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: %s script with infinite tail calls' timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (!exception) { + printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); try { while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } catch(e) { } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) || !shouldTerminateCallbackWasCalled) { + if (!((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired))) + printf("FAIL: %s script did not time out as expected.\n", tierOptions.tier); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (exception) + printf("PASS: %s TerminatedExecutionException was not catchable as expected.\n", tierOptions.tier); + else { + printf("FAIL: %s TerminatedExecutionException was caught.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test script timeout with no callback: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, 0, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && !shouldTerminateCallbackWasCalled) + printf("PASS: %s script timed out as expected when no callback is specified.\n", tierOptions.tier); + else { + if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) + printf("FAIL: %s script did not time out as expected when no callback is specified.\n", tierOptions.tier); + else + printf("FAIL: %s script called stale callback function.\n", tierOptions.tier); + failed = true; + } + + if (!exception) { + printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test script timeout cancellation: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, cancelTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + cancelTerminateCallbackWasCalled = false; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) && cancelTerminateCallbackWasCalled && !exception) + printf("PASS: %s script timeout was cancelled as expected.\n", tierOptions.tier); + else { + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) || exception) + printf("FAIL: %s script timeout was not cancelled.\n", tierOptions.tier); + if (!cancelTerminateCallbackWasCalled) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (exception) { + printf("FAIL: %s Unexpected TerminatedExecutionException thrown.\n", tierOptions.tier); + failed = true; + } + } + + /* Test script timeout extension: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, extendTerminateCallback, 0); + { + unsigned timeBeforeExtendedDeadline = 250 + tierAdjustmentMillis; + unsigned timeAfterExtendedDeadline = 600 + tierAdjustmentMillis; + unsigned maxBusyLoopTime = 750 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(maxBusyLoopTime / 1000.0); // in seconds. + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + extendTerminateCallbackCalled = 0; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + auto deltaTime = endTime - startTime; + + if ((deltaTime >= milliseconds(timeBeforeExtendedDeadline)) && (deltaTime < milliseconds(timeAfterExtendedDeadline)) && (extendTerminateCallbackCalled == 2) && exception) + printf("PASS: %s script timeout was extended as expected.\n", tierOptions.tier); + else { + if (deltaTime < milliseconds(timeBeforeExtendedDeadline)) + printf("FAIL: %s script timeout was not extended as expected.\n", tierOptions.tier); + else if (deltaTime >= milliseconds(timeAfterExtendedDeadline)) + printf("FAIL: %s script did not timeout.\n", tierOptions.tier); + + if (extendTerminateCallbackCalled < 1) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + if (extendTerminateCallbackCalled < 2) + printf("FAIL: %s script timeout callback was not called after timeout extension.\n", tierOptions.tier); + + if (!exception) + printf("FAIL: %s TerminatedExecutionException was not thrown during timeout extension test.\n", tierOptions.tier); + + failed = true; + } + } + + JSGlobalContextRelease(context); + + Options::setOptions(savedOptionsBuilder.toString().ascii().data()); + } + + return failed; +} diff --git a/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.h b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.h new file mode 100644 index 000000000..8294a86a6 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 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 ExecutionTimeLimitTest_h +#define ExecutionTimeLimitTest_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns 1 if failures were encountered. Else, returns 0. */ +int testExecutionTimeLimit(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ExecutionTimeLimitTest_h */ diff --git a/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp new file mode 100644 index 000000000..7023bc365 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 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 "GlobalContextWithFinalizerTest.h" + +#include "JavaScriptCore.h" +#include <wtf/DataLog.h> + +static bool failed = true; + +static void finalize(JSObjectRef) +{ + failed = false; +} + +int testGlobalContextWithFinalizer() +{ + JSClassDefinition def = kJSClassDefinitionEmpty; + def.className = "testClass"; + def.finalize = finalize; + JSClassRef classRef = JSClassCreate(&def); + + JSGlobalContextRef ref = JSGlobalContextCreateInGroup(nullptr, classRef); + JSGlobalContextRelease(ref); + JSClassRelease(classRef); + + if (failed) + printf("FAIL: JSGlobalContextRef did not call its JSClassRef finalizer.\n"); + else + printf("PASS: JSGlobalContextRef called its JSClassRef finalizer as expected.\n"); + + return failed; +} diff --git a/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h new file mode 100644 index 000000000..55b439fff --- /dev/null +++ b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 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 GlobalContextWithFinalizerTest_h +#define GlobalContextWithFinalizerTest_h + +#include "JSContextRefPrivate.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns 1 if failures were encountered. Else, returns 0. */ +int testGlobalContextWithFinalizer(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GlobalContextWithFinalizerTest_h */ diff --git a/Source/JavaScriptCore/API/tests/JSExportTests.h b/Source/JavaScriptCore/API/tests/JSExportTests.h new file mode 100644 index 000000000..9d501ee7e --- /dev/null +++ b/Source/JavaScriptCore/API/tests/JSExportTests.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 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 <Foundation/Foundation.h> +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runJSExportTests(); + +#endif // JSC_OBJC_API_ENABLED + diff --git a/Source/JavaScriptCore/API/tests/JSNode.c b/Source/JavaScriptCore/API/tests/JSNode.c index d9a40bea6..d0a0dc3ec 100644 --- a/Source/JavaScriptCore/API/tests/JSNode.c +++ b/Source/JavaScriptCore/API/tests/JSNode.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -23,6 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JSNode.h" #include "JSNodeList.h" #include "JSObjectRef.h" diff --git a/Source/JavaScriptCore/API/tests/JSNode.h b/Source/JavaScriptCore/API/tests/JSNode.h index 7725733ca..a6aee2f7b 100644 --- a/Source/JavaScriptCore/API/tests/JSNode.h +++ b/Source/JavaScriptCore/API/tests/JSNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/tests/JSNodeList.c b/Source/JavaScriptCore/API/tests/JSNodeList.c index 61d7041a4..f037e094a 100644 --- a/Source/JavaScriptCore/API/tests/JSNodeList.c +++ b/Source/JavaScriptCore/API/tests/JSNodeList.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -23,6 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JSNode.h" #include "JSNodeList.h" #include "JSObjectRef.h" diff --git a/Source/JavaScriptCore/API/tests/JSNodeList.h b/Source/JavaScriptCore/API/tests/JSNodeList.h index f9309142e..d3eb52bb9 100644 --- a/Source/JavaScriptCore/API/tests/JSNodeList.h +++ b/Source/JavaScriptCore/API/tests/JSNodeList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/tests/Node.c b/Source/JavaScriptCore/API/tests/Node.c index 913da0a2a..db687e952 100644 --- a/Source/JavaScriptCore/API/tests/Node.c +++ b/Source/JavaScriptCore/API/tests/Node.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/tests/Node.h b/Source/JavaScriptCore/API/tests/Node.h index e9250b3ae..41b5d493a 100644 --- a/Source/JavaScriptCore/API/tests/Node.h +++ b/Source/JavaScriptCore/API/tests/Node.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/tests/NodeList.c b/Source/JavaScriptCore/API/tests/NodeList.c index ae4c17062..69f4cd5c4 100644 --- a/Source/JavaScriptCore/API/tests/NodeList.c +++ b/Source/JavaScriptCore/API/tests/NodeList.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/tests/NodeList.h b/Source/JavaScriptCore/API/tests/NodeList.h index 25b95bf4d..020b76f59 100644 --- a/Source/JavaScriptCore/API/tests/NodeList.h +++ b/Source/JavaScriptCore/API/tests/NodeList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp new file mode 100644 index 000000000..33f0772b3 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2015 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 "PingPongStackOverflowTest.h" + +#include "InitializeThreading.h" +#include "JSContextRefPrivate.h" +#include "JavaScriptCore.h" +#include "Options.h" +#include <wtf/text/StringBuilder.h> + +using JSC::Options; + +static JSGlobalContextRef context = nullptr; +static int nativeRecursionCount = 0; + +static bool PingPongStackOverflowObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(constructor); + + JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance"); + JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception); + JSStringRelease(hasInstanceName); + if (!hasInstance) + return false; + + int countAtEntry = nativeRecursionCount++; + + JSValueRef result = 0; + if (nativeRecursionCount < 100) { + JSObjectRef function = JSValueToObject(context, hasInstance, exception); + result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception); + } else { + StringBuilder builder; + builder.append("dummy.valueOf([0]"); + for (int i = 1; i < 35000; i++) { + builder.append(", ["); + builder.appendNumber(i); + builder.append("]"); + } + builder.append(");"); + + JSStringRef script = JSStringCreateWithUTF8CString(builder.toString().utf8().data()); + result = JSEvaluateScript(context, script, NULL, NULL, 1, exception); + JSStringRelease(script); + } + + --nativeRecursionCount; + if (nativeRecursionCount != countAtEntry) + printf(" ERROR: PingPongStackOverflow test saw a recursion count mismatch\n"); + + return result && JSValueToBoolean(context, result); +} + +JSClassDefinition PingPongStackOverflowObject_definition = { + 0, + kJSClassAttributeNone, + + "PingPongStackOverflowObject", + NULL, + + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + PingPongStackOverflowObject_hasInstance, + NULL, +}; + +static JSClassRef PingPongStackOverflowObject_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) + jsClass = JSClassCreate(&PingPongStackOverflowObject_definition); + + return jsClass; +} + +// This tests tests a stack overflow on VM reentry into a JS function from a native function +// after ping-pong'ing back and forth between JS and native functions multiple times. +// This test should not hang or crash. +int testPingPongStackOverflow() +{ + bool failed = false; + + JSC::initializeThreading(); + Options::initialize(); // Ensure options is initialized first. + + auto origReservedZoneSize = Options::reservedZoneSize(); + auto origErrorModeReservedZoneSize = Options::errorModeReservedZoneSize(); + auto origUseLLInt = Options::useLLInt(); + auto origMaxPerThreadStackUsage = Options::maxPerThreadStackUsage(); + + Options::reservedZoneSize() = 128 * KB; + Options::errorModeReservedZoneSize() = 64 * KB; +#if ENABLE(JIT) + // Normally, we want to disable the LLINT to force the use of JITted code which is necessary for + // reproducing the regression in https://bugs.webkit.org/show_bug.cgi?id=148749. However, we only + // want to do this if the LLINT isn't the only available execution engine. + Options::useLLInt() = false; +#endif + + const char* scriptString = + "var count = 0;" \ + "PingPongStackOverflowObject.hasInstance = function f() {" \ + " return (undefined instanceof PingPongStackOverflowObject);" \ + "};" \ + "PingPongStackOverflowObject.__proto__ = undefined;" \ + "undefined instanceof PingPongStackOverflowObject;"; + + JSValueRef scriptResult = nullptr; + JSValueRef exception = nullptr; + JSStringRef script = JSStringCreateWithUTF8CString(scriptString); + + nativeRecursionCount = 0; + context = JSGlobalContextCreateInGroup(nullptr, nullptr); + + JSObjectRef globalObject = JSContextGetGlobalObject(context); + ASSERT(JSValueIsObject(context, globalObject)); + + JSObjectRef PingPongStackOverflowObject = JSObjectMake(context, PingPongStackOverflowObject_class(context), NULL); + JSStringRef PingPongStackOverflowObjectString = JSStringCreateWithUTF8CString("PingPongStackOverflowObject"); + JSObjectSetProperty(context, globalObject, PingPongStackOverflowObjectString, PingPongStackOverflowObject, kJSPropertyAttributeNone, NULL); + JSStringRelease(PingPongStackOverflowObjectString); + + unsigned stackSize = 32 * KB; + Options::maxPerThreadStackUsage() = stackSize + Options::reservedZoneSize(); + + exception = nullptr; + scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + + if (!exception) { + printf("FAIL: PingPongStackOverflowError not thrown in PingPongStackOverflow test\n"); + failed = true; + } else if (nativeRecursionCount) { + printf("FAIL: Unbalanced native recursion count: %d in PingPongStackOverflow test\n", nativeRecursionCount); + failed = true; + } else { + printf("PASS: PingPongStackOverflow test.\n"); + } + + Options::reservedZoneSize() = origReservedZoneSize; + Options::errorModeReservedZoneSize() = origErrorModeReservedZoneSize; + Options::useLLInt() = origUseLLInt; + Options::maxPerThreadStackUsage() = origMaxPerThreadStackUsage; + + return failed; +} diff --git a/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h new file mode 100644 index 000000000..7f5911bcf --- /dev/null +++ b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 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 PingPongStackOverflowTest_h +#define PingPongStackOverflowTest_h + +#ifdef __cplusplus +extern "C" { +#endif + +int testPingPongStackOverflow(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* PingPongStackOverflowTest_h */ diff --git a/Source/JavaScriptCore/API/tests/Regress141275.h b/Source/JavaScriptCore/API/tests/Regress141275.h new file mode 100644 index 000000000..bf3492afa --- /dev/null +++ b/Source/JavaScriptCore/API/tests/Regress141275.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 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 <Foundation/Foundation.h> +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runRegress141275(); + +#endif // JSC_OBJC_API_ENABLED + diff --git a/Source/JavaScriptCore/API/tests/Regress141809.h b/Source/JavaScriptCore/API/tests/Regress141809.h new file mode 100644 index 000000000..43b099c94 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/Regress141809.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 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 <Foundation/Foundation.h> +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runRegress141809(); + +#endif // JSC_OBJC_API_ENABLED + diff --git a/Source/JavaScriptCore/API/tests/minidom.c b/Source/JavaScriptCore/API/tests/minidom.c index 8614e51e9..02b41a9c7 100644 --- a/Source/JavaScriptCore/API/tests/minidom.c +++ b/Source/JavaScriptCore/API/tests/minidom.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -24,6 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JSContextRef.h" #include "JSNode.h" #include "JSObjectRef.h" @@ -105,6 +107,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/Source/JavaScriptCore/API/tests/minidom.js b/Source/JavaScriptCore/API/tests/minidom.js index 480896052..85134d7cb 100644 --- a/Source/JavaScriptCore/API/tests/minidom.js +++ b/Source/JavaScriptCore/API/tests/minidom.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 diff --git a/Source/JavaScriptCore/API/tests/testapi.c b/Source/JavaScriptCore/API/tests/testapi.c index be18b2bf7..cbf9daf18 100644 --- a/Source/JavaScriptCore/API/tests/testapi.c +++ b/Source/JavaScriptCore/API/tests/testapi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,19 +10,21 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JavaScriptCore.h" #include "JSBasePrivate.h" #include "JSContextRefPrivate.h" @@ -33,34 +35,21 @@ #define ASSERT_DISABLED 0 #include <wtf/Assertions.h> -#if PLATFORM(MAC) || PLATFORM(IOS) -#include <mach/mach.h> -#include <mach/mach_time.h> -#include <sys/time.h> -#endif - #if OS(WINDOWS) #include <windows.h> #endif -#if COMPILER(MSVC) - -#include <wtf/MathExtras.h> - -static double nan(const char*) -{ - return std::numeric_limits<double>::quiet_NaN(); -} - -using std::isinf; -using std::isnan; - -#endif +#include "CompareAndSwapTest.h" +#include "CustomGlobalObjectClassTest.h" +#include "ExecutionTimeLimitTest.h" +#include "GlobalContextWithFinalizerTest.h" +#include "PingPongStackOverflowTest.h" #if JSC_OBJC_API_ENABLED void testObjectiveCAPI(void); #endif +bool assertTrue(bool value, const char* message); extern void JSSynchronousGarbageCollectForDebugging(JSContextRef); static JSGlobalContextRef context; @@ -93,11 +82,13 @@ static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString); char* jsBuffer = (char*)malloc(jsSize); JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize); - + unsigned i; for (i = 0; jsBuffer[i]; i++) { if (jsBuffer[i] != expectedValue[i]) { fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]); + fprintf(stderr, "value: %s\n", jsBuffer); + fprintf(stderr, "expectedValue: %s\n", expectedValue); failed = 1; } } @@ -132,7 +123,11 @@ static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedVa } if (jsLength != (size_t)cfLength) { - fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength); +#if OS(WINDOWS) + fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%Iu) != cfLength(%Iu)\n", jsLength, (size_t)cfLength); +#else + fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%zu) != cfLength(%zu)\n", jsLength, (size_t)cfLength); +#endif failed = 1; } @@ -582,7 +577,6 @@ static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObje break; default: return JSValueMakeNull(context); - break; } JSValueRef func = JSObjectGetProperty(context, object, funcName, exception); @@ -904,10 +898,8 @@ static void globalObject_initialize(JSContextRef context, JSObjectRef object) // Ensure that an execution context is passed in ASSERT(context); - // Ensure that the global object is set to the object that we were passed JSObjectRef globalObject = JSContextGetGlobalObject(context); ASSERT(globalObject); - ASSERT(object == globalObject); // Ensure that the standard global properties have been set on the global object JSStringRef array = JSStringCreateWithUTF8CString("Array"); @@ -966,6 +958,7 @@ static JSStaticValue globalObject_staticValues[] = { static JSStaticFunction globalObject_staticFunctions[] = { { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone }, + { "globalStaticFunction2", globalObject_call, kJSPropertyAttributeNone }, { "gc", functionGC, kJSPropertyAttributeNone }, { 0, 0, 0 } }; @@ -990,7 +983,7 @@ static void makeGlobalNumberValue(JSContextRef context) { v = NULL; } -static bool assertTrue(bool value, const char* message) +bool assertTrue(bool value, const char* message) { if (!value) { if (message) @@ -1043,85 +1036,104 @@ static bool checkForCycleInPrototypeChain() return result; } -static void checkConstnessInJSObjectNames() +static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { - JSStaticFunction fun; - fun.name = "something"; - JSStaticValue val; - val.name = "something"; + 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); } - -#if PLATFORM(MAC) || PLATFORM(IOS) -static double currentCPUTime() +static bool valueToObjectExceptionTest() { - mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; - thread_basic_info_data_t info; + 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); - /* 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); + 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); - double time = info.user_time.seconds + info.user_time.microseconds / 1000000.; - time += info.system_time.seconds + info.system_time.microseconds / 1000000.; + JSStringRelease(test); + JSClassRelease(globalObjectClass); + JSGlobalContextRelease(testContext); - return time; + return true; } -static JSValueRef currentCPUTime_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +static bool globalContextNameTest() { - UNUSED_PARAM(functionObject); - UNUSED_PARAM(thisObject); - UNUSED_PARAM(argumentCount); - UNUSED_PARAM(arguments); - UNUSED_PARAM(exception); + bool result = true; + JSGlobalContextRef context = JSGlobalContextCreate(0); - ASSERT(JSContextGetGlobalContext(ctx) == context); - return JSValueMakeNumber(ctx, currentCPUTime()); -} + JSStringRef str = JSGlobalContextCopyName(context); + result &= assertTrue(!str, "Default context name is NULL"); -bool shouldTerminateCallbackWasCalled = false; -static bool shouldTerminateCallback(JSContextRef ctx, void* context) -{ - UNUSED_PARAM(ctx); - UNUSED_PARAM(context); - shouldTerminateCallbackWasCalled = true; - return true; -} + JSStringRef name1 = JSStringCreateWithUTF8CString("name1"); + JSStringRef name2 = JSStringCreateWithUTF8CString("name2"); -bool cancelTerminateCallbackWasCalled = false; -static bool cancelTerminateCallback(JSContextRef ctx, void* context) -{ - UNUSED_PARAM(ctx); - UNUSED_PARAM(context); - cancelTerminateCallbackWasCalled = true; - return false; + JSGlobalContextSetName(context, name1); + JSStringRef fetchName1 = JSGlobalContextCopyName(context); + JSGlobalContextSetName(context, name2); + JSStringRef fetchName2 = JSGlobalContextCopyName(context); + JSGlobalContextSetName(context, NULL); + JSStringRef fetchName3 = 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"); + result &= assertTrue(!fetchName3, "Unexpected Context name"); + + JSStringRelease(name1); + JSStringRelease(name2); + JSStringRelease(fetchName1); + JSStringRelease(fetchName2); + + return result; } -int extendTerminateCallbackCalled = 0; -static bool extendTerminateCallback(JSContextRef ctx, void* context) +static void checkConstnessInJSObjectNames() { - UNUSED_PARAM(context); - extendTerminateCallbackCalled++; - if (extendTerminateCallbackCalled == 1) { - JSContextGroupRef contextGroup = JSContextGetGroup(ctx); - JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); - return false; - } - return true; + JSStaticFunction fun; + fun.name = "something"; + JSStaticValue val; + val.name = "something"; } -#endif /* PLATFORM(MAC) || PLATFORM(IOS) */ int main(int argc, char* argv[]) { #if OS(WINDOWS) +#if defined(_M_X64) || defined(__x86_64__) + // The VS2013 runtime has a bug where it mis-detects AVX-capable processors + // if the feature has been disabled in firmware. This causes us to crash + // in some of the math functions. For now, we disable those optimizations + // because Microsoft is not going to fix the problem in VS2013. + // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+. + _set_FMA3_enable(0); +#endif + // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. ::SetErrorMode(0); #endif + testCompareAndSwap(); + #if JSC_OBJC_API_ENABLED testObjectiveCAPI(); #endif @@ -1171,6 +1183,13 @@ int main(int argc, char* argv[]) JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL); JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context)); + JSObjectSetPrivate(globalObject, (void*)123); + if (JSObjectGetPrivate(globalObject) != (void*)123) { + printf("FAIL: Didn't return private data when set by JSObjectSetPrivate().\n"); + failed = 1; + } else + printf("PASS: returned private data when set by JSObjectSetPrivate().\n"); + // FIXME: test funny utf8 characters JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString(""); JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString); @@ -1228,6 +1247,8 @@ int main(int argc, char* argv[]) ASSERT(!JSValueIsBoolean(context, NULL)); ASSERT(!JSValueIsObject(context, NULL)); + ASSERT(!JSValueIsArray(context, NULL)); + ASSERT(!JSValueIsDate(context, NULL)); ASSERT(!JSValueIsString(context, NULL)); ASSERT(!JSValueIsNumber(context, NULL)); ASSERT(!JSValueIsUndefined(context, NULL)); @@ -1388,8 +1409,10 @@ int main(int argc, char* argv[]) } else printf("PASS: Correctly serialised with indent of 4.\n"); JSStringRelease(str); - JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); - JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL); + + str = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); + JSValueRef unstringifiableObj = JSEvaluateScript(context, str, NULL, NULL, 1, NULL); + JSStringRelease(str); str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0); if (str) { @@ -1572,7 +1595,27 @@ int main(int argc, char* argv[]) ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); ASSERT(JSValueIsObject(context, exception)); v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); - assertEqualsAsNumber(v, 1); + assertEqualsAsNumber(v, 2); + JSStringRelease(functionBody); + JSStringRelease(line); + + exception = NULL; + functionBody = JSStringCreateWithUTF8CString("rreturn Array;"); + line = JSStringCreateWithUTF8CString("line"); + ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, -42, &exception)); + ASSERT(JSValueIsObject(context, exception)); + v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); + assertEqualsAsNumber(v, 2); + JSStringRelease(functionBody); + JSStringRelease(line); + + exception = NULL; + functionBody = JSStringCreateWithUTF8CString("// Line one.\nrreturn Array;"); + line = JSStringCreateWithUTF8CString("line"); + ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); + ASSERT(JSValueIsObject(context, exception)); + v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); + assertEqualsAsNumber(v, 3); JSStringRelease(functionBody); JSStringRelease(line); @@ -1606,7 +1649,7 @@ int main(int argc, char* argv[]) JSStringRelease(functionBody); string = JSValueToStringCopy(context, function, NULL); - assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}"); + assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) {\nreturn foo;\n}"); JSStringRelease(string); JSStringRef print = JSStringCreateWithUTF8CString("print"); @@ -1737,6 +1780,28 @@ int main(int argc, char* argv[]) ASSERT(JSValueIsEqual(context, v, o, NULL)); JSStringRelease(script); + script = JSStringCreateWithUTF8CString("[ ]"); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsArray(context, v)); + JSStringRelease(script); + + script = JSStringCreateWithUTF8CString("new Date"); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsDate(context, v)); + JSStringRelease(script); + + exception = NULL; + script = JSStringCreateWithUTF8CString("rreturn Array;"); + JSStringRef sourceURL = JSStringCreateWithUTF8CString("file:///foo/bar.js"); + JSStringRef sourceURLKey = JSStringCreateWithUTF8CString("sourceURL"); + JSEvaluateScript(context, script, NULL, sourceURL, 1, &exception); + ASSERT(exception); + v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), sourceURLKey, NULL); + assertEqualsAsUTF8String(v, "file:///foo/bar.js"); + JSStringRelease(script); + JSStringRelease(sourceURL); + JSStringRelease(sourceURLKey); + // Verify that creating a constructor for a class with no static functions does not trigger // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785> nullDefinition = kJSClassDefinitionEmpty; @@ -1765,6 +1830,7 @@ int main(int argc, char* argv[]) } JSStringRelease(script); + exception = NULL; result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0; if (result && JSValueIsUndefined(context, result)) printf("PASS: Test script executed successfully.\n"); @@ -1781,158 +1847,53 @@ int main(int argc, char* argv[]) 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); + // Check Promise is not exposed. { - 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; + JSObjectRef globalObject = JSContextGetGlobalObject(context); + { + JSStringRef promiseProperty = JSStringCreateWithUTF8CString("Promise"); + ASSERT(JSObjectHasProperty(context, globalObject, promiseProperty)); + JSStringRelease(promiseProperty); } - - if (!exception) { - printf("FAIL: TerminatedExecutionException was not thrown.\n"); - failed = true; + { + JSStringRef script = JSStringCreateWithUTF8CString("typeof Promise"); + JSStringRef function = JSStringCreateWithUTF8CString("function"); + JSValueRef value = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsString(context, value)); + JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); + ASSERT(JSStringIsEqual(valueAsString, function)); + JSStringRelease(valueAsString); + JSStringRelease(function); + JSStringRelease(script); } + printf("PASS: Promise is exposed under JSContext API.\n"); } - /* Test script timeout cancellation: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0); + // Check microtasks. { - 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; + JSGlobalContextRef context = JSGlobalContextCreateInGroup(NULL, NULL); + { + JSObjectRef globalObject = JSContextGetGlobalObject(context); + JSValueRef exception; + JSStringRef code = JSStringCreateWithUTF8CString("result = 0; Promise.resolve(42).then(function (value) { result = value; });"); + JSStringRef file = JSStringCreateWithUTF8CString(""); + assertTrue(JSEvaluateScript(context, code, globalObject, file, 1, &exception), "An exception should not be thrown"); + JSStringRelease(code); + JSStringRelease(file); + + JSStringRef resultProperty = JSStringCreateWithUTF8CString("result"); + ASSERT(JSObjectHasProperty(context, globalObject, resultProperty)); + + JSValueRef resultValue = JSObjectGetProperty(context, globalObject, resultProperty, &exception); + assertEqualsAsNumber(resultValue, 42); + JSStringRelease(resultProperty); } + JSGlobalContextRelease(context); } - /* 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) */ + failed = testExecutionTimeLimit() || failed; + failed = testGlobalContextWithFinalizer() || failed; + failed = testPingPongStackOverflow() || failed; // Clear out local variables pointing at JSObjectRefs to allow their values to be collected function = NULL; @@ -1975,6 +1936,15 @@ 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"); + + customGlobalObjectClassTest(); + globalObjectSetPrototypeTest(); + globalObjectPrivatePropertyTest(); if (failed) { printf("FAIL: Some tests failed.\n"); @@ -1996,6 +1966,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; } @@ -2014,3 +1985,10 @@ static char* createStringWithContentsOfFile(const char* fileName) return buffer; } + +#if OS(WINDOWS) +extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]) +{ + return main(argc, const_cast<char**>(argv)); +} +#endif diff --git a/Source/JavaScriptCore/API/tests/testapi.js b/Source/JavaScriptCore/API/tests/testapi.js index 47c20a830..88d3701c2 100644 --- a/Source/JavaScriptCore/API/tests/testapi.js +++ b/Source/JavaScriptCore/API/tests/testapi.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,17 +10,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ function bludgeonArguments() { if (0) arguments; return function g() {} } @@ -74,6 +74,20 @@ function globalStaticFunction() shouldBe("globalStaticValue", 3); shouldBe("globalStaticFunction()", 4); +shouldBe("this.globalStaticFunction()", 4); + +function globalStaticFunction2() { + return 10; +} +shouldBe("globalStaticFunction2();", 10); +this.globalStaticFunction2 = function() { return 20; } +shouldBe("globalStaticFunction2();", 20); +shouldBe("this.globalStaticFunction2();", 20); + +function iAmNotAStaticFunction() { return 10; } +shouldBe("iAmNotAStaticFunction();", 10); +this.iAmNotAStaticFunction = function() { return 20; } +shouldBe("iAmNotAStaticFunction();", 20); shouldBe("typeof MyObject", "function"); // our object implements 'call' MyObject.cantFind = 1; @@ -253,6 +267,9 @@ shouldThrow("EvilExceptionObject*5"); EvilExceptionObject.toStringExplicit = function f() { return f(); } shouldThrow("String(EvilExceptionObject)"); +shouldBe("console", "[object Console]"); +shouldBe("typeof console.log", "function"); + shouldBe("EmptyObject", "[object CallbackObject]"); for (var i = 0; i < 6; ++i) diff --git a/Source/JavaScriptCore/API/tests/testapi.mm b/Source/JavaScriptCore/API/tests/testapi.mm deleted file mode 100644 index defb46e70..000000000 --- a/Source/JavaScriptCore/API/tests/testapi.mm +++ /dev/null @@ -1,841 +0,0 @@ -/* - * 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 <JavaScriptCore/JavaScriptCore.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 <JSExport> -@end - -@interface ParentObject : NSObject<ParentObject> -+ (NSString *)parentTest; -@end - -@implementation ParentObject -+ (NSString *)parentTest -{ - return [self description]; -} -@end - -@protocol TestObject <JSExport> -@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 <TestObject> -@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 <JSExport> -@property int x; -@property (readonly) int y; -@property (assign) JSValue *onclick; -@property (assign) JSValue *weakOnclick; -- (void)test:(NSString *)message; -@end - -@interface TextXYZ : NSObject <TextXYZ> -@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; -- (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]; -} -@end - -@class TinyDOMNode; - -@protocol TinyDOMNode <JSExport> -- (void)appendChild:(TinyDOMNode *)child; -- (NSUInteger)numberOfChildren; -- (TinyDOMNode *)childAtIndex:(NSUInteger)index; -- (void)removeChildAtIndex:(NSUInteger)index; -@end - -@interface TinyDOMNode : NSObject<TinyDOMNode> -+ (JSVirtualMachine *)sharedVirtualMachine; -+ (void)clearSharedVirtualMachine; -@end - -@implementation TinyDOMNode { - NSMutableArray *m_children; -} - -static JSVirtualMachine *sharedInstance = nil; - -+ (JSVirtualMachine *)sharedVirtualMachine -{ - if (!sharedInstance) - sharedInstance = [[JSVirtualMachine alloc] init]; - return sharedInstance; -} - -+ (void)clearSharedVirtualMachine -{ - sharedInstance = nil; -} - -- (id)init -{ - self = [super init]; - if (!self) - return nil; - - m_children = [[NSMutableArray alloc] initWithCapacity:0]; - - return self; -} - -- (void)dealloc -{ - NSEnumerator *enumerator = [m_children objectEnumerator]; - id nextChild; - while ((nextChild = [enumerator nextObject])) - [[TinyDOMNode sharedVirtualMachine] removeManagedReference:nextChild withOwner:self]; - -#if !__has_feature(objc_arc) - [super dealloc]; -#endif -} - -- (void)appendChild:(TinyDOMNode *)child -{ - [[TinyDOMNode 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; - [[TinyDOMNode sharedVirtualMachine] removeManagedReference:[m_children objectAtIndex:index] withOwner:self]; - [m_children removeObjectAtIndex:index]; -} - -@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 { - 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); - - checkResult(@"valueAtIndex:0 is undefined", [[array valueAtIndex:0] isUndefined]); - 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:@"[object TestObjectConstructor]"]); - } - - @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 { - JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine]; - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - TinyDOMNode *root = [[TinyDOMNode alloc] init]; - TinyDOMNode *lastNode = root; - for (NSUInteger i = 0; i < 3; i++) { - TinyDOMNode *newNode = [[TinyDOMNode alloc] init]; - [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); - - [TinyDOMNode clearSharedVirtualMachine]; - } - - @autoreleasepool { - JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine]; - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - TinyDOMNode *root = [[TinyDOMNode alloc] init]; - TinyDOMNode *lastNode = root; - for (NSUInteger i = 0; i < 3; i++) { - TinyDOMNode *newNode = [[TinyDOMNode alloc] init]; - [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); - - [TinyDOMNode clearSharedVirtualMachine]; - } - - @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]; - } - } -} - -#else - -void testObjectiveCAPI() -{ -} - -#endif |