diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/JavaScriptCore/API/tests | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/JavaScriptCore/API/tests')
28 files changed, 1505 insertions, 1103 deletions
diff --git a/Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp new file mode 100644 index 000000000..525ebc9cc --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CompareAndSwapTest.h" + +#include <stdio.h> +#include <wtf/Atomics.h> +#include <wtf/Threading.h> + +class Bitmap { +public: + Bitmap() { clearAll(); } + + inline void clearAll(); + inline bool concurrentTestAndSet(size_t n); + inline size_t numBits() const { return words * wordSize; } + +private: + static const size_t Size = 4096*10; + + static const unsigned wordSize = sizeof(uint8_t) * 8; + static const unsigned words = (Size + wordSize - 1) / wordSize; + static const uint8_t one = 1; + + uint8_t bits[words]; +}; + +inline void Bitmap::clearAll() +{ + memset(&bits, 0, sizeof(bits)); +} + +inline bool Bitmap::concurrentTestAndSet(size_t n) +{ + uint8_t mask = one << (n % wordSize); + size_t index = n / wordSize; + uint8_t* wordPtr = &bits[index]; + uint8_t oldValue; + do { + oldValue = *wordPtr; + if (oldValue & mask) + return true; + } while (!WTF::weakCompareAndSwap(wordPtr, oldValue, static_cast<uint8_t>(oldValue | mask))); + return false; +} + +struct Data { + Bitmap* bitmap; + int id; + int numThreads; +}; + +static void setBitThreadFunc(void* p) +{ + Data* data = reinterpret_cast<Data*>(p); + Bitmap* bitmap = data->bitmap; + size_t numBits = bitmap->numBits(); + + // The computed start index here is heuristic that seems to maximize (anecdotally) + // the chance for the CAS issue to manifest. + size_t start = (numBits * (data->numThreads - data->id)) / data->numThreads; + + printf(" started Thread %d\n", data->id); + for (size_t i = start; i < numBits; i++) + while (!bitmap->concurrentTestAndSet(i)) { } + for (size_t i = 0; i < start; i++) + while (!bitmap->concurrentTestAndSet(i)) { } + + printf(" finished Thread %d\n", data->id); +} + +void testCompareAndSwap() +{ + Bitmap bitmap; + const int numThreads = 5; + ThreadIdentifier threadIDs[numThreads]; + Data data[numThreads]; + + WTF::initializeThreading(); + + printf("Starting %d threads for CompareAndSwap test. Test should complete without hanging.\n", numThreads); + for (int i = 0; i < numThreads; i++) { + data[i].bitmap = &bitmap; + data[i].id = i; + data[i].numThreads = numThreads; + std::function<void()> threadFunc = std::bind(setBitThreadFunc, &data[i]); + threadIDs[i] = createThread("setBitThreadFunc", threadFunc); + } + + printf("Waiting for %d threads to join\n", numThreads); + for (int i = 0; i < numThreads; i++) + waitForThreadCompletion(threadIDs[i]); + + printf("PASS: CompareAndSwap test completed without a hang\n"); +} diff --git a/Source/JavaScriptCore/API/tests/CompareAndSwapTest.h b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.h new file mode 100644 index 000000000..73fa0de13 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CompareAndSwapTest.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CompareAndSwapTest_h +#define CompareAndSwapTest_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Regression test for webkit.org/b/142513 */ +void testCompareAndSwap(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* CompareAndSwapTest_h */ diff --git a/Source/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h b/Source/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h new file mode 100644 index 000000000..f228333c4 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CurrentThisInsideBlockGetterTest_h +#define CurrentThisInsideBlockGetterTest_h + +#include <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void currentThisInsideBlockGetterTest(); + +#endif // JSC_OBJC_API_ENABLED + + +#endif // CurrentThisInsideBlockGetterTest_h diff --git a/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.c b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.c new file mode 100644 index 000000000..62e63978e --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "CustomGlobalObjectClassTest.h" + +#include <JavaScriptCore/JSObjectRefPrivate.h> +#include <JavaScriptCore/JavaScriptCore.h> +#include <stdio.h> + +extern bool assertTrue(bool value, const char* message); + +static bool executedCallback = false; + +static JSValueRef jsDoSomething(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef args[], JSValueRef* exception) +{ + (void)function; + (void)thisObject; + (void)argc; + (void)args; + (void)exception; + executedCallback = true; + return JSValueMakeNull(ctx); +} + +static JSStaticFunction bridgedFunctions[] = { + {"doSomething", jsDoSomething, kJSPropertyAttributeDontDelete}, + {0, 0, 0}, +}; + +static JSClassRef bridgedObjectClass = NULL; +static JSClassDefinition bridgedClassDef; + +static JSClassRef jsClassRef() +{ + if (!bridgedObjectClass) { + bridgedClassDef = kJSClassDefinitionEmpty; + bridgedClassDef.className = "BridgedObject"; + bridgedClassDef.staticFunctions = bridgedFunctions; + bridgedObjectClass = JSClassCreate(&bridgedClassDef); + } + return bridgedObjectClass; +} + +void customGlobalObjectClassTest() +{ + JSClassRef bridgedObjectJsClassRef = jsClassRef(); + JSGlobalContextRef globalContext = JSGlobalContextCreate(bridgedObjectJsClassRef); + + JSObjectRef globalObj = JSContextGetGlobalObject(globalContext); + + JSPropertyNameArrayRef propertyNames = JSObjectCopyPropertyNames(globalContext, globalObj); + size_t propertyCount = JSPropertyNameArrayGetCount(propertyNames); + assertTrue(propertyCount == 1, "Property count == 1"); + + JSStringRef propertyNameRef = JSPropertyNameArrayGetNameAtIndex(propertyNames, 0); + size_t propertyNameLength = JSStringGetLength(propertyNameRef); + size_t bufferSize = sizeof(char) * (propertyNameLength + 1); + char* buffer = (char*)malloc(bufferSize); + JSStringGetUTF8CString(propertyNameRef, buffer, bufferSize); + buffer[propertyNameLength] = '\0'; + assertTrue(!strncmp(buffer, "doSomething", propertyNameLength), "First property name is doSomething"); + free(buffer); + + bool hasMethod = JSObjectHasProperty(globalContext, globalObj, propertyNameRef); + assertTrue(hasMethod, "Property found by name"); + + JSValueRef doSomethingProperty = + JSObjectGetProperty(globalContext, globalObj, propertyNameRef, NULL); + assertTrue(!JSValueIsUndefined(globalContext, doSomethingProperty), "Property is defined"); + + bool globalObjectClassMatchesClassRef = JSValueIsObjectOfClass(globalContext, globalObj, bridgedObjectJsClassRef); + assertTrue(globalObjectClassMatchesClassRef, "Global object is the right class"); + + JSStringRef script = JSStringCreateWithUTF8CString("doSomething();"); + JSEvaluateScript(globalContext, script, NULL, NULL, 1, NULL); + JSStringRelease(script); + + assertTrue(executedCallback, "Executed custom global object callback"); +} + +void globalObjectSetPrototypeTest() +{ + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.className = "Global"; + JSClassRef global = JSClassCreate(&definition); + JSGlobalContextRef context = JSGlobalContextCreate(global); + JSObjectRef object = JSContextGetGlobalObject(context); + + JSObjectRef above = JSObjectMake(context, 0, 0); + JSStringRef test = JSStringCreateWithUTF8CString("test"); + JSValueRef value = JSValueMakeString(context, test); + JSObjectSetProperty(context, above, test, value, kJSPropertyAttributeDontEnum, 0); + + JSObjectSetPrototype(context, object, above); + JSStringRef script = JSStringCreateWithUTF8CString("test === \"test\""); + JSValueRef result = JSEvaluateScript(context, script, 0, 0, 0, 0); + + assertTrue(JSValueToBoolean(context, result), "test === \"test\""); + + JSStringRelease(test); + JSStringRelease(script); +} + +void globalObjectPrivatePropertyTest() +{ + JSClassDefinition definition = kJSClassDefinitionEmpty; + definition.className = "Global"; + JSClassRef global = JSClassCreate(&definition); + JSGlobalContextRef context = JSGlobalContextCreate(global); + JSObjectRef globalObject = JSContextGetGlobalObject(context); + + JSStringRef privateName = JSStringCreateWithUTF8CString("private"); + JSValueRef privateValue = JSValueMakeString(context, privateName); + assertTrue(JSObjectSetPrivateProperty(context, globalObject, privateName, privateValue), "JSObjectSetPrivateProperty succeeded"); + JSValueRef result = JSObjectGetPrivateProperty(context, globalObject, privateName); + assertTrue(JSValueIsStrictEqual(context, privateValue, result), "privateValue === \"private\""); + + assertTrue(JSObjectDeletePrivateProperty(context, globalObject, privateName), "JSObjectDeletePrivateProperty succeeded"); + result = JSObjectGetPrivateProperty(context, globalObject, privateName); + assertTrue(JSValueIsNull(context, result), "Deleted private property is indeed no longer present"); + + JSStringRelease(privateName); +} diff --git a/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.h b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.h new file mode 100644 index 000000000..86914ca6f --- /dev/null +++ b/Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CustomGlobalObjectClassTest_h +#define CustomGlobalObjectClassTest_h + +void customGlobalObjectClassTest(void); +void globalObjectSetPrototypeTest(void); +void globalObjectPrivatePropertyTest(void); + +#endif // CustomGlobalObjectClassTest_h diff --git a/Source/JavaScriptCore/API/tests/DateTests.h b/Source/JavaScriptCore/API/tests/DateTests.h new file mode 100644 index 000000000..eeb47a165 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/DateTests.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runDateTests(); + +#endif // JSC_OBJC_API_ENABLED diff --git a/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp new file mode 100644 index 000000000..fc8cc10aa --- /dev/null +++ b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ExecutionTimeLimitTest.h" + +#include "InitializeThreading.h" +#include "JSContextRefPrivate.h" +#include "JavaScriptCore.h" +#include "Options.h" +#include <chrono> +#include <wtf/CurrentTime.h> +#include <wtf/text/StringBuilder.h> + +using namespace std::chrono; +using JSC::Options; + +static JSGlobalContextRef context = nullptr; + +static JSValueRef currentCPUTimeAsJSFunctionCallback(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(functionObject); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + ASSERT(JSContextGetGlobalContext(ctx) == context); + return JSValueMakeNumber(ctx, currentCPUTime().count() / 1000000.); +} + +bool shouldTerminateCallbackWasCalled = false; +static bool shouldTerminateCallback(JSContextRef, void*) +{ + shouldTerminateCallbackWasCalled = true; + return true; +} + +bool cancelTerminateCallbackWasCalled = false; +static bool cancelTerminateCallback(JSContextRef, void*) +{ + cancelTerminateCallbackWasCalled = true; + return false; +} + +int extendTerminateCallbackCalled = 0; +static bool extendTerminateCallback(JSContextRef ctx, void*) +{ + extendTerminateCallbackCalled++; + if (extendTerminateCallbackCalled == 1) { + JSContextGroupRef contextGroup = JSContextGetGroup(ctx); + JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); + return false; + } + return true; +} + +struct TierOptions { + const char* tier; + unsigned timeLimitAdjustmentMillis; + const char* optionsStr; +}; + +static void testResetAfterTimeout(bool& failed) +{ + JSValueRef v = nullptr; + JSValueRef exception = nullptr; + const char* reentryScript = "100"; + JSStringRef script = JSStringCreateWithUTF8CString(reentryScript); + v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + if (exception) { + printf("FAIL: Watchdog timeout was not reset.\n"); + failed = true; + } else if (!JSValueIsNumber(context, v) || JSValueToNumber(context, v, nullptr) != 100) { + printf("FAIL: Script result is not as expected.\n"); + failed = true; + } +} + +int testExecutionTimeLimit() +{ + static const TierOptions tierOptionsList[] = { + { "LLINT", 0, "--useConcurrentJIT=false --useLLInt=true --useJIT=false" }, + { "Baseline", 0, "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=false" }, + { "DFG", 0, "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=false" }, + { "FTL", 200, "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=true" }, + }; + + bool failed = false; + + JSC::initializeThreading(); + Options::initialize(); // Ensure options is initialized first. + + for (auto tierOptions : tierOptionsList) { + StringBuilder savedOptionsBuilder; + Options::dumpAllOptionsInALine(savedOptionsBuilder); + + Options::setOptions(tierOptions.optionsStr); + + unsigned tierAdjustmentMillis = tierOptions.timeLimitAdjustmentMillis; + double timeLimit; + + context = JSGlobalContextCreateInGroup(nullptr, nullptr); + + JSContextGroupRef contextGroup = JSContextGetGroup(context); + JSObjectRef globalObject = JSContextGetGlobalObject(context); + ASSERT(JSValueIsObject(context, globalObject)); + + JSValueRef exception = nullptr; + + JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime"); + JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTimeAsJSFunctionCallback); + JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, nullptr); + JSStringRelease(currentCPUTimeStr); + + /* Test script timeout: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && shouldTerminateCallbackWasCalled) + printf("PASS: %s script timed out as expected.\n", tierOptions.tier); + else { + if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) + printf("FAIL: %s script did not time out as expected.\n", tierOptions.tier); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (!exception) { + printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test script timeout with tail calls: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("var startTime = currentCPUTime();" + "function recurse(i) {" + "'use strict';" + "if (i % 1000 === 0) {" + "if (currentCPUTime() - startTime >"); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(" ) { return; }"); + scriptBuilder.append(" }"); + scriptBuilder.append(" return recurse(i + 1); }"); + scriptBuilder.append("recurse(0);"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && shouldTerminateCallbackWasCalled) + printf("PASS: %s script with infinite tail calls timed out as expected .\n", tierOptions.tier); + else { + if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) + printf("FAIL: %s script with infinite tail calls did not time out as expected.\n", tierOptions.tier); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: %s script with infinite tail calls' timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (!exception) { + printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, shouldTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); try { while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } catch(e) { } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) || !shouldTerminateCallbackWasCalled) { + if (!((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired))) + printf("FAIL: %s script did not time out as expected.\n", tierOptions.tier); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (exception) + printf("PASS: %s TerminatedExecutionException was not catchable as expected.\n", tierOptions.tier); + else { + printf("FAIL: %s TerminatedExecutionException was caught.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test script timeout with no callback: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, 0, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) && !shouldTerminateCallbackWasCalled) + printf("PASS: %s script timed out as expected when no callback is specified.\n", tierOptions.tier); + else { + if ((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) + printf("FAIL: %s script did not time out as expected when no callback is specified.\n", tierOptions.tier); + else + printf("FAIL: %s script called stale callback function.\n", tierOptions.tier); + failed = true; + } + + if (!exception) { + printf("FAIL: %s TerminatedExecutionException was not thrown.\n", tierOptions.tier); + failed = true; + } + + testResetAfterTimeout(failed); + } + + /* Test script timeout cancellation: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, cancelTerminateCallback, 0); + { + unsigned timeAfterWatchdogShouldHaveFired = 300 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(timeAfterWatchdogShouldHaveFired / 1000.0); + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + cancelTerminateCallbackWasCalled = false; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + + if (((endTime - startTime) >= milliseconds(timeAfterWatchdogShouldHaveFired)) && cancelTerminateCallbackWasCalled && !exception) + printf("PASS: %s script timeout was cancelled as expected.\n", tierOptions.tier); + else { + if (((endTime - startTime) < milliseconds(timeAfterWatchdogShouldHaveFired)) || exception) + printf("FAIL: %s script timeout was not cancelled.\n", tierOptions.tier); + if (!cancelTerminateCallbackWasCalled) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + failed = true; + } + + if (exception) { + printf("FAIL: %s Unexpected TerminatedExecutionException thrown.\n", tierOptions.tier); + failed = true; + } + } + + /* Test script timeout extension: */ + timeLimit = (100 + tierAdjustmentMillis) / 1000.0; + JSContextGroupSetExecutionTimeLimit(contextGroup, timeLimit, extendTerminateCallback, 0); + { + unsigned timeBeforeExtendedDeadline = 250 + tierAdjustmentMillis; + unsigned timeAfterExtendedDeadline = 600 + tierAdjustmentMillis; + unsigned maxBusyLoopTime = 750 + tierAdjustmentMillis; + + StringBuilder scriptBuilder; + scriptBuilder.append("function foo() { var startTime = currentCPUTime(); while (true) { for (var i = 0; i < 1000; i++); if (currentCPUTime() - startTime > "); + scriptBuilder.appendNumber(maxBusyLoopTime / 1000.0); // in seconds. + scriptBuilder.append(") break; } } foo();"); + + JSStringRef script = JSStringCreateWithUTF8CString(scriptBuilder.toString().utf8().data()); + exception = nullptr; + extendTerminateCallbackCalled = 0; + + auto startTime = currentCPUTime(); + JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + auto endTime = currentCPUTime(); + auto deltaTime = endTime - startTime; + + if ((deltaTime >= milliseconds(timeBeforeExtendedDeadline)) && (deltaTime < milliseconds(timeAfterExtendedDeadline)) && (extendTerminateCallbackCalled == 2) && exception) + printf("PASS: %s script timeout was extended as expected.\n", tierOptions.tier); + else { + if (deltaTime < milliseconds(timeBeforeExtendedDeadline)) + printf("FAIL: %s script timeout was not extended as expected.\n", tierOptions.tier); + else if (deltaTime >= milliseconds(timeAfterExtendedDeadline)) + printf("FAIL: %s script did not timeout.\n", tierOptions.tier); + + if (extendTerminateCallbackCalled < 1) + printf("FAIL: %s script timeout callback was not called.\n", tierOptions.tier); + if (extendTerminateCallbackCalled < 2) + printf("FAIL: %s script timeout callback was not called after timeout extension.\n", tierOptions.tier); + + if (!exception) + printf("FAIL: %s TerminatedExecutionException was not thrown during timeout extension test.\n", tierOptions.tier); + + failed = true; + } + } + + JSGlobalContextRelease(context); + + Options::setOptions(savedOptionsBuilder.toString().ascii().data()); + } + + return failed; +} diff --git a/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.h b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.h new file mode 100644 index 000000000..8294a86a6 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ExecutionTimeLimitTest_h +#define ExecutionTimeLimitTest_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns 1 if failures were encountered. Else, returns 0. */ +int testExecutionTimeLimit(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ExecutionTimeLimitTest_h */ diff --git a/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp new file mode 100644 index 000000000..7023bc365 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlobalContextWithFinalizerTest.h" + +#include "JavaScriptCore.h" +#include <wtf/DataLog.h> + +static bool failed = true; + +static void finalize(JSObjectRef) +{ + failed = false; +} + +int testGlobalContextWithFinalizer() +{ + JSClassDefinition def = kJSClassDefinitionEmpty; + def.className = "testClass"; + def.finalize = finalize; + JSClassRef classRef = JSClassCreate(&def); + + JSGlobalContextRef ref = JSGlobalContextCreateInGroup(nullptr, classRef); + JSGlobalContextRelease(ref); + JSClassRelease(classRef); + + if (failed) + printf("FAIL: JSGlobalContextRef did not call its JSClassRef finalizer.\n"); + else + printf("PASS: JSGlobalContextRef called its JSClassRef finalizer as expected.\n"); + + return failed; +} diff --git a/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h new file mode 100644 index 000000000..55b439fff --- /dev/null +++ b/Source/JavaScriptCore/API/tests/GlobalContextWithFinalizerTest.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GlobalContextWithFinalizerTest_h +#define GlobalContextWithFinalizerTest_h + +#include "JSContextRefPrivate.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns 1 if failures were encountered. Else, returns 0. */ +int testGlobalContextWithFinalizer(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GlobalContextWithFinalizerTest_h */ diff --git a/Source/JavaScriptCore/API/tests/JSExportTests.h b/Source/JavaScriptCore/API/tests/JSExportTests.h new file mode 100644 index 000000000..9d501ee7e --- /dev/null +++ b/Source/JavaScriptCore/API/tests/JSExportTests.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runJSExportTests(); + +#endif // JSC_OBJC_API_ENABLED + diff --git a/Source/JavaScriptCore/API/tests/JSNode.c b/Source/JavaScriptCore/API/tests/JSNode.c index d9a40bea6..d0a0dc3ec 100644 --- a/Source/JavaScriptCore/API/tests/JSNode.c +++ b/Source/JavaScriptCore/API/tests/JSNode.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,6 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JSNode.h" #include "JSNodeList.h" #include "JSObjectRef.h" diff --git a/Source/JavaScriptCore/API/tests/JSNode.h b/Source/JavaScriptCore/API/tests/JSNode.h index 7725733ca..a6aee2f7b 100644 --- a/Source/JavaScriptCore/API/tests/JSNode.h +++ b/Source/JavaScriptCore/API/tests/JSNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/JavaScriptCore/API/tests/JSNodeList.c b/Source/JavaScriptCore/API/tests/JSNodeList.c index 61d7041a4..f037e094a 100644 --- a/Source/JavaScriptCore/API/tests/JSNodeList.c +++ b/Source/JavaScriptCore/API/tests/JSNodeList.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,6 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JSNode.h" #include "JSNodeList.h" #include "JSObjectRef.h" diff --git a/Source/JavaScriptCore/API/tests/JSNodeList.h b/Source/JavaScriptCore/API/tests/JSNodeList.h index f9309142e..d3eb52bb9 100644 --- a/Source/JavaScriptCore/API/tests/JSNodeList.h +++ b/Source/JavaScriptCore/API/tests/JSNodeList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/JavaScriptCore/API/tests/Node.c b/Source/JavaScriptCore/API/tests/Node.c index 913da0a2a..db687e952 100644 --- a/Source/JavaScriptCore/API/tests/Node.c +++ b/Source/JavaScriptCore/API/tests/Node.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/JavaScriptCore/API/tests/Node.h b/Source/JavaScriptCore/API/tests/Node.h index e9250b3ae..41b5d493a 100644 --- a/Source/JavaScriptCore/API/tests/Node.h +++ b/Source/JavaScriptCore/API/tests/Node.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/JavaScriptCore/API/tests/NodeList.c b/Source/JavaScriptCore/API/tests/NodeList.c index ae4c17062..69f4cd5c4 100644 --- a/Source/JavaScriptCore/API/tests/NodeList.c +++ b/Source/JavaScriptCore/API/tests/NodeList.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/JavaScriptCore/API/tests/NodeList.h b/Source/JavaScriptCore/API/tests/NodeList.h index 25b95bf4d..020b76f59 100644 --- a/Source/JavaScriptCore/API/tests/NodeList.h +++ b/Source/JavaScriptCore/API/tests/NodeList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp new file mode 100644 index 000000000..33f0772b3 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PingPongStackOverflowTest.h" + +#include "InitializeThreading.h" +#include "JSContextRefPrivate.h" +#include "JavaScriptCore.h" +#include "Options.h" +#include <wtf/text/StringBuilder.h> + +using JSC::Options; + +static JSGlobalContextRef context = nullptr; +static int nativeRecursionCount = 0; + +static bool PingPongStackOverflowObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) +{ + UNUSED_PARAM(context); + UNUSED_PARAM(constructor); + + JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance"); + JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception); + JSStringRelease(hasInstanceName); + if (!hasInstance) + return false; + + int countAtEntry = nativeRecursionCount++; + + JSValueRef result = 0; + if (nativeRecursionCount < 100) { + JSObjectRef function = JSValueToObject(context, hasInstance, exception); + result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception); + } else { + StringBuilder builder; + builder.append("dummy.valueOf([0]"); + for (int i = 1; i < 35000; i++) { + builder.append(", ["); + builder.appendNumber(i); + builder.append("]"); + } + builder.append(");"); + + JSStringRef script = JSStringCreateWithUTF8CString(builder.toString().utf8().data()); + result = JSEvaluateScript(context, script, NULL, NULL, 1, exception); + JSStringRelease(script); + } + + --nativeRecursionCount; + if (nativeRecursionCount != countAtEntry) + printf(" ERROR: PingPongStackOverflow test saw a recursion count mismatch\n"); + + return result && JSValueToBoolean(context, result); +} + +JSClassDefinition PingPongStackOverflowObject_definition = { + 0, + kJSClassAttributeNone, + + "PingPongStackOverflowObject", + NULL, + + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + PingPongStackOverflowObject_hasInstance, + NULL, +}; + +static JSClassRef PingPongStackOverflowObject_class(JSContextRef context) +{ + UNUSED_PARAM(context); + + static JSClassRef jsClass; + if (!jsClass) + jsClass = JSClassCreate(&PingPongStackOverflowObject_definition); + + return jsClass; +} + +// This tests tests a stack overflow on VM reentry into a JS function from a native function +// after ping-pong'ing back and forth between JS and native functions multiple times. +// This test should not hang or crash. +int testPingPongStackOverflow() +{ + bool failed = false; + + JSC::initializeThreading(); + Options::initialize(); // Ensure options is initialized first. + + auto origReservedZoneSize = Options::reservedZoneSize(); + auto origErrorModeReservedZoneSize = Options::errorModeReservedZoneSize(); + auto origUseLLInt = Options::useLLInt(); + auto origMaxPerThreadStackUsage = Options::maxPerThreadStackUsage(); + + Options::reservedZoneSize() = 128 * KB; + Options::errorModeReservedZoneSize() = 64 * KB; +#if ENABLE(JIT) + // Normally, we want to disable the LLINT to force the use of JITted code which is necessary for + // reproducing the regression in https://bugs.webkit.org/show_bug.cgi?id=148749. However, we only + // want to do this if the LLINT isn't the only available execution engine. + Options::useLLInt() = false; +#endif + + const char* scriptString = + "var count = 0;" \ + "PingPongStackOverflowObject.hasInstance = function f() {" \ + " return (undefined instanceof PingPongStackOverflowObject);" \ + "};" \ + "PingPongStackOverflowObject.__proto__ = undefined;" \ + "undefined instanceof PingPongStackOverflowObject;"; + + JSValueRef scriptResult = nullptr; + JSValueRef exception = nullptr; + JSStringRef script = JSStringCreateWithUTF8CString(scriptString); + + nativeRecursionCount = 0; + context = JSGlobalContextCreateInGroup(nullptr, nullptr); + + JSObjectRef globalObject = JSContextGetGlobalObject(context); + ASSERT(JSValueIsObject(context, globalObject)); + + JSObjectRef PingPongStackOverflowObject = JSObjectMake(context, PingPongStackOverflowObject_class(context), NULL); + JSStringRef PingPongStackOverflowObjectString = JSStringCreateWithUTF8CString("PingPongStackOverflowObject"); + JSObjectSetProperty(context, globalObject, PingPongStackOverflowObjectString, PingPongStackOverflowObject, kJSPropertyAttributeNone, NULL); + JSStringRelease(PingPongStackOverflowObjectString); + + unsigned stackSize = 32 * KB; + Options::maxPerThreadStackUsage() = stackSize + Options::reservedZoneSize(); + + exception = nullptr; + scriptResult = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + + if (!exception) { + printf("FAIL: PingPongStackOverflowError not thrown in PingPongStackOverflow test\n"); + failed = true; + } else if (nativeRecursionCount) { + printf("FAIL: Unbalanced native recursion count: %d in PingPongStackOverflow test\n", nativeRecursionCount); + failed = true; + } else { + printf("PASS: PingPongStackOverflow test.\n"); + } + + Options::reservedZoneSize() = origReservedZoneSize; + Options::errorModeReservedZoneSize() = origErrorModeReservedZoneSize; + Options::useLLInt() = origUseLLInt; + Options::maxPerThreadStackUsage() = origMaxPerThreadStackUsage; + + return failed; +} diff --git a/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h new file mode 100644 index 000000000..7f5911bcf --- /dev/null +++ b/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PingPongStackOverflowTest_h +#define PingPongStackOverflowTest_h + +#ifdef __cplusplus +extern "C" { +#endif + +int testPingPongStackOverflow(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* PingPongStackOverflowTest_h */ diff --git a/Source/JavaScriptCore/API/tests/Regress141275.h b/Source/JavaScriptCore/API/tests/Regress141275.h new file mode 100644 index 000000000..bf3492afa --- /dev/null +++ b/Source/JavaScriptCore/API/tests/Regress141275.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runRegress141275(); + +#endif // JSC_OBJC_API_ENABLED + diff --git a/Source/JavaScriptCore/API/tests/Regress141809.h b/Source/JavaScriptCore/API/tests/Regress141809.h new file mode 100644 index 000000000..43b099c94 --- /dev/null +++ b/Source/JavaScriptCore/API/tests/Regress141809.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JavaScriptCore.h> + +#if JSC_OBJC_API_ENABLED + +void runRegress141809(); + +#endif // JSC_OBJC_API_ENABLED + diff --git a/Source/JavaScriptCore/API/tests/minidom.c b/Source/JavaScriptCore/API/tests/minidom.c index 8614e51e9..02b41a9c7 100644 --- a/Source/JavaScriptCore/API/tests/minidom.c +++ b/Source/JavaScriptCore/API/tests/minidom.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,6 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JSContextRef.h" #include "JSNode.h" #include "JSObjectRef.h" @@ -105,6 +107,7 @@ static char* createStringWithContentsOfFile(const char* fileName) FILE* f = fopen(fileName, "r"); if (!f) { fprintf(stderr, "Could not open file: %s\n", fileName); + free(buffer); return 0; } diff --git a/Source/JavaScriptCore/API/tests/minidom.js b/Source/JavaScriptCore/API/tests/minidom.js index 480896052..85134d7cb 100644 --- a/Source/JavaScriptCore/API/tests/minidom.js +++ b/Source/JavaScriptCore/API/tests/minidom.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/JavaScriptCore/API/tests/testapi.c b/Source/JavaScriptCore/API/tests/testapi.c index be18b2bf7..cbf9daf18 100644 --- a/Source/JavaScriptCore/API/tests/testapi.c +++ b/Source/JavaScriptCore/API/tests/testapi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,19 +10,21 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/Platform.h> + #include "JavaScriptCore.h" #include "JSBasePrivate.h" #include "JSContextRefPrivate.h" @@ -33,34 +35,21 @@ #define ASSERT_DISABLED 0 #include <wtf/Assertions.h> -#if PLATFORM(MAC) || PLATFORM(IOS) -#include <mach/mach.h> -#include <mach/mach_time.h> -#include <sys/time.h> -#endif - #if OS(WINDOWS) #include <windows.h> #endif -#if COMPILER(MSVC) - -#include <wtf/MathExtras.h> - -static double nan(const char*) -{ - return std::numeric_limits<double>::quiet_NaN(); -} - -using std::isinf; -using std::isnan; - -#endif +#include "CompareAndSwapTest.h" +#include "CustomGlobalObjectClassTest.h" +#include "ExecutionTimeLimitTest.h" +#include "GlobalContextWithFinalizerTest.h" +#include "PingPongStackOverflowTest.h" #if JSC_OBJC_API_ENABLED void testObjectiveCAPI(void); #endif +bool assertTrue(bool value, const char* message); extern void JSSynchronousGarbageCollectForDebugging(JSContextRef); static JSGlobalContextRef context; @@ -93,11 +82,13 @@ static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString); char* jsBuffer = (char*)malloc(jsSize); JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize); - + unsigned i; for (i = 0; jsBuffer[i]; i++) { if (jsBuffer[i] != expectedValue[i]) { fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]); + fprintf(stderr, "value: %s\n", jsBuffer); + fprintf(stderr, "expectedValue: %s\n", expectedValue); failed = 1; } } @@ -132,7 +123,11 @@ static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedVa } if (jsLength != (size_t)cfLength) { - fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength); +#if OS(WINDOWS) + fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%Iu) != cfLength(%Iu)\n", jsLength, (size_t)cfLength); +#else + fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%zu) != cfLength(%zu)\n", jsLength, (size_t)cfLength); +#endif failed = 1; } @@ -582,7 +577,6 @@ static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObje break; default: return JSValueMakeNull(context); - break; } JSValueRef func = JSObjectGetProperty(context, object, funcName, exception); @@ -904,10 +898,8 @@ static void globalObject_initialize(JSContextRef context, JSObjectRef object) // Ensure that an execution context is passed in ASSERT(context); - // Ensure that the global object is set to the object that we were passed JSObjectRef globalObject = JSContextGetGlobalObject(context); ASSERT(globalObject); - ASSERT(object == globalObject); // Ensure that the standard global properties have been set on the global object JSStringRef array = JSStringCreateWithUTF8CString("Array"); @@ -966,6 +958,7 @@ static JSStaticValue globalObject_staticValues[] = { static JSStaticFunction globalObject_staticFunctions[] = { { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone }, + { "globalStaticFunction2", globalObject_call, kJSPropertyAttributeNone }, { "gc", functionGC, kJSPropertyAttributeNone }, { 0, 0, 0 } }; @@ -990,7 +983,7 @@ static void makeGlobalNumberValue(JSContextRef context) { v = NULL; } -static bool assertTrue(bool value, const char* message) +bool assertTrue(bool value, const char* message) { if (!value) { if (message) @@ -1043,85 +1036,104 @@ static bool checkForCycleInPrototypeChain() return result; } -static void checkConstnessInJSObjectNames() +static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { - JSStaticFunction fun; - fun.name = "something"; - JSStaticValue val; - val.name = "something"; + UNUSED_PARAM(function); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + JSValueRef jsUndefined = JSValueMakeUndefined(JSContextGetGlobalContext(ctx)); + JSValueToObject(JSContextGetGlobalContext(ctx), jsUndefined, exception); + + return JSValueMakeUndefined(ctx); } - -#if PLATFORM(MAC) || PLATFORM(IOS) -static double currentCPUTime() +static bool valueToObjectExceptionTest() { - mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; - thread_basic_info_data_t info; + JSGlobalContextRef testContext; + JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; + globalObjectClassDefinition.initialize = globalObject_initialize; + globalObjectClassDefinition.staticValues = globalObject_staticValues; + globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; + globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); + testContext = JSGlobalContextCreateInGroup(NULL, globalObjectClass); + JSObjectRef globalObject = JSContextGetGlobalObject(testContext); - /* Get thread information */ - mach_port_t threadPort = mach_thread_self(); - thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount); - mach_port_deallocate(mach_task_self(), threadPort); + JSStringRef valueToObject = JSStringCreateWithUTF8CString("valueToObject"); + JSObjectRef valueToObjectFunction = JSObjectMakeFunctionWithCallback(testContext, valueToObject, valueToObjectExceptionCallAsFunction); + JSObjectSetProperty(testContext, globalObject, valueToObject, valueToObjectFunction, kJSPropertyAttributeNone, NULL); + JSStringRelease(valueToObject); + + JSStringRef test = JSStringCreateWithUTF8CString("valueToObject();"); + JSEvaluateScript(testContext, test, NULL, NULL, 1, NULL); - double time = info.user_time.seconds + info.user_time.microseconds / 1000000.; - time += info.system_time.seconds + info.system_time.microseconds / 1000000.; + JSStringRelease(test); + JSClassRelease(globalObjectClass); + JSGlobalContextRelease(testContext); - return time; + return true; } -static JSValueRef currentCPUTime_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +static bool globalContextNameTest() { - UNUSED_PARAM(functionObject); - UNUSED_PARAM(thisObject); - UNUSED_PARAM(argumentCount); - UNUSED_PARAM(arguments); - UNUSED_PARAM(exception); + bool result = true; + JSGlobalContextRef context = JSGlobalContextCreate(0); - ASSERT(JSContextGetGlobalContext(ctx) == context); - return JSValueMakeNumber(ctx, currentCPUTime()); -} + JSStringRef str = JSGlobalContextCopyName(context); + result &= assertTrue(!str, "Default context name is NULL"); -bool shouldTerminateCallbackWasCalled = false; -static bool shouldTerminateCallback(JSContextRef ctx, void* context) -{ - UNUSED_PARAM(ctx); - UNUSED_PARAM(context); - shouldTerminateCallbackWasCalled = true; - return true; -} + JSStringRef name1 = JSStringCreateWithUTF8CString("name1"); + JSStringRef name2 = JSStringCreateWithUTF8CString("name2"); -bool cancelTerminateCallbackWasCalled = false; -static bool cancelTerminateCallback(JSContextRef ctx, void* context) -{ - UNUSED_PARAM(ctx); - UNUSED_PARAM(context); - cancelTerminateCallbackWasCalled = true; - return false; + JSGlobalContextSetName(context, name1); + JSStringRef fetchName1 = JSGlobalContextCopyName(context); + JSGlobalContextSetName(context, name2); + JSStringRef fetchName2 = JSGlobalContextCopyName(context); + JSGlobalContextSetName(context, NULL); + JSStringRef fetchName3 = JSGlobalContextCopyName(context); + + result &= assertTrue(JSStringIsEqual(name1, fetchName1), "Unexpected Context name"); + result &= assertTrue(JSStringIsEqual(name2, fetchName2), "Unexpected Context name"); + result &= assertTrue(!JSStringIsEqual(fetchName1, fetchName2), "Unexpected Context name"); + result &= assertTrue(!fetchName3, "Unexpected Context name"); + + JSStringRelease(name1); + JSStringRelease(name2); + JSStringRelease(fetchName1); + JSStringRelease(fetchName2); + + return result; } -int extendTerminateCallbackCalled = 0; -static bool extendTerminateCallback(JSContextRef ctx, void* context) +static void checkConstnessInJSObjectNames() { - UNUSED_PARAM(context); - extendTerminateCallbackCalled++; - if (extendTerminateCallbackCalled == 1) { - JSContextGroupRef contextGroup = JSContextGetGroup(ctx); - JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); - return false; - } - return true; + JSStaticFunction fun; + fun.name = "something"; + JSStaticValue val; + val.name = "something"; } -#endif /* PLATFORM(MAC) || PLATFORM(IOS) */ int main(int argc, char* argv[]) { #if OS(WINDOWS) +#if defined(_M_X64) || defined(__x86_64__) + // The VS2013 runtime has a bug where it mis-detects AVX-capable processors + // if the feature has been disabled in firmware. This causes us to crash + // in some of the math functions. For now, we disable those optimizations + // because Microsoft is not going to fix the problem in VS2013. + // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+. + _set_FMA3_enable(0); +#endif + // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. ::SetErrorMode(0); #endif + testCompareAndSwap(); + #if JSC_OBJC_API_ENABLED testObjectiveCAPI(); #endif @@ -1171,6 +1183,13 @@ int main(int argc, char* argv[]) JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL); JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context)); + JSObjectSetPrivate(globalObject, (void*)123); + if (JSObjectGetPrivate(globalObject) != (void*)123) { + printf("FAIL: Didn't return private data when set by JSObjectSetPrivate().\n"); + failed = 1; + } else + printf("PASS: returned private data when set by JSObjectSetPrivate().\n"); + // FIXME: test funny utf8 characters JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString(""); JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString); @@ -1228,6 +1247,8 @@ int main(int argc, char* argv[]) ASSERT(!JSValueIsBoolean(context, NULL)); ASSERT(!JSValueIsObject(context, NULL)); + ASSERT(!JSValueIsArray(context, NULL)); + ASSERT(!JSValueIsDate(context, NULL)); ASSERT(!JSValueIsString(context, NULL)); ASSERT(!JSValueIsNumber(context, NULL)); ASSERT(!JSValueIsUndefined(context, NULL)); @@ -1388,8 +1409,10 @@ int main(int argc, char* argv[]) } else printf("PASS: Correctly serialised with indent of 4.\n"); JSStringRelease(str); - JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); - JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL); + + str = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); + JSValueRef unstringifiableObj = JSEvaluateScript(context, str, NULL, NULL, 1, NULL); + JSStringRelease(str); str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0); if (str) { @@ -1572,7 +1595,27 @@ int main(int argc, char* argv[]) ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); ASSERT(JSValueIsObject(context, exception)); v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); - assertEqualsAsNumber(v, 1); + assertEqualsAsNumber(v, 2); + JSStringRelease(functionBody); + JSStringRelease(line); + + exception = NULL; + functionBody = JSStringCreateWithUTF8CString("rreturn Array;"); + line = JSStringCreateWithUTF8CString("line"); + ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, -42, &exception)); + ASSERT(JSValueIsObject(context, exception)); + v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); + assertEqualsAsNumber(v, 2); + JSStringRelease(functionBody); + JSStringRelease(line); + + exception = NULL; + functionBody = JSStringCreateWithUTF8CString("// Line one.\nrreturn Array;"); + line = JSStringCreateWithUTF8CString("line"); + ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); + ASSERT(JSValueIsObject(context, exception)); + v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); + assertEqualsAsNumber(v, 3); JSStringRelease(functionBody); JSStringRelease(line); @@ -1606,7 +1649,7 @@ int main(int argc, char* argv[]) JSStringRelease(functionBody); string = JSValueToStringCopy(context, function, NULL); - assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}"); + assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) {\nreturn foo;\n}"); JSStringRelease(string); JSStringRef print = JSStringCreateWithUTF8CString("print"); @@ -1737,6 +1780,28 @@ int main(int argc, char* argv[]) ASSERT(JSValueIsEqual(context, v, o, NULL)); JSStringRelease(script); + script = JSStringCreateWithUTF8CString("[ ]"); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsArray(context, v)); + JSStringRelease(script); + + script = JSStringCreateWithUTF8CString("new Date"); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsDate(context, v)); + JSStringRelease(script); + + exception = NULL; + script = JSStringCreateWithUTF8CString("rreturn Array;"); + JSStringRef sourceURL = JSStringCreateWithUTF8CString("file:///foo/bar.js"); + JSStringRef sourceURLKey = JSStringCreateWithUTF8CString("sourceURL"); + JSEvaluateScript(context, script, NULL, sourceURL, 1, &exception); + ASSERT(exception); + v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), sourceURLKey, NULL); + assertEqualsAsUTF8String(v, "file:///foo/bar.js"); + JSStringRelease(script); + JSStringRelease(sourceURL); + JSStringRelease(sourceURLKey); + // Verify that creating a constructor for a class with no static functions does not trigger // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785> nullDefinition = kJSClassDefinitionEmpty; @@ -1765,6 +1830,7 @@ int main(int argc, char* argv[]) } JSStringRelease(script); + exception = NULL; result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0; if (result && JSValueIsUndefined(context, result)) printf("PASS: Test script executed successfully.\n"); @@ -1781,158 +1847,53 @@ int main(int argc, char* argv[]) free(scriptUTF8); } -#if PLATFORM(MAC) || PLATFORM(IOS) - JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime"); - JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTime_callAsFunction); - JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, NULL); - JSStringRelease(currentCPUTimeStr); - - /* Test script timeout: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0); - { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - shouldTerminateCallbackWasCalled = false; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) - printf("PASS: script timed out as expected.\n"); - else { - if (!((endTime - startTime) < .150f)) - printf("FAIL: script did not timed out as expected.\n"); - if (!shouldTerminateCallbackWasCalled) - printf("FAIL: script timeout callback was not called.\n"); - failed = true; - } - - if (!exception) { - printf("FAIL: TerminatedExecutionException was not thrown.\n"); - failed = true; - } - } - - /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0); - { - const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }"; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - shouldTerminateCallbackWasCalled = false; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) { - if (!((endTime - startTime) < .150f)) - printf("FAIL: script did not timed out as expected.\n"); - if (!shouldTerminateCallbackWasCalled) - printf("FAIL: script timeout callback was not called.\n"); - failed = true; - } - - if (exception) - printf("PASS: TerminatedExecutionException was not catchable as expected.\n"); - else { - printf("FAIL: TerminatedExecutionException was caught.\n"); - failed = true; - } - } - - /* Test script timeout with no callback: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0); + // Check Promise is not exposed. { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) - printf("PASS: script timed out as expected when no callback is specified.\n"); - else { - if (!((endTime - startTime) < .150f)) - printf("FAIL: script did not timed out as expected when no callback is specified.\n"); - failed = true; + JSObjectRef globalObject = JSContextGetGlobalObject(context); + { + JSStringRef promiseProperty = JSStringCreateWithUTF8CString("Promise"); + ASSERT(JSObjectHasProperty(context, globalObject, promiseProperty)); + JSStringRelease(promiseProperty); } - - if (!exception) { - printf("FAIL: TerminatedExecutionException was not thrown.\n"); - failed = true; + { + JSStringRef script = JSStringCreateWithUTF8CString("typeof Promise"); + JSStringRef function = JSStringCreateWithUTF8CString("function"); + JSValueRef value = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsString(context, value)); + JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); + ASSERT(JSStringIsEqual(valueAsString, function)); + JSStringRelease(valueAsString); + JSStringRelease(function); + JSStringRelease(script); } + printf("PASS: Promise is exposed under JSContext API.\n"); } - /* Test script timeout cancellation: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0); + // Check microtasks. { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception) - printf("PASS: script timeout was cancelled as expected.\n"); - else { - if (((endTime - startTime) < .150) || exception) - printf("FAIL: script timeout was not cancelled.\n"); - if (!cancelTerminateCallbackWasCalled) - printf("FAIL: script timeout callback was not called.\n"); - failed = true; - } - - if (exception) { - printf("FAIL: Unexpected TerminatedExecutionException thrown.\n"); - failed = true; + JSGlobalContextRef context = JSGlobalContextCreateInGroup(NULL, NULL); + { + JSObjectRef globalObject = JSContextGetGlobalObject(context); + JSValueRef exception; + JSStringRef code = JSStringCreateWithUTF8CString("result = 0; Promise.resolve(42).then(function (value) { result = value; });"); + JSStringRef file = JSStringCreateWithUTF8CString(""); + assertTrue(JSEvaluateScript(context, code, globalObject, file, 1, &exception), "An exception should not be thrown"); + JSStringRelease(code); + JSStringRelease(file); + + JSStringRef resultProperty = JSStringCreateWithUTF8CString("result"); + ASSERT(JSObjectHasProperty(context, globalObject, resultProperty)); + + JSValueRef resultValue = JSObjectGetProperty(context, globalObject, resultProperty, &exception); + assertEqualsAsNumber(resultValue, 42); + JSStringRelease(resultProperty); } + JSGlobalContextRelease(context); } - /* Test script timeout extension: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0); - { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - double deltaTime; - exception = NULL; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - deltaTime = endTime - startTime; - - if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception) - printf("PASS: script timeout was extended as expected.\n"); - else { - if (deltaTime < .200f) - printf("FAIL: script timeout was not extended as expected.\n"); - else if (deltaTime >= .500f) - printf("FAIL: script did not timeout.\n"); - - if (extendTerminateCallbackCalled < 1) - printf("FAIL: script timeout callback was not called.\n"); - if (extendTerminateCallbackCalled < 2) - printf("FAIL: script timeout callback was not called after timeout extension.\n"); - - if (!exception) - printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n"); - - failed = true; - } - } -#endif /* PLATFORM(MAC) || PLATFORM(IOS) */ + failed = testExecutionTimeLimit() || failed; + failed = testGlobalContextWithFinalizer() || failed; + failed = testPingPongStackOverflow() || failed; // Clear out local variables pointing at JSObjectRefs to allow their values to be collected function = NULL; @@ -1975,6 +1936,15 @@ int main(int argc, char* argv[]) printf("FAIL: A cycle in a prototype chain can be created.\n"); failed = true; } + if (valueToObjectExceptionTest()) + printf("PASS: throwException did not crash when handling an error with appendMessageToError set and no codeBlock available.\n"); + + if (globalContextNameTest()) + printf("PASS: global context name behaves as expected.\n"); + + customGlobalObjectClassTest(); + globalObjectSetPrototypeTest(); + globalObjectPrivatePropertyTest(); if (failed) { printf("FAIL: Some tests failed.\n"); @@ -1996,6 +1966,7 @@ static char* createStringWithContentsOfFile(const char* fileName) FILE* f = fopen(fileName, "r"); if (!f) { fprintf(stderr, "Could not open file: %s\n", fileName); + free(buffer); return 0; } @@ -2014,3 +1985,10 @@ static char* createStringWithContentsOfFile(const char* fileName) return buffer; } + +#if OS(WINDOWS) +extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]) +{ + return main(argc, const_cast<char**>(argv)); +} +#endif diff --git a/Source/JavaScriptCore/API/tests/testapi.js b/Source/JavaScriptCore/API/tests/testapi.js index 47c20a830..88d3701c2 100644 --- a/Source/JavaScriptCore/API/tests/testapi.js +++ b/Source/JavaScriptCore/API/tests/testapi.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,17 +10,17 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ function bludgeonArguments() { if (0) arguments; return function g() {} } @@ -74,6 +74,20 @@ function globalStaticFunction() shouldBe("globalStaticValue", 3); shouldBe("globalStaticFunction()", 4); +shouldBe("this.globalStaticFunction()", 4); + +function globalStaticFunction2() { + return 10; +} +shouldBe("globalStaticFunction2();", 10); +this.globalStaticFunction2 = function() { return 20; } +shouldBe("globalStaticFunction2();", 20); +shouldBe("this.globalStaticFunction2();", 20); + +function iAmNotAStaticFunction() { return 10; } +shouldBe("iAmNotAStaticFunction();", 10); +this.iAmNotAStaticFunction = function() { return 20; } +shouldBe("iAmNotAStaticFunction();", 20); shouldBe("typeof MyObject", "function"); // our object implements 'call' MyObject.cantFind = 1; @@ -253,6 +267,9 @@ shouldThrow("EvilExceptionObject*5"); EvilExceptionObject.toStringExplicit = function f() { return f(); } shouldThrow("String(EvilExceptionObject)"); +shouldBe("console", "[object Console]"); +shouldBe("typeof console.log", "function"); + shouldBe("EmptyObject", "[object CallbackObject]"); for (var i = 0; i < 6; ++i) diff --git a/Source/JavaScriptCore/API/tests/testapi.mm b/Source/JavaScriptCore/API/tests/testapi.mm deleted file mode 100644 index defb46e70..000000000 --- a/Source/JavaScriptCore/API/tests/testapi.mm +++ /dev/null @@ -1,841 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import <JavaScriptCore/JavaScriptCore.h> - -extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef); - -extern "C" bool _Block_has_signature(id); -extern "C" const char * _Block_signature(id); - -extern int failed; -extern "C" void testObjectiveCAPI(void); - -#if JSC_OBJC_API_ENABLED - -@protocol ParentObject <JSExport> -@end - -@interface ParentObject : NSObject<ParentObject> -+ (NSString *)parentTest; -@end - -@implementation ParentObject -+ (NSString *)parentTest -{ - return [self description]; -} -@end - -@protocol TestObject <JSExport> -@property int variable; -@property (readonly) int six; -@property CGPoint point; -+ (NSString *)classTest; -+ (NSString *)parentTest; -- (NSString *)getString; -JSExportAs(testArgumentTypes, -- (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o -); -- (void)callback:(JSValue *)function; -- (void)bogusCallback:(void(^)(int))function; -@end - -@interface TestObject : ParentObject <TestObject> -@property int six; -+ (id)testObject; -@end - -@implementation TestObject -@synthesize variable; -@synthesize six; -@synthesize point; -+ (id)testObject -{ - return [[TestObject alloc] init]; -} -+ (NSString *)classTest -{ - return @"classTest - okay"; -} -- (NSString *)getString -{ - return @"42"; -} -- (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o -{ - return [NSString stringWithFormat:@"%d,%g,%d,%@,%d,%@,%@", i, d, b==YES?true:false,s,[n intValue],a[1],o[@"x"]]; -} -- (void)callback:(JSValue *)function -{ - [function callWithArguments:[NSArray arrayWithObject:[NSNumber numberWithInt:42]]]; -} -- (void)bogusCallback:(void(^)(int))function -{ - function(42); -} -@end - -bool testXYZTested = false; - -@protocol TextXYZ <JSExport> -@property int x; -@property (readonly) int y; -@property (assign) JSValue *onclick; -@property (assign) JSValue *weakOnclick; -- (void)test:(NSString *)message; -@end - -@interface TextXYZ : NSObject <TextXYZ> -@property int x; -@property int y; -@property int z; -- (void)click; -@end - -@implementation TextXYZ { - JSManagedValue *m_weakOnclickHandler; - JSManagedValue *m_onclickHandler; -} -@synthesize x; -@synthesize y; -@synthesize z; -- (void)test:(NSString *)message -{ - testXYZTested = [message isEqual:@"test"] && x == 13 & y == 4 && z == 5; -} -- (void)setWeakOnclick:(JSValue *)value -{ - m_weakOnclickHandler = [JSManagedValue managedValueWithValue:value]; -} - -- (void)setOnclick:(JSValue *)value -{ - m_onclickHandler = [JSManagedValue managedValueWithValue:value]; - [value.context.virtualMachine addManagedReference:m_onclickHandler withOwner:self]; -} -- (JSValue *)weakOnclick -{ - return [m_weakOnclickHandler value]; -} -- (JSValue *)onclick -{ - return [m_onclickHandler value]; -} -- (void)click -{ - if (!m_onclickHandler) - return; - - JSValue *function = [m_onclickHandler value]; - [function callWithArguments:[NSArray array]]; -} -- (void)dealloc -{ - [[m_onclickHandler value].context.virtualMachine removeManagedReference:m_onclickHandler withOwner:self]; -} -@end - -@class TinyDOMNode; - -@protocol TinyDOMNode <JSExport> -- (void)appendChild:(TinyDOMNode *)child; -- (NSUInteger)numberOfChildren; -- (TinyDOMNode *)childAtIndex:(NSUInteger)index; -- (void)removeChildAtIndex:(NSUInteger)index; -@end - -@interface TinyDOMNode : NSObject<TinyDOMNode> -+ (JSVirtualMachine *)sharedVirtualMachine; -+ (void)clearSharedVirtualMachine; -@end - -@implementation TinyDOMNode { - NSMutableArray *m_children; -} - -static JSVirtualMachine *sharedInstance = nil; - -+ (JSVirtualMachine *)sharedVirtualMachine -{ - if (!sharedInstance) - sharedInstance = [[JSVirtualMachine alloc] init]; - return sharedInstance; -} - -+ (void)clearSharedVirtualMachine -{ - sharedInstance = nil; -} - -- (id)init -{ - self = [super init]; - if (!self) - return nil; - - m_children = [[NSMutableArray alloc] initWithCapacity:0]; - - return self; -} - -- (void)dealloc -{ - NSEnumerator *enumerator = [m_children objectEnumerator]; - id nextChild; - while ((nextChild = [enumerator nextObject])) - [[TinyDOMNode sharedVirtualMachine] removeManagedReference:nextChild withOwner:self]; - -#if !__has_feature(objc_arc) - [super dealloc]; -#endif -} - -- (void)appendChild:(TinyDOMNode *)child -{ - [[TinyDOMNode sharedVirtualMachine] addManagedReference:child withOwner:self]; - [m_children addObject:child]; -} - -- (NSUInteger)numberOfChildren -{ - return [m_children count]; -} - -- (TinyDOMNode *)childAtIndex:(NSUInteger)index -{ - if (index >= [m_children count]) - return nil; - return [m_children objectAtIndex:index]; -} - -- (void)removeChildAtIndex:(NSUInteger)index -{ - if (index >= [m_children count]) - return; - [[TinyDOMNode sharedVirtualMachine] removeManagedReference:[m_children objectAtIndex:index] withOwner:self]; - [m_children removeObjectAtIndex:index]; -} - -@end - -static void checkResult(NSString *description, bool passed) -{ - NSLog(@"TEST: \"%@\": %@", description, passed ? @"PASSED" : @"FAILED"); - if (!passed) - failed = 1; -} - -static bool blockSignatureContainsClass() -{ - static bool containsClass = ^{ - id block = ^(NSString *string){ return string; }; - return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString"); - }(); - return containsClass; -} - -void testObjectiveCAPI() -{ - NSLog(@"Testing Objective-C API"); - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - JSValue *result = [context evaluateScript:@"2 + 2"]; - checkResult(@"2 + 2", [result isNumber] && [result toInt32] == 4); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - NSString *result = [NSString stringWithFormat:@"Two plus two is %@", [context evaluateScript:@"2 + 2"]]; - checkResult(@"stringWithFormat", [result isEqual:@"Two plus two is 4"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"message"] = @"Hello"; - JSValue *result = [context evaluateScript:@"message + ', World!'"]; - checkResult(@"Hello, World!", [result isString] && [result isEqualToObject:@"Hello, World!"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - JSValue *result = [context evaluateScript:@"({ x:42 })"]; - checkResult(@"({ x:42 })", [result isObject] && [result[@"x"] isEqualToObject:@42]); - id obj = [result toObject]; - checkResult(@"Check dictionary literal", [obj isKindOfClass:[NSDictionary class]]); - id num = (NSDictionary *)obj[@"x"]; - checkResult(@"Check numeric literal", [num isKindOfClass:[NSNumber class]]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - __block int result; - context[@"blockCallback"] = ^(int value){ - result = value; - }; - [context evaluateScript:@"blockCallback(42)"]; - checkResult(@"blockCallback", result == 42); - } - - if (blockSignatureContainsClass()) { - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - __block bool result = false; - context[@"blockCallback"] = ^(NSString *value){ - result = [@"42" isEqualToString:value] == YES; - }; - [context evaluateScript:@"blockCallback(42)"]; - checkResult(@"blockCallback(NSString *)", result); - } - } else - NSLog(@"Skipping 'blockCallback(NSString *)' test case"); - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - checkResult(@"!context.exception", !context.exception); - [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"]; - checkResult(@"context.exception", context.exception); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - __block bool caught = false; - context.exceptionHandler = ^(JSContext *context, JSValue *exception) { - (void)context; - (void)exception; - caught = true; - }; - [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"]; - checkResult(@"JSContext.exceptionHandler", caught); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"callback"] = ^{ - JSContext *context = [JSContext currentContext]; - context.exception = [JSValue valueWithNewErrorFromMessage:@"Something went wrong." inContext:context]; - }; - JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"]; - checkResult(@"Explicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]); - checkResult(@"Explicit throw in callback - not thrown to Objective-C", !context.exception); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"callback"] = ^{ - JSContext *context = [JSContext currentContext]; - [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"]; - }; - JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"]; - checkResult(@"Implicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]); - checkResult(@"Implicit throw in callback - not thrown to Objective-C", !context.exception); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - [context evaluateScript: - @"function sum(array) { \ - var result = 0; \ - for (var i in array) \ - result += array[i]; \ - return result; \ - }"]; - JSValue *array = [JSValue valueWithObject:@[@13, @2, @7] inContext:context]; - JSValue *sumFunction = context[@"sum"]; - JSValue *result = [sumFunction callWithArguments:@[ array ]]; - checkResult(@"sum([13, 2, 7])", [result toInt32] == 22); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - JSValue *mulAddFunction = [context evaluateScript: - @"(function(array, object) { \ - var result = []; \ - for (var i in array) \ - result.push(array[i] * object.x + object.y); \ - return result; \ - })"]; - JSValue *result = [mulAddFunction callWithArguments:@[ @[ @2, @4, @8 ], @{ @"x":@0.5, @"y":@42 } ]]; - checkResult(@"mulAddFunction", [result isObject] && [[result toString] isEqual:@"43,44,46"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - JSValue *array = [JSValue valueWithNewArrayInContext:context]; - checkResult(@"arrayLengthEmpty", [[array[@"length"] toNumber] unsignedIntegerValue] == 0); - JSValue *value1 = [JSValue valueWithInt32:42 inContext:context]; - JSValue *value2 = [JSValue valueWithInt32:24 inContext:context]; - NSUInteger lowIndex = 5; - NSUInteger maxLength = UINT_MAX; - - [array setValue:value1 atIndex:lowIndex]; - checkResult(@"array.length after put to low index", [[array[@"length"] toNumber] unsignedIntegerValue] == (lowIndex + 1)); - - [array setValue:value1 atIndex:(maxLength - 1)]; - checkResult(@"array.length after put to maxLength - 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength); - - [array setValue:value2 atIndex:maxLength]; - checkResult(@"array.length after put to maxLength", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength); - - [array setValue:value2 atIndex:(maxLength + 1)]; - checkResult(@"array.length after put to maxLength + 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength); - - checkResult(@"valueAtIndex:0 is undefined", [[array valueAtIndex:0] isUndefined]); - checkResult(@"valueAtIndex:lowIndex", [[array valueAtIndex:lowIndex] toInt32] == 42); - checkResult(@"valueAtIndex:maxLength - 1", [[array valueAtIndex:(maxLength - 1)] toInt32] == 42); - checkResult(@"valueAtIndex:maxLength", [[array valueAtIndex:maxLength] toInt32] == 24); - checkResult(@"valueAtIndex:maxLength + 1", [[array valueAtIndex:(maxLength + 1)] toInt32] == 24); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - JSValue *object = [JSValue valueWithNewObjectInContext:context]; - - object[@"point"] = @{ @"x":@1, @"y":@2 }; - object[@"point"][@"x"] = @3; - CGPoint point = [object[@"point"] toPoint]; - checkResult(@"toPoint", point.x == 3 && point.y == 2); - - object[@{ @"toString":^{ return @"foo"; } }] = @"bar"; - checkResult(@"toString in object literal used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]); - - object[[@"foobar" substringToIndex:3]] = @"bar"; - checkResult(@"substring used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TextXYZ *testXYZ = [[TextXYZ alloc] init]; - context[@"testXYZ"] = testXYZ; - testXYZ.x = 3; - testXYZ.y = 4; - testXYZ.z = 5; - [context evaluateScript:@"testXYZ.x = 13; testXYZ.y = 14;"]; - [context evaluateScript:@"testXYZ.test('test')"]; - checkResult(@"TextXYZ - testXYZTested", testXYZTested); - JSValue *result = [context evaluateScript:@"testXYZ.x + ',' + testXYZ.y + ',' + testXYZ.z"]; - checkResult(@"TextXYZ - result", [result isEqualToObject:@"13,4,undefined"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - [context[@"Object"][@"prototype"] defineProperty:@"getterProperty" descriptor:@{ - JSPropertyDescriptorGetKey:^{ - return [JSContext currentThis][@"x"]; - } - }]; - JSValue *object = [JSValue valueWithObject:@{ @"x":@101 } inContext:context]; - int result = [object [@"getterProperty"] toInt32]; - checkResult(@"getterProperty", result == 101); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"concatenate"] = ^{ - NSArray *arguments = [JSContext currentArguments]; - if (![arguments count]) - return @""; - NSString *message = [arguments[0] description]; - for (NSUInteger index = 1; index < [arguments count]; ++index) - message = [NSString stringWithFormat:@"%@ %@", message, arguments[index]]; - return message; - }; - JSValue *result = [context evaluateScript:@"concatenate('Hello,', 'World!')"]; - checkResult(@"concatenate", [result isEqualToObject:@"Hello, World!"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"foo"] = @YES; - checkResult(@"@YES is boolean", [context[@"foo"] isBoolean]); - JSValue *result = [context evaluateScript:@"typeof foo"]; - checkResult(@"@YES is boolean", [result isEqualToObject:@"boolean"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - JSValue *result = [context evaluateScript:@"String(testObject)"]; - checkResult(@"String(testObject)", [result isEqualToObject:@"[object TestObject]"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - JSValue *result = [context evaluateScript:@"String(testObject.__proto__)"]; - checkResult(@"String(testObject.__proto__)", [result isEqualToObject:@"[object TestObjectPrototype]"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"TestObject"] = [TestObject class]; - JSValue *result = [context evaluateScript:@"String(TestObject)"]; - checkResult(@"String(TestObject)", [result isEqualToObject:@"[object TestObjectConstructor]"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - JSValue* value = [JSValue valueWithObject:[TestObject class] inContext:context]; - checkResult(@"[value toObject] == [TestObject class]", [value toObject] == [TestObject class]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"TestObject"] = [TestObject class]; - JSValue *result = [context evaluateScript:@"TestObject.parentTest()"]; - checkResult(@"TestObject.parentTest()", [result isEqualToObject:@"TestObject"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObjectA"] = testObject; - context[@"testObjectB"] = testObject; - JSValue *result = [context evaluateScript:@"testObjectA == testObjectB"]; - checkResult(@"testObjectA == testObjectB", [result isBoolean] && [result toBool]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - testObject.point = (CGPoint){3,4}; - JSValue *result = [context evaluateScript:@"var result = JSON.stringify(testObject.point); testObject.point = {x:12,y:14}; result"]; - checkResult(@"testObject.point - result", [result isEqualToObject:@"{\"x\":3,\"y\":4}"]); - checkResult(@"testObject.point - {x:12,y:14}", testObject.point.x == 12 && testObject.point.y == 14); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - testObject.six = 6; - context[@"testObject"] = testObject; - context[@"mul"] = ^(int x, int y){ return x * y; }; - JSValue *result = [context evaluateScript:@"mul(testObject.six, 7)"]; - checkResult(@"mul(testObject.six, 7)", [result isNumber] && [result toInt32] == 42); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - context[@"testObject"][@"variable"] = @4; - [context evaluateScript:@"++testObject.variable"]; - checkResult(@"++testObject.variable", testObject.variable == 5); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"point"] = @{ @"x":@6, @"y":@7 }; - JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"]; - checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"point"] = @{ @"x":@6, @"y":@7 }; - JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"]; - checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - JSValue *result = [context evaluateScript:@"testObject.getString()"]; - checkResult(@"testObject.getString()", [result isString] && [result toInt32] == 42); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - JSValue *result = [context evaluateScript:@"testObject.testArgumentTypes(101,0.5,true,'foo',666,[false,'bar',false],{x:'baz'})"]; - checkResult(@"testObject.testArgumentTypes", [result isEqualToObject:@"101,0.5,1,foo,666,bar,baz"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - JSValue *result = [context evaluateScript:@"testObject.getString.call(testObject)"]; - checkResult(@"testObject.getString.call(testObject)", [result isString] && [result toInt32] == 42); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - checkResult(@"testObject.getString.call({}) pre", !context.exception); - [context evaluateScript:@"testObject.getString.call({})"]; - checkResult(@"testObject.getString.call({}) post", context.exception); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject* testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - JSValue *result = [context evaluateScript:@"var result = 0; testObject.callback(function(x){ result = x; }); result"]; - checkResult(@"testObject.callback", [result isNumber] && [result toInt32] == 42); - result = [context evaluateScript:@"testObject.bogusCallback"]; - checkResult(@"testObject.bogusCallback == undefined", [result isUndefined]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject *testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - JSValue *result = [context evaluateScript:@"Function.prototype.toString.call(testObject.callback)"]; - checkResult(@"Function.prototype.toString", !context.exception && ![result isUndefined]); - } - - @autoreleasepool { - JSContext *context1 = [[JSContext alloc] init]; - JSContext *context2 = [[JSContext alloc] initWithVirtualMachine:context1.virtualMachine]; - JSValue *value = [JSValue valueWithDouble:42 inContext:context2]; - context1[@"passValueBetweenContexts"] = value; - JSValue *result = [context1 evaluateScript:@"passValueBetweenContexts"]; - checkResult(@"[value isEqualToObject:result]", [value isEqualToObject:result]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"handleTheDictionary"] = ^(NSDictionary *dict) { - NSDictionary *expectedDict = @{ - @"foo" : [NSNumber numberWithInt:1], - @"bar" : @{ - @"baz": [NSNumber numberWithInt:2] - } - }; - checkResult(@"recursively convert nested dictionaries", [dict isEqualToDictionary:expectedDict]); - }; - [context evaluateScript:@"var myDict = { \ - 'foo': 1, \ - 'bar': {'baz': 2} \ - }; \ - handleTheDictionary(myDict);"]; - - context[@"handleTheArray"] = ^(NSArray *array) { - NSArray *expectedArray = @[@"foo", @"bar", @[@"baz"]]; - checkResult(@"recursively convert nested arrays", [array isEqualToArray:expectedArray]); - }; - [context evaluateScript:@"var myArray = ['foo', 'bar', ['baz']]; handleTheArray(myArray);"]; - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject *testObject = [TestObject testObject]; - @autoreleasepool { - context[@"testObject"] = testObject; - [context evaluateScript:@"var constructor = Object.getPrototypeOf(testObject).constructor; constructor.prototype = undefined;"]; - [context evaluateScript:@"testObject = undefined"]; - } - - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - - @autoreleasepool { - context[@"testObject"] = testObject; - } - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TextXYZ *testXYZ = [[TextXYZ alloc] init]; - - @autoreleasepool { - context[@"testXYZ"] = testXYZ; - - [context evaluateScript:@" \ - didClick = false; \ - testXYZ.onclick = function() { \ - didClick = true; \ - }; \ - \ - testXYZ.weakOnclick = function() { \ - return 'foo'; \ - }; \ - "]; - } - - @autoreleasepool { - [testXYZ click]; - JSValue *result = [context evaluateScript:@"didClick"]; - checkResult(@"Event handler onclick", [result toBool]); - } - - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - - @autoreleasepool { - JSValue *result = [context evaluateScript:@"testXYZ.onclick"]; - checkResult(@"onclick still around after GC", !([result isNull] || [result isUndefined])); - } - - - @autoreleasepool { - JSValue *result = [context evaluateScript:@"testXYZ.weakOnclick"]; - checkResult(@"weakOnclick not around after GC", [result isNull] || [result isUndefined]); - } - - @autoreleasepool { - [context evaluateScript:@" \ - didClick = false; \ - testXYZ = null; \ - "]; - } - - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - - @autoreleasepool { - [testXYZ click]; - JSValue *result = [context evaluateScript:@"didClick"]; - checkResult(@"Event handler onclick doesn't fire", ![result toBool]); - } - } - - @autoreleasepool { - JSVirtualMachine *vm = [[JSVirtualMachine alloc] init]; - TestObject *testObject = [TestObject testObject]; - JSManagedValue *weakValue; - @autoreleasepool { - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - context[@"testObject"] = testObject; - weakValue = [[JSManagedValue alloc] initWithValue:context[@"testObject"]]; - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - context[@"testObject"] = testObject; - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - checkResult(@"weak value == nil", ![weakValue value]); - checkResult(@"root is still alive", ![context[@"testObject"] isUndefined]); - } - } - - @autoreleasepool { - JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine]; - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - TinyDOMNode *root = [[TinyDOMNode alloc] init]; - TinyDOMNode *lastNode = root; - for (NSUInteger i = 0; i < 3; i++) { - TinyDOMNode *newNode = [[TinyDOMNode alloc] init]; - [lastNode appendChild:newNode]; - lastNode = newNode; - } - - @autoreleasepool { - context[@"root"] = root; - context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){ - TinyDOMNode *lastNode = nil; - while (head) { - lastNode = head; - head = [lastNode childAtIndex:0]; - } - return lastNode; - }; - [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"]; - } - - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - - JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"]; - checkResult(@"My custom property == 42", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42); - - [TinyDOMNode clearSharedVirtualMachine]; - } - - @autoreleasepool { - JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine]; - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - TinyDOMNode *root = [[TinyDOMNode alloc] init]; - TinyDOMNode *lastNode = root; - for (NSUInteger i = 0; i < 3; i++) { - TinyDOMNode *newNode = [[TinyDOMNode alloc] init]; - [lastNode appendChild:newNode]; - lastNode = newNode; - } - - @autoreleasepool { - context[@"root"] = root; - context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){ - TinyDOMNode *lastNode = nil; - while (head) { - lastNode = head; - head = [lastNode childAtIndex:0]; - } - return lastNode; - }; - [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"]; - - [root appendChild:[root childAtIndex:0]]; - [root removeChildAtIndex:0]; - } - - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - - JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"]; - checkResult(@"duplicate calls to addManagedReference don't cause things to die", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42); - - [TinyDOMNode clearSharedVirtualMachine]; - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - JSValue *o = [JSValue valueWithNewObjectInContext:context]; - o[@"foo"] = @"foo"; - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - - checkResult(@"JSValue correctly protected its internal value", [[o[@"foo"] toString] isEqualToString:@"foo"]); - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - TestObject *testObject = [TestObject testObject]; - context[@"testObject"] = testObject; - [context evaluateScript:@"testObject.__lookupGetter__('variable').call({})"]; - checkResult(@"Make sure we throw an exception when calling getter on incorrect |this|", context.exception); - } - - @autoreleasepool { - TestObject *testObject = [TestObject testObject]; - JSManagedValue *managedTestObject; - @autoreleasepool { - JSContext *context = [[JSContext alloc] init]; - context[@"testObject"] = testObject; - managedTestObject = [JSManagedValue managedValueWithValue:context[@"testObject"]]; - [context.virtualMachine addManagedReference:managedTestObject withOwner:testObject]; - } - } -} - -#else - -void testObjectiveCAPI() -{ -} - -#endif |