[JSC API] We should support the symbol type in our C/Obj-C API
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Jul 2018 02:32:25 +0000 (02:32 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Jul 2018 02:32:25 +0000 (02:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175836

Reviewed by Filip Pizlo.

This patch makes the following API additions:
1) Test if a JSValue/JSValueRef is a symbol via any of the methods API are able to test for the types of other JSValues.
2) Create a symbol on both APIs.
3) Get/Set/Delete/Define property now take ids in the Obj-C API.
4) Add Get/Set/Delete in the C API.

We can do 3 because it is both binary and source compatable with
the existing API. I added (4) because the current property access
APIs only have the ability to get Strings. It was possible to
merge symbols into JSStringRef but that felt confusing and exposes
implementation details of our engine. The new functions match the
same meaning that they have in JS, thus should be forward
compatible with any future language extensions.

Lastly, this patch adds the same availability preproccessing phase
in WebCore to JavaScriptCore, which enables TBA features for
testing on previous releases.

* API/APICast.h:
* API/JSBasePrivate.h:
* API/JSContext.h:
* API/JSContextPrivate.h:
* API/JSContextRef.h:
* API/JSContextRefInternal.h:
* API/JSContextRefPrivate.h:
* API/JSManagedValue.h:
* API/JSObjectRef.cpp:
(JSObjectHasPropertyKey):
(JSObjectGetPropertyKey):
(JSObjectSetPropertyKey):
(JSObjectDeletePropertyKey):
* API/JSObjectRef.h:
* API/JSRemoteInspector.h:
* API/JSTypedArray.h:
* API/JSValue.h:
* API/JSValue.mm:
(+[JSValue valueWithNewSymbolFromDescription:inContext:]):
(performPropertyOperation):
(-[JSValue valueForProperty:valueForProperty:]):
(-[JSValue setValue:forProperty:setValue:forProperty:]):
(-[JSValue deleteProperty:deleteProperty:]):
(-[JSValue hasProperty:hasProperty:]):
(-[JSValue defineProperty:descriptor:defineProperty:descriptor:]):
(-[JSValue isSymbol]):
(-[JSValue objectForKeyedSubscript:]):
(-[JSValue setObject:forKeyedSubscript:]):
(-[JSValue valueForProperty:]): Deleted.
(-[JSValue setValue:forProperty:]): Deleted.
(-[JSValue deleteProperty:]): Deleted.
(-[JSValue hasProperty:]): Deleted.
(-[JSValue defineProperty:descriptor:]): Deleted.
* API/JSValueRef.cpp:
(JSValueGetType):
(JSValueIsSymbol):
(JSValueMakeSymbol):
* API/JSValueRef.h:
* API/WebKitAvailability.h:
* API/tests/CurrentThisInsideBlockGetterTest.mm:
* API/tests/CustomGlobalObjectClassTest.c:
* API/tests/DateTests.mm:
* API/tests/JSExportTests.mm:
* API/tests/JSNode.c:
* API/tests/JSNodeList.c:
* API/tests/Node.c:
* API/tests/NodeList.c:
* API/tests/minidom.c:
* API/tests/testapi.c:
(main):
* API/tests/testapi.cpp: Added.
(APIString::APIString):
(APIString::~APIString):
(APIString::operator JSStringRef):
(APIContext::APIContext):
(APIContext::~APIContext):
(APIContext::operator JSGlobalContextRef):
(APIVector::APIVector):
(APIVector::~APIVector):
(APIVector::append):
(testCAPIViaCpp):
(TestAPI::evaluateScript):
(TestAPI::callFunction):
(TestAPI::functionReturnsTrue):
(TestAPI::check):
(TestAPI::checkJSAndAPIMatch):
(TestAPI::interestingObjects):
(TestAPI::interestingKeys):
(TestAPI::run):
* API/tests/testapi.mm:
(testObjectiveCAPIMain):
* JavaScriptCore.xcodeproj/project.pbxproj:
* config.h:
* postprocess-headers.sh:
* shell/CMakeLists.txt:
* testmem/testmem.mm:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@234227 268f45cc-cd09-0410-ab3c-d52691b4dbfc

35 files changed:
Source/JavaScriptCore/API/APICast.h
Source/JavaScriptCore/API/JSBasePrivate.h
Source/JavaScriptCore/API/JSContext.h
Source/JavaScriptCore/API/JSContextPrivate.h
Source/JavaScriptCore/API/JSContextRef.h
Source/JavaScriptCore/API/JSContextRefInternal.h
Source/JavaScriptCore/API/JSContextRefPrivate.h
Source/JavaScriptCore/API/JSManagedValue.h
Source/JavaScriptCore/API/JSObjectRef.cpp
Source/JavaScriptCore/API/JSObjectRef.h
Source/JavaScriptCore/API/JSRemoteInspector.h
Source/JavaScriptCore/API/JSTypedArray.h
Source/JavaScriptCore/API/JSValue.h
Source/JavaScriptCore/API/JSValue.mm
Source/JavaScriptCore/API/JSValueRef.cpp
Source/JavaScriptCore/API/JSValueRef.h
Source/JavaScriptCore/API/WebKitAvailability.h
Source/JavaScriptCore/API/tests/CurrentThisInsideBlockGetterTest.mm
Source/JavaScriptCore/API/tests/CustomGlobalObjectClassTest.c
Source/JavaScriptCore/API/tests/DateTests.mm
Source/JavaScriptCore/API/tests/JSExportTests.mm
Source/JavaScriptCore/API/tests/JSNode.c
Source/JavaScriptCore/API/tests/JSNodeList.c
Source/JavaScriptCore/API/tests/Node.c
Source/JavaScriptCore/API/tests/NodeList.c
Source/JavaScriptCore/API/tests/minidom.c
Source/JavaScriptCore/API/tests/testapi.c
Source/JavaScriptCore/API/tests/testapi.cpp [new file with mode: 0644]
Source/JavaScriptCore/API/tests/testapi.mm
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/config.h
Source/JavaScriptCore/postprocess-headers.sh
Source/JavaScriptCore/shell/CMakeLists.txt
Source/JavaScriptCore/testmem/testmem.mm

index 2c22975..491bb8a 100644 (file)
@@ -30,6 +30,7 @@
 #include "JSCJSValue.h"
 #include "JSCJSValueInlines.h"
 #include "JSGlobalObject.h"
+#include "HeapCellInlines.h"
 
 namespace JSC {
     class ExecState;
index 1375949..b6c9204 100644 (file)
@@ -43,7 +43,7 @@ owns a large non-GC memory region. Calling this function will encourage the
 garbage collector to collect soon, hoping to reclaim that large non-GC memory
 region.
 */
-JS_EXPORT void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 JS_EXPORT void JSDisableGCTimer(void);
 
index 194e352..89c87f9 100644 (file)
@@ -78,7 +78,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
 @param sourceURL A URL for the script's source file. Used by debuggers and when reporting exceptions. This parameter is informative only: it does not change the behavior of the script.
 @result The last value generated by the script.
 */
-- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL NS_AVAILABLE(10_10, 8_0);
+- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @methodgroup Callback Accessors
@@ -101,7 +101,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
  a callback from JavaScript this method will return nil.
 @result The currently executing JavaScript function or nil if there isn't one.
 */
-+ (JSValue *)currentCallee NS_AVAILABLE(10_10, 8_0);
++ (JSValue *)currentCallee JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @method
@@ -176,7 +176,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
 @property
 @discussion Name of the JSContext. Exposed when remote debugging the context.
 */
-@property (copy) NSString *name NS_AVAILABLE(10_10, 8_0);
+@property (copy) NSString *name JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 @end
 
index 7d1d0cb..ff9622a 100644 (file)
 @property
 @discussion Remote inspection setting of the JSContext. Default value is YES.
 */
-@property (setter=_setRemoteInspectionEnabled:) BOOL _remoteInspectionEnabled NS_AVAILABLE(10_10, 8_0);
+@property (setter=_setRemoteInspectionEnabled:) BOOL _remoteInspectionEnabled JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @property
 @discussion Set whether or not the native call stack is included when reporting exceptions. Default value is YES.
 */
-@property (setter=_setIncludesNativeCallStackWhenReportingExceptions:) BOOL _includesNativeCallStackWhenReportingExceptions NS_AVAILABLE(10_10, 8_0);
+@property (setter=_setIncludesNativeCallStackWhenReportingExceptions:) BOOL _includesNativeCallStackWhenReportingExceptions JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @property
 @discussion Set the run loop the Web Inspector debugger should use when evaluating JavaScript in the JSContext.
 */
-@property (setter=_setDebuggerRunLoop:) CFRunLoopRef _debuggerRunLoop NS_AVAILABLE(10_10, 8_0);
+@property (setter=_setDebuggerRunLoop:) CFRunLoopRef _debuggerRunLoop JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 @end
 
index e15cae5..28d0a67 100644 (file)
@@ -53,7 +53,7 @@ extern "C" {
  JSContextGroup's run loop once it has been created.
 @result The created JSContextGroup.
 */
-JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
@@ -61,14 +61,14 @@ JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) CF_AVAILABLE(10_6, 7_0);
 @param group The JSContextGroup to retain.
 @result A JSContextGroup that is the same as group.
 */
-JS_EXPORT JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
 @abstract Releases a JavaScript context group.
 @param group The JSContextGroup to release.
 */
-JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
@@ -83,7 +83,7 @@ JS_EXPORT void JSContextGroupRelease(JSContextGroupRef group) CF_AVAILABLE(10_6,
  NULL to use the default object class.
 @result A JSGlobalContext with a global object of class globalObjectClass.
 */
-JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) CF_AVAILABLE(10_5, 7_0);
+JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) JSC_API_AVAILABLE(macosx(10.5), ios(7.0));
 
 /*!
 @function
@@ -97,7 +97,7 @@ JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
 @result A JSGlobalContext with a global object of class globalObjectClass and a context
  group equal to group.
 */
-JS_EXPORT JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
@@ -128,7 +128,7 @@ JS_EXPORT JSObjectRef JSContextGetGlobalObject(JSContextRef ctx);
 @param ctx The JSContext whose group you want to get.
 @result ctx's group.
 */
-JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
@@ -136,7 +136,7 @@ JS_EXPORT JSContextGroupRef JSContextGetGroup(JSContextRef ctx) CF_AVAILABLE(10_
 @param ctx The JSContext whose global context you want to get.
 @result ctx's global context.
 */
-JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) CF_AVAILABLE(10_7, 7_0);
+JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) JSC_API_AVAILABLE(macosx(10.7), ios(7.0));
 
 /*!
 @function
@@ -146,7 +146,7 @@ JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) CF_AVAI
 @discussion A JSGlobalContext's name is exposed for remote debugging to make it
 easier to identify the context you would like to attach to.
 */
-JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
+JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @function
@@ -154,7 +154,7 @@ JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) CF_AVAILAB
 @param ctx The JSGlobalContext that you want to name.
 @param name The remote debugging name to set on ctx.
 */
-JS_EXPORT void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) CF_AVAILABLE(10_10, 8_0);
+JS_EXPORT void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 #ifdef __cplusplus
 }
index 79d7eb6..9d4f18a 100644 (file)
@@ -42,7 +42,7 @@ extern "C" {
 @abstract Gets the run loop used by the Web Inspector debugger when evaluating JavaScript in this context.
 @param ctx The JSGlobalContext whose setting you want to get.
 */
-JS_EXPORT CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
+JS_EXPORT CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @function
@@ -50,7 +50,7 @@ JS_EXPORT CFRunLoopRef JSGlobalContextGetDebuggerRunLoop(JSGlobalContextRef ctx)
 @param ctx The JSGlobalContext that you want to change.
 @param runLoop The new value of the setting for the context.
 */
-JS_EXPORT void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runLoop) CF_AVAILABLE(10_10, 8_0);
+JS_EXPORT void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runLoop) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 #endif
 
 #ifdef __cplusplus
index 19604ea..ec676d8 100644 (file)
@@ -44,7 +44,7 @@ extern "C" {
 @param ctx The JSContext whose backtrace you want to get
 @result A string containing the backtrace
 */
-JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
     
 
 /*! 
@@ -85,14 +85,14 @@ typedef bool
  need to call JSContextGroupSetExecutionTimeLimit before you start executing
  any scripts.
 */
-JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* context) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* context) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
 @abstract Clears the script execution time limit.
 @param group The JavaScript context group that the time limit is cleared on.
 */
-JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
@@ -101,7 +101,7 @@ JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) CF
 @result The value of the setting, true if remote inspection is enabled, otherwise false.
 @discussion Remote inspection is true by default.
 */
-JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
+JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @function
@@ -109,7 +109,7 @@ JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx)
 @param ctx The JSGlobalContext that you want to change.
 @param enabled The new remote inspection enabled setting for the context.
 */
-JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled) CF_AVAILABLE(10_10, 8_0);    
+JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));    
 
 /*!
 @function
@@ -118,7 +118,7 @@ JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx,
 @result The value of the setting, true if remote inspection is enabled, otherwise false.
 @discussion This setting is true by default.
 */
-JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) CF_AVAILABLE(10_10, 8_0);
+JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @function
@@ -126,7 +126,7 @@ JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(
 @param ctx The JSGlobalContext that you want to change.
 @param includesNativeCallStack The new value of the setting for the context.
 */
-JS_EXPORT void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) CF_AVAILABLE(10_10, 8_0);
+JS_EXPORT void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 #ifdef __cplusplus
 }
index 01073fa..418074b 100644 (file)
@@ -57,7 +57,7 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
 @result The new JSManagedValue.
 */
 + (JSManagedValue *)managedValueWithValue:(JSValue *)value;
-+ (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner NS_AVAILABLE(10_10, 8_0);
++ (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner JSC_API_AVAILABLE(macosx(10.10), ios(8.0));
 
 /*!
 @method
index 566b736..5451a2f 100644 (file)
@@ -366,6 +366,100 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope
     handleExceptionIfNeeded(scope, exec, exception);
 }
 
+bool JSObjectHasPropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception)
+{
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+    ExecState* exec = toJS(ctx);
+    VM& vm = exec->vm();
+    JSLockHolder locker(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
+    JSObject* jsObject = toJS(object);
+    Identifier ident = toJS(exec, key).toPropertyKey(exec);
+    if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
+        return false;
+
+    bool result = jsObject->hasProperty(exec, ident);
+    handleExceptionIfNeeded(scope, exec, exception);
+    return result;
+}
+
+JSValueRef JSObjectGetPropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception)
+{
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+    ExecState* exec = toJS(ctx);
+    VM& vm = exec->vm();
+    JSLockHolder locker(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
+    JSObject* jsObject = toJS(object);
+    Identifier ident = toJS(exec, key).toPropertyKey(exec);
+    if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
+        return nullptr;
+
+    JSValue jsValue = jsObject->get(exec, ident);
+    handleExceptionIfNeeded(scope, exec, exception);
+    return toRef(exec, jsValue);
+}
+
+void JSObjectSetPropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
+{
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+    ExecState* exec = toJS(ctx);
+    VM& vm = exec->vm();
+    JSLockHolder locker(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
+    JSObject* jsObject = toJS(object);
+    JSValue jsValue = toJS(exec, value);
+
+    Identifier ident = toJS(exec, key).toPropertyKey(exec);
+    if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
+        return;
+
+    bool doesNotHaveProperty = attributes && !jsObject->hasProperty(exec, ident);
+    if (LIKELY(!scope.exception())) {
+        if (doesNotHaveProperty) {
+            PropertyDescriptor desc(jsValue, attributes);
+            jsObject->methodTable(vm)->defineOwnProperty(jsObject, exec, ident, desc, false);
+        } else {
+            PutPropertySlot slot(jsObject);
+            jsObject->methodTable(vm)->put(jsObject, exec, ident, jsValue, slot);
+        }
+    }
+    handleExceptionIfNeeded(scope, exec, exception);
+}
+
+bool JSObjectDeletePropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception)
+{
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+    ExecState* exec = toJS(ctx);
+    VM& vm = exec->vm();
+    JSLockHolder locker(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
+    JSObject* jsObject = toJS(object);
+    Identifier ident = toJS(exec, key).toPropertyKey(exec);
+    if (handleExceptionIfNeeded(scope, exec, exception) == ExceptionStatus::DidThrow)
+        return false;
+
+    bool result = jsObject->methodTable(vm)->deleteProperty(jsObject, exec, ident);
+    handleExceptionIfNeeded(scope, exec, exception);
+    return result;
+}
+
 JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
 {
     if (!ctx) {
index 95d53b7..db5569a 100644 (file)
@@ -441,7 +441,7 @@ JS_EXPORT JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsCla
  @discussion The behavior of this function does not exactly match the behavior of the built-in Array constructor. Specifically, if one argument 
  is supplied, this function returns an array with one element.
  */
-JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
  @function
@@ -452,7 +452,7 @@ JS_EXPORT JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount,
  @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result A JSObject that is a Date.
  */
-JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
  @function
@@ -463,7 +463,7 @@ JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, c
  @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result A JSObject that is a Error.
  */
-JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
  @function
@@ -474,7 +474,7 @@ JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount,
  @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result A JSObject that is a RegExp.
  */
-JS_EXPORT JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) CF_AVAILABLE(10_6, 7_0);
+JS_EXPORT JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.6), ios(7.0));
 
 /*!
 @function
@@ -536,9 +536,9 @@ JS_EXPORT JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, J
 @param ctx The execution context to use.
 @param object The JSObject whose property you want to set.
 @param propertyName A JSString containing the property's name.
-@param value A JSValue to use as the property's value.
-@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
+@param value A JSValueRef to use as the property's value.
 @param attributes A logically ORed set of JSPropertyAttributes to give to the property.
+@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
 */
 JS_EXPORT void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception);
 
@@ -555,6 +555,54 @@ JS_EXPORT bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSSt
 
 /*!
 @function
+@abstract Tests whether an object has a given property using a JSValueRef as the property key.
+@param object The JSObject to test.
+@param propertyKey A JSValueRef containing the property key to use when looking up the property.
+@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
+@result true if the object has a property whose name matches propertyKey, otherwise false.
+@discussion This function is the same as performing "propertyKey in object" from JavaScript.
+*/
+JS_EXPORT bool JSObjectHasPropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef* exception) JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA));
+
+/*!
+@function
+@abstract Gets a property from an object using a JSValueRef as the property key.
+@param ctx The execution context to use.
+@param object The JSObject whose property you want to get.
+@param propertyKey A JSValueRef containing the property key to use when looking up the property.
+@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
+@result The property's value if object has the property key, otherwise the undefined value.
+@discussion This function is the same as performing "object[propertyKey]" from JavaScript.
+*/
+JS_EXPORT JSValueRef JSObjectGetPropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef* exception) JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA));
+
+/*!
+@function
+@abstract Sets a property on an object using a JSValueRef as the property key.
+@param ctx The execution context to use.
+@param object The JSObject whose property you want to set.
+@param propertyKey A JSValueRef containing the property key to use when looking up the property.
+@param value A JSValueRef to use as the property's value.
+@param attributes A logically ORed set of JSPropertyAttributes to give to the property.
+@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
+@discussion This function is the same as performing "object[propertyKey] = value" from JavaScript.
+*/
+JS_EXPORT void JSObjectSetPropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA));
+
+/*!
+@function
+@abstract Deletes a property from an object using a JSValueRef as the property key.
+@param ctx The execution context to use.
+@param object The JSObject whose property you want to delete.
+@param propertyKey A JSValueRef containing the property key to use when looking up the property.
+@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
+@result true if the delete operation succeeds, otherwise false (for example, if the property has the kJSPropertyAttributeDontDelete attribute set).
+@discussion This function is the same as performing "delete object[propertyKey]" from JavaScript.
+*/
+JS_EXPORT bool JSObjectDeletePropertyKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef* exception) JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA));
+
+/*!
+@function
 @abstract Gets a property from an object by numeric index.
 @param ctx The execution context to use.
 @param object The JSObject whose property you want to get.
index c8bac6d..6186b92 100644 (file)
@@ -40,14 +40,14 @@ typedef pid_t JSProcessID;
 extern "C" {
 #endif
 
-JS_EXPORT void JSRemoteInspectorDisableAutoStart(void) CF_AVAILABLE(10_11, 9_0);
-JS_EXPORT void JSRemoteInspectorStart(void) CF_AVAILABLE(10_11, 9_0);
-JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(JSProcessID, const uint8_t* auditData, size_t auditLength) CF_AVAILABLE(10_11, 9_0);
+JS_EXPORT void JSRemoteInspectorDisableAutoStart(void) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
+JS_EXPORT void JSRemoteInspectorStart(void) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
+JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(JSProcessID, const uint8_t* auditData, size_t auditLength) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
 
-JS_EXPORT void JSRemoteInspectorSetLogToSystemConsole(bool) CF_AVAILABLE(10_11, 9_0);
+JS_EXPORT void JSRemoteInspectorSetLogToSystemConsole(bool) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
 
-JS_EXPORT bool JSRemoteInspectorGetInspectionEnabledByDefault(void) CF_AVAILABLE(10_11, 9_0);
-JS_EXPORT void JSRemoteInspectorSetInspectionEnabledByDefault(bool) CF_AVAILABLE(10_11, 9_0);
+JS_EXPORT bool JSRemoteInspectorGetInspectionEnabledByDefault(void) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
+JS_EXPORT void JSRemoteInspectorSetInspectionEnabledByDefault(bool) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
 
 #ifdef __cplusplus
 }
index e23b76d..6d86022 100644 (file)
@@ -45,7 +45,7 @@ extern "C" {
  @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result             A JSObjectRef that is a Typed Array with all elements set to zero or NULL if there was an error.
  */
-JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t length, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t length, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -60,7 +60,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType
  @result                   A JSObjectRef Typed Array whose backing store is the same as the one pointed to by bytes or NULL if there was an error.
  @discussion               If an exception is thrown during this function the bytesDeallocator will always be called.
  */
-JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithBytesNoCopy(JSContextRef ctx, JSTypedArrayType arrayType, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithBytesNoCopy(JSContextRef ctx, JSTypedArrayType arrayType, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -71,7 +71,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithBytesNoCopy(JSContextRef ctx, JS
  @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result             A JSObjectRef that is a Typed Array or NULL if there was an error. The backing store of the Typed Array will be buffer.
  */
-JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -84,7 +84,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBuffer(JSContextRef ctx, JS
  @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result             A JSObjectRef that is a Typed Array or NULL if there was an error. The backing store of the Typed Array will be buffer.
  */
-JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, size_t byteOffset, size_t length, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRef ctx, JSTypedArrayType arrayType, JSObjectRef buffer, size_t byteOffset, size_t length, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -95,7 +95,7 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRe
  @result             A pointer to the raw data buffer that serves as object's backing store or NULL if object is not a Typed Array object.
  @discussion         The pointer returned by this function is temporary and is not guaranteed to remain valid across JavaScriptCore API calls.
  */
-JS_EXPORT void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -105,7 +105,7 @@ JS_EXPORT void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef obje
  @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result             The length of the Typed Array object or 0 if the object is not a Typed Array object.
  */
-JS_EXPORT size_t JSObjectGetTypedArrayLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT size_t JSObjectGetTypedArrayLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -115,7 +115,7 @@ JS_EXPORT size_t JSObjectGetTypedArrayLength(JSContextRef ctx, JSObjectRef objec
  @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result             The byte length of the Typed Array object or 0 if the object is not a Typed Array object.
  */
-JS_EXPORT size_t JSObjectGetTypedArrayByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT size_t JSObjectGetTypedArrayByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -125,7 +125,7 @@ JS_EXPORT size_t JSObjectGetTypedArrayByteLength(JSContextRef ctx, JSObjectRef o
  @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result             The byte offset of the Typed Array object or 0 if the object is not a Typed Array object.
  */
-JS_EXPORT size_t JSObjectGetTypedArrayByteOffset(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT size_t JSObjectGetTypedArrayByteOffset(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -135,7 +135,7 @@ JS_EXPORT size_t JSObjectGetTypedArrayByteOffset(JSContextRef ctx, JSObjectRef o
  @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result             A JSObjectRef with a JSTypedArrayType of kJSTypedArrayTypeArrayBuffer or NULL if object is not a Typed Array.
  */
-JS_EXPORT JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 // ------------- Array Buffer functions -------------
 
@@ -151,7 +151,7 @@ JS_EXPORT JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef
  @result                   A JSObjectRef Array Buffer whose backing store is the same as the one pointed to by bytes or NULL if there was an error.
  @discussion               If an exception is thrown during this function the bytesDeallocator will always be called.
  */
-JS_EXPORT JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -161,7 +161,7 @@ JS_EXPORT JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, v
  @result           A pointer to the raw data buffer that serves as object's backing store or NULL if object is not an Array Buffer object.
  @discussion       The pointer returned by this function is temporary and is not guaranteed to remain valid across JavaScriptCore API calls.
  */
-JS_EXPORT void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /*!
  @function
@@ -171,7 +171,7 @@ JS_EXPORT void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef obj
  @param exception  A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result           The number of bytes stored in the data object.
  */
-JS_EXPORT size_t JSObjectGetArrayBufferByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT size_t JSObjectGetArrayBufferByteLength(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 #ifdef __cplusplus
 }
index 1410dd7..024ebb0 100644 (file)
 NS_CLASS_AVAILABLE(10_9, 7_0)
 @interface JSValue : NSObject
 
+#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < JSC_MAC_VERSION_TBA) || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < JSC_IOS_VERSION_TBA)
+typedef NSString *JSValuePropertyKeyType;
+#else
+typedef id JSValuePropertyKeyType;
+#endif
+
 /*!
 @property
 @abstract The JSContext that this value originates from.
@@ -149,6 +155,15 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
 + (JSValue *)valueWithUndefinedInContext:(JSContext *)context;
 
 /*!
+ @method
+ @abstract Create a new, unique, symbol object.
+ @param description The description of the symbol object being created.
+ @param context The JSContext to which the resulting JSValue belongs.
+ @result The JSValue representing a unique JavaScript value with type symbol.
+ */
++ (JSValue *)valueWithNewSymbolFromDescription:(NSString *)description inContext:(JSContext *)context JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA));
+
+/*!
 @methodgroup Converting to Objective-C Types
 @discussion When converting between JavaScript values and Objective-C objects a copy is
  performed. Values of types listed below are copied to the corresponding
@@ -305,43 +320,48 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
 /*!
 @methodgroup Accessing Properties
 */
+
 /*!
 @method
 @abstract Access a property of a JSValue.
 @result The JSValue for the requested property or the JSValue <code>undefined</code> 
  if the property does not exist.
+@discussion Corresponds to the JavaScript operation <code>object[property]</code>. Pass an NSString * to access a named property. Other valid properties include symbols, numbers, and stringifiable objects. In macOS 10.13 and iOS 11 and below, 'property' was an NSString *.
 */
-- (JSValue *)valueForProperty:(NSString *)property;
+- (JSValue *)valueForProperty:(JSValuePropertyKeyType)property;
 
 /*!
 @method
 @abstract Set a property on a JSValue.
+@discussion Corresponds to the JavaScript operation <code>object[property] = value</code>. Pass an NSString * to access a named property. Other valid properties include symbols, numbers, and stringifiable objects. In macOS 10.13 and iOS 11 and below, 'property' was an NSString *.
 */
-- (void)setValue:(id)value forProperty:(NSString *)property;
+- (void)setValue:(id)value forProperty:(JSValuePropertyKeyType)property;
 
 /*!
 @method
 @abstract Delete a property from a JSValue.
 @result YES if deletion is successful, NO otherwise.
+@discussion Corresponds to the JavaScript operation <code>delete object[property]</code>. Pass an NSString * to access a named property. Other valid properties include symbols, numbers, and stringifiable objects. In macOS 10.13 and iOS 11 and below, 'property' was an NSString *.
 */
-- (BOOL)deleteProperty:(NSString *)property;
+- (BOOL)deleteProperty:(JSValuePropertyKeyType)property;
 
 /*!
 @method
 @abstract Check if a JSValue has a property.
 @discussion This method has the same function as the JavaScript operator <code>in</code>.
 @result Returns YES if property is present on the value.
+@discussion Corresponds to the JavaScript operation <code>property in object</code>. Pass an NSString * to access a named property. Other valid properties include symbols, numbers, and stringifiable objects. In macOS 10.13 and iOS 11 and below, 'property' was an NSString *.
 */
-- (BOOL)hasProperty:(NSString *)property;
+- (BOOL)hasProperty:(JSValuePropertyKeyType)property;
 
 /*!
 @method
 @abstract Define properties with custom descriptors on JSValues.
 @discussion This method may be used to create a data or accessor property on an object.
  This method operates in accordance with the Object.defineProperty method in the 
- JavaScript language.
+ JavaScript language. Pass an NSString * to access a named property. Other valid properties include symbols, numbers, and stringifiable objects. In macOS 10.13 and iOS 11 and below, 'property' was an NSString *.
 */
-- (void)defineProperty:(NSString *)property descriptor:(id)descriptor;
+- (void)defineProperty:(JSValuePropertyKeyType)property descriptor:(id)descriptor;
 
 /*!
 @method
@@ -404,15 +424,21 @@ NS_CLASS_AVAILABLE(10_9, 7_0)
 
 /*!
 @property
+@abstract Check if a JSValue is a symbol.
+*/
+@property (readonly) BOOL isSymbol JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA));
+
+/*!
+@property
 @abstract Check if a JSValue is an array.
 */ 
-@property (readonly) BOOL isArray NS_AVAILABLE(10_11, 9_0);
+@property (readonly) BOOL isArray JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
 
 /*!
 @property
 @abstract Check if a JSValue is a date.
 */ 
-@property (readonly) BOOL isDate NS_AVAILABLE(10_11, 9_0);
+@property (readonly) BOOL isDate JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
 
 /*!
 @method
@@ -569,13 +595,16 @@ Create a JSValue from a CGRect.
 @/textblock
 
  An object key passed as a subscript will be converted to a JavaScript value,
- and then the value converted to a string used as a property name.
+ and then the value converted to a string used as a property name. In macOS
+ 10.13 and iOS 11 and below, the <code>key</code> argument of
+ <code>setObject:object forKeyedSubscript:key</code> was restricted to an
+ <code>NSString <NSCopying> *</code> but that restriction was never used.
 */
 @interface JSValue (SubscriptSupport)
 
-- (JSValue *)objectForKeyedSubscript:(id)key;
+- (JSValue *)objectForKeyedSubscript:(JSValuePropertyKeyType)key;
 - (JSValue *)objectAtIndexedSubscript:(NSUInteger)index;
-- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key;
+- (void)setObject:(id)object forKeyedSubscript:(JSValuePropertyKeyType)key;
 - (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index;
 
 @end
index a266844..3ff5c47 100644 (file)
@@ -39,6 +39,7 @@
 #import "JSCJSValue.h"
 #import "Strong.h"
 #import "StrongInlines.h"
+#import <wtf/Expected.h>
 #import <wtf/HashMap.h>
 #import <wtf/HashSet.h>
 #import <wtf/Lock.h>
@@ -151,6 +152,13 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
     return [JSValue valueWithJSValueRef:JSValueMakeUndefined([context JSGlobalContextRef]) inContext:context];
 }
 
++ (JSValue *)valueWithNewSymbolFromDescription:(NSString *)description inContext:(JSContext *)context
+{
+    JSStringRef string = JSStringCreateWithCFString(reinterpret_cast<CFStringRef>(description));
+    return [JSValue valueWithJSValueRef:JSValueMakeSymbol([context JSGlobalContextRef], string) inContext:context];
+}
+
+
 - (id)toObject
 {
     return valueToObject(_context, m_value);
@@ -234,72 +242,81 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
     return result;
 }
 
-- (JSValue *)valueForProperty:(NSString *)propertyName
+template<typename Result, typename NSStringFunction, typename JSValueFunction, typename... Types>
+inline Expected<Result, JSValueRef> performPropertyOperation(NSStringFunction stringFunction, JSValueFunction jsFunction, JSValue* value, id propertyKey, Types... arguments)
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
+    JSContext* context = [value context];
+    JSValueRef exception = nullptr;
+    JSObjectRef object = JSValueToObject([context JSGlobalContextRef], [value JSValueRef], &exception);
     if (exception)
-        return [_context valueFromNotifyException:exception];
+        return Unexpected<JSValueRef>(exception);
 
-    JSStringRef name = JSStringCreateWithCFString((__bridge CFStringRef)propertyName);
-    JSValueRef result = JSObjectGetProperty([_context JSGlobalContextRef], object, name, &exception);
-    JSStringRelease(name);
-    if (exception)
-        return [_context valueFromNotifyException:exception];
+    Result result;
+    // If it's a NSString already, reduce indirection and just pass the NSString.
+    if ([propertyKey isKindOfClass:[NSString class]]) {
+        JSStringRef name = JSStringCreateWithCFString((__bridge CFStringRef)propertyKey);
+        result = stringFunction([context JSGlobalContextRef], object, name, arguments..., &exception);
+        JSStringRelease(name);
+    } else
+        result = jsFunction([context JSGlobalContextRef], object, [[JSValue valueWithObject:propertyKey inContext:context] JSValueRef], arguments..., &exception);
+    return Expected<Result, JSValueRef>(result);
+}
 
-    return [JSValue valueWithJSValueRef:result inContext:_context];
+- (JSValue *)valueForProperty:(id)key
+{
+    auto result = performPropertyOperation<JSValueRef>(JSObjectGetProperty, JSObjectGetPropertyKey, self, key);
+    if (!result)
+        return [_context valueFromNotifyException:result.error()];
+
+    return [JSValue valueWithJSValueRef:result.value() inContext:_context];
 }
 
-- (void)setValue:(id)value forProperty:(NSString *)propertyName
+
+- (void)setValue:(id)value forProperty:(JSValuePropertyKeyType)key
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
-    if (exception) {
-        [_context notifyException:exception];
-        return;
-    }
+    // We need Unit business because void can't be assigned to in performPropertyOperation and I don't want to duplicate the code...
+    using Unit = std::tuple<>;
+    auto stringSetProperty = [] (auto... args) -> Unit {
+        JSObjectSetProperty(args...);
+        return { };
+    };
 
-    JSStringRef name = JSStringCreateWithCFString((__bridge CFStringRef)propertyName);
-    JSObjectSetProperty([_context JSGlobalContextRef], object, name, objectToValue(_context, value), 0, &exception);
-    JSStringRelease(name);
-    if (exception) {
-        [_context notifyException:exception];
+    auto jsValueSetProperty = [] (auto... args) -> Unit {
+        JSObjectSetPropertyKey(args...);
+        return { };
+    };
+
+    auto result = performPropertyOperation<Unit>(stringSetProperty, jsValueSetProperty, self, key, objectToValue(_context, value), kJSPropertyAttributeNone);
+    if (!result) {
+        [_context notifyException:result.error()];
         return;
     }
 }
 
-- (BOOL)deleteProperty:(NSString *)propertyName
+- (BOOL)deleteProperty:(JSValuePropertyKeyType)key
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
-    if (exception)
-        return [_context boolFromNotifyException:exception];
-
-    JSStringRef name = JSStringCreateWithCFString((__bridge CFStringRef)propertyName);
-    BOOL result = JSObjectDeleteProperty([_context JSGlobalContextRef], object, name, &exception);
-    JSStringRelease(name);
-    if (exception)
-        return [_context boolFromNotifyException:exception];
-
-    return result;
+    Expected<BOOL, JSValueRef> result = performPropertyOperation<BOOL>(JSObjectDeleteProperty, JSObjectDeletePropertyKey, self, key);
+    if (!result)
+        return [_context boolFromNotifyException:result.error()];
+    return result.value();
 }
 
-- (BOOL)hasProperty:(NSString *)propertyName
+- (BOOL)hasProperty:(JSValuePropertyKeyType)key
 {
-    JSValueRef exception = 0;
-    JSObjectRef object = JSValueToObject([_context JSGlobalContextRef], m_value, &exception);
-    if (exception)
-        return [_context boolFromNotifyException:exception];
+    // The C-api doesn't return an exception value for the string version of has property.
+    auto stringHasProperty = [] (JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef*) -> BOOL {
+        return JSObjectHasProperty(ctx, object, propertyName);
+    };
 
-    JSStringRef name = JSStringCreateWithCFString((__bridge CFStringRef)propertyName);
-    BOOL result = JSObjectHasProperty([_context JSGlobalContextRef], object, name);
-    JSStringRelease(name);
-    return result;
+    Expected<BOOL, JSValueRef> result = performPropertyOperation<BOOL>(stringHasProperty, JSObjectHasPropertyKey, self, key);
+    if (!result)
+        return [_context boolFromNotifyException:result.error()];
+    return result.value();
 }
 
-- (void)defineProperty:(NSString *)property descriptor:(id)descriptor
+- (void)defineProperty:(JSValuePropertyKeyType)key descriptor:(id)descriptor
 {
-    [[_context globalObject][@"Object"] invokeMethod:@"defineProperty" withArguments:@[ self, property, descriptor ]];
+    [[_context globalObject][@"Object"] invokeMethod:@"defineProperty" withArguments:@[ self, key, descriptor ]];
 }
 
 - (JSValue *)valueAtIndex:(NSUInteger)index
@@ -372,6 +389,11 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
     return JSValueIsObject([_context JSGlobalContextRef], m_value);
 }
 
+- (BOOL)isSymbol
+{
+    return JSValueIsSymbol([_context JSGlobalContextRef], m_value);
+}
+
 - (BOOL)isArray
 {
     return JSValueIsArray([_context JSGlobalContextRef], m_value);
@@ -554,13 +576,7 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
 
 - (JSValue *)objectForKeyedSubscript:(id)key
 {
-    if (![key isKindOfClass:[NSString class]]) {
-        key = [[JSValue valueWithObject:key inContext:_context] toString];
-        if (!key)
-            return [JSValue valueWithUndefinedInContext:_context];
-    }
-
-    return [self valueForProperty:(NSString *)key];
+    return [self valueForProperty:key];
 }
 
 - (JSValue *)objectAtIndexedSubscript:(NSUInteger)index
@@ -568,15 +584,9 @@ NSString * const JSPropertyDescriptorSetKey = @"set";
     return [self valueAtIndex:index];
 }
 
-- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key
+- (void)setObject:(id)object forKeyedSubscript:(id)key
 {
-    if (![key isKindOfClass:[NSString class]]) {
-        key = [[JSValue valueWithObject:key inContext:_context] toString];
-        if (!key)
-            return;
-    }
-
-    [self setValue:object forProperty:(NSString *)key];
+    [self setValue:object forProperty:key];
 }
 
 - (void)setObject:(id)object atIndexedSubscript:(NSUInteger)index
index 79559be..daca0e1 100644 (file)
@@ -86,6 +86,8 @@ static bool evernoteHackNeeded()
         return kJSTypeNumber;
     if (jsValue.isString())
         return kJSTypeString;
+    if (jsValue.isSymbol())
+        return kJSTypeSymbol;
     ASSERT(jsValue.isObject());
     return kJSTypeObject;
 }
@@ -162,6 +164,18 @@ bool JSValueIsObject(JSContextRef ctx, JSValueRef value)
     return toJS(exec, value).isObject();
 }
 
+bool JSValueIsSymbol(JSContextRef ctx, JSValueRef value)
+{
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+    ExecState* exec = toJS(ctx);
+    JSLockHolder locker(exec);
+
+    return toJS(exec, value).isSymbol();
+}
+
 bool JSValueIsArray(JSContextRef ctx, JSValueRef value)
 {
     if (!ctx) {
@@ -320,6 +334,22 @@ JSValueRef JSValueMakeNumber(JSContextRef ctx, double value)
     return toRef(exec, jsNumber(purifyNaN(value)));
 }
 
+JSValueRef JSValueMakeSymbol(JSContextRef ctx, JSStringRef description)
+{
+    if (!ctx) {
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+    ExecState* exec = toJS(ctx);
+    JSLockHolder locker(exec);
+    auto scope = DECLARE_CATCH_SCOPE(exec->vm());
+
+    JSString* jsDescription = jsString(exec, description ? description->string() : String());
+    RETURN_IF_EXCEPTION(scope, nullptr);
+
+    return toRef(exec, Symbol::create(exec, jsDescription));
+}
+
 JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
 {
     if (!ctx) {
index 9815de7..12f2dcc 100644 (file)
@@ -42,6 +42,7 @@
 @constant     kJSTypeNumber     A primitive number value.
 @constant     kJSTypeString     A primitive string value.
 @constant     kJSTypeObject     An object value (meaning that this JSValueRef is a JSObjectRef).
+@constant     kJSTypeSymbol     A primitive symbol value.
 */
 typedef enum {
     kJSTypeUndefined,
@@ -49,7 +50,8 @@ typedef enum {
     kJSTypeBoolean,
     kJSTypeNumber,
     kJSTypeString,
-    kJSTypeObject
+    kJSTypeObject,
+    kJSTypeSymbol JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA))
 } JSType;
 
 /*!
@@ -80,7 +82,7 @@ typedef enum {
     kJSTypedArrayTypeFloat64Array,
     kJSTypedArrayTypeArrayBuffer,
     kJSTypedArrayTypeNone,
-} JSTypedArrayType CF_ENUM_AVAILABLE(10_12, 10_0);
+} JSTypedArrayType JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 #ifdef __cplusplus
 extern "C" {
@@ -151,6 +153,16 @@ JS_EXPORT bool JSValueIsObject(JSContextRef ctx, JSValueRef value);
 
 /*!
 @function
+@abstract       Tests whether a JavaScript value's type is the symbol type.
+@param ctx      The execution context to use.
+@param value    The JSValue to test.
+@result         true if value's type is the symbol type, otherwise false.
+*/
+JS_EXPORT bool JSValueIsSymbol(JSContextRef ctx, JSValueRef value) JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA));
+
+
+/*!
+@function
 @abstract Tests whether a JavaScript value is an object with a given class in its class chain.
 @param ctx The execution context to use.
 @param value The JSValue to test.
@@ -166,7 +178,7 @@ JS_EXPORT bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClas
 @param value    The JSValue to test.
 @result         true if value is an array, otherwise false.
 */
-JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0);
+JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
 
 /*!
 @function
@@ -175,7 +187,7 @@ JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(1
 @param value    The JSValue to test.
 @result         true if value is a date, otherwise false.
 */
-JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0);
+JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) JSC_API_AVAILABLE(macosx(10.11), ios(9.0));
 
 /*!
 @function
@@ -185,7 +197,7 @@ JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10
 @param exception    A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
 @result             A value of type JSTypedArrayType that identifies value's Typed Array type, or kJSTypedArrayTypeNone if the value is not a Typed Array object.
  */
-JS_EXPORT JSTypedArrayType JSValueGetTypedArrayType(JSContextRef ctx, JSValueRef value, JSValueRef* exception) CF_AVAILABLE(10_12, 10_0);
+JS_EXPORT JSTypedArrayType JSValueGetTypedArrayType(JSContextRef ctx, JSValueRef value, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.12), ios(10.0));
 
 /* Comparing values */
 
@@ -259,6 +271,15 @@ JS_EXPORT JSValueRef JSValueMakeNumber(JSContextRef ctx, double number);
 
 /*!
 @function
+@abstract            Creates a JavaScript value of the symbol type.
+@param ctx           The execution context to use.
+@param description   A description of the newly created symbol value.
+@result              A unique JSValue of the symbol type, whose description matches the one provided.
+*/
+JS_EXPORT JSValueRef JSValueMakeSymbol(JSContextRef ctx, JSStringRef description);
+
+/*!
+@function
 @abstract       Creates a JavaScript value of the string type.
 @param ctx  The execution context to use.
 @param string   The JSString to assign to the newly created JSValue. The
@@ -276,7 +297,7 @@ JS_EXPORT JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string);
  @param string   The JSString containing the JSON string to be parsed.
  @result         A JSValue containing the parsed value, or NULL if the input is invalid.
  */
-JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) CF_AVAILABLE(10_7, 7_0);
+JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) JSC_API_AVAILABLE(macosx(10.7), ios(7.0));
 
 /*!
  @function
@@ -287,7 +308,7 @@ JS_EXPORT JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef str
  @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
  @result         A JSString with the result of serialization, or NULL if an exception is thrown.
  */
-JS_EXPORT JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef value, unsigned indent, JSValueRef* exception) CF_AVAILABLE(10_7, 7_0);
+JS_EXPORT JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef value, unsigned indent, JSValueRef* exception) JSC_API_AVAILABLE(macosx(10.7), ios(7.0));
 
 /* Converting to primitive values */
 
index 8227520..0f6afb6 100644 (file)
 #endif /* !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100 */
 
 #if defined(BUILDING_GTK__)
-#undef CF_AVAILABLE
-#define CF_AVAILABLE(_mac, _ios)
-#undef CF_ENUM_AVAILABLE
-#define CF_ENUM_AVAILABLE(_mac, _ios)
+#undef JSC_API_AVAILABLE
+#define JSC_API_AVAILABLE(...)
 #endif
 
 #else
-#define CF_AVAILABLE(_mac, _ios)
-#define CF_ENUM_AVAILABLE(_mac, _ios)
+#define JSC_API_AVAILABLE(...)
 #endif
 
 #endif /* __WebKitAvailability__ */
index 53188fb..bd7e8a6 100644 (file)
@@ -23,6 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "config.h"
 #include "CurrentThisInsideBlockGetterTest.h"
 
 #if JSC_OBJC_API_ENABLED
index ac5471a..9ffe233 100644 (file)
@@ -23,6 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "config.h"
 #include "CustomGlobalObjectClassTest.h"
 
 #include <JavaScriptCore/JSObjectRefPrivate.h>
index 2bda3ad..6652177 100644 (file)
@@ -23,6 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#import "config.h"
 #import "DateTests.h"
 #import <Foundation/Foundation.h>
 
index 1cec939..dfdc95f 100644 (file)
@@ -23,6 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#import "config.h"
 #import "JSExportTests.h"
 
 #import <objc/runtime.h>
index d0a0dc3..bc0040a 100644 (file)
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#include <wtf/Platform.h>
+#include "config.h"
 
 #include "JSNode.h"
 #include "JSNodeList.h"
index f037e09..99a3295 100644 (file)
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#include <wtf/Platform.h>
+#include "config.h"
 
 #include "JSNode.h"
 #include "JSNodeList.h"
index db687e9..8f7d06b 100644 (file)
@@ -23,7 +23,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
+#include "config.h"
 #include "Node.h"
+
 #include <stddef.h>
 #include <stdlib.h>
 
index 69f4cd5..22d387c 100644 (file)
@@ -23,6 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
+#include "config.h"
 #include "NodeList.h"
 
 #include <stdlib.h>
index 02b41a9..41f18cd 100644 (file)
@@ -24,7 +24,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#include <wtf/Platform.h>
+#include "config.h"
 
 #include "JSContextRef.h"
 #include "JSNode.h"
index 7becdfe..9fb69a6 100644 (file)
@@ -23,7 +23,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <wtf/Platform.h>
+#define ASSERT_DISABLED 0
+#include "config.h"
 
 #if USE(CF)
 #include "JavaScriptCore.h"
@@ -44,7 +45,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#define ASSERT_DISABLED 0
 #include <wtf/Assertions.h>
 
 #if OS(WINDOWS)
@@ -66,6 +66,8 @@
 void testObjectiveCAPI(void);
 #endif
 
+int testCAPIViaCpp(void);
+
 bool assertTrue(bool value, const char* message);
 
 static JSGlobalContextRef context;
@@ -1361,6 +1363,7 @@ int main(int argc, char* argv[])
 #if JSC_OBJC_API_ENABLED
     testObjectiveCAPI();
 #endif
+    RELEASE_ASSERT(!testCAPIViaCpp());
 
     const char *scriptPath = "testapi.js";
     if (argc > 1) {
diff --git a/Source/JavaScriptCore/API/tests/testapi.cpp b/Source/JavaScriptCore/API/tests/testapi.cpp
new file mode 100644 (file)
index 0000000..45c36f8
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "APICast.h"
+#include "JSCJSValueInlines.h"
+#include "JSObject.h"
+
+#include <JavaScriptCore/JavaScript.h>
+#include <wtf/DataLog.h>
+#include <wtf/Expected.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+extern "C" int testCAPIViaCpp();
+
+class APIString {
+    WTF_MAKE_NONCOPYABLE(APIString);
+public:
+
+    APIString(const char* string)
+        : m_string(JSStringCreateWithUTF8CString(string))
+    {
+    }
+
+    ~APIString()
+    {
+        JSStringRelease(m_string);
+    }
+
+    operator JSStringRef() { return m_string; }
+
+private:
+    JSStringRef m_string;
+};
+
+class APIContext {
+    WTF_MAKE_NONCOPYABLE(APIContext);
+public:
+
+    APIContext()
+        : m_context(JSGlobalContextCreate(nullptr))
+    {
+        APIString print("print");
+        JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(m_context, print, [] (JSContextRef ctx, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef*) {
+
+            JSC::ExecState* exec = toJS(ctx);
+            for (unsigned i = 0; i < argumentCount; i++)
+                dataLog(toJS(exec, arguments[i]));
+            dataLogLn();
+            return JSValueMakeUndefined(ctx);
+        });
+
+        JSObjectSetProperty(m_context, JSContextGetGlobalObject(m_context), print, printFunction, kJSPropertyAttributeNone, nullptr);
+    }
+
+    ~APIContext()
+    {
+        JSGlobalContextRelease(m_context);
+    }
+
+    operator JSGlobalContextRef() { return m_context; }
+
+private:
+    JSGlobalContextRef m_context;
+};
+
+template<typename T>
+class APIVector : protected Vector<T> {
+    using Base = Vector<T>;
+public:
+    APIVector(APIContext& context)
+        : Base()
+        , m_context(context)
+    {
+    }
+
+    ~APIVector()
+    {
+        for (auto& value : *this)
+            JSValueUnprotect(m_context, value);
+    }
+
+    using Vector<T>::operator[];
+    using Vector<T>::size;
+    using Vector<T>::begin;
+    using Vector<T>::end;
+    using typename Vector<T>::iterator;
+
+    void append(T value)
+    {
+        JSValueProtect(m_context, value);
+        Base::append(WTFMove(value));
+    }
+
+private:
+    APIContext& m_context;
+};
+
+class TestAPI {
+public:
+    int run();
+private:
+
+    template<typename... Strings>
+    bool check(bool condition, Strings... message);
+
+    template<typename JSFunctor, typename APIFunctor>
+    void checkJSAndAPIMatch(const JSFunctor&, const APIFunctor&, const char* description);
+
+    // Helper methods.
+    using ScriptResult = Expected<JSValueRef, JSValueRef>;
+    ScriptResult evaluateScript(const char* script, JSObjectRef thisObject = nullptr);
+    template<typename... ArgumentTypes>
+    ScriptResult callFunction(const char* functionSource, ArgumentTypes... arguments);
+    template<typename... ArgumentTypes>
+    bool functionReturnsTrue(const char* functionSource, ArgumentTypes... arguments);
+
+    // Ways to make sets of interesting things.
+    APIVector<JSObjectRef> interestingObjects();
+    APIVector<JSValueRef> interestingKeys();
+
+    int failed { 0 };
+    APIContext context;
+};
+
+int testCAPIViaCpp()
+{
+    TestAPI tester;
+    return tester.run();
+}
+
+TestAPI::ScriptResult TestAPI::evaluateScript(const char* script, JSObjectRef thisObject)
+{
+    APIString scriptAPIString(script);
+    JSValueRef exception = nullptr;
+
+    JSValueRef result = JSEvaluateScript(context, scriptAPIString, thisObject, nullptr, 0, &exception);
+    if (exception)
+        return Unexpected<JSValueRef>(exception);
+    return ScriptResult(result);
+}
+
+template<typename... ArgumentTypes>
+TestAPI::ScriptResult TestAPI::callFunction(const char* functionSource, ArgumentTypes... arguments)
+{
+    JSValueRef function;
+    {
+        ScriptResult functionResult = evaluateScript(functionSource);
+        if (!functionResult)
+            return functionResult;
+        function = functionResult.value();
+    }
+
+    JSValueRef exception = nullptr;
+    if (JSObjectRef functionObject = JSValueToObject(context, function, &exception)) {
+        JSValueRef args[sizeof...(arguments)] { arguments... };
+        JSValueRef result = JSObjectCallAsFunction(context, functionObject, functionObject, sizeof...(arguments), args, &exception);
+        if (!exception)
+            return ScriptResult(result);
+    }
+
+    RELEASE_ASSERT(exception);
+    return Unexpected<JSValueRef>(exception);
+}
+
+template<typename... ArgumentTypes>
+bool TestAPI::functionReturnsTrue(const char* functionSource, ArgumentTypes... arguments)
+{
+    JSValueRef trueValue = JSValueMakeBoolean(context, true);
+    ScriptResult result = callFunction(functionSource, arguments...);
+    if (!result)
+        return false;
+    return JSValueIsStrictEqual(context, trueValue, result.value());
+}
+
+template<typename... Strings>
+bool TestAPI::check(bool condition, Strings... messages)
+{
+    if (!condition) {
+        dataLogLn(messages..., ": FAILED");
+        failed++;
+    } else
+        dataLogLn(messages..., ": PASSED");
+
+    return condition;
+}
+
+template<typename JSFunctor, typename APIFunctor>
+void TestAPI::checkJSAndAPIMatch(const JSFunctor& jsFunctor, const APIFunctor& apiFunctor, const char* description)
+{
+    JSValueRef exception = nullptr;
+    JSValueRef result = apiFunctor(&exception);
+    ScriptResult jsResult = jsFunctor();
+    if (!jsResult) {
+        check(exception, "JS and API calls should both throw an exception while ", description);
+        check(functionReturnsTrue("(function(a, b) { return a.constructor === b.constructor; })", exception, jsResult.error()), "JS and API calls should both throw the same exception while ", description);
+    } else {
+        check(!exception, "JS and API calls should both not throw an exception while ", description);
+        check(JSValueIsStrictEqual(context, result, jsResult.value()), "JS result and API calls should return the same value while ", description);
+    }
+}
+
+APIVector<JSObjectRef> TestAPI::interestingObjects()
+{
+    APIVector<JSObjectRef> result(context);
+    JSObjectRef array = JSValueToObject(context, evaluateScript(
+        "[{}, [], { [Symbol.iterator]: 1 }, new Date(), new String('str'), new Map(), new Set(), new WeakMap(), new WeakSet(), new Error(), new Number(42), new Boolean(), { get length() { throw new Error(); } }];").value(), nullptr);
+
+    APIString lengthString("length");
+    unsigned length = JSValueToNumber(context, JSObjectGetProperty(context, array, lengthString, nullptr), nullptr);
+    for (unsigned i = 0; i < length; i++) {
+        JSObjectRef object = JSValueToObject(context, JSObjectGetPropertyAtIndex(context, array, i, nullptr), nullptr);
+        ASSERT(object);
+        result.append(object);
+    }
+
+    return result;
+}
+
+APIVector<JSValueRef> TestAPI::interestingKeys()
+{
+    APIVector<JSValueRef> result(context);
+    JSObjectRef array = JSValueToObject(context, evaluateScript("[{}, [], 1, Symbol.iterator, 'length']").value(), nullptr);
+
+    APIString lengthString("length");
+    unsigned length = JSValueToNumber(context, JSObjectGetProperty(context, array, lengthString, nullptr), nullptr);
+    for (unsigned i = 0; i < length; i++) {
+        JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, nullptr);
+        ASSERT(value);
+        result.append(value);
+    }
+
+    return result;
+}
+
+int TestAPI::run()
+{
+    dataLogLn("Starting C-API tests in C++");
+    const char* isSymbolFunction = "(function isSymbol(symbol) { return typeof(symbol) === 'symbol'; })";
+    const char* getFunction = "(function get(object, key) { return object[key]; })";
+    const char* setFunction = "(function set(object, key, value) { object[key] = value; })";
+    const char* hasFunction = "(function has(object, key) { return key in object; })";
+    const char* deleteFunction = "(function del(object, key) { return delete object[key]; })";
+
+    JSC::ExecState* exec = toJS(context);
+
+    {
+        // Can't call Symbol as a constructor since it's not subclassable.
+        auto result = evaluateScript("Symbol('dope');");
+        check(JSValueGetType(context, result.value()) == kJSTypeSymbol, "dope get type is a symbol");
+        check(JSValueIsSymbol(context, result.value()), "dope is a symbol");
+    }
+
+    {
+        APIString description("dope");
+        JSValueRef symbol = JSValueMakeSymbol(context, description);
+        check(functionReturnsTrue(isSymbolFunction, symbol), "JSValueMakeSymbol makes a symbol value");
+    }
+
+    {
+        auto objects = interestingObjects();
+        auto keys = interestingKeys();
+
+        for (auto& object : objects) {
+            dataLogLn("\nnext object: ", toJS(exec, object));
+            for (auto& key : keys) {
+                dataLogLn("Using key: ", toJS(exec, key));
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(getFunction, object, key);
+                    }, [&] (JSValueRef* exception) {
+                        return JSObjectGetPropertyKey(context, object, key, exception);
+                    }, "checking get property keys");
+            }
+        }
+    }
+
+    {
+        auto jsObjects = interestingObjects();
+        auto apiObjects = interestingObjects();
+        auto keys = interestingKeys();
+
+        JSValueRef theAnswer = JSValueMakeNumber(context, 42);
+        for (size_t i = 0; i < jsObjects.size(); i++) {
+            for (auto& key : keys) {
+                JSObjectRef jsObject = jsObjects[i];
+                JSObjectRef apiObject = apiObjects[i];
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(setFunction, jsObject, key, theAnswer);
+                    } , [&] (JSValueRef* exception) {
+                        JSObjectSetPropertyKey(context, apiObject, key, theAnswer, kJSPropertyAttributeNone, exception);
+                        return JSValueMakeUndefined(context);
+                    }, "setting property keys to the answer");
+                // Check get is the same on API object.
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(getFunction, apiObject, key);
+                    }, [&] (JSValueRef* exception) {
+                        return JSObjectGetPropertyKey(context, apiObject, key, exception);
+                    }, "getting property keys from API objects");
+                // Check get is the same on respective objects.
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(getFunction, jsObject, key);
+                    }, [&] (JSValueRef* exception) {
+                        return JSObjectGetPropertyKey(context, apiObject, key, exception);
+                    }, "getting property keys from respective objects");
+            }
+        }
+    }
+
+    {
+        auto objects = interestingObjects();
+        auto keys = interestingKeys();
+
+        JSValueRef theAnswer = JSValueMakeNumber(context, 42);
+        for (auto& object : objects) {
+            dataLogLn("\nNext object: ", toJS(exec, object));
+            for (auto& key : keys) {
+                dataLogLn("Using key: ", toJS(exec, key));
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(hasFunction, object, key);
+                    }, [&] (JSValueRef* exception) {
+                        return JSValueMakeBoolean(context, JSObjectHasPropertyKey(context, object, key, exception));
+                    }, "checking has property keys unset");
+
+                check(!!callFunction(setFunction, object, key, theAnswer), "set property to the answer");
+
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(hasFunction, object, key);
+                    }, [&] (JSValueRef* exception) {
+                        return JSValueMakeBoolean(context, JSObjectHasPropertyKey(context, object, key, exception));
+                    }, "checking has property keys set");
+            }
+        }
+    }
+
+    {
+        auto objects = interestingObjects();
+        auto keys = interestingKeys();
+
+        JSValueRef theAnswer = JSValueMakeNumber(context, 42);
+        for (auto& object : objects) {
+            dataLogLn("\nNext object: ", toJS(exec, object));
+            for (auto& key : keys) {
+                dataLogLn("Using key: ", toJS(exec, key));
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(deleteFunction, object, key);
+                    }, [&] (JSValueRef* exception) {
+                        return JSValueMakeBoolean(context, JSObjectDeletePropertyKey(context, object, key, exception));
+                    }, "checking has property keys unset");
+
+                check(!!callFunction(setFunction, object, key, theAnswer), "set property to the answer");
+
+                checkJSAndAPIMatch(
+                    [&] {
+                        return callFunction(deleteFunction, object, key);
+                    }, [&] (JSValueRef* exception) {
+                        return JSValueMakeBoolean(context, JSObjectDeletePropertyKey(context, object, key, exception));
+                    }, "checking has property keys set");
+            }
+        }
+    }
+
+    dataLogLn("C-API tests in C++ had ", failed, " failures");
+    return failed;
+}
index a1654ae..3828054 100644 (file)
@@ -23,6 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#import "config.h"
 #import "JSExportMacros.h"
 #import <JavaScriptCore/JavaScriptCore.h>
 
@@ -42,6 +43,7 @@
 #import <vector>
 #import <wtf/MemoryFootprint.h>
 #import <wtf/Optional.h>
+#import <wtf/DataLog.h>
 
 extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);
 extern "C" void JSSynchronousEdenCollectForDebugging(JSContextRef);
@@ -627,6 +629,105 @@ static void testObjectiveCAPIMain()
     }
 
     @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *symbol = [context evaluateScript:@"Symbol('dope');"];
+        JSValue *notSymbol = [context evaluateScript:@"'dope'"];
+        checkResult(@"Should be a symbol value", symbol.isSymbol);
+        checkResult(@"Should not be a symbol value", !notSymbol.isSymbol);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *symbol = [JSValue valueWithNewSymbolFromDescription:@"dope" inContext:context];
+        checkResult(@"Should be a created from Obj-C", symbol.isSymbol);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *arrayIterator = [context evaluateScript:@"Array.prototype[Symbol.iterator]"];
+        JSValue *iteratorSymbol = context[@"Symbol"][@"iterator"];
+        JSValue *array = [JSValue valueWithNewArrayInContext:context];
+        checkResult(@"Looking up by subscript with symbol should work", [array[iteratorSymbol] isEqual:arrayIterator]);
+        checkResult(@"Looking up by method with symbol should work", [[array valueForProperty:iteratorSymbol] isEqual:arrayIterator]);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *iteratorSymbol = context[@"Symbol"][@"iterator"];
+        JSValue *object = [JSValue valueWithNewObjectInContext:context];
+        JSValue *theAnswer = [JSValue valueWithUInt32:42 inContext:context];
+        object[iteratorSymbol] = theAnswer;
+        checkResult(@"Setting by subscript with symbol should work", [object[iteratorSymbol] isEqual:theAnswer]);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *iteratorSymbol = context[@"Symbol"][@"iterator"];
+        JSValue *object = [JSValue valueWithNewObjectInContext:context];
+        JSValue *theAnswer = [JSValue valueWithUInt32:42 inContext:context];
+        [object setValue:theAnswer forProperty:iteratorSymbol];
+        checkResult(@"Setting by method with symbol should work", [object[iteratorSymbol] isEqual:theAnswer]);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *iteratorSymbol = context[@"Symbol"][@"iterator"];
+        JSValue *object = [JSValue valueWithNewObjectInContext:context];
+        JSValue *theAnswer = [JSValue valueWithUInt32:42 inContext:context];
+        object[iteratorSymbol] = theAnswer;
+        checkResult(@"has property with symbol should work", [object hasProperty:iteratorSymbol]);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *iteratorSymbol = context[@"Symbol"][@"iterator"];
+        JSValue *object = [JSValue valueWithNewObjectInContext:context];
+        JSValue *theAnswer = [JSValue valueWithUInt32:42 inContext:context];
+        checkResult(@"delete property with symbol should work without property", [object deleteProperty:iteratorSymbol]);
+        object[iteratorSymbol] = theAnswer;
+        checkResult(@"delete property with symbol should work with property", [object deleteProperty:iteratorSymbol]);
+        checkResult(@"delete should be false with non-configurable property", ![context[@"Array"] deleteProperty:@"prototype"]);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *object = [JSValue valueWithNewObjectInContext:context];
+        NSObject *objCObject = [[NSObject alloc] init];
+        JSValue *result = object[objCObject];
+        checkResult(@"getting a non-convertable object should return undefined", [result isUndefined]);
+        object[objCObject] = @(1);
+        result = object[objCObject];
+        checkResult(@"getting a non-convertable object should return the stored value", [result toUInt32] == 1);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        JSValue *object = [JSValue valueWithNewObjectInContext:context];
+        JSValue *iteratorSymbol = context[@"Symbol"][@"iterator"];
+        object[@"value"] = @(1);
+        context[@"object"] = object;
+
+        object[iteratorSymbol] = ^{
+            JSValue *result = [JSValue valueWithNewObjectInContext:context];
+            result[@"object"] = [JSContext currentThis];
+            result[@"next"] = ^{
+                JSValue *result = [JSValue valueWithNewObjectInContext:context];
+                JSValue *value = [JSContext currentThis][@"object"][@"value"];
+                [[JSContext currentThis][@"object"] deleteProperty:@"value"];
+                result[@"value"] = value;
+                result[@"done"] = [JSValue valueWithBool:[value isUndefined] inContext:context];
+                return result;
+            };
+            return result;
+        };
+
+
+        JSValue *count = [context evaluateScript:@"let count = 0; for (let v of object) { if (v !== 1) throw new Error(); count++; } count;"];
+        checkResult(@"iterator should not throw", ![context exception]);
+        checkResult(@"iteration count should be 1", [count toUInt32] == 1);
+    }
+
+    @autoreleasepool {
         JSCollection* myPrivateProperties = [[JSCollection alloc] init];
 
         @autoreleasepool {
index 5ea0082..d1bd09b 100644 (file)
@@ -1,3 +1,105 @@
+2018-07-25  Keith Miller  <keith_miller@apple.com>
+
+        [JSC API] We should support the symbol type in our C/Obj-C API
+        https://bugs.webkit.org/show_bug.cgi?id=175836
+
+        Reviewed by Filip Pizlo.
+
+        This patch makes the following API additions:
+        1) Test if a JSValue/JSValueRef is a symbol via any of the methods API are able to test for the types of other JSValues.
+        2) Create a symbol on both APIs.
+        3) Get/Set/Delete/Define property now take ids in the Obj-C API.
+        4) Add Get/Set/Delete in the C API.
+
+        We can do 3 because it is both binary and source compatable with
+        the existing API. I added (4) because the current property access
+        APIs only have the ability to get Strings. It was possible to
+        merge symbols into JSStringRef but that felt confusing and exposes
+        implementation details of our engine. The new functions match the
+        same meaning that they have in JS, thus should be forward
+        compatible with any future language extensions.
+
+        Lastly, this patch adds the same availability preproccessing phase
+        in WebCore to JavaScriptCore, which enables TBA features for
+        testing on previous releases.
+
+        * API/APICast.h:
+        * API/JSBasePrivate.h:
+        * API/JSContext.h:
+        * API/JSContextPrivate.h:
+        * API/JSContextRef.h:
+        * API/JSContextRefInternal.h:
+        * API/JSContextRefPrivate.h:
+        * API/JSManagedValue.h:
+        * API/JSObjectRef.cpp:
+        (JSObjectHasPropertyKey):
+        (JSObjectGetPropertyKey):
+        (JSObjectSetPropertyKey):
+        (JSObjectDeletePropertyKey):
+        * API/JSObjectRef.h:
+        * API/JSRemoteInspector.h:
+        * API/JSTypedArray.h:
+        * API/JSValue.h:
+        * API/JSValue.mm:
+        (+[JSValue valueWithNewSymbolFromDescription:inContext:]):
+        (performPropertyOperation):
+        (-[JSValue valueForProperty:valueForProperty:]):
+        (-[JSValue setValue:forProperty:setValue:forProperty:]):
+        (-[JSValue deleteProperty:deleteProperty:]):
+        (-[JSValue hasProperty:hasProperty:]):
+        (-[JSValue defineProperty:descriptor:defineProperty:descriptor:]):
+        (-[JSValue isSymbol]):
+        (-[JSValue objectForKeyedSubscript:]):
+        (-[JSValue setObject:forKeyedSubscript:]):
+        (-[JSValue valueForProperty:]): Deleted.
+        (-[JSValue setValue:forProperty:]): Deleted.
+        (-[JSValue deleteProperty:]): Deleted.
+        (-[JSValue hasProperty:]): Deleted.
+        (-[JSValue defineProperty:descriptor:]): Deleted.
+        * API/JSValueRef.cpp:
+        (JSValueGetType):
+        (JSValueIsSymbol):
+        (JSValueMakeSymbol):
+        * API/JSValueRef.h:
+        * API/WebKitAvailability.h:
+        * API/tests/CurrentThisInsideBlockGetterTest.mm:
+        * API/tests/CustomGlobalObjectClassTest.c:
+        * API/tests/DateTests.mm:
+        * API/tests/JSExportTests.mm:
+        * API/tests/JSNode.c:
+        * API/tests/JSNodeList.c:
+        * API/tests/Node.c:
+        * API/tests/NodeList.c:
+        * API/tests/minidom.c:
+        * API/tests/testapi.c:
+        (main):
+        * API/tests/testapi.cpp: Added.
+        (APIString::APIString):
+        (APIString::~APIString):
+        (APIString::operator JSStringRef):
+        (APIContext::APIContext):
+        (APIContext::~APIContext):
+        (APIContext::operator JSGlobalContextRef):
+        (APIVector::APIVector):
+        (APIVector::~APIVector):
+        (APIVector::append):
+        (testCAPIViaCpp):
+        (TestAPI::evaluateScript):
+        (TestAPI::callFunction):
+        (TestAPI::functionReturnsTrue):
+        (TestAPI::check):
+        (TestAPI::checkJSAndAPIMatch):
+        (TestAPI::interestingObjects):
+        (TestAPI::interestingKeys):
+        (TestAPI::run):
+        * API/tests/testapi.mm:
+        (testObjectiveCAPIMain):
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * config.h:
+        * postprocess-headers.sh:
+        * shell/CMakeLists.txt:
+        * testmem/testmem.mm:
+
 2018-07-25  Andy VanWagoner  <andy@vanwagoner.family>
 
         [INTL] Call Typed Array elements toLocaleString with locale and options
index ad09fd0..c0ffc8c 100644 (file)
                53E777E41E92E265007CBEC4 /* WasmModuleInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = 53E777E21E92E265007CBEC4 /* WasmModuleInformation.h */; };
                53E9E0AC1EAE83DF00FEE251 /* WasmMachineThreads.h in Headers */ = {isa = PBXBuildFile; fileRef = 53E9E0AA1EAE83DE00FEE251 /* WasmMachineThreads.h */; };
                53E9E0AF1EAEC45700FEE251 /* WasmTierUpCount.h in Headers */ = {isa = PBXBuildFile; fileRef = 53E9E0AE1EAEC45700FEE251 /* WasmTierUpCount.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               53F11F41209138D700E411A7 /* JSImmutableButterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F11F40209138D700E411A7 /* JSImmutableButterfly.h */; };
-               53F40E851D58F9770099A1B6 /* WasmSections.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E841D58F9770099A1B6 /* WasmSections.h */; };
+                53F11F41209138D700E411A7 /* JSImmutableButterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F11F40209138D700E411A7 /* JSImmutableButterfly.h */; };
+                53EAFE2F208DFAB4007D524B /* testapi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 531D4E191F59CDD200EC836C /* testapi.cpp */; };
+                53F40E851D58F9770099A1B6 /* WasmSections.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E841D58F9770099A1B6 /* WasmSections.h */; };
                53F40E8B1D5901BB0099A1B6 /* WasmFunctionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */; };
                53F40E8D1D5901F20099A1B6 /* WasmParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8C1D5901F20099A1B6 /* WasmParser.h */; };
                53F40E931D5A4AB30099A1B6 /* WasmB3IRGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E921D5A4AB30099A1B6 /* WasmB3IRGenerator.h */; };
                5311BD491EA581E500525281 /* WasmOMGPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmOMGPlan.h; sourceTree = "<group>"; };
                531374BC1D5CE67600AF7A0B /* WasmPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmPlan.h; sourceTree = "<group>"; };
                531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmPlan.cpp; sourceTree = "<group>"; };
+               531D4E191F59CDD200EC836C /* testapi.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = testapi.cpp; path = API/tests/testapi.cpp; sourceTree = "<group>"; };
                533B15DE1DC7F463004D500A /* WasmOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmOps.h; sourceTree = "<group>"; };
                5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3WasmBoundsCheckValue.cpp; path = b3/B3WasmBoundsCheckValue.cpp; sourceTree = "<group>"; };
                5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3WasmBoundsCheckValue.h; path = b3/B3WasmBoundsCheckValue.h; sourceTree = "<group>"; };
                53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGenericTypedArrayViewPrototypeFunctions.h; sourceTree = "<group>"; };
                53917E7C1B791106000EBD33 /* JSTypedArrayViewPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArrayViewPrototype.h; sourceTree = "<group>"; };
                53917E831B791CB8000EBD33 /* TypedArrayPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypedArrayPrototype.js; path = builtins/TypedArrayPrototype.js; sourceTree = SOURCE_ROOT; };
-               539EB0711D553DF800C82EF7 /* testWasm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testWasm.cpp; sourceTree = "<group>"; };
                539FB8B91C99DA7C00940FA1 /* JSArrayInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSArrayInlines.h; sourceTree = "<group>"; };
                53B0BE331E561AC900A8FC29 /* GetterSetterAccessCase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetterSetterAccessCase.cpp; sourceTree = "<group>"; };
                53B0BE351E561B0900A8FC29 /* ProxyableAccessCase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProxyableAccessCase.cpp; sourceTree = "<group>"; };
                                FEB51F6B1A97B688001F921C /* Regress141809.mm */,
                                FECB8B291D25CABB006F2463 /* testapi-function-overrides.js */,
                                14BD5A2D0A3E91F600BAF59C /* testapi.c */,
+                               531D4E191F59CDD200EC836C /* testapi.cpp */,
                                14D857740A4696C80032146C /* testapi.js */,
                                86D22219167EF9440024C804 /* testapi.mm */,
                                651122E5140469BA002B101D /* testRegExp.cpp */,
-                               539EB0711D553DF800C82EF7 /* testWasm.cpp */,
                                534902821C7242C80012BCB8 /* TypedArrayCTest.cpp */,
                                534902831C7242C80012BCB8 /* TypedArrayCTest.h */,
                        );
                                0FB467801FDDA6F1003FCB09 /* IsoCellSet.h in Headers */,
                                0FB467811FDDA6F7003FCB09 /* IsoCellSetInlines.h in Headers */,
                                0FDCE12D1FAFB4E5006F3901 /* IsoSubspace.h in Headers */,
-                               0FD2FD9520B52BE200F09441 /* IsoSubspaceInlines.h in Headers */,
-                               0F5E0FE72086AD480097F0DE /* IsoSubspacePerVM.h in Headers */,
+                                0FD2FD9520B52BE200F09441 /* IsoSubspaceInlines.h in Headers */,
+                                0F5E0FE72086AD480097F0DE /* IsoSubspacePerVM.h in Headers */,
                                8B9F6D561D5912FA001C739F /* IterationKind.h in Headers */,
                                FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */,
                                70113D4C1A8DB093003848C4 /* IteratorOperations.h in Headers */,
                                65570F5A1AA4C3EA009B3C23 /* Regress141275.mm in Sources */,
                                FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */,
                                1440F6100A4F85670005F061 /* testapi.c in Sources */,
+                               53EAFE2F208DFAB4007D524B /* testapi.cpp in Sources */,
                                86D2221A167EF9440024C804 /* testapi.mm in Sources */,
                                534902851C7276B70012BCB8 /* TypedArrayCTest.cpp in Sources */,
                        );
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
                        buildSettings = {
+                               HEADER_SEARCH_PATHS = (
+                                       "\"$(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders\"",
+                                       "$(inherited)",
+                               );
                        };
                        name = Debug;
                };
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
                        buildSettings = {
+                               HEADER_SEARCH_PATHS = (
+                                       "\"$(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders\"",
+                                       "$(inherited)",
+                               );
                        };
                        name = Release;
                };
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
                        buildSettings = {
+                               HEADER_SEARCH_PATHS = (
+                                       "\"$(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders\"",
+                                       "$(inherited)",
+                               );
                        };
                        name = Production;
                };
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */;
                        buildSettings = {
+                               HEADER_SEARCH_PATHS = (
+                                       "\"$(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders\"",
+                                       "$(inherited)",
+                               );
                        };
                        name = Profiling;
                };
index 1d1ed7b..9299754 100644 (file)
 #include "cmakeconfig.h"
 #endif
 
+#define JSC_API_AVAILABLE(...)
+// Use zero since it will be less than any possible version number.
+#define JSC_MAC_VERSION_TBA 0
+#define JSC_IOS_VERSION_TBA 0
+
 #include "JSExportMacros.h"
 
 #ifdef __cplusplus
index c861843..fcde8a1 100755 (executable)
-cd "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}"
-
-UNIFDEF_OPTIONS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=${TARGET_MAC_OS_X_VERSION_MAJOR}"
-
-for ((i = 0; i < ${SCRIPT_INPUT_FILE_COUNT}; ++i)); do
-    eval HEADER=\${SCRIPT_INPUT_FILE_${i}};
-    unifdef -B ${UNIFDEF_OPTIONS} -o "${HEADER}".unifdef "${HEADER}"
-    case $? in
-    0)
-        rm "${HEADER}".unifdef
-        ;;
-    1)
-        mv "${HEADER}"{.unifdef,}
-        ;;
-    *)
-        exit 1
-    esac
-done
+#!/bin/sh
+#
+# Copyright (C) 2014-2018 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.
+#
+
+if [[ "${JSC_FRAMEWORK_HEADER_POSTPROCESSING_DISABLED}" == "YES" ]]; then
+    exit 0;
+fi
+
+TIMESTAMP_PATH=${TARGET_TEMP_DIR}/${0##*/}
+
+if [[ -e $TIMESTAMP_PATH && $0 -nt $TIMESTAMP_PATH ]]; then
+    rm "${TIMESTAMP_PATH}";
+fi
+
+function process_definitions () {
+    local DEFINITIONS_FILE=$1
+
+    if [[ ! -f "${DEFINITIONS_FILE}" ]]; then
+        return 1
+    fi
+
+    if [[ -e $TIMESTAMP_PATH && "${DEFINITIONS_FILE}" -nt $TIMESTAMP_PATH ]]; then
+        rm "${TIMESTAMP_PATH}";
+    fi
+
+    source "${DEFINITIONS_FILE}"
+}
+
+function rewrite_headers () {
+    if [[ "${PLATFORM_NAME}" == "macosx" ]]; then
+        [[ -n ${OSX_VERSION} ]] || OSX_VERSION=${MACOSX_DEPLOYMENT_TARGET}
+        [[ -n ${IOS_VERSION} ]] || IOS_VERSION="NA"
+        [[ -n ${OSX_VERSION_NUMBER} ]] || OSX_VERSION_NUMBER=${TARGET_MAC_OS_X_VERSION_MAJOR}
+        [[ -n ${IOS_VERSION_NUMBER} ]] || IOS_VERSION_NUMBER="0"
+    elif [[ "${PLATFORM_NAME}" =~ "iphone" ]]; then
+        [[ -n ${IOS_VERSION} ]] || IOS_VERSION=${IPHONEOS_DEPLOYMENT_TARGET}
+        [[ -n ${OSX_VERSION} ]] || OSX_VERSION="NA"
+        [[ -n ${OSX_VERSION_NUMBER} ]] || OSX_VERSION_NUMBER="0"
+        [[ -n ${IOS_VERSION_NUMBER} ]] || IOS_VERSION_NUMBER=${SDK_VERSION_MAJOR}
+    fi
+
+    SED_OPTIONS=(
+    )
+
+    if [[ -n "$OSX_VERSION" && -n "$IOS_VERSION" ]]; then
+        SED_OPTIONS+=(
+            -e s/JSC_MAC_TBA/${OSX_VERSION}/g
+            -e s/JSC_IOS_TBA/${IOS_VERSION}/g
+            -e s/JSC_MAC_VERSION_TBA/${OSX_VERSION_NUMBER}/g
+            -e s/JSC_IOS_VERSION_TBA/${IOS_VERSION_NUMBER}/g
+            -e s/JSC_API_AVAILABLE/API_AVAILABLE/
+            -e s/JSC_API_DEPRECATED/API_DEPRECATED/
+            -e "s/^JSC_CLASS_AVAILABLE/JSC_EXTERN API_AVAILABLE/"
+            -e "s/^JSC_CLASS_DEPRECATED/JSC_EXTERN API_DEPRECATED/"
+        )
+    else
+        SED_OPTIONS+=(-e 's/JSC_(API_|CLASS_)AVAILABLE\(.*\)\s*\)//g' -e 's/JSC_(API_|CLASS_)DEPRECATED(_WITH_REPLACEMENT)?\(.*\)\s*\)//g')
+    fi
+
+    SED_OPTIONS+=(${OTHER_SED_OPTIONS[*]})
+
+    for HEADER_PATH in "${1}/"*.h; do
+        if [[ "$HEADER_PATH" -nt $TIMESTAMP_PATH ]]; then
+            ditto "${HEADER_PATH}" "${TARGET_TEMP_DIR}/${HEADER_PATH##*/}"
+            sed -i .tmp -E "${SED_OPTIONS[@]}" "${TARGET_TEMP_DIR}/${HEADER_PATH##*/}" || exit $?
+            mv "${TARGET_TEMP_DIR}/${HEADER_PATH##*/}" "$HEADER_PATH"
+        fi
+    done
+}
+
+DEFINITIONS_PATH=usr/local/include/WebKitAdditions/Scripts/postprocess-framework-headers-definitions
+
+process_definitions "${BUILT_PRODUCTS_DIR}/${DEFINITIONS_PATH}" || process_definitions "${SDKROOT}/${DEFINITIONS_PATH}"
+
+rewrite_headers "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}"
+rewrite_headers "${TARGET_BUILD_DIR}/${PRIVATE_HEADERS_FOLDER_PATH}"
+
+touch ${TIMESTAMP_PATH}
index b3c7e0b..87153e3 100644 (file)
@@ -28,6 +28,7 @@ set(TESTAPI_SOURCES
     ../API/tests/PingPongStackOverflowTest.cpp
     ../API/tests/TypedArrayCTest.cpp
     ../API/tests/testapi.c
+    ../API/tests/testapi.cpp
 )
 
 WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS()
index b4d2ad3..9bc4b40 100644 (file)
@@ -23,6 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#import "config.h"
 #import <JavaScriptCore/JavaScriptCore.h>
 #import <inttypes.h>
 #import <stdio.h>