diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
commit | a4e969f4965059196ca948db781e52f7cfebf19e (patch) | |
tree | 6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/JavaScriptCore/API | |
parent | 41386e9cb918eed93b3f13648cbef387e371e451 (diff) | |
download | WebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz |
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/JavaScriptCore/API')
88 files changed, 7081 insertions, 636 deletions
diff --git a/Source/JavaScriptCore/API/APICallbackFunction.h b/Source/JavaScriptCore/API/APICallbackFunction.h index 65c519b7a..94b10c420 100644 --- a/Source/JavaScriptCore/API/APICallbackFunction.h +++ b/Source/JavaScriptCore/API/APICallbackFunction.h @@ -27,9 +27,9 @@ #define APICallbackFunction_h #include "APICast.h" -#include "APIShims.h" #include "Error.h" #include "JSCallbackConstructor.h" +#include "JSLock.h" #include <wtf/Vector.h> namespace JSC { @@ -46,7 +46,7 @@ EncodedJSValue JSC_HOST_CALL APICallbackFunction::call(ExecState* exec) { JSContextRef execRef = toRef(exec); JSObjectRef functionRef = toRef(exec->callee()); - JSObjectRef thisObjRef = toRef(jsCast<JSObject*>(exec->hostThisValue().toThis(exec, NotStrictMode))); + JSObjectRef thisObjRef = toRef(jsCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode))); int argumentCount = static_cast<int>(exec->argumentCount()); Vector<JSValueRef, 16> arguments; @@ -57,7 +57,7 @@ EncodedJSValue JSC_HOST_CALL APICallbackFunction::call(ExecState* exec) JSValueRef exception = 0; JSValueRef result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); result = jsCast<T*>(toJS(functionRef))->functionCallback()(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception); } if (exception) @@ -88,7 +88,7 @@ EncodedJSValue JSC_HOST_CALL APICallbackFunction::construct(ExecState* exec) JSValueRef exception = 0; JSObjectRef result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); result = callback(ctx, constructorRef, argumentCount, arguments.data(), &exception); } if (exception) { diff --git a/Source/JavaScriptCore/API/APICast.h b/Source/JavaScriptCore/API/APICast.h index 6526d8907..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 @@ -124,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 a133b8ed4..000000000 --- a/Source/JavaScriptCore/API/APIShims.h +++ /dev/null @@ -1,125 +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->vm().exclusiveThread ? 0 : exec) - { - } - - // JSPropertyNameAccumulator only has a vm. - APIEntryShim(VM* vm, bool registerThread = true) - : APIEntryShimWithoutLock(vm, registerThread) - , m_lockHolder(vm->exclusiveThread ? 0 : 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(shouldDropAllLocks(exec->vm()) ? exec : nullptr) - , m_vm(&exec->vm()) - { - wtfThreadData().resetCurrentIdentifierTable(); - } - - APICallbackShim(VM& vm) - : m_dropAllLocks(shouldDropAllLocks(vm) ? &vm : nullptr) - , m_vm(&vm) - { - wtfThreadData().resetCurrentIdentifierTable(); - } - - ~APICallbackShim() - { - wtfThreadData().setCurrentIdentifierTable(m_vm->identifierTable); - } - -private: - static bool shouldDropAllLocks(VM& vm) - { - if (vm.exclusiveThread) - return false; - - // If the VM is in the middle of being destroyed then we don't want to resurrect it - // by allowing DropAllLocks to ref it. By this point the APILock has already been - // released anyways, so it doesn't matter that DropAllLocks is a no-op. - if (!vm.refCount()) - return false; - - return true; - } - - JSLock::DropAllLocks m_dropAllLocks; - 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/JSBase.cpp b/Source/JavaScriptCore/API/JSBase.cpp index 506561573..6b2a907f1 100644 --- a/Source/JavaScriptCore/API/JSBase.cpp +++ b/Source/JavaScriptCore/API/JSBase.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 @@ -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,7 +54,7 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSObject* jsThisObject = toJS(thisObject); @@ -57,14 +62,22 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th // evaluate sets "this" to the global object if it is NULL JSGlobalObject* globalObject = exec->vmEntryGlobalObject(); - SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + 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; } @@ -82,11 +95,11 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc return false; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); startingLineNumber = std::max(1, startingLineNumber); - SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + SourceCode source = makeSource(script->string(), sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); JSValue syntaxException; bool isValidSyntax = checkSyntax(exec->vmEntryGlobalObject()->globalExec(), source, &syntaxException); @@ -94,6 +107,10 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc 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; } @@ -111,7 +128,7 @@ void JSGarbageCollect(JSContextRef ctx) return; ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec, false); + JSLockHolder locker(exec); exec->vm().heap.reportAbandonedObjectGraph(); } @@ -123,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) { @@ -135,10 +154,20 @@ 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; diff --git a/Source/JavaScriptCore/API/JSBase.h b/Source/JavaScriptCore/API/JSBase.h index 153d359d4..b91743c57 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,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 @@ -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,7 +96,7 @@ 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 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. @@ -141,11 +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) -#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 -#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 && !defined(__i386__)) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE))) -#else -#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 && !defined(__i386__)) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE))) -#endif +#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && !defined(BUILDING_GTK__) && ((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 133176e1c..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 diff --git a/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp b/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp index 2e93ac114..d314c5d48 100644 --- a/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp +++ b/Source/JavaScriptCore/API/JSCTestRunnerUtils.cpp @@ -27,22 +27,39 @@ #include "JSCTestRunnerUtils.h" #include "APICast.h" -#include "Operations.h" +#include "JSCInlines.h" #include "TestRunnerUtils.h" namespace JSC { + +JSValueRef failNextNewCodeBlock(JSContextRef context) +{ + ExecState* exec= toJS(context); + JSLockHolder holder(exec); + return toRef(exec, failNextNewCodeBlock(exec)); +} + JSValueRef numberOfDFGCompiles(JSContextRef context, JSValueRef theFunctionValueRef) { ExecState* exec= toJS(context); + JSLockHolder holder(exec); return toRef(exec, numberOfDFGCompiles(toJS(exec, theFunctionValueRef))); } JSValueRef setNeverInline(JSContextRef context, JSValueRef theFunctionValueRef) { 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 8ea97a447..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 @@ -28,17 +28,16 @@ #include "APICallbackFunction.h" #include "APICast.h" -#include "APIShims.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) diff --git a/Source/JavaScriptCore/API/JSCallbackConstructor.h b/Source/JavaScriptCore/API/JSCallbackConstructor.h index 7eedb52e4..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) { @@ -56,7 +57,6 @@ public: protected: JSCallbackConstructor(JSGlobalObject*, Structure*, JSClassRef, JSObjectCallAsConstructorCallback); void finishCreation(JSGlobalObject*, JSClassRef); - static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; private: friend struct APICallbackFunction; diff --git a/Source/JavaScriptCore/API/JSCallbackFunction.cpp b/Source/JavaScriptCore/API/JSCallbackFunction.cpp index 1996991f7..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 @@ -28,7 +28,6 @@ #include "APICallbackFunction.h" #include "APICast.h" -#include "APIShims.h" #include "CodeBlock.h" #include "Error.h" #include "ExceptionHelpers.h" @@ -36,14 +35,14 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSLock.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/Vector.h> namespace JSC { 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(VM& vm, Structure* structure, JSObjectCallAsFunctionCallback callback) : InternalFunction(vm, structure) diff --git a/Source/JavaScriptCore/API/JSCallbackFunction.h b/Source/JavaScriptCore/API/JSCallbackFunction.h index dff18de56..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 diff --git a/Source/JavaScriptCore/API/JSCallbackObject.cpp b/Source/JavaScriptCore/API/JSCallbackObject.cpp index 94713da36..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; @@ -61,15 +61,4 @@ Structure* JSCallbackObject<JSGlobalObject>::createStructure(VM& vm, JSGlobalObj 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 3f58906d9..addd21986 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) @@ -42,7 +43,7 @@ struct JSCallbackObjectData : WeakHandleOwner { JSClassRetain(jsClass); } - virtual ~JSCallbackObjectData() + ~JSCallbackObjectData() { JSClassRelease(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*) override; + 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) { @@ -168,9 +173,6 @@ public: using Parent::methodTable; -protected: - static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Parent::StructureFlags; - private: static String className(const JSObject*); @@ -196,8 +198,6 @@ private: { JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); ASSERT_GC_OBJECT_INHERITS((static_cast<Parent*>(thisObject)), JSCallbackObject<Parent>::info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->Parent::structure()->typeInfo().overridesVisitChildren()); Parent::visitChildren(thisObject, visitor); thisObject->m_callbackObjectData->visitChildren(visitor); } @@ -211,10 +211,10 @@ private: static EncodedJSValue JSC_HOST_CALL construct(ExecState*); JSValue getStaticValue(ExecState*, PropertyName); - static EncodedJSValue staticFunctionGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName); - static EncodedJSValue callbackGetter(ExecState*, EncodedJSValue, EncodedJSValue, 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 5be053f1e..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" @@ -59,7 +58,7 @@ inline JSCallbackObject<Parent>* JSCallbackObject<Parent>::asCallbackObject(Enco 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)) { } @@ -68,11 +67,21 @@ 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()); @@ -104,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> @@ -136,13 +138,13 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* e 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, ReadOnly | DontEnum, callbackGetter); return true; @@ -153,7 +155,7 @@ bool JSCallbackObject<Parent>::getOwnPropertySlot(JSObject* object, ExecState* e JSValueRef exception = 0; JSValueRef value; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); } if (exception) { @@ -228,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) @@ -236,7 +238,7 @@ 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) @@ -253,7 +255,7 @@ 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, entry->propertyNameRef.get(), valueRef, &exception); } if (exception) @@ -266,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 @@ -295,7 +300,7 @@ 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) @@ -312,7 +317,7 @@ 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, entry->propertyNameRef.get(), valueRef, &exception); } if (exception) @@ -343,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) @@ -351,7 +356,7 @@ 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) @@ -418,7 +423,7 @@ EncodedJSValue JSCallbackObject<Parent>::construct(ExecState* exec) JSValueRef exception = 0; JSObject* result; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); } if (exception) @@ -444,7 +449,7 @@ 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) @@ -473,7 +478,7 @@ EncodedJSValue JSCallbackObject<Parent>::call(ExecState* exec) { JSContextRef execRef = toRef(exec); JSObjectRef functionRef = toRef(exec->callee()); - JSObjectRef thisObjRef = toRef(jsCast<JSObject*>(exec->hostThisValue().toThis(exec, NotStrictMode))); + 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) { @@ -485,7 +490,7 @@ EncodedJSValue JSCallbackObject<Parent>::call(ExecState* exec) 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) @@ -507,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)); } @@ -517,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))); + } } } @@ -528,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))); + } } } } @@ -564,7 +573,7 @@ JSValue JSCallbackObject<Parent>::getStaticValue(ExecState* exec, PropertyName p { JSObjectRef thisRef = toRef(this); - 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)) { @@ -572,7 +581,7 @@ JSValue JSCallbackObject<Parent>::getStaticValue(ExecState* exec, PropertyName p JSValueRef exception = 0; JSValueRef value; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(toRef(exec), thisRef, entry->propertyNameRef.get(), &exception); } if (exception) { @@ -591,16 +600,16 @@ JSValue JSCallbackObject<Parent>::getStaticValue(ExecState* exec, PropertyName p } template <class Parent> -EncodedJSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, EncodedJSValue slotParent, EncodedJSValue, 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 JSValue::encode(slot2.getValue(exec, propertyName)); - if (StringImpl* name = propertyName.publicName()) { + 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)) { @@ -619,14 +628,14 @@ EncodedJSValue JSCallbackObject<Parent>::staticFunctionGetter(ExecState* exec, E } template <class Parent> -EncodedJSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, EncodedJSValue slotParent, EncodedJSValue, 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) @@ -634,7 +643,7 @@ EncodedJSValue JSCallbackObject<Parent>::callbackGetter(ExecState* exec, Encoded JSValueRef exception = 0; JSValueRef value; { - APICallbackShim callbackShim(exec); + JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); } if (exception) { diff --git a/Source/JavaScriptCore/API/JSClassRef.cpp b/Source/JavaScriptCore/API/JSClassRef.cpp index 544c359b1..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,7 +62,7 @@ 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()) @@ -72,7 +72,7 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* } 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()) @@ -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,7 +124,7 @@ 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) @@ -134,7 +134,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsCl 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()); + 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)); } @@ -144,7 +144,7 @@ OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsCl 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()); + ASSERT(!it->key->isAtomic()); staticFunctions->add(it->key->isolatedCopy(), std::make_unique<StaticFunctionEntry>(it->value->callAsFunction, it->value->attributes)); } } @@ -160,7 +160,7 @@ OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec) 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(); } diff --git a/Source/JavaScriptCore/API/JSClassRef.h b/Source/JavaScriptCore/API/JSClassRef.h index f979f3b2c..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 @@ -85,8 +85,8 @@ public: }; 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(); @@ -118,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 new file mode 100644 index 000000000..ddb51adfe --- /dev/null +++ b/Source/JavaScriptCore/API/JSContext.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSContext_h +#define JSContext_h + +#include <JavaScriptCore/JavaScript.h> +#include <JavaScriptCore/WebKitAvailability.h> + +#if JSC_OBJC_API_ENABLED + +@class JSVirtualMachine, JSValue; + +/*! +@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 + +/*! +@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; + +/*! +@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; + +/*! +@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; + +/*! +@method +@abstract Get the arguments to the current callback. +@discussion This method may be called from within an Objective-C block or method invoked + as a callback from JavaScript to retrieve the callback's arguments, objects + in the returned array are instances of JSValue. Outside of a callback from + JavaScript this method will return nil. +@result An NSArray of the arguments nil if there is no current callback. +*/ ++ (NSArray *)currentArguments; + +/*! +@methodgroup Global Properties +*/ +/*! +@property +@abstract Get the global object of the context. +@discussion This method retrieves the global object of the JavaScript execution context. + Instances of JSContext originating from WebKit will return a reference to the + WindowProxy object. +@result The global object. +*/ +@property (readonly, strong) JSValue *globalObject; + +/*! +@property +@discussion The <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 + +/*! +@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 + +/*! +@category +@discussion These functions are for bridging between the C API and the Objective-C API. +*/ +@interface JSContext (JSContextRefSupport) + +/*! +@method +@abstract Create a JSContext, wrapping its C API counterpart. +@param jsGlobalContextRef +@result The JSContext equivalent of the provided JSGlobalContextRef. +*/ ++ (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)jsGlobalContextRef; + +/*! +@property +@abstract Get the C API counterpart wrapped by a JSContext. +@result The C API equivalent of this JSContext. +*/ +@property (readonly) JSGlobalContextRef JSGlobalContextRef; +@end + +#endif + +#endif // JSContext_h diff --git a/Source/JavaScriptCore/API/JSContextInternal.h b/Source/JavaScriptCore/API/JSContextInternal.h new file mode 100644 index 000000000..5308fbb92 --- /dev/null +++ b/Source/JavaScriptCore/API/JSContextInternal.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSContextInternal_h +#define JSContextInternal_h + +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +#import <JavaScriptCore/JSContext.h> + +struct CallbackData { + CallbackData *next; + JSContext *context; + JSValue *preservedException; + JSValueRef calleeValue; + JSValueRef thisValue; + size_t argumentCount; + const JSValueRef *arguments; + NSArray *currentArguments; +}; + +class WeakContextRef { +public: + WeakContextRef(JSContext * = nil); + ~WeakContextRef(); + + JSContext * get(); + void set(JSContext *); + +private: + JSContext *m_weakContext; +}; + +@class JSWrapperMap; + +@interface JSContext(Internal) + +- (id)initWithGlobalContextRef:(JSGlobalContextRef)context; + +- (void)notifyException:(JSValueRef)exception; +- (JSValue *)valueFromNotifyException:(JSValueRef)exception; +- (BOOL)boolFromNotifyException:(JSValueRef)exception; + +- (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments; +- (void)endCallbackWithData:(CallbackData *)callbackData; + +- (JSValue *)wrapperForObjCObject:(id)object; +- (JSValue *)wrapperForJSObject:(JSValueRef)value; + +@property (readonly, retain) JSWrapperMap *wrapperMap; + +@end + +#endif + +#endif // JSContextInternal_h diff --git a/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 81b61cf47..98cd8b030 100644 --- a/Source/JavaScriptCore/API/JSContextRef.cpp +++ b/Source/JavaScriptCore/API/JSContextRef.cpp @@ -10,37 +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 "CallFrameInlines.h" #include "InitializeThreading.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> @@ -57,7 +67,7 @@ using namespace JSC; JSContextGroupRef JSContextGroupCreate() { initializeThreading(); - return toRef(VM::createContextGroup().leakRef()); + return toRef(&VM::createContextGroup().leakRef()); } JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) @@ -68,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) @@ -91,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. @@ -131,12 +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())); - globalObject->setGlobalThis(*vm, JSProxy::create(*vm, JSProxy::createStructure(*vm, globalObject, globalObject->prototype()), globalObject)); +#if ENABLE(REMOTE_INSPECTOR) + if (JSRemoteInspectorGetInspectionEnabledByDefault()) + globalObject->setRemoteDebuggingEnabled(true); +#endif return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec())); } @@ -146,13 +152,17 @@ 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->vmEntryGlobalObject()); @@ -162,21 +172,14 @@ JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx) void JSGlobalContextRelease(JSGlobalContextRef ctx) { - IdentifierTable* savedIdentifierTable; ExecState* exec = toJS(ctx); - { - JSLockHolder lock(exec); - - VM& vm = exec->vm(); - savedIdentifierTable = wtfThreadData().setCurrentIdentifierTable(vm.identifierTable); + JSLockHolder locker(exec); - bool protectCountIsZero = Heap::heap(exec->vmEntryGlobalObject())->unprotect(exec->vmEntryGlobalObject()); - if (protectCountIsZero) - vm.heap.reportAbandonedObjectGraph(); - vm.deref(); - } - - 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) @@ -186,7 +189,7 @@ JSObjectRef JSContextGetGlobalObject(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(jsCast<JSObject*>(exec->lexicalGlobalObject()->methodTable()->toThis(exec->lexicalGlobalObject(), exec, NotStrictMode))); } @@ -208,7 +211,7 @@ JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toGlobalRef(exec->lexicalGlobalObject()->globalExec()); } @@ -221,7 +224,7 @@ JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); String name = exec->vmEntryGlobalObject()->name(); if (name.isNull()) @@ -238,7 +241,7 @@ void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); exec->vmEntryGlobalObject()->setName(name ? name->string() : String()); } @@ -310,4 +313,119 @@ JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) 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 c8db1e56d..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,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 @@ -48,7 +48,7 @@ extern "C" { synchronization is required. @result The created JSContextGroup. */ -JS_EXPORT JSContextGroupRef JSContextGroupCreate() CF_AVAILABLE(10_6, 7_0); +JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) CF_AVAILABLE(10_6, 7_0); /*! @function @@ -141,7 +141,7 @@ JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) CF_AVAI @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); +JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0); /*! @function @@ -149,7 +149,7 @@ JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx); @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); +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 780a60306..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 @@ -94,6 +94,40 @@ JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef, double lim */ 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 } #endif diff --git a/Source/JavaScriptCore/API/JSExport.h b/Source/JavaScriptCore/API/JSExport.h new file mode 100644 index 000000000..b8a484909 --- /dev/null +++ b/Source/JavaScriptCore/API/JSExport.h @@ -0,0 +1,146 @@ +/* + * 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> + +#if JSC_OBJC_API_ENABLED + +/*! +@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 + +/*! +@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 + +#endif diff --git a/Source/JavaScriptCore/API/JSManagedValue.h b/Source/JavaScriptCore/API/JSManagedValue.h new file mode 100644 index 000000000..d13733d08 --- /dev/null +++ b/Source/JavaScriptCore/API/JSManagedValue.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSManagedValue_h +#define JSManagedValue_h + +#import <JavaScriptCore/JSBase.h> +#import <JavaScriptCore/WebKitAvailability.h> + +#if JSC_OBJC_API_ENABLED + +@class JSValue; +@class JSContext; + +/*! +@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 + +/*! +@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); + +/*! +@method +@abstract Create a JSManagedValue. +@param value +@result The new JSManagedValue. +*/ +- (instancetype)initWithValue:(JSValue *)value; + +/*! +@property +@abstract Get the JSValue from the JSManagedValue. +@result The corresponding JSValue for this JSManagedValue or + nil if the JSValue has been collected. +*/ +@property (readonly, strong) JSValue *value; + +@end + +#endif // JSC_OBJC_API_ENABLED + +#endif // JSManagedValue_h diff --git a/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 56fe90b47..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,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 @@ -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,7 +129,7 @@ JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(JSCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), callAsFunction, name ? name->string() : ASCIILiteral("anonymous"))); } @@ -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,23 +158,19 @@ JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned pa return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); startingLineNumber = std::max(1, startingLineNumber); - Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier(exec, "anonymous"); + 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); } @@ -160,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) { @@ -172,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); } @@ -189,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); } @@ -213,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); } @@ -236,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); } @@ -260,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()); @@ -273,11 +278,19 @@ 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); + 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()); } @@ -288,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); @@ -302,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); } @@ -322,7 +331,7 @@ 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())); @@ -336,11 +345,7 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope 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) @@ -350,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); } @@ -371,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) @@ -391,23 +388,23 @@ 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); - + + // 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>::info())) @@ -423,7 +420,11 @@ void* JSObjectGetPrivate(JSObjectRef object) bool JSObjectSetPrivate(JSObjectRef object, void* data) { JSObject* jsObject = uncheckedToJS(object); - + + // 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; @@ -445,10 +446,15 @@ 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())); + + // 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>::info())) @@ -463,10 +469,15 @@ 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())); + + // 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; @@ -487,9 +498,14 @@ 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())); + + // 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; @@ -507,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; @@ -519,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; @@ -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; } @@ -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 5e7fd69a9..754dff363 100644 --- a/Source/JavaScriptCore/API/JSObjectRef.h +++ b/Source/JavaScriptCore/API/JSObjectRef.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/JSProfilerPrivate.cpp b/Source/JavaScriptCore/API/JSProfilerPrivate.cpp new file mode 100644 index 000000000..ac112ae6e --- /dev/null +++ b/Source/JavaScriptCore/API/JSProfilerPrivate.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSProfilerPrivate.h" + +#include "APICast.h" +#include "LegacyProfiler.h" +#include "OpaqueJSString.h" + +using namespace JSC; + +void JSStartProfiling(JSContextRef ctx, JSStringRef title) +{ + // 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) +{ + ExecState* exec = toJS(ctx); + LegacyProfiler* profiler = LegacyProfiler::profiler(); + profiler->stopProfiling(exec, title->string()); +} + diff --git a/Source/JavaScriptCore/API/JSProfilerPrivate.h b/Source/JavaScriptCore/API/JSProfilerPrivate.h new file mode 100644 index 000000000..34f26a202 --- /dev/null +++ b/Source/JavaScriptCore/API/JSProfilerPrivate.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSProfiler_h +#define JSProfiler_h + +#include <JavaScriptCore/JSBase.h> + +#ifndef __cplusplus +#include <stdbool.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +@function JSStartProfiling +@abstract Enables the profler. +@param ctx The execution context to use. +@param title The title of the profile. +@result The profiler is turned on. +*/ +JS_EXPORT void JSStartProfiling(JSContextRef ctx, JSStringRef title); + +/*! +@function JSEndProfiling +@abstract Disables the profler. +@param ctx The execution context to use. +@param title The title of the profile. +@result The profiler is turned off. If there is no name, the most recently started + profile is stopped. If the name does not match any profile then no profile + is stopped. +*/ +JS_EXPORT void JSEndProfiling(JSContextRef ctx, JSStringRef title); + +#ifdef __cplusplus +} +#endif + +#endif /* JSProfiler_h */ 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 9277001d2..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)); } - virtual 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()) { } 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,7 +85,7 @@ 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; @@ -85,15 +93,15 @@ JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupRef context startingLineNumber = std::max(1, startingLineNumber); - RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url->string(), startingLineNumber, String(StringImpl::createFromLiteral(source, length))); + 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(); @@ -102,19 +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(); @@ -122,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/JSStringRef.cpp b/Source/JavaScriptCore/API/JSStringRef.cpp index 25b84c7d2..c9b380ce6 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(chars, numChars).leakRef(); } JSStringRef JSStringCreateWithUTF8CString(const char* string) @@ -51,12 +51,12 @@ 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) @@ -78,11 +78,15 @@ void JSStringRelease(JSStringRef string) size_t JSStringGetLength(JSStringRef string) { + if (!string) + return 0; return string->length(); } const JSChar* JSStringGetCharactersPtr(JSStringRef string) { + if (!string) + return nullptr; return string->characters(); } @@ -94,7 +98,7 @@ size_t JSStringGetMaximumUTF8CStringSize(JSStringRef string) size_t JSStringGetUTF8CString(JSStringRef string, char* buffer, size_t bufferSize) { - if (!bufferSize) + if (!string || !buffer || !bufferSize) return 0; char* destination = buffer; diff --git a/Source/JavaScriptCore/API/JSStringRef.h b/Source/JavaScriptCore/API/JSStringRef.h index aded73626..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,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/JSStringRefBSTR.cpp b/Source/JavaScriptCore/API/JSStringRefBSTR.cpp new file mode 100644 index 000000000..e900d24d8 --- /dev/null +++ b/Source/JavaScriptCore/API/JSStringRefBSTR.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSStringRefBSTR.h" + +#include "JSStringRef.h" + +JSStringRef JSStringCreateWithBSTR(BSTR string) +{ + return JSStringCreateWithCharacters(string ? string : L"", string ? SysStringLen(string) : 0); +} + +BSTR JSStringCopyBSTR(const JSStringRef string) +{ + return SysAllocStringLen(JSStringGetCharactersPtr(string), JSStringGetLength(string)); +} diff --git a/Source/JavaScriptCore/API/JSStringRefBSTR.h b/Source/JavaScriptCore/API/JSStringRefBSTR.h new file mode 100644 index 000000000..066c68d53 --- /dev/null +++ b/Source/JavaScriptCore/API/JSStringRefBSTR.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSStringRefBSTR_h +#define JSStringRefBSTR_h + +#include "JSBase.h" + +#include <windows.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* COM convenience methods */ + +/*! +@function +@abstract Creates a JavaScript string from a BSTR. +@param string The BSTR to copy into the new JSString. +@result A JSString containing string. Ownership follows the Create Rule. +*/ +JS_EXPORT JSStringRef JSStringCreateWithBSTR(const BSTR string); + +/*! +@function +@abstract Creates a BSTR from a JavaScript string. +@param string The JSString to copy into the new BSTR. +@result A BSTR containing string. Ownership follows the Create Rule. +*/ +JS_EXPORT BSTR JSStringCopyBSTR(const JSStringRef string); + +#ifdef __cplusplus +} +#endif + +#endif /* JSStringRefBSTR_h */ diff --git a/Source/JavaScriptCore/API/JSStringRefCF.cpp b/Source/JavaScriptCore/API/JSStringRefCF.cpp new file mode 100644 index 000000000..05872593f --- /dev/null +++ b/Source/JavaScriptCore/API/JSStringRefCF.cpp @@ -0,0 +1,67 @@ +/* + * 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 + * 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 "JSStringRefCF.h" + +#include "APICast.h" +#include "InitializeThreading.h" +#include "JSCJSValue.h" +#include "JSStringRef.h" +#include "OpaqueJSString.h" +#include <wtf/StdLibExtras.h> + +JSStringRef JSStringCreateWithCFString(CFStringRef string) +{ + JSC::initializeThreading(); + + // 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) + 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 allocator, JSStringRef string) +{ + 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 new file mode 100644 index 000000000..1e210c7a9 --- /dev/null +++ b/Source/JavaScriptCore/API/JSStringRefCF.h @@ -0,0 +1,60 @@ +/* + * 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 + * 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 JSStringRefCF_h +#define JSStringRefCF_h + +#include "JSBase.h" +#include <CoreFoundation/CoreFoundation.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* CFString convenience methods */ + +/*! +@function +@abstract Creates a JavaScript string from a CFString. +@discussion This function is optimized to take advantage of cases when + CFStringGetCharactersPtr returns a valid pointer. +@param string The CFString to copy into the new JSString. +@result A JSString containing string. Ownership follows the Create Rule. +*/ +JS_EXPORT JSStringRef JSStringCreateWithCFString(CFStringRef string); +/*! +@function +@abstract Creates a CFString from a JavaScript string. +@param alloc The alloc parameter to pass to CFStringCreate. +@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) CF_RETURNS_RETAINED; + +#ifdef __cplusplus +} +#endif + +#endif /* JSStringRefCF_h */ diff --git a/Source/JavaScriptCore/API/JSValue.h b/Source/JavaScriptCore/API/JSValue.h new file mode 100644 index 000000000..37d759407 --- /dev/null +++ b/Source/JavaScriptCore/API/JSValue.h @@ -0,0 +1,673 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSValue_h +#define JSValue_h + +#if JSC_OBJC_API_ENABLED + +#import <CoreGraphics/CGGeometry.h> + +@class JSContext; + +/*! +@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 + +/*! +@property +@abstract The JSContext that this value originates from. +*/ +@property (readonly, strong) JSContext *context; + +/*! +@methodgroup Creating JavaScript Values +*/ +/*! +@method +@abstract Create a JSValue by converting an Objective-C object. +@discussion The resulting JSValue retains the provided Objective-C object. +@param value The Objective-C object to be converted. +@result The new JSValue. +*/ ++ (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JavaScript value from a BOOL primitive. +@param value +@param context The JSContext in which the resulting JSValue will be created. +@result The new JSValue representing the equivalent boolean value. +*/ ++ (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JavaScript value from a double primitive. +@param value +@param context The JSContext in which the resulting JSValue will be created. +@result The new JSValue representing the equivalent boolean value. +*/ ++ (JSValue *)valueWithDouble:(double)value inContext:(JSContext *)context; + +/*! +@method +@abstract Create a JavaScript value from an <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; + +/*! +@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; + +/*! +@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; + +/*! +@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; + +/*! +@method +@abstract Convert a JSValue to a boolean. +@discussion The JSValue is converted to a boolean according to the rules specified + by the JavaScript language. +@result The boolean result of the conversion. +*/ +- (BOOL)toBool; + +/*! +@method +@abstract Convert a JSValue to a double. +@discussion The JSValue is converted to a number according to the rules specified + by the JavaScript language. +@result The double result of the conversion. +*/ +- (double)toDouble; + +/*! +@method +@abstract Convert a JSValue to an <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; + +/*! +@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; + +/*! +@method +@abstract Convert a JSValue to a NSNumber. +@discussion If the JSValue represents a boolean, a NSNumber value of YES or NO + will be returned. For all other types the value will be converted to a number according + to the rules specified by the JavaScript language. +@result The NSNumber result of the conversion. +*/ +- (NSNumber *)toNumber; + +/*! +@method +@abstract Convert a JSValue to a NSString. +@discussion The JSValue is converted to a string according to the rules specified + by the JavaScript language. +@result The NSString containing the result of the conversion. +*/ +- (NSString *)toString; + +/*! +@method +@abstract Convert a JSValue to a NSDate. +@discussion The value is converted to a number representing a time interval + since 1970 which is then used to create a new NSDate instance. +@result The NSDate created using the converted time interval. +*/ +- (NSDate *)toDate; + +/*! +@method +@abstract Convert a JSValue to a NSArray. +@discussion If the value is <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; + +/*! +@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; + +/*! +@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; + +/*! +@method +@abstract Set a property on a JSValue. +*/ +- (void)setValue:(id)value forProperty:(NSString *)property; + +/*! +@method +@abstract Delete a property from a JSValue. +@result YES if deletion is successful, NO otherwise. +*/ +- (BOOL)deleteProperty:(NSString *)property; + +/*! +@method +@abstract Check if a JSValue has a property. +@discussion This method has the same function as the JavaScript operator <code>in</code>. +@result Returns YES if property is present on the value. +*/ +- (BOOL)hasProperty:(NSString *)property; + +/*! +@method +@abstract Define properties with custom descriptors on JSValues. +@discussion This method may be used to create a data or accessor property on an object. + This method operates in accordance with the Object.defineProperty method in the + JavaScript language. +*/ +- (void)defineProperty:(NSString *)property descriptor:(id)descriptor; + +/*! +@method +@abstract Access an indexed (numerical) property on a JSValue. +@result The JSValue for the property at the specified index. + Returns the JavaScript value <code>undefined</code> if no property exists at that index. +*/ +- (JSValue *)valueAtIndex:(NSUInteger)index; + +/*! +@method +@abstract Set an indexed (numerical) property on a JSValue. +@discussion For JSValues that are JavaScript arrays, indices greater than + UINT_MAX - 1 will not affect the length of the array. +*/ +- (void)setValue:(id)value atIndex:(NSUInteger)index; + +/*! +@methodgroup Checking JavaScript Types +*/ +/*! +@method +@abstract Check if a JSValue corresponds to the JavaScript value <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; + +/*! +@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; + +/*! +@method +@abstract Compare two JSValues using JavaScript's <code>==</code> operator. +*/ +- (BOOL)isEqualWithTypeCoercionToObject:(id)value; + +/*! +@method +@abstract Check if a JSValue is an instance of another object. +@discussion This method has the same function as the JavaScript operator <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; + +/*! +@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; + +/*! +@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; + +/*! +@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 + +/*! +@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; + +/*! +@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; + +/*! +@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; + +/*! +@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; + +/*! +@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; + +/*! +@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; + +/*! +@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; + +/*! +@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 + +/*! +@category +@discussion Instances of JSValue implement the following methods in order to enable + support for subscript access by key and index, for example: + +@textblock + JSValue *objectA, *objectB; + JSValue *v1 = object[@"X"]; // Get value for property "X" from 'object'. + JSValue *v2 = object[42]; // Get value for index 42 from 'object'. + object[@"Y"] = v1; // Assign 'v1' to property "Y" of 'object'. + object[101] = v2; // Assign 'v2' to index 101 of 'object'. +@/textblock + + An object key passed as a subscript will be converted to a JavaScript value, + and then the value converted to a string used as a property name. +*/ +@interface JSValue (SubscriptSupport) + +- (JSValue *)objectForKeyedSubscript:(id)key; +- (JSValue *)objectAtIndexedSubscript:(NSUInteger)index; +- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key; +- (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index; + +@end + +/*! +@category +@discussion These functions are for bridging between the C API and the Objective-C API. +*/ +@interface JSValue (JSValueRefSupport) + +/*! +@method +@abstract Creates a JSValue, wrapping its C API counterpart. +@param value +@param context +@result The Objective-C API equivalent of the specified JSValueRef. +*/ ++ (JSValue *)valueWithJSValueRef:(JSValueRef)value inContext:(JSContext *)context; + +/*! +@property +@abstract Returns the C API counterpart wrapped by a JSContext. +@result The C API equivalent of this JSValue. +*/ +@property (readonly) JSValueRef JSValueRef; +@end + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +@group Property Descriptor Constants +@discussion These keys may assist in creating a property descriptor for use with the + defineProperty method on JSValue. + Property descriptors must fit one of three descriptions: + + Data Descriptor: + - A descriptor containing one or both of the keys <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 +} // extern "C" +#endif + +#endif + +#endif // JSValue_h diff --git a/Source/JavaScriptCore/API/JSValueInternal.h b/Source/JavaScriptCore/API/JSValueInternal.h new file mode 100644 index 000000000..4f1a8f69c --- /dev/null +++ b/Source/JavaScriptCore/API/JSValueInternal.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSValueInternal_h +#define JSValueInternal_h + +#import <JavaScriptCore/JavaScriptCore.h> +#import <JavaScriptCore/JSValue.h> + +#if JSC_OBJC_API_ENABLED + +@interface JSValue(Internal) + +JSValueRef valueInternalValue(JSValue *); + +- (JSValue *)initWithValue:(JSValueRef)value inContext:(JSContext *)context; + +JSValueRef objectToValue(JSContext *, id); +id valueToObject(JSContext *, JSValueRef); +id valueToNumber(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToString(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToDate(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToArray(JSGlobalContextRef, JSValueRef, JSValueRef* exception); +id valueToDictionary(JSGlobalContextRef, JSValueRef, JSValueRef* exception); + ++ (SEL)selectorForStructToValue:(const char *)structTag; ++ (SEL)selectorForValueToStruct:(const char *)structTag; + +@end + +NSInvocation *typeToValueInvocationFor(const char* encodedType); +NSInvocation *valueToTypeInvocationFor(const char* encodedType); + +#endif + +#endif // JSValueInternal_h diff --git a/Source/JavaScriptCore/API/JSValueRef.cpp b/Source/JavaScriptCore/API/JSValueRef.cpp index 3e0cbbd7a..54405e2af 100644 --- a/Source/JavaScriptCore/API/JSValueRef.cpp +++ b/Source/JavaScriptCore/API/JSValueRef.cpp @@ -10,46 +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 "JSGlobalObject.h" #include "JSONObject.h" #include "JSString.h" #include "LiteralParser.h" -#include "Operations.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() { @@ -68,7 +91,7 @@ static bool evernoteHackNeeded() return kJSTypeUndefined; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); @@ -93,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) @@ -106,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) @@ -119,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) @@ -132,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) @@ -145,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) @@ -158,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) @@ -171,11 +212,14 @@ 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(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>::info())) @@ -195,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; } @@ -216,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); @@ -231,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); @@ -239,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; } @@ -254,7 +291,7 @@ JSValueRef JSValueMakeUndefined(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(exec, jsUndefined()); } @@ -266,7 +303,7 @@ JSValueRef JSValueMakeNull(JSContextRef ctx) return 0; } ExecState* exec = toJS(ctx); - APIEntryShim entryShim(exec); + JSLockHolder locker(exec); return toRef(exec, jsNull()); } @@ -278,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)); } @@ -290,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) @@ -308,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) @@ -320,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.deprecatedCharacters(), length, StrictJSON); + LiteralParser<UChar> parser(exec, str.characters16(), length, StrictJSON); return toRef(exec, parser.tryLiteralParse()); } @@ -338,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(); } @@ -359,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); @@ -369,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; } @@ -393,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(); } @@ -414,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) { @@ -435,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); @@ -449,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 97385c01e..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 */ /*! diff --git a/Source/JavaScriptCore/API/JSVirtualMachine.h b/Source/JavaScriptCore/API/JSVirtualMachine.h new file mode 100644 index 000000000..ccf9264d5 --- /dev/null +++ b/Source/JavaScriptCore/API/JSVirtualMachine.h @@ -0,0 +1,82 @@ +/* + * 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> + +#if JSC_OBJC_API_ENABLED + +/*! +@interface +@discussion An instance of JSVirtualMachine represents a single JavaScript "object space" + or set of execution resources. Thread safety is supported by locking the + virtual machine, with concurrent JavaScript execution supported by allocating + separate instances of JSVirtualMachine. +*/ +NS_CLASS_AVAILABLE(10_9, 7_0) +@interface JSVirtualMachine : NSObject + +/*! +@methodgroup Creating New Virtual Machines +*/ +/*! +@method +@abstract Create a new JSVirtualMachine. +*/ +- (instancetype)init; + +/*! +@methodgroup Memory Management +*/ +/*! +@method +@abstract Notify the JSVirtualMachine of an external object relationship. +@discussion Allows clients of JSVirtualMachine to make the JavaScript runtime aware of + arbitrary external Objective-C object graphs. The runtime can then use + this information to retain any JavaScript values that are referenced + from somewhere in said object graph. + + For correct behavior clients must make their external object graphs + reachable from within the JavaScript runtime. If an Objective-C object is + reachable from within the JavaScript runtime, all managed references + transitively reachable from it as recorded using + -addManagedReference:withOwner: will be scanned by the garbage collector. +@param object The object that the owner points to. +@param owner The object that owns the pointed to object. +*/ +- (void)addManagedReference:(id)object withOwner:(id)owner; + +/*! +@method +@abstract Notify the JSVirtualMachine that a previous object relationship no longer exists. +@discussion The JavaScript runtime will continue to scan any references that were + reported to it by -addManagedReference:withOwner: until those references are removed. +@param object The object that was formerly owned. +@param owner The former owner. +*/ +- (void)removeManagedReference:(id)object withOwner:(id)owner; + +@end + +#endif diff --git a/Source/JavaScriptCore/API/JSVirtualMachineInternal.h b/Source/JavaScriptCore/API/JSVirtualMachineInternal.h new file mode 100644 index 000000000..5a4fbefa5 --- /dev/null +++ b/Source/JavaScriptCore/API/JSVirtualMachineInternal.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSVirtualMachineInternal_h +#define JSVirtualMachineInternal_h + +#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 *); + ++ (JSVirtualMachine *)virtualMachineWithContextGroupRef:(JSContextGroupRef)group; + +- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext; +- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext; + +- (NSMapTable *)externalObjectGraph; + +@end +#endif // defined(__OBJC__) + +void scanExternalObjectGraph(JSC::VM&, JSC::SlotVisitor&, void* root); +void scanExternalRememberedSet(JSC::VM&, JSC::SlotVisitor&); + +#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 new file mode 100644 index 000000000..925c00f0b --- /dev/null +++ b/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010 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 "JSWeakObjectMapRefPrivate.h" + +#include "APICast.h" +#include "JSCJSValue.h" +#include "JSCallbackObject.h" +#include "JSWeakObjectMapRefInternal.h" +#include "JSCInlines.h" +#include "Weak.h" +#include "WeakGCMapInlines.h" +#include <wtf/HashMap.h> +#include <wtf/text/StringHash.h> + +using namespace WTF; +using namespace JSC; + +#ifdef __cplusplus +extern "C" { +#endif + +JSWeakObjectMapRef JSWeakObjectMapCreate(JSContextRef context, void* privateData, JSWeakMapDestroyedCallback callback) +{ + ExecState* exec = toJS(context); + JSLockHolder locker(exec); + RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create(exec->vm(), privateData, callback); + exec->lexicalGlobalObject()->registerWeakMap(map.get()); + return map.get(); +} + +void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSObjectRef object) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + JSObject* obj = toJS(object); + if (!obj) + return; + ASSERT(obj->inherits(JSProxy::info()) + || obj->inherits(JSCallbackObject<JSGlobalObject>::info()) + || obj->inherits(JSCallbackObject<JSDestructibleObject>::info())); + map->map().set(key, obj); +} + +JSObjectRef JSWeakObjectMapGet(JSContextRef ctx, JSWeakObjectMapRef map, void* key) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + return toRef(jsCast<JSObject*>(map->map().get(key))); +} + +void JSWeakObjectMapRemove(JSContextRef ctx, JSWeakObjectMapRef map, void* key) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + map->map().remove(key); +} + +// We need to keep this function in the build to keep the nightlies running. +JS_EXPORT bool JSWeakObjectMapClear(JSContextRef, JSWeakObjectMapRef, void*, JSObjectRef); +bool JSWeakObjectMapClear(JSContextRef, JSWeakObjectMapRef, void*, JSObjectRef) +{ + return true; +} + +#ifdef __cplusplus +} +#endif diff --git a/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.h b/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.h new file mode 100644 index 000000000..5a07cf7c4 --- /dev/null +++ b/Source/JavaScriptCore/API/JSWeakObjectMapRefPrivate.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010 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 JSWeakObjectMapRefPrivate_h +#define JSWeakObjectMapRefPrivate_h + +#include <JavaScriptCore/JSContextRef.h> +#include <JavaScriptCore/JSValueRef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*! @typedef JSWeakObjectMapRef A weak map for storing JSObjectRefs */ +typedef struct OpaqueJSWeakObjectMap* JSWeakObjectMapRef; + +/*! + @typedef JSWeakMapDestroyedCallback + @abstract The callback invoked when a JSWeakObjectMapRef is being destroyed. + @param map The map that is being destroyed. + @param data The private data (if any) that was associated with the map instance. + */ +typedef void (*JSWeakMapDestroyedCallback)(JSWeakObjectMapRef map, void* data); + +/*! + @function + @abstract Creates a weak value map that can be used to reference user defined objects without preventing them from being collected. + @param ctx The execution context to use. + @param data A void* to set as the map's private data. Pass NULL to specify no private data. + @param destructor A function to call when the weak map is destroyed. + @result A JSWeakObjectMapRef bound to the given context, data and destructor. + @discussion The JSWeakObjectMapRef can be used as a storage mechanism to hold custom JS objects without forcing those objects to + remain live as JSValueProtect would. + */ +JS_EXPORT JSWeakObjectMapRef JSWeakObjectMapCreate(JSContextRef ctx, void* data, JSWeakMapDestroyedCallback destructor); + +/*! + @function + @abstract Associates a JSObjectRef with the given key in a JSWeakObjectMap. + @param ctx The execution context to use. + @param map The map to operate on. + @param key The key to associate a weak reference with. + @param object The user defined object to associate with the key. + */ +JS_EXPORT void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSObjectRef); + +/*! + @function + @abstract Retrieves the JSObjectRef associated with a key. + @param ctx The execution context to use. + @param map The map to query. + @param key The key to search for. + @result Either the live object associated with the provided key, or NULL. + */ +JS_EXPORT JSObjectRef JSWeakObjectMapGet(JSContextRef ctx, JSWeakObjectMapRef map, void* key); + +/*! + @function + @abstract Removes the entry for the given key if the key is present, otherwise it has no effect. + @param ctx The execution context to use. + @param map The map to use. + @param key The key to remove. + */ +JS_EXPORT void JSWeakObjectMapRemove(JSContextRef ctx, JSWeakObjectMapRef map, void* key); + +#ifdef __cplusplus +} +#endif + +#endif // JSWeakObjectMapPrivate_h diff --git a/Source/JavaScriptCore/API/JSWrapperMap.h b/Source/JavaScriptCore/API/JSWrapperMap.h new file mode 100644 index 000000000..c6aa1af13 --- /dev/null +++ b/Source/JavaScriptCore/API/JSWrapperMap.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <JavaScriptCore/JavaScriptCore.h> +#import <JSValueInternal.h> +#import <objc/objc-runtime.h> + +#if JSC_OBJC_API_ENABLED + +@interface JSWrapperMap : NSObject + +- (id)initWithContext:(JSContext *)context; + +- (JSValue *)jsWrapperForObject:(id)object; + +- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value; + +@end + +id tryUnwrapObjcObject(JSGlobalContextRef, JSValueRef); + +bool supportsInitMethodConstructors(); +Protocol *getJSExportProtocol(); +Class getNSBlockClass(); + +#endif diff --git a/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 new file mode 100644 index 000000000..b2fde1dbe --- /dev/null +++ b/Source/JavaScriptCore/API/JavaScriptCore.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JavaScriptCore_h +#define JavaScriptCore_h + +#include <JavaScriptCore/JavaScript.h> +#include <JavaScriptCore/JSStringRefCF.h> + +#if defined(__OBJC__) && JSC_OBJC_API_ENABLED + +#import "JSContext.h" +#import "JSValue.h" +#import "JSManagedValue.h" +#import "JSVirtualMachine.h" +#import "JSExport.h" + +#endif + +#endif /* JavaScriptCore_h */ diff --git a/Source/JavaScriptCore/API/ObjCCallbackFunction.h b/Source/JavaScriptCore/API/ObjCCallbackFunction.h index 046bf650d..adb167c76 100644 --- a/Source/JavaScriptCore/API/ObjCCallbackFunction.h +++ b/Source/JavaScriptCore/API/ObjCCallbackFunction.h @@ -48,7 +48,7 @@ class ObjCCallbackFunction : public InternalFunction { public: typedef InternalFunction Base; - static ObjCCallbackFunction* create(VM&, 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) @@ -62,7 +62,7 @@ public: ObjCCallbackFunctionImpl* impl() const { return m_impl.get(); } protected: - ObjCCallbackFunction(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, JSObjectCallAsConstructorCallback, PassOwnPtr<ObjCCallbackFunctionImpl>); + ObjCCallbackFunction(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, JSObjectCallAsConstructorCallback, std::unique_ptr<ObjCCallbackFunctionImpl>); private: static CallType getCallData(JSCell*, CallData&); @@ -73,7 +73,7 @@ private: JSObjectCallAsFunctionCallback m_functionCallback; JSObjectCallAsConstructorCallback m_constructCallback; - OwnPtr<ObjCCallbackFunctionImpl> m_impl; + std::unique_ptr<ObjCCallbackFunctionImpl> m_impl; }; } // namespace JSC diff --git a/Source/JavaScriptCore/API/ObjcRuntimeExtras.h b/Source/JavaScriptCore/API/ObjcRuntimeExtras.h new file mode 100644 index 000000000..128df5c90 --- /dev/null +++ b/Source/JavaScriptCore/API/ObjcRuntimeExtras.h @@ -0,0 +1,242 @@ +/* + * 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 <objc/Protocol.h> +#import <objc/runtime.h> +#import <wtf/HashSet.h> +#import <wtf/Vector.h> + +inline bool protocolImplementsProtocol(Protocol *candidate, Protocol *target) +{ + unsigned protocolProtocolsCount; + Protocol ** protocolProtocols = protocol_copyProtocolList(candidate, &protocolProtocolsCount); + for (unsigned i = 0; i < protocolProtocolsCount; ++i) { + if (protocol_isEqual(protocolProtocols[i], target)) { + free(protocolProtocols); + return true; + } + } + free(protocolProtocols); + return false; +} + +inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, void (^callback)(Protocol *)) +{ + ASSERT(cls); + ASSERT(target); + + Vector<Protocol *> worklist; + HashSet<void*> visited; + + // Initially fill the worklist with the Class's protocols. + unsigned protocolsCount; + Protocol ** protocols = class_copyProtocolList(cls, &protocolsCount); + worklist.append(protocols, protocolsCount); + free(protocols); + + while (!worklist.isEmpty()) { + Protocol *protocol = worklist.last(); + worklist.removeLast(); + + // Are we encountering this Protocol for the first time? + if (!visited.add(protocol).isNewEntry) + continue; + + // If it implements the protocol, make the callback. + if (protocolImplementsProtocol(protocol, target)) + callback(protocol); + + // Add incorporated protocols to the worklist. + protocols = protocol_copyProtocolList(protocol, &protocolsCount); + worklist.append(protocols, protocolsCount); + free(protocols); + } +} + +inline void forEachMethodInClass(Class cls, void (^callback)(Method)) +{ + unsigned count; + Method* methods = class_copyMethodList(cls, &count); + for (unsigned i = 0; i < count; ++i) + callback(methods[i]); + free(methods); +} + +inline void forEachMethodInProtocol(Protocol *protocol, BOOL isRequiredMethod, BOOL isInstanceMethod, void (^callback)(SEL, const char*)) +{ + unsigned count; + struct objc_method_description* methods = protocol_copyMethodDescriptionList(protocol, isRequiredMethod, isInstanceMethod, &count); + for (unsigned i = 0; i < count; ++i) + callback(methods[i].name, methods[i].types); + free(methods); +} + +inline void forEachPropertyInProtocol(Protocol *protocol, void (^callback)(objc_property_t)) +{ + unsigned count; + objc_property_t* properties = protocol_copyPropertyList(protocol, &count); + for (unsigned i = 0; i < count; ++i) + callback(properties[i]); + free(properties); +} + +template<char open, char close> +void skipPair(const char*& position) +{ + size_t count = 1; + do { + char c = *position++; + if (!c) + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Malformed type encoding" userInfo:nil]; + if (c == open) + ++count; + else if (c == close) + --count; + } while (count); +} + +class StringRange { + WTF_MAKE_NONCOPYABLE(StringRange); +public: + StringRange(const char* begin, const char* end) : m_ptr(strndup(begin, end - begin)) { } + ~StringRange() { free(m_ptr); } + operator const char*() const { return m_ptr; } + const char* get() const { return m_ptr; } + +private: + char* m_ptr; +}; + +class StructBuffer { + WTF_MAKE_NONCOPYABLE(StructBuffer); +public: + StructBuffer(const char* encodedType) + { + NSUInteger size, alignment; + NSGetSizeAndAlignment(encodedType, &size, &alignment); + --alignment; + m_allocation = static_cast<char*>(malloc(size + alignment)); + m_buffer = reinterpret_cast<char*>((reinterpret_cast<intptr_t>(m_allocation) + alignment) & ~alignment); + } + + ~StructBuffer() { free(m_allocation); } + operator void*() const { return m_buffer; } + +private: + void* m_allocation; + void* m_buffer; +}; + +template<typename DelegateType> +typename DelegateType::ResultType parseObjCType(const char*& position) +{ + ASSERT(*position); + + switch (*position++) { + case 'c': + return DelegateType::template typeInteger<char>(); + case 'i': + return DelegateType::template typeInteger<int>(); + case 's': + return DelegateType::template typeInteger<short>(); + case 'l': + return DelegateType::template typeInteger<long>(); + case 'q': + return DelegateType::template typeDouble<long long>(); + case 'C': + return DelegateType::template typeInteger<unsigned char>(); + case 'I': + return DelegateType::template typeInteger<unsigned>(); + case 'S': + return DelegateType::template typeInteger<unsigned short>(); + case 'L': + return DelegateType::template typeInteger<unsigned long>(); + case 'Q': + return DelegateType::template typeDouble<unsigned long long>(); + case 'f': + return DelegateType::template typeDouble<float>(); + case 'd': + return DelegateType::template typeDouble<double>(); + case 'B': + return DelegateType::typeBool(); + case 'v': + return DelegateType::typeVoid(); + + case '@': { // An object (whether statically typed or typed id) + if (position[0] == '?' && position[1] == '<') { + position += 2; + const char* begin = position; + skipPair<'<','>'>(position); + return DelegateType::typeBlock(begin, position - 1); + } + + if (*position == '"') { + const char* begin = position + 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(); + } + + case '{': { // {name=type...} A structure + const char* begin = position - 1; + skipPair<'{','}'>(position); + return DelegateType::typeStruct(begin, position); + } + + // NOT supporting C strings, arrays, pointers, unions, bitfields, function pointers. + case '*': // A character string (char *) + case '[': // [array type] An array + case '(': // (name=type...) A union + case 'b': // bnum A bit field of num bits + case '^': // ^type A pointer to type + case '?': // An unknown type (among other things, this code is used for function pointers) + // NOT supporting Objective-C Class, SEL + case '#': // A class object (Class) + case ':': // A method selector (SEL) + default: + return nil; + } +} + +extern "C" { + // Forward declare some Objective-C runtime internal methods that are not API. + const char *_protocol_getMethodTypeEncoding(Protocol *, SEL, BOOL isRequiredMethod, BOOL isInstanceMethod); + id objc_initWeak(id *, id); + void objc_destroyWeak(id *); + bool _Block_has_signature(void *); + const char * _Block_signature(void *); +} diff --git a/Source/JavaScriptCore/API/OpaqueJSString.cpp b/Source/JavaScriptCore/API/OpaqueJSString.cpp index 5cc2e0ab8..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 @@ -28,11 +28,13 @@ #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 nullptr; @@ -47,7 +49,7 @@ OpaqueJSString::~OpaqueJSString() if (!characters) return; - if (!m_string.is8Bit() && m_string.deprecatedCharacters() == characters) + if (!m_string.is8Bit() && m_string.characters16() == characters) return; fastFree(characters); @@ -55,32 +57,26 @@ OpaqueJSString::~OpaqueJSString() String OpaqueJSString::string() const { - if (!this) - return String(); - // 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(vm, m_string.characters16(), m_string.length()); + return Identifier::fromString(vm, m_string.characters16(), m_string.length()); } const UChar* OpaqueJSString::characters() { - if (!this) - return nullptr; - // m_characters is put in a local here to avoid an extra atomic load. UChar* characters = m_characters; if (characters) @@ -91,12 +87,7 @@ const UChar* OpaqueJSString::characters() unsigned length = m_string.length(); UChar* newCharacters = static_cast<UChar*>(fastMalloc(length * sizeof(UChar))); - - if (m_string.is8Bit()) { - for (size_t i = 0; i < length; ++i) - newCharacters[i] = m_string.characters8()[i]; - } else - memcpy(newCharacters, m_string.characters16(), length * sizeof(UChar)); + StringView(m_string).getCharactersWithUpconvert(newCharacters); if (!m_characters.compare_exchange_strong(characters, newCharacters)) { fastFree(newCharacters); diff --git a/Source/JavaScriptCore/API/OpaqueJSString.h b/Source/JavaScriptCore/API/OpaqueJSString.h index f1dd6a43d..208131b3b 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 @@ -36,29 +36,29 @@ namespace JSC { } struct OpaqueJSString : public ThreadSafeRefCounted<OpaqueJSString> { - static PassRefPtr<OpaqueJSString> create() + 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 this ? m_string.is8Bit() : false; } - const LChar* characters8() { return this ? m_string.characters8() : nullptr; } - const UChar* characters16() { return this ? m_string.characters16() : nullptr; } - unsigned length() { return this ? m_string.length() : 0; } + 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(); diff --git a/Source/JavaScriptCore/API/WebKitAvailability.h b/Source/JavaScriptCore/API/WebKitAvailability.h index 6af619825..f878beae9 100644 --- a/Source/JavaScriptCore/API/WebKitAvailability.h +++ b/Source/JavaScriptCore/API/WebKitAvailability.h @@ -26,9 +26,49 @@ #ifndef __WebKitAvailability__ #define __WebKitAvailability__ -#if defined(__APPLE__) && !defined(BUILDING_GTK__) +#if defined(__APPLE__) + #include <AvailabilityMacros.h> #include <CoreFoundation/CoreFoundation.h> + +#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. +*/ + +#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 + +#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 + +#ifndef __AVAILABILITY_INTERNAL__MAC_10_9 +#define __AVAILABILITY_INTERNAL__MAC_10_9 +#endif + +#ifndef __AVAILABILITY_INTERNAL__MAC_10_10 +#define __AVAILABILITY_INTERNAL__MAC_10_10 +#endif + +#ifndef AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER +#define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER +#endif + +#ifndef AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER +#define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER +#endif + +#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED <= 101100 */ + +#if defined(BUILDING_GTK__) +#undef CF_AVAILABLE +#define CF_AVAILABLE(_mac, _ios) +#endif + #else #define CF_AVAILABLE(_mac, _ios) #endif 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 f4ccf91e4..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" diff --git a/Source/JavaScriptCore/API/tests/minidom.html b/Source/JavaScriptCore/API/tests/minidom.html new file mode 100644 index 000000000..7ea474752 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/minidom.html @@ -0,0 +1,9 @@ +<html> +<head> +<script src="minidom.js"></script> +</head> + +<body onload="test()"> + <pre id='pre'></pre> +</body> +</html> diff --git a/Source/JavaScriptCore/API/tests/minidom.js b/Source/JavaScriptCore/API/tests/minidom.js new file mode 100644 index 000000000..85134d7cb --- /dev/null +++ b/Source/JavaScriptCore/API/tests/minidom.js @@ -0,0 +1,110 @@ +/* + * 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 + * 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. + */ + +function shouldBe(a, b) +{ + var evalA; + try { + evalA = eval(a); + } catch(e) { + evalA = e; + } + + if (evalA == b || isNaN(evalA) && typeof evalA == 'number' && isNaN(b) && typeof b == 'number') + print("PASS: " + a + " should be " + b + " and is.", "green"); + else + print("__FAIL__: " + a + " should be " + b + " but instead is " + evalA + ".", "red"); +} + +function test() +{ + print("Node is " + Node); + for (var p in Node) + print(p + ": " + Node[p]); + + node = new Node(); + print("node is " + node); + for (var p in node) + print(p + ": " + node[p]); + + child1 = new Node(); + child2 = new Node(); + child3 = new Node(); + + node.appendChild(child1); + node.appendChild(child2); + + var childNodes = node.childNodes; + + for (var i = 0; i < childNodes.length + 1; i++) { + print("item " + i + ": " + childNodes.item(i)); + } + + for (var i = 0; i < childNodes.length + 1; i++) { + print(i + ": " + childNodes[i]); + } + + node.removeChild(child1); + node.replaceChild(child3, child2); + + for (var i = 0; i < childNodes.length + 1; i++) { + print("item " + i + ": " + childNodes.item(i)); + } + + for (var i = 0; i < childNodes.length + 1; i++) { + print(i + ": " + childNodes[i]); + } + + try { + node.appendChild(null); + } catch(e) { + print("caught: " + e); + } + + try { + var o = new Object(); + o.appendChild = node.appendChild; + o.appendChild(node); + } catch(e) { + print("caught: " + e); + } + + try { + node.appendChild(); + } catch(e) { + print("caught: " + e); + } + + oldNodeType = node.nodeType; + node.nodeType = 1; + shouldBe("node.nodeType", oldNodeType); + + shouldBe("node instanceof Node", true); + shouldBe("new Object() instanceof Node", false); + + print(Node); +} + +test(); diff --git a/Source/JavaScriptCore/API/tests/testapi.c b/Source/JavaScriptCore/API/tests/testapi.c new file mode 100644 index 000000000..cbf9daf18 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/testapi.c @@ -0,0 +1,1994 @@ +/* + * 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 + * 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 <wtf/Platform.h> + +#include "JavaScriptCore.h" +#include "JSBasePrivate.h" +#include "JSContextRefPrivate.h" +#include "JSObjectRefPrivate.h" +#include "JSScriptRefPrivate.h" +#include "JSStringRefPrivate.h" +#include <math.h> +#define ASSERT_DISABLED 0 +#include <wtf/Assertions.h> + +#if OS(WINDOWS) +#include <windows.h> +#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; +int failed; +static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue) +{ + if (JSValueToBoolean(context, value) != expectedValue) { + fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue); + failed = 1; + } +} + +static void assertEqualsAsNumber(JSValueRef value, double expectedValue) +{ + double number = JSValueToNumber(context, value, NULL); + + // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function, + // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team. + // After that's resolved, we can remove these casts + if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) { + fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue); + failed = 1; + } +} + +static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue) +{ + JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); + + 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; + } + } + + if (jsSize < strlen(jsBuffer) + 1) { + fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n"); + failed = 1; + } + + free(jsBuffer); + JSStringRelease(valueAsString); +} + +static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue) +{ + JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); + + size_t jsLength = JSStringGetLength(valueAsString); + const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString); + + CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, + expectedValue, + kCFStringEncodingUTF8); + CFIndex cfLength = CFStringGetLength(expectedValueAsCFString); + UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar)); + CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer); + CFRelease(expectedValueAsCFString); + + if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) { + fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n"); + failed = 1; + } + + if (jsLength != (size_t)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; + } + + free(cfBuffer); + JSStringRelease(valueAsString); +} + +static bool timeZoneIsPST() +{ + char timeZoneName[70]; + struct tm gtm; + memset(>m, 0, sizeof(gtm)); + strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); + + return 0 == strcmp("PST", timeZoneName); +} + +static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect() + +/* MyObject pseudo-class */ + +static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + + if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne") + || JSStringIsEqualToUTF8CString(propertyName, "cantFind") + || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet") + || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName") + || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie") + || JSStringIsEqualToUTF8CString(propertyName, "0")) { + return true; + } + + return false; +} + +static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + + if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) { + return JSValueMakeNumber(context, 1); + } + + if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) { + return JSValueMakeNumber(context, 1); + } + + if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) { + return JSValueMakeUndefined(context); + } + + if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) { + return 0; + } + + if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) { + return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); + } + + if (JSStringIsEqualToUTF8CString(propertyName, "0")) { + *exception = JSValueMakeNumber(context, 1); + return JSValueMakeNumber(context, 1); + } + + return JSValueMakeNull(context); +} + +static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + UNUSED_PARAM(value); + UNUSED_PARAM(exception); + + if (JSStringIsEqualToUTF8CString(propertyName, "cantSet")) + return true; // pretend we set the property in order to swallow it + + if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) { + JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); + } + + return false; +} + +static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + + if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete")) + return true; + + if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) { + JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); + return false; + } + + return false; +} + +static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + + JSStringRef propertyName; + + propertyName = JSStringCreateWithUTF8CString("alwaysOne"); + JSPropertyNameAccumulatorAddName(propertyNames, propertyName); + JSStringRelease(propertyName); + + propertyName = JSStringCreateWithUTF8CString("myPropertyName"); + JSPropertyNameAccumulatorAddName(propertyNames, propertyName); + JSStringRelease(propertyName); +} + +static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(exception); + + if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) { + JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); + return JSValueMakeUndefined(context); + } + + if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0))) + return JSValueMakeNumber(context, 1); + + return JSValueMakeUndefined(context); +} + +static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + + if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) { + JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); + return object; + } + + if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0))) + return JSValueToObject(context, JSValueMakeNumber(context, 1), exception); + + return JSValueToObject(context, JSValueMakeNumber(context, 0), exception); +} + +static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(constructor); + + if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) { + JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception); + return false; + } + + JSStringRef numberString = JSStringCreateWithUTF8CString("Number"); + JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception); + JSStringRelease(numberString); + + return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception); +} + +static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(exception); + + switch (type) { + case kJSTypeNumber: + return JSValueMakeNumber(context, 1); + case kJSTypeString: + { + JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString"); + JSValueRef result = JSValueMakeString(context, string); + JSStringRelease(string); + return result; + } + default: + break; + } + + // string conversion -- forward to default object class + return JSValueMakeNull(context); +} + +static JSValueRef MyObject_convertToTypeWrapper(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + UNUSED_PARAM(type); + UNUSED_PARAM(exception); + // Forward to default object class + return 0; +} + +static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + UNUSED_PARAM(ctx); + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(value); + UNUSED_PARAM(exception); + return false; // Forward to parent class. +} + +static JSStaticValue evilStaticValues[] = { + { "nullGetSet", 0, 0, kJSPropertyAttributeNone }, + { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone }, + { 0, 0, 0, 0 } +}; + +static JSStaticFunction evilStaticFunctions[] = { + { "nullCall", 0, kJSPropertyAttributeNone }, + { 0, 0, 0 } +}; + +JSClassDefinition MyObject_definition = { + 0, + kJSClassAttributeNone, + + "MyObject", + NULL, + + evilStaticValues, + evilStaticFunctions, + + NULL, + NULL, + MyObject_hasProperty, + MyObject_getProperty, + MyObject_setProperty, + MyObject_deleteProperty, + MyObject_getPropertyNames, + MyObject_callAsFunction, + MyObject_callAsConstructor, + MyObject_hasInstance, + MyObject_convertToType, +}; + +JSClassDefinition MyObject_convertToTypeWrapperDefinition = { + 0, + kJSClassAttributeNone, + + "MyObject", + NULL, + + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + MyObject_convertToTypeWrapper, +}; + +JSClassDefinition MyObject_nullWrapperDefinition = { + 0, + kJSClassAttributeNone, + + "MyObject", + NULL, + + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static JSClassRef MyObject_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) { + JSClassRef baseClass = JSClassCreate(&MyObject_definition); + MyObject_convertToTypeWrapperDefinition.parentClass = baseClass; + JSClassRef wrapperClass = JSClassCreate(&MyObject_convertToTypeWrapperDefinition); + MyObject_nullWrapperDefinition.parentClass = wrapperClass; + jsClass = JSClassCreate(&MyObject_nullWrapperDefinition); + } + + return jsClass; +} + +static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + if (JSStringIsEqualToUTF8CString(propertyName, "x")) { + static size_t count; + if (count++ < 5) + return NULL; + + // Swallow all .x gets after 5, returning null. + return JSValueMakeNull(context); + } + + if (JSStringIsEqualToUTF8CString(propertyName, "y")) { + static size_t count; + if (count++ < 5) + return NULL; + + // Swallow all .y gets after 5, returning null. + return JSValueMakeNull(context); + } + + if (JSStringIsEqualToUTF8CString(propertyName, "z")) { + static size_t count; + if (count++ < 5) + return NULL; + + // Swallow all .y gets after 5, returning null. + return JSValueMakeNull(context); + } + + return NULL; +} + +static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(value); + UNUSED_PARAM(exception); + + if (JSStringIsEqualToUTF8CString(propertyName, "x")) { + static size_t count; + if (count++ < 5) + return false; + + // Swallow all .x sets after 4. + return true; + } + + if (JSStringIsEqualToUTF8CString(propertyName, "make_throw") || JSStringIsEqualToUTF8CString(propertyName, "0")) { + *exception = JSValueMakeNumber(context, 5); + return true; + } + + return false; +} + +static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(object); + + static size_t count; + static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + + // Provide a property of a different name every time. + JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]); + JSPropertyNameAccumulatorAddName(propertyNames, propertyName); + JSStringRelease(propertyName); +} + +JSClassDefinition PropertyCatchalls_definition = { + 0, + kJSClassAttributeNone, + + "PropertyCatchalls", + NULL, + + NULL, + NULL, + + NULL, + NULL, + NULL, + PropertyCatchalls_getProperty, + PropertyCatchalls_setProperty, + NULL, + PropertyCatchalls_getPropertyNames, + NULL, + NULL, + NULL, + NULL, +}; + +static JSClassRef PropertyCatchalls_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) + jsClass = JSClassCreate(&PropertyCatchalls_definition); + + return jsClass; +} + +static bool EvilExceptionObject_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; + JSObjectRef function = JSValueToObject(context, hasInstance, exception); + JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception); + return result && JSValueToBoolean(context, result); +} + +static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(exception); + JSStringRef funcName; + switch (type) { + case kJSTypeNumber: + funcName = JSStringCreateWithUTF8CString("toNumber"); + break; + case kJSTypeString: + funcName = JSStringCreateWithUTF8CString("toStringExplicit"); + break; + default: + return JSValueMakeNull(context); + } + + JSValueRef func = JSObjectGetProperty(context, object, funcName, exception); + JSStringRelease(funcName); + JSObjectRef function = JSValueToObject(context, func, exception); + if (!function) + return JSValueMakeNull(context); + JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception); + if (!value) { + JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed"); + JSValueRef errorStringRef = JSValueMakeString(context, errorString); + JSStringRelease(errorString); + return errorStringRef; + } + return value; +} + +JSClassDefinition EvilExceptionObject_definition = { + 0, + kJSClassAttributeNone, + + "EvilExceptionObject", + NULL, + + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + EvilExceptionObject_hasInstance, + EvilExceptionObject_convertToType, +}; + +static JSClassRef EvilExceptionObject_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) + jsClass = JSClassCreate(&EvilExceptionObject_definition); + + return jsClass; +} + +JSClassDefinition EmptyObject_definition = { + 0, + kJSClassAttributeNone, + + NULL, + NULL, + + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static JSClassRef EmptyObject_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) + jsClass = JSClassCreate(&EmptyObject_definition); + + return jsClass; +} + + +static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get +} + +static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(value); + + *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set + return true; +} + +static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call +} + +static JSValueRef Base_returnHardNull(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(ctx); + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + return 0; // should convert to undefined! +} + +static JSStaticFunction Base_staticFunctions[] = { + { "baseProtoDup", NULL, kJSPropertyAttributeNone }, + { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone }, + { "baseHardNull", Base_returnHardNull, kJSPropertyAttributeNone }, + { 0, 0, 0 } +}; + +static JSStaticValue Base_staticValues[] = { + { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone }, + { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone }, + { 0, 0, 0, 0 } +}; + +static bool TestInitializeFinalize; +static void Base_initialize(JSContextRef context, JSObjectRef object) +{ + UNUSED_PARAM(context); + + if (TestInitializeFinalize) { + ASSERT((void*)1 == JSObjectGetPrivate(object)); + JSObjectSetPrivate(object, (void*)2); + } +} + +static unsigned Base_didFinalize; +static void Base_finalize(JSObjectRef object) +{ + UNUSED_PARAM(object); + if (TestInitializeFinalize) { + ASSERT((void*)4 == JSObjectGetPrivate(object)); + Base_didFinalize = true; + } +} + +static JSClassRef Base_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) { + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.staticValues = Base_staticValues; + definition.staticFunctions = Base_staticFunctions; + definition.initialize = Base_initialize; + definition.finalize = Base_finalize; + jsClass = JSClassCreate(&definition); + } + return jsClass; +} + +static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get +} + +static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + UNUSED_PARAM(ctx); + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(value); + + *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set + return true; +} + +static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call +} + +static JSStaticFunction Derived_staticFunctions[] = { + { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone }, + { "protoDup", NULL, kJSPropertyAttributeNone }, + { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone }, + { 0, 0, 0 } +}; + +static JSStaticValue Derived_staticValues[] = { + { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone }, + { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone }, + { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone }, + { 0, 0, 0, 0 } +}; + +static void Derived_initialize(JSContextRef context, JSObjectRef object) +{ + UNUSED_PARAM(context); + + if (TestInitializeFinalize) { + ASSERT((void*)2 == JSObjectGetPrivate(object)); + JSObjectSetPrivate(object, (void*)3); + } +} + +static void Derived_finalize(JSObjectRef object) +{ + if (TestInitializeFinalize) { + ASSERT((void*)3 == JSObjectGetPrivate(object)); + JSObjectSetPrivate(object, (void*)4); + } +} + +static JSClassRef Derived_class(JSContextRef context) +{ + static JSClassRef jsClass; + if (!jsClass) { + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.parentClass = Base_class(context); + definition.staticValues = Derived_staticValues; + definition.staticFunctions = Derived_staticFunctions; + definition.initialize = Derived_initialize; + definition.finalize = Derived_finalize; + jsClass = JSClassCreate(&definition); + } + return jsClass; +} + +static JSClassRef Derived2_class(JSContextRef context) +{ + static JSClassRef jsClass; + if (!jsClass) { + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.parentClass = Derived_class(context); + jsClass = JSClassCreate(&definition); + } + return jsClass; +} + +static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(functionObject); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(exception); + + ASSERT(JSContextGetGlobalContext(ctx) == context); + + if (argumentCount > 0) { + JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL); + size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string); + char* stringUTF8 = (char*)malloc(sizeUTF8); + JSStringGetUTF8CString(string, stringUTF8, sizeUTF8); + printf("%s\n", stringUTF8); + free(stringUTF8); + JSStringRelease(string); + } + + return JSValueMakeUndefined(ctx); +} + +static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(constructorObject); + UNUSED_PARAM(exception); + + JSObjectRef result = JSObjectMake(context, NULL, NULL); + if (argumentCount > 0) { + JSStringRef value = JSStringCreateWithUTF8CString("value"); + JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL); + JSStringRelease(value); + } + + return result; +} + +static JSObjectRef myBadConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(constructorObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + return 0; +} + + +static void globalObject_initialize(JSContextRef context, JSObjectRef object) +{ + UNUSED_PARAM(object); + // Ensure that an execution context is passed in + ASSERT(context); + + JSObjectRef globalObject = JSContextGetGlobalObject(context); + ASSERT(globalObject); + + // Ensure that the standard global properties have been set on the global object + JSStringRef array = JSStringCreateWithUTF8CString("Array"); + JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL); + JSStringRelease(array); + + UNUSED_PARAM(arrayConstructor); + ASSERT(arrayConstructor); +} + +static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(exception); + + return JSValueMakeNumber(ctx, 3); +} + +static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) +{ + UNUSED_PARAM(object); + UNUSED_PARAM(propertyName); + UNUSED_PARAM(value); + + *exception = JSValueMakeNumber(ctx, 3); + return true; +} + +static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + return JSValueMakeNumber(ctx, 3); +} + +static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + JSGarbageCollect(context); + return JSValueMakeUndefined(context); +} + +static JSStaticValue globalObject_staticValues[] = { + { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone }, + { 0, 0, 0, 0 } +}; + +static JSStaticFunction globalObject_staticFunctions[] = { + { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone }, + { "globalStaticFunction2", globalObject_call, kJSPropertyAttributeNone }, + { "gc", functionGC, kJSPropertyAttributeNone }, + { 0, 0, 0 } +}; + +static char* createStringWithContentsOfFile(const char* fileName); + +static void testInitializeFinalize() +{ + JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1); + UNUSED_PARAM(o); + ASSERT(JSObjectGetPrivate(o) == (void*)3); +} + +static JSValueRef jsNumberValue = NULL; + +static JSObjectRef aHeapRef = NULL; + +static void makeGlobalNumberValue(JSContextRef context) { + JSValueRef v = JSValueMakeNumber(context, 420); + JSValueProtect(context, v); + jsNumberValue = v; + v = NULL; +} + +bool assertTrue(bool value, const char* message) +{ + if (!value) { + if (message) + fprintf(stderr, "assertTrue failed: '%s'\n", message); + else + fprintf(stderr, "assertTrue failed.\n"); + failed = 1; + } + return value; +} + +static bool checkForCycleInPrototypeChain() +{ + bool result = true; + JSGlobalContextRef context = JSGlobalContextCreate(0); + JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); + JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); + JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); + + JSObjectSetPrototype(context, object1, JSValueMakeNull(context)); + ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1))); + + // object1 -> object1 + JSObjectSetPrototype(context, object1, object1); + result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype"); + + // object1 -> object2 -> object1 + JSObjectSetPrototype(context, object2, object1); + ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1)); + JSObjectSetPrototype(context, object1, object2); + result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle"); + + // object1 -> object2 -> object3 -> object1 + JSObjectSetPrototype(context, object2, object3); + ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3)); + JSObjectSetPrototype(context, object1, object2); + ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2)); + JSObjectSetPrototype(context, object3, object1); + result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle"); + + JSValueRef exception; + JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o"); + JSStringRef file = JSStringCreateWithUTF8CString(""); + result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception) + , "An exception should be thrown"); + + JSStringRelease(code); + JSStringRelease(file); + JSGlobalContextRelease(context); + return result; +} + +static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + JSValueRef jsUndefined = JSValueMakeUndefined(JSContextGetGlobalContext(ctx)); + JSValueToObject(JSContextGetGlobalContext(ctx), jsUndefined, exception); + + return JSValueMakeUndefined(ctx); +} +static bool valueToObjectExceptionTest() +{ + JSGlobalContextRef testContext; + JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; + globalObjectClassDefinition.initialize = globalObject_initialize; + globalObjectClassDefinition.staticValues = globalObject_staticValues; + globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; + globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); + testContext = JSGlobalContextCreateInGroup(NULL, globalObjectClass); + JSObjectRef globalObject = JSContextGetGlobalObject(testContext); + + JSStringRef valueToObject = JSStringCreateWithUTF8CString("valueToObject"); + JSObjectRef valueToObjectFunction = JSObjectMakeFunctionWithCallback(testContext, valueToObject, valueToObjectExceptionCallAsFunction); + JSObjectSetProperty(testContext, globalObject, valueToObject, valueToObjectFunction, kJSPropertyAttributeNone, NULL); + JSStringRelease(valueToObject); + + JSStringRef test = JSStringCreateWithUTF8CString("valueToObject();"); + JSEvaluateScript(testContext, test, NULL, NULL, 1, NULL); + + JSStringRelease(test); + JSClassRelease(globalObjectClass); + JSGlobalContextRelease(testContext); + + return true; +} + +static bool globalContextNameTest() +{ + bool result = true; + JSGlobalContextRef context = JSGlobalContextCreate(0); + + JSStringRef str = JSGlobalContextCopyName(context); + result &= assertTrue(!str, "Default context name is NULL"); + + JSStringRef name1 = JSStringCreateWithUTF8CString("name1"); + JSStringRef name2 = JSStringCreateWithUTF8CString("name2"); + + JSGlobalContextSetName(context, name1); + JSStringRef fetchName1 = JSGlobalContextCopyName(context); + JSGlobalContextSetName(context, name2); + JSStringRef fetchName2 = JSGlobalContextCopyName(context); + 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; +} + +static void checkConstnessInJSObjectNames() +{ + JSStaticFunction fun; + fun.name = "something"; + JSStaticValue val; + val.name = "something"; +} + + +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 + + const char *scriptPath = "testapi.js"; + if (argc > 1) { + scriptPath = argv[1]; + } + + // Test garbage collection with a fresh context + context = JSGlobalContextCreateInGroup(NULL, NULL); + TestInitializeFinalize = true; + testInitializeFinalize(); + JSGlobalContextRelease(context); + TestInitializeFinalize = false; + + ASSERT(Base_didFinalize); + + JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; + globalObjectClassDefinition.initialize = globalObject_initialize; + globalObjectClassDefinition.staticValues = globalObject_staticValues; + globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; + globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); + context = JSGlobalContextCreateInGroup(NULL, globalObjectClass); + + JSContextGroupRef contextGroup = JSContextGetGroup(context); + + JSGlobalContextRetain(context); + JSGlobalContextRelease(context); + ASSERT(JSContextGetGlobalContext(context) == context); + + JSReportExtraMemoryCost(context, 0); + JSReportExtraMemoryCost(context, 1); + JSReportExtraMemoryCost(context, 1024); + + JSObjectRef globalObject = JSContextGetGlobalObject(context); + ASSERT(JSValueIsObject(context, globalObject)); + + JSValueRef jsUndefined = JSValueMakeUndefined(context); + JSValueRef jsNull = JSValueMakeNull(context); + JSValueRef jsTrue = JSValueMakeBoolean(context, true); + JSValueRef jsFalse = JSValueMakeBoolean(context, false); + JSValueRef jsZero = JSValueMakeNumber(context, 0); + JSValueRef jsOne = JSValueMakeNumber(context, 1); + JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0); + 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); + + JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1"); + JSValueRef jsOneString = JSValueMakeString(context, jsOneIString); + + UniChar singleUniChar = 65; // Capital A + CFMutableStringRef cfString = + CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, + &singleUniChar, + 1, + 1, + kCFAllocatorNull); + + JSStringRef jsCFIString = JSStringCreateWithCFString(cfString); + JSValueRef jsCFString = JSValueMakeString(context, jsCFIString); + + CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8); + + JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString); + JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString); + + CFIndex cfStringLength = CFStringGetLength(cfString); + UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar)); + CFStringGetCharacters(cfString, + CFRangeMake(0, cfStringLength), + buffer); + JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength); + JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters); + + JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString)); + free(buffer); + JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters); + + JSChar constantString[] = { 'H', 'e', 'l', 'l', 'o', }; + JSStringRef constantStringRef = JSStringCreateWithCharactersNoCopy(constantString, sizeof(constantString) / sizeof(constantString[0])); + ASSERT(JSStringGetCharactersPtr(constantStringRef) == constantString); + JSStringRelease(constantStringRef); + + ASSERT(JSValueGetType(context, NULL) == kJSTypeNull); + ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined); + ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull); + ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean); + ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean); + ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber); + ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber); + ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber); + ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString); + ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString); + ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString); + ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString); + ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString); + ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString); + + 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)); + ASSERT(JSValueIsNull(context, NULL)); + ASSERT(!JSObjectCallAsFunction(context, NULL, NULL, 0, NULL, NULL)); + ASSERT(!JSObjectCallAsConstructor(context, NULL, 0, NULL, NULL)); + ASSERT(!JSObjectIsConstructor(context, NULL)); + ASSERT(!JSObjectIsFunction(context, NULL)); + + JSStringRef nullString = JSStringCreateWithUTF8CString(0); + const JSChar* characters = JSStringGetCharactersPtr(nullString); + if (characters) { + printf("FAIL: Didn't return null when accessing character pointer of a null String.\n"); + failed = 1; + } else + printf("PASS: returned null when accessing character pointer of a null String.\n"); + + JSStringRef emptyString = JSStringCreateWithCFString(CFSTR("")); + characters = JSStringGetCharactersPtr(emptyString); + if (!characters) { + printf("FAIL: Returned null when accessing character pointer of an empty String.\n"); + failed = 1; + } else + printf("PASS: returned empty when accessing character pointer of an empty String.\n"); + + size_t length = JSStringGetLength(nullString); + if (length) { + printf("FAIL: Didn't return 0 length for null String.\n"); + failed = 1; + } else + printf("PASS: returned 0 length for null String.\n"); + JSStringRelease(nullString); + + length = JSStringGetLength(emptyString); + if (length) { + printf("FAIL: Didn't return 0 length for empty String.\n"); + failed = 1; + } else + printf("PASS: returned 0 length for empty String.\n"); + JSStringRelease(emptyString); + + JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL); + JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls"); + JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL); + JSStringRelease(propertyCatchallsString); + + JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL); + JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject"); + JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL); + JSStringRelease(myObjectIString); + + JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL); + JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject"); + JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL); + JSStringRelease(EvilExceptionObjectIString); + + JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL); + JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject"); + JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL); + JSStringRelease(EmptyObjectIString); + + JSStringRef lengthStr = JSStringCreateWithUTF8CString("length"); + JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0); + aHeapRef = aStackRef; + JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0); + JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty"); + if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) { + printf("FAIL: Could not set private property.\n"); + failed = 1; + } else + printf("PASS: Set private property.\n"); + aStackRef = 0; + if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) { + printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n"); + failed = 1; + } else + printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n"); + if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) { + printf("FAIL: Could not retrieve private property.\n"); + failed = 1; + } else + printf("PASS: Retrieved private property.\n"); + if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) { + printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n"); + failed = 1; + } else + printf("PASS: JSObjectGetPrivateProperty return NULL.\n"); + + if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) { + printf("FAIL: Accessed private property through ordinary property lookup.\n"); + failed = 1; + } else + printf("PASS: Cannot access private property through ordinary property lookup.\n"); + + JSGarbageCollect(context); + + for (int i = 0; i < 10000; i++) + JSObjectMake(context, 0, 0); + + aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0); + if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) { + printf("FAIL: Private property has been collected.\n"); + failed = 1; + } else + printf("PASS: Private property does not appear to have been collected.\n"); + JSStringRelease(lengthStr); + + if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) { + printf("FAIL: Could not set private property to NULL.\n"); + failed = 1; + } else + printf("PASS: Set private property to NULL.\n"); + if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) { + printf("FAIL: Could not retrieve private property.\n"); + failed = 1; + } else + printf("PASS: Retrieved private property.\n"); + + JSStringRef nullJSON = JSStringCreateWithUTF8CString(0); + JSValueRef nullJSONObject = JSValueMakeFromJSONString(context, nullJSON); + if (nullJSONObject) { + printf("FAIL: Did not parse null String as JSON correctly\n"); + failed = 1; + } else + printf("PASS: Parsed null String as JSON correctly.\n"); + JSStringRelease(nullJSON); + + JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}"); + JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON); + JSStringRelease(validJSON); + if (!JSValueIsObject(context, jsonObject)) { + printf("FAIL: Did not parse valid JSON correctly\n"); + failed = 1; + } else + printf("PASS: Parsed valid JSON string.\n"); + JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty"); + assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true); + JSStringRelease(propertyName); + JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!"); + if (JSValueMakeFromJSONString(context, invalidJSON)) { + printf("FAIL: Should return null for invalid JSON data\n"); + failed = 1; + } else + printf("PASS: Correctly returned null for invalid JSON data.\n"); + JSValueRef exception; + JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0); + if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) { + printf("FAIL: Did not correctly serialise with indent of 0.\n"); + failed = 1; + } else + printf("PASS: Correctly serialised with indent of 0.\n"); + JSStringRelease(str); + + str = JSValueCreateJSONString(context, jsonObject, 4, 0); + if (!JSStringIsEqualToUTF8CString(str, "{\n \"aProperty\": true\n}")) { + printf("FAIL: Did not correctly serialise with indent of 4.\n"); + failed = 1; + } else + printf("PASS: Correctly serialised with indent of 4.\n"); + JSStringRelease(str); + + str = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); + JSValueRef unstringifiableObj = JSEvaluateScript(context, str, NULL, NULL, 1, NULL); + JSStringRelease(str); + + str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0); + if (str) { + printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n"); + JSStringRelease(str); + failed = 1; + } else + printf("PASS: returned null when attempting to serialize unserializable value.\n"); + + str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception); + if (str) { + printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n"); + JSStringRelease(str); + failed = 1; + } else + printf("PASS: returned null when attempting to serialize unserializable value.\n"); + if (!exception) { + printf("FAIL: Did not set exception on serialisation error\n"); + failed = 1; + } else + printf("PASS: set exception on serialisation error\n"); + // Conversions that throw exceptions + exception = NULL; + ASSERT(NULL == JSValueToObject(context, jsNull, &exception)); + ASSERT(exception); + + exception = NULL; + // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function, + // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team. + // After that's resolved, we can remove these casts + ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception))); + ASSERT(exception); + + exception = NULL; + ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception)); + ASSERT(exception); + + ASSERT(JSValueToBoolean(context, myObject)); + + exception = NULL; + ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception)); + ASSERT(exception); + + exception = NULL; + JSObjectGetPropertyAtIndex(context, myObject, 0, &exception); + ASSERT(1 == JSValueToNumber(context, exception, NULL)); + + assertEqualsAsBoolean(jsUndefined, false); + assertEqualsAsBoolean(jsNull, false); + assertEqualsAsBoolean(jsTrue, true); + assertEqualsAsBoolean(jsFalse, false); + assertEqualsAsBoolean(jsZero, false); + assertEqualsAsBoolean(jsOne, true); + assertEqualsAsBoolean(jsOneThird, true); + assertEqualsAsBoolean(jsEmptyString, false); + assertEqualsAsBoolean(jsOneString, true); + assertEqualsAsBoolean(jsCFString, true); + assertEqualsAsBoolean(jsCFStringWithCharacters, true); + assertEqualsAsBoolean(jsCFEmptyString, false); + assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false); + + assertEqualsAsNumber(jsUndefined, nan("")); + assertEqualsAsNumber(jsNull, 0); + assertEqualsAsNumber(jsTrue, 1); + assertEqualsAsNumber(jsFalse, 0); + assertEqualsAsNumber(jsZero, 0); + assertEqualsAsNumber(jsOne, 1); + assertEqualsAsNumber(jsOneThird, 1.0 / 3.0); + assertEqualsAsNumber(jsEmptyString, 0); + assertEqualsAsNumber(jsOneString, 1); + assertEqualsAsNumber(jsCFString, nan("")); + assertEqualsAsNumber(jsCFStringWithCharacters, nan("")); + assertEqualsAsNumber(jsCFEmptyString, 0); + assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0); + ASSERT(sizeof(JSChar) == sizeof(UniChar)); + + assertEqualsAsCharactersPtr(jsUndefined, "undefined"); + assertEqualsAsCharactersPtr(jsNull, "null"); + assertEqualsAsCharactersPtr(jsTrue, "true"); + assertEqualsAsCharactersPtr(jsFalse, "false"); + assertEqualsAsCharactersPtr(jsZero, "0"); + assertEqualsAsCharactersPtr(jsOne, "1"); + assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333"); + assertEqualsAsCharactersPtr(jsEmptyString, ""); + assertEqualsAsCharactersPtr(jsOneString, "1"); + assertEqualsAsCharactersPtr(jsCFString, "A"); + assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A"); + assertEqualsAsCharactersPtr(jsCFEmptyString, ""); + assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, ""); + + assertEqualsAsUTF8String(jsUndefined, "undefined"); + assertEqualsAsUTF8String(jsNull, "null"); + assertEqualsAsUTF8String(jsTrue, "true"); + assertEqualsAsUTF8String(jsFalse, "false"); + assertEqualsAsUTF8String(jsZero, "0"); + assertEqualsAsUTF8String(jsOne, "1"); + assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333"); + assertEqualsAsUTF8String(jsEmptyString, ""); + assertEqualsAsUTF8String(jsOneString, "1"); + assertEqualsAsUTF8String(jsCFString, "A"); + assertEqualsAsUTF8String(jsCFStringWithCharacters, "A"); + assertEqualsAsUTF8String(jsCFEmptyString, ""); + assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, ""); + + checkConstnessInJSObjectNames(); + + ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue)); + ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString)); + + ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL)); + ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL)); + + CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString); + CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString); + ASSERT(CFEqual(cfJSString, cfString)); + ASSERT(CFEqual(cfJSEmptyString, cfEmptyString)); + CFRelease(cfJSString); + CFRelease(cfJSEmptyString); + + CFRelease(cfString); + CFRelease(cfEmptyString); + + jsGlobalValue = JSObjectMake(context, NULL, NULL); + makeGlobalNumberValue(context); + JSValueProtect(context, jsGlobalValue); + JSGarbageCollect(context); + ASSERT(JSValueIsObject(context, jsGlobalValue)); + JSValueUnprotect(context, jsGlobalValue); + JSValueUnprotect(context, jsNumberValue); + + JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;"); + const char* badSyntaxConstant = "x := 1;"; + JSStringRef badSyntax = JSStringCreateWithUTF8CString(badSyntaxConstant); + ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL)); + ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL)); + ASSERT(!JSScriptCreateFromString(contextGroup, 0, 0, badSyntax, 0, 0)); + ASSERT(!JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, badSyntaxConstant, strlen(badSyntaxConstant), 0, 0)); + + JSValueRef result; + JSValueRef v; + JSObjectRef o; + JSStringRef string; + + result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL); + ASSERT(result); + ASSERT(JSValueIsEqual(context, result, jsOne, NULL)); + + exception = NULL; + result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception); + ASSERT(!result); + ASSERT(JSValueIsObject(context, exception)); + + JSStringRef array = JSStringCreateWithUTF8CString("Array"); + JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL); + JSStringRelease(array); + result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL); + ASSERT(result); + ASSERT(JSValueIsObject(context, result)); + ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL)); + ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL)); + + o = JSValueToObject(context, result, NULL); + exception = NULL; + ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception))); + ASSERT(!exception); + + JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception); + ASSERT(!exception); + + exception = NULL; + ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception)); + ASSERT(!exception); + + JSStringRef functionBody; + JSObjectRef function; + + exception = NULL; + functionBody = JSStringCreateWithUTF8CString("rreturn Array;"); + JSStringRef 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, 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); + + exception = NULL; + functionBody = JSStringCreateWithUTF8CString("return Array;"); + function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception); + JSStringRelease(functionBody); + ASSERT(!exception); + ASSERT(JSObjectIsFunction(context, function)); + v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); + ASSERT(v); + ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL)); + + exception = NULL; + function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception); + ASSERT(!exception); + v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception); + ASSERT(v && !exception); + ASSERT(JSValueIsUndefined(context, v)); + + exception = NULL; + v = NULL; + JSStringRef foo = JSStringCreateWithUTF8CString("foo"); + JSStringRef argumentNames[] = { foo }; + functionBody = JSStringCreateWithUTF8CString("return foo;"); + function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception); + ASSERT(function && !exception); + JSValueRef arguments[] = { JSValueMakeNumber(context, 2) }; + JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception); + JSStringRelease(foo); + JSStringRelease(functionBody); + + string = JSValueToStringCopy(context, function, NULL); + assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) {\nreturn foo;\n}"); + JSStringRelease(string); + + JSStringRef print = JSStringCreateWithUTF8CString("print"); + JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction); + JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL); + JSStringRelease(print); + + ASSERT(!JSObjectSetPrivate(printFunction, (void*)1)); + ASSERT(!JSObjectGetPrivate(printFunction)); + + JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor"); + JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor); + JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL); + JSStringRelease(myConstructorIString); + + JSStringRef myBadConstructorIString = JSStringCreateWithUTF8CString("MyBadConstructor"); + JSObjectRef myBadConstructor = JSObjectMakeConstructor(context, NULL, myBadConstructor_callAsConstructor); + JSObjectSetProperty(context, globalObject, myBadConstructorIString, myBadConstructor, kJSPropertyAttributeNone, NULL); + JSStringRelease(myBadConstructorIString); + + ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1)); + ASSERT(!JSObjectGetPrivate(myConstructor)); + + string = JSStringCreateWithUTF8CString("Base"); + JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL); + JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL); + JSStringRelease(string); + + string = JSStringCreateWithUTF8CString("Derived"); + JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL); + JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL); + JSStringRelease(string); + + string = JSStringCreateWithUTF8CString("Derived2"); + JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL); + JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL); + JSStringRelease(string); + + o = JSObjectMake(context, NULL, NULL); + JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL); + JSObjectSetProperty(context, o, jsCFIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL); + JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o); + size_t expectedCount = JSPropertyNameArrayGetCount(nameArray); + size_t count; + for (count = 0; count < expectedCount; ++count) + JSPropertyNameArrayGetNameAtIndex(nameArray, count); + JSPropertyNameArrayRelease(nameArray); + ASSERT(count == 1); // jsCFString should not be enumerated + + JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) }; + o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL); + string = JSStringCreateWithUTF8CString("length"); + v = JSObjectGetProperty(context, o, string, NULL); + assertEqualsAsNumber(v, 2); + v = JSObjectGetPropertyAtIndex(context, o, 0, NULL); + assertEqualsAsNumber(v, 10); + v = JSObjectGetPropertyAtIndex(context, o, 1, NULL); + assertEqualsAsNumber(v, 20); + + o = JSObjectMakeArray(context, 0, NULL, NULL); + v = JSObjectGetProperty(context, o, string, NULL); + assertEqualsAsNumber(v, 0); + JSStringRelease(string); + + JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) }; + o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL); + if (timeZoneIsPST()) + assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)"); + + string = JSStringCreateWithUTF8CString("an error message"); + JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) }; + o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL); + assertEqualsAsUTF8String(o, "Error: an error message"); + JSStringRelease(string); + + string = JSStringCreateWithUTF8CString("foo"); + JSStringRef string2 = JSStringCreateWithUTF8CString("gi"); + JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) }; + o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL); + assertEqualsAsUTF8String(o, "/foo/gi"); + JSStringRelease(string); + JSStringRelease(string2); + + JSClassDefinition nullDefinition = kJSClassDefinitionEmpty; + nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + JSClassRef nullClass = JSClassCreate(&nullDefinition); + JSClassRelease(nullClass); + + nullDefinition = kJSClassDefinitionEmpty; + nullClass = JSClassCreate(&nullDefinition); + JSClassRelease(nullClass); + + functionBody = JSStringCreateWithUTF8CString("return this;"); + function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL); + JSStringRelease(functionBody); + v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); + ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); + v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL); + ASSERT(JSValueIsEqual(context, v, o, NULL)); + + functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");"); + function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL); + JSStringRelease(functionBody); + v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); + ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); + v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL); + ASSERT(JSValueIsEqual(context, v, o, NULL)); + + const char* thisScript = "this;"; + JSStringRef script = JSStringCreateWithUTF8CString(thisScript); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); + v = JSEvaluateScript(context, script, o, NULL, 1, NULL); + ASSERT(JSValueIsEqual(context, v, o, NULL)); + JSStringRelease(script); + + JSScriptRef scriptObject = JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, thisScript, strlen(thisScript), 0, 0); + v = JSScriptEvaluate(context, scriptObject, NULL, NULL); + ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); + v = JSScriptEvaluate(context, scriptObject, o, NULL); + ASSERT(JSValueIsEqual(context, v, o, NULL)); + JSScriptRelease(scriptObject); + + script = JSStringCreateWithUTF8CString("eval(this);"); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); + v = JSEvaluateScript(context, script, o, NULL, 1, NULL); + 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; + nullClass = JSClassCreate(&nullDefinition); + JSObjectMakeConstructor(context, nullClass, 0); + JSClassRelease(nullClass); + + char* scriptUTF8 = createStringWithContentsOfFile(scriptPath); + if (!scriptUTF8) { + printf("FAIL: Test script could not be loaded.\n"); + failed = 1; + } else { + JSStringRef url = JSStringCreateWithUTF8CString(scriptPath); + JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8); + JSStringRef errorMessage = 0; + int errorLine = 0; + JSScriptRef scriptObject = JSScriptCreateFromString(contextGroup, url, 1, script, &errorMessage, &errorLine); + ASSERT((!scriptObject) != (!errorMessage)); + if (!scriptObject) { + printf("FAIL: Test script did not parse\n\t%s:%d\n\t", scriptPath, errorLine); + CFStringRef errorCF = JSStringCopyCFString(kCFAllocatorDefault, errorMessage); + CFShow(errorCF); + CFRelease(errorCF); + JSStringRelease(errorMessage); + failed = 1; + } + + JSStringRelease(script); + exception = NULL; + result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0; + if (result && JSValueIsUndefined(context, result)) + printf("PASS: Test script executed successfully.\n"); + else { + printf("FAIL: Test script returned unexpected value:\n"); + JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL); + CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString); + CFShow(exceptionCF); + CFRelease(exceptionCF); + JSStringRelease(exceptionIString); + failed = 1; + } + JSScriptRelease(scriptObject); + free(scriptUTF8); + } + + // Check Promise is not exposed. + { + JSObjectRef globalObject = JSContextGetGlobalObject(context); + { + JSStringRef promiseProperty = JSStringCreateWithUTF8CString("Promise"); + ASSERT(JSObjectHasProperty(context, globalObject, promiseProperty)); + JSStringRelease(promiseProperty); + } + { + 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"); + } + + // Check microtasks. + { + 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); + } + + 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; + v = NULL; + o = NULL; + globalObject = NULL; + myConstructor = NULL; + + JSStringRelease(jsEmptyIString); + JSStringRelease(jsOneIString); + JSStringRelease(jsCFIString); + JSStringRelease(jsCFEmptyIString); + JSStringRelease(jsCFIStringWithCharacters); + JSStringRelease(jsCFEmptyIStringWithCharacters); + JSStringRelease(goodSyntax); + JSStringRelease(badSyntax); + + JSGlobalContextRelease(context); + JSClassRelease(globalObjectClass); + + // Test for an infinite prototype chain that used to be created. This test + // passes if the call to JSObjectHasProperty() does not hang. + + JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty; + prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions; + JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition); + JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass); + + JSStringRef nameProperty = JSStringCreateWithUTF8CString("name"); + JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty); + + JSGlobalContextRelease(prototypeLoopContext); + JSClassRelease(prototypeLoopClass); + + printf("PASS: Infinite prototype chain does not occur.\n"); + + if (checkForCycleInPrototypeChain()) + printf("PASS: A cycle in a prototype chain can't be created.\n"); + else { + 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"); + return 1; + } + + printf("PASS: Program exited normally.\n"); + return 0; +} + +static char* createStringWithContentsOfFile(const char* fileName) +{ + char* buffer; + + size_t buffer_size = 0; + size_t buffer_capacity = 1024; + buffer = (char*)malloc(buffer_capacity); + + FILE* f = fopen(fileName, "r"); + if (!f) { + fprintf(stderr, "Could not open file: %s\n", fileName); + free(buffer); + return 0; + } + + while (!feof(f) && !ferror(f)) { + buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f); + if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0' + buffer_capacity *= 2; + buffer = (char*)realloc(buffer, buffer_capacity); + ASSERT(buffer); + } + + ASSERT(buffer_size < buffer_capacity); + } + fclose(f); + buffer[buffer_size] = '\0'; + + 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 new file mode 100644 index 000000000..88d3701c2 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/testapi.js @@ -0,0 +1,307 @@ +/* + * 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 + * 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. + */ + +function bludgeonArguments() { if (0) arguments; return function g() {} } +h = bludgeonArguments(); +gc(); + +var failed = false; +function pass(msg) +{ + print("PASS: " + msg, "green"); +} + +function fail(msg) +{ + print("FAIL: " + msg, "red"); + failed = true; +} + +function shouldBe(a, b) +{ + var evalA; + try { + evalA = eval(a); + } catch(e) { + evalA = e; + } + + if (evalA == b || isNaN(evalA) && typeof evalA == 'number' && isNaN(b) && typeof b == 'number') + pass(a + " should be " + b + " and is."); + else + fail(a + " should be " + b + " but instead is " + evalA + "."); +} + +function shouldThrow(a) +{ + var evalA; + try { + eval(a); + } catch(e) { + pass(a + " threw: " + e); + return; + } + + fail(a + " did not throw an exception."); +} + +function globalStaticFunction() +{ + return 4; +} + +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; +shouldBe("MyObject.cantFind", undefined); +MyObject.regularType = 1; +shouldBe("MyObject.regularType", 1); +MyObject.alwaysOne = 2; +shouldBe("MyObject.alwaysOne", 1); +MyObject.cantDelete = 1; +delete MyObject.cantDelete; +shouldBe("MyObject.cantDelete", 1); +shouldBe("delete MyObject.throwOnDelete", "an exception"); +MyObject.cantSet = 1; +shouldBe("MyObject.cantSet", undefined); +shouldBe("MyObject.throwOnGet", "an exception"); +shouldBe("MyObject.throwOnSet = 5", "an exception"); +shouldBe("MyObject('throwOnCall')", "an exception"); +shouldBe("new MyObject('throwOnConstruct')", "an exception"); +shouldBe("'throwOnHasInstance' instanceof MyObject", "an exception"); + +MyObject.nullGetForwardSet = 1; +shouldBe("MyObject.nullGetForwardSet", 1); + +var foundMyPropertyName = false; +var foundRegularType = false; +for (var p in MyObject) { + if (p == "myPropertyName") + foundMyPropertyName = true; + if (p == "regularType") + foundRegularType = true; +} + +if (foundMyPropertyName) + pass("MyObject.myPropertyName was enumerated"); +else + fail("MyObject.myPropertyName was not enumerated"); + +if (foundRegularType) + pass("MyObject.regularType was enumerated"); +else + fail("MyObject.regularType was not enumerated"); + +var alwaysOneDescriptor = Object.getOwnPropertyDescriptor(MyObject, "alwaysOne"); +shouldBe('typeof alwaysOneDescriptor', "object"); +shouldBe('alwaysOneDescriptor.value', MyObject.alwaysOne); +shouldBe('alwaysOneDescriptor.configurable', true); +shouldBe('alwaysOneDescriptor.enumerable', false); // Actually it is. +var cantFindDescriptor = Object.getOwnPropertyDescriptor(MyObject, "cantFind"); +shouldBe('typeof cantFindDescriptor', "object"); +shouldBe('cantFindDescriptor.value', MyObject.cantFind); +shouldBe('cantFindDescriptor.configurable', true); +shouldBe('cantFindDescriptor.enumerable', false); +try { + // If getOwnPropertyDescriptor() returned an access descriptor, this wouldn't throw. + Object.getOwnPropertyDescriptor(MyObject, "throwOnGet"); +} catch (e) { + pass("getting property descriptor of throwOnGet threw exception"); +} +var myPropertyNameDescriptor = Object.getOwnPropertyDescriptor(MyObject, "myPropertyName"); +shouldBe('typeof myPropertyNameDescriptor', "object"); +shouldBe('myPropertyNameDescriptor.value', MyObject.myPropertyName); +shouldBe('myPropertyNameDescriptor.configurable', true); +shouldBe('myPropertyNameDescriptor.enumerable', false); // Actually it is. +try { + // if getOwnPropertyDescriptor() returned an access descriptor, this wouldn't throw. + Object.getOwnPropertyDescriptor(MyObject, "hasPropertyLie"); +} catch (e) { + pass("getting property descriptor of hasPropertyLie threw exception"); +} +shouldBe('Object.getOwnPropertyDescriptor(MyObject, "doesNotExist")', undefined); + +myObject = new MyObject(); + +shouldBe("delete MyObject.regularType", true); +shouldBe("MyObject.regularType", undefined); +shouldBe("MyObject(0)", 1); +shouldBe("MyObject()", undefined); +shouldBe("typeof myObject", "object"); +shouldBe("MyObject ? 1 : 0", true); // toBoolean +shouldBe("+MyObject", 1); // toNumber +shouldBe("(Object.prototype.toString.call(MyObject))", "[object MyObject]"); // Object.prototype.toString +shouldBe("(MyObject.toString())", "[object MyObject]"); // toString +shouldBe("String(MyObject)", "MyObjectAsString"); // toString +shouldBe("MyObject - 0", 1); // toNumber +shouldBe("MyObject.valueOf()", 1); // valueOf + +shouldBe("typeof MyConstructor", "object"); +constructedObject = new MyConstructor(1); +shouldBe("typeof constructedObject", "object"); +shouldBe("constructedObject.value", 1); +shouldBe("myObject instanceof MyObject", true); +shouldBe("(new Object()) instanceof MyObject", false); + +shouldThrow("new MyBadConstructor()"); + +MyObject.nullGetSet = 1; +shouldBe("MyObject.nullGetSet", 1); +shouldThrow("MyObject.nullCall()"); +shouldThrow("MyObject.hasPropertyLie"); + +derived = new Derived(); + +shouldBe("derived instanceof Derived", true); +shouldBe("derived instanceof Base", true); + +// base properties and functions return 1 when called/gotten; derived, 2 +shouldBe("derived.baseProtoDup()", 2); +shouldBe("derived.baseProto()", 1); +shouldBe("derived.baseDup", 2); +shouldBe("derived.baseOnly", 1); +shouldBe("derived.protoOnly()", 2); +shouldBe("derived.protoDup", 2); +shouldBe("derived.derivedOnly", 2) + +shouldBe("derived.baseHardNull()", undefined) + +// base properties throw 1 when set; derived, 2 +shouldBe("derived.baseDup = 0", 2); +shouldBe("derived.baseOnly = 0", 1); +shouldBe("derived.derivedOnly = 0", 2) +shouldBe("derived.protoDup = 0", 2); + +derived2 = new Derived2(); + +shouldBe("derived2 instanceof Derived2", true); +shouldBe("derived2 instanceof Derived", true); +shouldBe("derived2 instanceof Base", true); + +// base properties and functions return 1 when called/gotten; derived, 2 +shouldBe("derived2.baseProtoDup()", 2); +shouldBe("derived2.baseProto()", 1); +shouldBe("derived2.baseDup", 2); +shouldBe("derived2.baseOnly", 1); +shouldBe("derived2.protoOnly()", 2); +shouldBe("derived2.protoDup", 2); +shouldBe("derived2.derivedOnly", 2) + +// base properties throw 1 when set; derived, 2 +shouldBe("derived2.baseDup = 0", 2); +shouldBe("derived2.baseOnly = 0", 1); +shouldBe("derived2.derivedOnly = 0", 2) +shouldBe("derived2.protoDup = 0", 2); + +shouldBe('Object.getOwnPropertyDescriptor(derived, "baseProto")', undefined); +shouldBe('Object.getOwnPropertyDescriptor(derived, "baseProtoDup")', undefined); +var baseDupDescriptor = Object.getOwnPropertyDescriptor(derived, "baseDup"); +shouldBe('typeof baseDupDescriptor', "object"); +shouldBe('baseDupDescriptor.value', derived.baseDup); +shouldBe('baseDupDescriptor.configurable', true); +shouldBe('baseDupDescriptor.enumerable', false); +var baseOnlyDescriptor = Object.getOwnPropertyDescriptor(derived, "baseOnly"); +shouldBe('typeof baseOnlyDescriptor', "object"); +shouldBe('baseOnlyDescriptor.value', derived.baseOnly); +shouldBe('baseOnlyDescriptor.configurable', true); +shouldBe('baseOnlyDescriptor.enumerable', false); +shouldBe('Object.getOwnPropertyDescriptor(derived, "protoOnly")', undefined); +var protoDupDescriptor = Object.getOwnPropertyDescriptor(derived, "protoDup"); +shouldBe('typeof protoDupDescriptor', "object"); +shouldBe('protoDupDescriptor.value', derived.protoDup); +shouldBe('protoDupDescriptor.configurable', true); +shouldBe('protoDupDescriptor.enumerable', false); +var derivedOnlyDescriptor = Object.getOwnPropertyDescriptor(derived, "derivedOnly"); +shouldBe('typeof derivedOnlyDescriptor', "object"); +shouldBe('derivedOnlyDescriptor.value', derived.derivedOnly); +shouldBe('derivedOnlyDescriptor.configurable', true); +shouldBe('derivedOnlyDescriptor.enumerable', false); + +shouldBe("undefined instanceof MyObject", false); +EvilExceptionObject.hasInstance = function f() { return f(); }; +EvilExceptionObject.__proto__ = undefined; +shouldThrow("undefined instanceof EvilExceptionObject"); +EvilExceptionObject.hasInstance = function () { return true; }; +shouldBe("undefined instanceof EvilExceptionObject", true); + +EvilExceptionObject.toNumber = function f() { return f(); } +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) + PropertyCatchalls.x = i; +shouldBe("PropertyCatchalls.x", 4); + +for (var i = 0; i < 6; ++i) + var x = PropertyCatchalls.x; +shouldBe("x", null); +var make_throw = 'make_throw'; +shouldThrow("PropertyCatchalls[make_throw]=1"); +make_throw = 0; +shouldThrow("PropertyCatchalls[make_throw]=1"); + +for (var i = 0; i < 10; ++i) { + for (var p in PropertyCatchalls) { + if (p == "x") + continue; + shouldBe("p", i % 10); + break; + } +} + +PropertyCatchalls.__proto__ = { y: 1 }; +for (var i = 0; i < 6; ++i) + var y = PropertyCatchalls.y; +shouldBe("y", null); + +var o = { __proto__: PropertyCatchalls }; +for (var i = 0; i < 6; ++i) + var z = PropertyCatchalls.z; +shouldBe("z", null); + +if (failed) + throw "Some tests failed"; |