diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index b126b3e4f..b5bc2f6de 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -59,7 +59,7 @@ class SwiftRuntimeHeap { allocHeap(value: any) { const isObject = typeof value == "object"; - const entry = this._heapEntryByValue.get(value); + const entry = this._heapEntryByValue.get(value); if (isObject && entry) { entry.rc++ return entry.id @@ -124,10 +124,12 @@ export class SwiftRuntime { const exports = this.instance.exports as any as SwiftRuntimeExportedFunctions; const argc = args.length const argv = exports.swjs_prepare_host_function_call(argc) + const uint32Memory = new Uint32Array(memory().buffer, argv, args.length * 3); for (let index = 0; index < args.length; index++) { - const argument = args[index] - const base = argv + 24 * index - writeValue(argument, base, base + 4, base + 8, base + 16) + const argument = args[index]; + const offset = 12 * index; + const dataView = new DataView(memory().buffer, argv + offset, 12); + encodeValue(argument, dataView); } let output: any; const callback_func_ref = this.heap.allocHeap(function (result: any) { @@ -142,24 +144,20 @@ export class SwiftRuntime { const textEncoder = new TextEncoder(); // Only support utf-8 const readString = (ptr: pointer, len: number) => { - const uint8Memory = new Uint8Array(memory().buffer); - return textDecoder.decode(uint8Memory.subarray(ptr, ptr + len)); + const uint8Memory = new Uint8Array(memory().buffer, ptr, len); + return textDecoder.decode(uint8Memory); } const writeString = (ptr: pointer, bytes: Uint8Array) => { - const uint8Memory = new Uint8Array(memory().buffer); + const uint8Memory = new Uint8Array(memory().buffer, ptr); for (const [index, byte] of bytes.entries()) { - uint8Memory[ptr + index] = byte + uint8Memory[index] = byte } - uint8Memory[ptr] } const readUInt32 = (ptr: pointer) => { - const uint8Memory = new Uint8Array(memory().buffer); - return uint8Memory[ptr + 0] - + (uint8Memory[ptr + 1] << 8) - + (uint8Memory[ptr + 2] << 16) - + (uint8Memory[ptr + 3] << 24) + const uint32Memory = new Uint32Array(memory().buffer, ptr); + return uint32Memory[0]; } const readFloat64 = (ptr: pointer) => { @@ -168,11 +166,8 @@ export class SwiftRuntime { } const writeUint32 = (ptr: pointer, value: number) => { - const uint8Memory = new Uint8Array(memory().buffer); - uint8Memory[ptr + 0] = (value & 0x000000ff) >> 0 - uint8Memory[ptr + 1] = (value & 0x0000ff00) >> 8 - uint8Memory[ptr + 2] = (value & 0x00ff0000) >> 16 - uint8Memory[ptr + 3] = (value & 0xff000000) >> 24 + const uint32Memory = new Uint32Array(memory().buffer, ptr); + uint32Memory[0] = (value & 0xffffffff); } const writeFloat64 = (ptr: pointer, value: number) => { @@ -181,86 +176,83 @@ export class SwiftRuntime { } const decodeValue = ( - kind: JavaScriptValueKind, - payload1: number, payload2: number, payload3: number - ) => { - switch (kind) { - case JavaScriptValueKind.Boolean: { - switch (payload1) { - case 0: return false - case 1: return true + dataView: DataView + ) => { + const kind = dataView.getUint32(0, true) + switch (kind) { + case JavaScriptValueKind.Boolean: { + switch (dataView.getUint32(Uint32Array.BYTES_PER_ELEMENT, true)) { + case 0: return false + case 1: return true + } + } + case JavaScriptValueKind.Number: { + return dataView.getFloat64(Uint32Array.BYTES_PER_ELEMENT, true); + } + case JavaScriptValueKind.String: { + return readString(dataView.getUint32(Uint32Array.BYTES_PER_ELEMENT, true), + dataView.getUint32(2 * Uint32Array.BYTES_PER_ELEMENT, true)) + } + case JavaScriptValueKind.Object: { + return this.heap.referenceHeap(dataView.getUint32(Uint32Array.BYTES_PER_ELEMENT, true)) + } + case JavaScriptValueKind.Null: { + return null + } + case JavaScriptValueKind.Undefined: { + return undefined + } + case JavaScriptValueKind.Function: { + return this.heap.referenceHeap(dataView.getUint32(Uint32Array.BYTES_PER_ELEMENT, true)) + } + default: + throw new Error(`Type kind "${kind}" is not supported`) } } - case JavaScriptValueKind.Number: { - return payload3; - } - case JavaScriptValueKind.String: { - return readString(payload1, payload2) - } - case JavaScriptValueKind.Object: { - return this.heap.referenceHeap(payload1) - } - case JavaScriptValueKind.Null: { - return null - } - case JavaScriptValueKind.Undefined: { - return undefined - } - case JavaScriptValueKind.Function: { - return this.heap.referenceHeap(payload1) - } - default: - throw new Error(`Type kind "${kind}" is not supported`) - } - } - const writeValue = ( - value: any, kind_ptr: pointer, - payload1_ptr: pointer, payload2_ptr: pointer, payload3_ptr: pointer - ) => { + const encodeValue = (value: any, dataView: DataView) => { if (value === null) { - writeUint32(kind_ptr, JavaScriptValueKind.Null); - writeUint32(payload1_ptr, 0); - writeUint32(payload2_ptr, 0); + dataView.setUint32(0, JavaScriptValueKind.Null, true); + dataView.setUint32(Uint32Array.BYTES_PER_ELEMENT, 0, true); + dataView.setUint32(2 * Uint32Array.BYTES_PER_ELEMENT, 0, true); return; } switch (typeof value) { case "boolean": { - writeUint32(kind_ptr, JavaScriptValueKind.Boolean); - writeUint32(payload1_ptr, value ? 1 : 0); - writeUint32(payload2_ptr, 0); + dataView.setUint32(0, JavaScriptValueKind.Boolean, true); + dataView.setUint32(Uint32Array.BYTES_PER_ELEMENT, value ? 1 : 0, true); + dataView.setUint32(2 * Uint32Array.BYTES_PER_ELEMENT, 0, true); break; } case "number": { - writeUint32(kind_ptr, JavaScriptValueKind.Number); - writeUint32(payload1_ptr, 0); - writeUint32(payload2_ptr, 0); - writeFloat64(payload3_ptr, value); + dataView.setUint32(0, JavaScriptValueKind.Number, true); + dataView.setFloat64(Uint32Array.BYTES_PER_ELEMENT, value, true); break; } case "string": { const bytes = textEncoder.encode(value); - writeUint32(kind_ptr, JavaScriptValueKind.String); - writeUint32(payload1_ptr, this.heap.allocHeap(bytes)); - writeUint32(payload2_ptr, bytes.length); + dataView.setUint32(0, JavaScriptValueKind.String, true); + dataView.setUint32(Uint32Array.BYTES_PER_ELEMENT, this.heap.allocHeap(value), true); + dataView.setUint32(2 * Uint32Array.BYTES_PER_ELEMENT, bytes.length, true); break; } case "undefined": { - writeUint32(kind_ptr, JavaScriptValueKind.Undefined); - writeUint32(payload1_ptr, 0); - writeUint32(payload2_ptr, 0); + dataView.setUint32(0, JavaScriptValueKind.Undefined, true); + dataView.setUint32(Uint32Array.BYTES_PER_ELEMENT, 0, true); + dataView.setUint32(2 * Uint32Array.BYTES_PER_ELEMENT, 0, true); break; } case "object": { - writeUint32(kind_ptr, JavaScriptValueKind.Object); - writeUint32(payload1_ptr, this.heap.allocHeap(value)); - writeUint32(payload2_ptr, 0); + dataView.setUint32(0, JavaScriptValueKind.Object, true); + dataView.setUint32(Uint32Array.BYTES_PER_ELEMENT, this.heap.allocHeap(value), true); + dataView.setUint32(2 * Uint32Array.BYTES_PER_ELEMENT, 0, true); break; } case "function": { - writeUint32(kind_ptr, JavaScriptValueKind.Function); - writeUint32(payload1_ptr, this.heap.allocHeap(value)); - writeUint32(payload2_ptr, 0); + dataView.setUint32(0, JavaScriptValueKind.Function, true); + dataView.setUint32(Uint32Array.BYTES_PER_ELEMENT, this.heap.allocHeap(value), true); + dataView.setUint32(2 * Uint32Array.BYTES_PER_ELEMENT, 0, true); + break; } default: @@ -269,17 +261,14 @@ export class SwiftRuntime { } // Note: - // `decodeValues` assumes that the size of RawJSValue is 24 + // `decodeValues` assumes that the size of RawJSValue is 12 // and the alignment of it is 8 const decodeValues = (ptr: pointer, length: number) => { let result = [] for (let index = 0; index < length; index++) { - const base = ptr + 24 * index - const kind = readUInt32(base) - const payload1 = readUInt32(base + 4) - const payload2 = readUInt32(base + 8) - const payload3 = readFloat64(base + 16) - result.push(decodeValue(kind, payload1, payload2, payload3)) + const offset = 12 * index; + const dataView = new DataView(memory().buffer, ptr + offset, 12); + result.push(decodeValue(dataView)) } return result } @@ -287,37 +276,37 @@ export class SwiftRuntime { return { swjs_set_prop: ( ref: ref, name: pointer, length: number, - kind: JavaScriptValueKind, - payload1: number, payload2: number, payload3: number + rawJSValuePtr: pointer ) => { const obj = this.heap.referenceHeap(ref); - Reflect.set(obj, readString(name, length), decodeValue(kind, payload1, payload2, payload3)) + const dataView = new DataView(memory().buffer, rawJSValuePtr, 12); + Reflect.set(obj, readString(name, length), decodeValue(dataView)) }, swjs_get_prop: ( ref: ref, name: pointer, length: number, - kind_ptr: pointer, - payload1_ptr: pointer, payload2_ptr: pointer, payload3_ptr: number + rawJSValuePtr: pointer ) => { const obj = this.heap.referenceHeap(ref); const result = Reflect.get(obj, readString(name, length)); - writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, payload3_ptr); + const dataView = new DataView(memory().buffer, rawJSValuePtr, 12); + encodeValue(result, dataView); }, swjs_set_subscript: ( ref: ref, index: number, - kind: JavaScriptValueKind, - payload1: number, payload2: number, payload3: number + rawJSValuePtr: pointer ) => { const obj = this.heap.referenceHeap(ref); - Reflect.set(obj, index, decodeValue(kind, payload1, payload2, payload3)) + const dataView = new DataView(memory().buffer, rawJSValuePtr, 12); + Reflect.set(obj, index, decodeValue(dataView)) }, swjs_get_subscript: ( ref: ref, index: number, - kind_ptr: pointer, - payload1_ptr: pointer, payload2_ptr: pointer, payload3_ptr: pointer + rawJSValuePtr: pointer ) => { const obj = this.heap.referenceHeap(ref); const result = Reflect.get(obj, index); - writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, payload3_ptr); + const dataView = new DataView(memory().buffer, rawJSValuePtr, 12); + encodeValue(result, dataView); }, swjs_load_string: (ref: ref, buffer: pointer) => { const bytes = this.heap.referenceHeap(ref); @@ -325,23 +314,23 @@ export class SwiftRuntime { }, swjs_call_function: ( ref: ref, argv: pointer, argc: number, - kind_ptr: pointer, - payload1_ptr: pointer, payload2_ptr: pointer, payload3_ptr: pointer + rawJSValuePtr: pointer ) => { const func = this.heap.referenceHeap(ref) const result = Reflect.apply(func, undefined, decodeValues(argv, argc)) - writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, payload3_ptr); + const dataView = new DataView(memory().buffer, rawJSValuePtr, 12); + encodeValue(result, dataView); }, swjs_call_function_with_this: ( obj_ref: ref, func_ref: ref, argv: pointer, argc: number, - kind_ptr: pointer, - payload1_ptr: pointer, payload2_ptr: pointer, payload3_ptr: pointer + rawJSValuePtr: pointer ) => { const obj = this.heap.referenceHeap(obj_ref) const func = this.heap.referenceHeap(func_ref) const result = Reflect.apply(func, obj, decodeValues(argv, argc)) - writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, payload3_ptr); + const dataView = new DataView(memory().buffer, rawJSValuePtr, 12); + encodeValue(result, dataView); }, swjs_create_function: ( host_func_id: number, @@ -364,6 +353,25 @@ export class SwiftRuntime { }, swjs_destroy_ref: (ref: ref) => { this.heap.freeHeap(ref) + }, + swjs_instance_of: ( + ref: ref, name: pointer, length: number, + rawJSValuePtr: pointer) => { + + const obj = this.heap.referenceHeap(ref) + const cName = readString(name, length) + const result = (cName in window) && (obj instanceof (window as any)[cName]) + const dataView = new DataView(memory().buffer, rawJSValuePtr, 12); + encodeValue(result, dataView); + }, + swjs_copy_typed_array_content: ( + ref: ref, elementsPtr: pointer, length: number) => { + + const obj = this.heap.referenceHeap(ref) + const view = new obj.constructor(memory().buffer, elementsPtr, length); + view.forEach(function(value: number, index: number, array: any){ + obj[index] = value; + }); } } } diff --git a/Sources/JavaScriptKit/JSFunction.swift b/Sources/JavaScriptKit/JSFunction.swift index 09586c6cb..483bbb3a3 100644 --- a/Sources/JavaScriptKit/JSFunction.swift +++ b/Sources/JavaScriptKit/JSFunction.swift @@ -2,16 +2,21 @@ import _CJavaScriptKit @dynamicCallable public class JSFunctionRef: JSObjectRef { + + public override class func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isFunction + } + @discardableResult - public func dynamicallyCall(withArguments arguments: [JSValueConvertible]) -> JSValue { + public func dynamicallyCall(withArguments arguments: [JSValueEncodable]) -> JSValue { let result = arguments.withRawJSValues { rawValues -> RawJSValue in rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in let argv = bufferPointer.baseAddress let argc = bufferPointer.count var result = RawJSValue() _call_function( - self.id, argv, Int32(argc), - &result.kind, &result.payload1, &result.payload2, &result.payload3 + self._id, argv, Int32(argc), + &result ) return result } @@ -19,33 +24,33 @@ public class JSFunctionRef: JSObjectRef { return result.jsValue() } - public func apply(this: JSObjectRef, arguments: JSValueConvertible...) -> JSValue { + public func apply(this: JSObjectRef, arguments: JSValueEncodable...) -> JSValue { apply(this: this, argumentList: arguments) } - - public func apply(this: JSObjectRef, argumentList: [JSValueConvertible]) -> JSValue { + public func apply(this: JSObjectRef, argumentList: [JSValueEncodable]) -> JSValue { let result = argumentList.withRawJSValues { rawValues in rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in let argv = bufferPointer.baseAddress let argc = bufferPointer.count var result = RawJSValue() - _call_function_with_this(this.id, - self.id, argv, Int32(argc), - &result.kind, &result.payload1, &result.payload2, &result.payload3) + _call_function_with_this(this._id, + self._id, argv, Int32(argc), + &result + ) return result } } return result.jsValue() } - public func new(_ arguments: JSValueConvertible...) -> JSObjectRef { + public func new(_ arguments: JSValueEncodable...) -> JSObjectRef { return arguments.withRawJSValues { rawValues in rawValues.withUnsafeBufferPointer { bufferPointer in let argv = bufferPointer.baseAddress let argc = bufferPointer.count var resultObj = JavaScriptObjectRef() _call_new( - self.id, argv, Int32(argc), + self._id, argv, Int32(argc), &resultObj ) return JSObjectRef(id: resultObj) @@ -58,6 +63,15 @@ public class JSFunctionRef: JSObjectRef { fatalError("unavailable") } + public convenience required init(jsValue: JSValue) { + switch jsValue { + case .function(let value): + self.init(id: value._id) + default: + fatalError() + } + } + override public func jsValue() -> JSValue { .function(self) } @@ -113,3 +127,52 @@ public func _call_host_function( let callbackFuncRef = JSFunctionRef(id: callbackFuncRef) _ = callbackFuncRef(result) } + + +extension JSFunctionRef { + + public static func from(_ body: @escaping (A0) -> RT) -> JSFunctionRef { + + return from({ arguments in body(arguments[0].fromJSValue()).jsValue() }) + } + + public static func from(_ body: @escaping (A0, A1) -> RT) -> JSFunctionRef { + + return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue()).jsValue() }) + } + + public static func from(_ body: @escaping (A0, A1, A2) -> RT) -> JSFunctionRef { + + return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue(), arguments[2].fromJSValue()).jsValue() }) + } + + public static func from(_ body: @escaping (A0, A1, A2, A3) -> RT) -> JSFunctionRef { + + return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue(), arguments[2].fromJSValue(), arguments[3].fromJSValue()).jsValue() }) + } + + public static func from(_ body: @escaping (A0, A1, A2, A3, A4) -> RT) -> JSFunctionRef { + + return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue(), arguments[2].fromJSValue(), arguments[3].fromJSValue(), arguments[4].fromJSValue()).jsValue() }) + } + + public func wrappedClosure() -> (A0) -> RT { + return { (arg0) in self.dynamicallyCall(withArguments: [arg0]).fromJSValue() } + } + + public func wrappedClosure() -> (A0, A1) -> RT { + return { (arg0, arg1) in self.dynamicallyCall(withArguments: [arg0, arg1]).fromJSValue() } + } + + public func wrappedClosure() -> (A0, A1, A2) -> RT { + return { (arg0, arg1, arg2) in self.dynamicallyCall(withArguments: [arg0, arg1, arg2]).fromJSValue() } + } + + public func wrappedClosure() -> (A0, A1, A2, A3) -> RT { + return { (arg0, arg1, arg2, arg3) in self.dynamicallyCall(withArguments: [arg0, arg1, arg2, arg3]).fromJSValue() } + } + + public func wrappedClosure() -> (A0, A1, A2, A3, A4) -> RT { + return { (arg0, arg1, arg2, arg3, arg4) in self.dynamicallyCall(withArguments: [arg0, arg1, arg2, arg3, arg4]).fromJSValue() } + } +} diff --git a/Sources/JavaScriptKit/JSObject.swift b/Sources/JavaScriptKit/JSObject.swift index 2253d9775..a68458380 100644 --- a/Sources/JavaScriptKit/JSObject.swift +++ b/Sources/JavaScriptKit/JSObject.swift @@ -2,55 +2,101 @@ import _CJavaScriptKit @dynamicMemberLookup public class JSObjectRef: Equatable { - internal var id: UInt32 - init(id: UInt32) { - self.id = id + + public class func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isObject + } + + private var functionCache = [String : JSFunctionRef]() + public let _id: UInt32 + public init(id: UInt32) { + self._id = id } @_disfavoredOverload - public subscript(dynamicMember name: String) -> ((JSValueConvertible...) -> JSValue)? { - guard let function = self[dynamicMember: name].function else { return nil } - return { (arguments: JSValueConvertible...) in - function.apply(this: self, argumentList: arguments) + public subscript(dynamicMember name: String) -> ((JSValueEncodable...) -> JSValue)? { + get { + let function: JSFunctionRef + if let f = functionCache[name] { + function = f + } else if let f = self[dynamicMember: name].function { + functionCache[name] = f + function = f + } else { + return nil + } + return { (arguments: JSValueEncodable...) in + function.apply(this: self, argumentList: arguments) + } } } public subscript(dynamicMember name: String) -> JSValue { - get { get(name) } - set { set(name, newValue) } + get { js_get(name) } + set { js_set(name, newValue) } + } + + public subscript(dynamicMember name: String) -> Type { + get { js_get(name).fromJSValue() } + set { js_set(name, newValue.jsValue()) } } - public func get(_ name: String) -> JSValue { + func js_get(_ name: String) -> JSValue { getJSValue(this: self, name: name) } - public func set(_ name: String, _ value: JSValue) { + func js_set(_ name: String, _ value: JSValue) { setJSValue(this: self, name: name, value: value) } - public func get(_ index: Int) -> JSValue { + func js_get(_ index: Int) -> JSValue { getJSValue(this: self, index: Int32(index)) } public subscript(_ index: Int) -> JSValue { - get { get(index) } - set { set(index, newValue) } + get { js_get(index) } + set { js_set(index, newValue) } } - public func set(_ index: Int, _ value: JSValue) { + func js_set(_ index: Int, _ value: JSValue) { setJSValue(this: self, index: Int32(index), value: value) } - static let _JS_Predef_Value_Global: UInt32 = 0 + public func instanceOf(_ constructor: String) -> Bool { + var result = RawJSValue() + _instance_of(_id, constructor, Int32(constructor.count), &result) + + return result.jsValue().fromJSValue() + } + public static let global = JSObjectRef(id: _JS_Predef_Value_Global) - deinit { _destroy_ref(id) } + deinit { _destroy_ref(_id) } public static func == (lhs: JSObjectRef, rhs: JSObjectRef) -> Bool { - return lhs.id == rhs.id + return lhs._id == rhs._id + } + + public convenience required init(jsValue: JSValue) { + switch jsValue { + case .object(let value): + self.init(id: value._id) + default: + fatalError() + } } public func jsValue() -> JSValue { .object(self) } } + +extension JSObjectRef { + + public func copyTypedArrayContent(_ array: [Type]) { + + array.withUnsafeBufferPointer { (ptr) in + _copy_typed_array_content(_id, ptr.baseAddress, Int32(array.count)) + } + } +} diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index 14434130f..7d4469380 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -41,14 +41,54 @@ public enum JSValue: Equatable { object.flatMap { JSArrayRef($0) } } - public var isNull: Bool { return self == .null } - public var isUndefined: Bool { return self == .undefined } public var function: JSFunctionRef? { switch self { case let .function(function): return function default: return nil } } + + public var isNull: Bool { return self == .null } + public var isUndefined: Bool { return self == .undefined } + + public var isBoolean: Bool { + guard case .boolean = self else { return false } + return true + } + + public var isString: Bool { + guard case .string = self else { return false } + return true + } + + public var isNumber: Bool { + guard case .number = self else { return false } + return true + } + + public var isObject: Bool { + guard case .object = self else { return false } + return true + } + + public var isNull: Bool { + return self == .null + } + + public var isUndefined: Bool { + return self == .undefined + } + + public var isFunction: Bool { + guard case .function = self else { return false } + return true + } +} + +extension JSValue { + public func fromJSValue() -> Type where Type: JSValueDecodable { + return Type(jsValue: self) + } } extension JSValue { @@ -64,37 +104,60 @@ extension JSValue: ExpressibleByStringLiteral { } extension JSValue: ExpressibleByIntegerLiteral { - public init(integerLiteral value: Double) { + public init(integerLiteral value: Int32) { + self = .number(Double(value)) + } +} + +extension JSValue: ExpressibleByFloatLiteral { + public init(floatLiteral value: Double) { self = .number(value) } } public func getJSValue(this: JSObjectRef, name: String) -> JSValue { var rawValue = RawJSValue() - _get_prop(this.id, name, Int32(name.count), - &rawValue.kind, - &rawValue.payload1, &rawValue.payload2, &rawValue.payload3) + _get_prop(this._id, name, Int32(name.count), &rawValue) return rawValue.jsValue() } public func setJSValue(this: JSObjectRef, name: String, value: JSValue) { value.withRawJSValue { rawValue in - _set_prop(this.id, name, Int32(name.count), rawValue.kind, rawValue.payload1, rawValue.payload2, rawValue.payload3) + _set_prop(this._id, name, Int32(name.count), &rawValue) } } public func getJSValue(this: JSObjectRef, index: Int32) -> JSValue { var rawValue = RawJSValue() - _get_subscript(this.id, index, - &rawValue.kind, - &rawValue.payload1, &rawValue.payload2, &rawValue.payload3) + _get_subscript(this._id, index, &rawValue) return rawValue.jsValue() } public func setJSValue(this: JSObjectRef, index: Int32, value: JSValue) { value.withRawJSValue { rawValue in - _set_subscript(this.id, index, - rawValue.kind, - rawValue.payload1, rawValue.payload2, rawValue.payload3) + _set_subscript(this._id, index, &rawValue) + } +} + +extension JSValue { + + public func instanceOf(_ constructor: String) -> Bool { + + switch self { + case .boolean: + return constructor == "Bool" + case .string: + return constructor == "String" + case .number: + fatalError() + case .object(let ref): + return ref.instanceOf(constructor) + case .null: + fatalError() + case .undefined: + fatalError() + case .function(_): + fatalError() + } } } diff --git a/Sources/JavaScriptKit/JSValueConvertible.swift b/Sources/JavaScriptKit/JSValueConvertible.swift index 06d62d22b..bc0861027 100644 --- a/Sources/JavaScriptKit/JSValueConvertible.swift +++ b/Sources/JavaScriptKit/JSValueConvertible.swift @@ -1,91 +1,199 @@ import _CJavaScriptKit -public protocol JSValueConvertible { - func jsValue() -> JSValue -} -extension JSValue: JSValueConvertible { - public func jsValue() -> JSValue { self } +public protocol JSBridgedType: JSValueCodable, CustomStringConvertible { + var objectRef: JSObjectRef { get } + init(objectRef: JSObjectRef) } -extension Bool: JSValueConvertible { - public func jsValue() -> JSValue { .boolean(self) } +public protocol JSValueEncodable { + func jsValue() -> JSValue } -extension Int: JSValueConvertible { - public func jsValue() -> JSValue { .number(Double(self)) } -} +public protocol JSValueDecodable { + init(jsValue: JSValue) -extension Int8: JSValueConvertible { - public func jsValue() -> JSValue { .number(Double(self)) } + static func canDecode(from jsValue: JSValue) -> Bool } -extension Int16: JSValueConvertible { - public func jsValue() -> JSValue { .number(Double(self)) } -} +extension JSBridgedType { -extension Int32: JSValueConvertible { - public func jsValue() -> JSValue { .number(Double(self)) } + public var description: String { + return objectRef.toString!().fromJSValue() + } } -extension UInt: JSValueConvertible { - public func jsValue() -> JSValue { .number(Double(self)) } +public typealias JSValueCodable = JSValueEncodable & JSValueDecodable + +extension JSBridgedType { + + public static func canDecode(from jsValue: JSValue) -> Bool { + jsValue.isObject && jsValue.instanceOf(String(describing: Self.self)) + } + + public init(jsValue: JSValue) { + + self.init(objectRef: jsValue.object!) + } + + public func jsValue() -> JSValue { + return JSValue.object(objectRef) + } } -extension UInt8: JSValueConvertible { - public func jsValue() -> JSValue { .number(Double(self)) } +extension JSValue: JSValueCodable { + + public static func canDecode(from: JSValue) -> Bool { + return true + } + + public init(jsValue: JSValue) { + self = jsValue + } + + public func jsValue() -> JSValue { self } } -extension UInt16: JSValueConvertible { - public func jsValue() -> JSValue { .number(Double(self)) } +extension Bool: JSValueCodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isBoolean + } + + public init(jsValue: JSValue) { + switch jsValue { + case .boolean(let value): + self = value + default: + fatalError("JSValue \(jsValue) is not decodable to Bool") + } + } + + public func jsValue() -> JSValue { .boolean(self) } } -extension Float: JSValueConvertible { +extension Int: JSValueCodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = Int(value) + default: + fatalError() + } + } + public func jsValue() -> JSValue { .number(Double(self)) } } -extension Double: JSValueConvertible { +extension Double: JSValueCodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = value + default: + fatalError() + } + } + public func jsValue() -> JSValue { .number(self) } } -extension String: JSValueConvertible { +extension String: JSValueCodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isString + } + + public init(jsValue: JSValue) { + switch jsValue { + case .string(let value): + self = value + default: + fatalError() + } + } + public func jsValue() -> JSValue { .string(self) } } -extension JSObjectRef: JSValueConvertible { +extension JSObjectRef: JSValueCodable { + // `JSObjectRef.jsValue` is defined in JSObjectRef.swift to be able to overridden // from `JSFunctionRef` } private let Object = JSObjectRef.global.Object.function! -extension Dictionary where Value: JSValueConvertible, Key == String { - public func jsValue() -> JSValue { - Swift.Dictionary.jsValue(self)() - } -} +extension Dictionary: JSValueEncodable where Value: JSValueEncodable, Key == String { -extension Dictionary: JSValueConvertible where Value == JSValueConvertible, Key == String { public func jsValue() -> JSValue { let object = Object.new() for (key, value) in self { - object.set(key, value.jsValue()) + object.js_set(key, value.jsValue()) } return .object(object) } } -private let Array = JSObjectRef.global.Array.function! +extension Dictionary: JSValueDecodable where Value: JSValueDecodable, Key == String { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isObject + } + + public init(jsValue: JSValue) { + + let objectRef: JSObjectRef = jsValue.object! + + let keys: [String] = Object.keys!(objectRef.jsValue()).fromJSValue() + self = Dictionary(uniqueKeysWithValues: keys.map({ + return ($0, objectRef[dynamicMember: $0].fromJSValue()) + })) + } +} + +extension Optional: JSValueDecodable where Wrapped: JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNull || Wrapped.canDecode(from: jsValue) + } + + public init(jsValue: JSValue) { + switch jsValue { + case .null: + self = .none + default: + self = Wrapped(jsValue: jsValue) + } + } +} + +extension Optional: JSValueEncodable where Wrapped: JSValueEncodable { -extension Array where Element: JSValueConvertible { public func jsValue() -> JSValue { - Swift.Array.jsValue(self)() + switch self { + case .none: return .null + case .some(let wrapped): return wrapped.jsValue() + } } } -extension Array: JSValueConvertible where Element == JSValueConvertible { +private let JSArray = JSObjectRef.global.Array.function! + +extension Array: JSValueEncodable where Element: JSValueEncodable { + public func jsValue() -> JSValue { - let array = Array.new(count) + let array = JSArray.new(count) for (index, element) in enumerated() { array[index] = element.jsValue() } @@ -93,7 +201,25 @@ extension Array: JSValueConvertible where Element == JSValueConvertible { } } -extension RawJSValue: JSValueConvertible { +extension Array: JSValueDecodable where Element: JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isObject + } + + public init(jsValue: JSValue) { + + let objectRef: JSObjectRef = jsValue.object! + let count: Int = objectRef.length.fromJSValue() + + self = (0 ..< count).map { + return objectRef[$0].fromJSValue() + } + } +} + +extension RawJSValue: JSValueEncodable { + public func jsValue() -> JSValue { switch kind { case .invalid: @@ -101,7 +227,7 @@ extension RawJSValue: JSValueConvertible { case .boolean: return .boolean(payload1 != 0) case .number: - return .number(payload3) + return .number(Double(bitPattern: UInt64(payload1) | (UInt64(payload2) << 32))) case .string: // +1 for null terminator let buffer = malloc(Int(payload2 + 1))!.assumingMemoryBound(to: UInt8.self) @@ -125,7 +251,7 @@ extension RawJSValue: JSValueConvertible { } extension JSValue { - func withRawJSValue(_ body: (RawJSValue) -> T) -> T { + func withRawJSValue(_ body: (inout RawJSValue) -> T) -> T { let kind: JavaScriptValueKind let payload1: JavaScriptPayload1 let payload2: JavaScriptPayload2 @@ -137,19 +263,18 @@ extension JSValue { payload2 = 0 case let .number(numberValue): kind = .number - payload1 = 0 - payload2 = 0 - payload3 = numberValue + payload1 = UInt32(numberValue.bitPattern & 0x00000000ffffffff) + payload2 = UInt32((numberValue.bitPattern & 0xffffffff00000000) >> 32) case var .string(stringValue): kind = .string return stringValue.withUTF8 { bufferPtr in let ptrValue = UInt32(UInt(bitPattern: bufferPtr.baseAddress!)) - let rawValue = RawJSValue(kind: kind, payload1: JavaScriptPayload1(ptrValue), payload2: JavaScriptPayload2(bufferPtr.count), payload3: 0) - return body(rawValue) + var rawValue = RawJSValue(kind: kind, payload1: ptrValue, payload2: JavaScriptPayload(bufferPtr.count)) + return body(&rawValue) } case let .object(ref): kind = .object - payload1 = JavaScriptPayload1(ref.id) + payload1 = ref._id payload2 = 0 case .null: kind = .null @@ -161,20 +286,19 @@ extension JSValue { payload2 = 0 case let .function(functionRef): kind = .function - payload1 = JavaScriptPayload1(functionRef.id) + payload1 = functionRef._id payload2 = 0 } - let rawValue = RawJSValue(kind: kind, payload1: payload1, payload2: payload2, payload3: payload3) - return body(rawValue) + var rawValue = RawJSValue(kind: kind, payload1: payload1, payload2: payload2) + return body(&rawValue) } } -extension Array where Element == JSValueConvertible { +extension Array where Element == JSValueEncodable { func withRawJSValues(_ body: ([RawJSValue]) -> T) -> T { func _withRawJSValues( - _ values: [JSValueConvertible], _ index: Int, - _ results: inout [RawJSValue], _ body: ([RawJSValue]) -> T - ) -> T { + _ values: [JSValueEncodable], _ index: Int, + _ results: inout [RawJSValue], _ body: ([RawJSValue]) -> T) -> T { if index == values.count { return body(results) } return values[index].jsValue().withRawJSValue { (rawValue) -> T in results.append(rawValue) @@ -186,8 +310,8 @@ extension Array where Element == JSValueConvertible { } } -extension Array where Element: JSValueConvertible { +extension Array where Element: JSValueEncodable { func withRawJSValues(_ body: ([RawJSValue]) -> T) -> T { - Swift.Array.withRawJSValues(self)(body) + Swift.Array.withRawJSValues(self)(body) } } diff --git a/Sources/JavaScriptKit/Support.swift b/Sources/JavaScriptKit/Support.swift new file mode 100644 index 000000000..8a2735b28 --- /dev/null +++ b/Sources/JavaScriptKit/Support.swift @@ -0,0 +1,246 @@ + +extension UInt8: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = UInt8(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension UInt16: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = UInt16(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension UInt32: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = UInt32(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension UInt64: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = UInt64(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension Int8: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = Int8(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension Int16: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = Int16(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension Int32: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = Int32(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension Int64: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = Int64(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +extension Float: JSValueEncodable, JSValueDecodable { + + public static func canDecode(from jsValue: JSValue) -> Bool { + return jsValue.isNumber + } + + public init(jsValue: JSValue) { + switch jsValue { + case .number(let value): + self = Float(value) + default: + fatalError() + } + } + + public func jsValue() -> JSValue { + return .number(Double(self)) + } +} + +protocol _AnyJSValueCodable { + + func jsValue() -> JSValue +} + +public struct AnyJSValueCodable: JSValueCodable, ExpressibleByNilLiteral { + + public static func canDecode(from jsValue: JSValue) -> Bool { + true + } + + public static let void = AnyJSValueCodable(jsValue: .undefined) + + private struct Box: _AnyJSValueCodable { + let value: T + + func jsValue() -> JSValue { + return value.jsValue() + } + } + + private struct ConcreteBox: _AnyJSValueCodable { + let value: JSValue + + func jsValue() -> JSValue { + return value + } + } + + private let value: _AnyJSValueCodable + + public init(_ value: T) where T: JSValueEncodable { + self.value = Box(value: value) + } + + public init(jsValue: JSValue) { + self.value = ConcreteBox(value: jsValue) + } + + public init(nilLiteral: ()) { + self.value = ConcreteBox(value: .null) + } + + public func jsValue() -> JSValue { + return value.jsValue() + } + + public func fromJSValue() -> Type { + return jsValue().fromJSValue() + } +} + + +public func staticCast(_ ref: JSBridgedType) -> Type { + + return Type(objectRef: ref.objectRef) +} + +public func dynamicCast(_ ref: JSBridgedType) -> Type? { + + guard ref.objectRef.instanceOf(String(describing: Type.self)) else { + return nil + } + return staticCast(ref) +} diff --git a/Sources/JavaScriptKit/XcodeSupport.swift b/Sources/JavaScriptKit/XcodeSupport.swift index b75972444..29f0e86d6 100644 --- a/Sources/JavaScriptKit/XcodeSupport.swift +++ b/Sources/JavaScriptKit/XcodeSupport.swift @@ -6,67 +6,49 @@ import _CJavaScriptKit /// avoid link failure. /// When running with JavaScript runtime library, they are ignored completely. #if !arch(wasm32) - func _set_prop( - _: JavaScriptObjectRef, - _: UnsafePointer!, _: Int32, - _: JavaScriptValueKind, - _: JavaScriptPayload1, - _: JavaScriptPayload2, - _: JavaScriptPayload3 - ) { fatalError() } - func _get_prop( - _: JavaScriptObjectRef, - _: UnsafePointer!, _: Int32, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer! - ) { fatalError() } - func _set_subscript( - _: JavaScriptObjectRef, - _: Int32, - _: JavaScriptValueKind, - _: JavaScriptPayload1, - _: JavaScriptPayload2, - _: JavaScriptPayload3 - ) { fatalError() } - func _get_subscript( - _: JavaScriptObjectRef, - _: Int32, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer! - ) { fatalError() } - func _load_string( - _: JavaScriptObjectRef, - _: UnsafeMutablePointer! - ) { fatalError() } - func _call_function( - _: JavaScriptObjectRef, - _: UnsafePointer!, _: Int32, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer! - ) { fatalError() } - func _call_function_with_this( - _: JavaScriptObjectRef, - _: JavaScriptObjectRef, - _: UnsafePointer!, _: Int32, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer!, - _: UnsafeMutablePointer! - ) { fatalError() } - func _call_new( - _: JavaScriptObjectRef, - _: UnsafePointer!, _: Int32, - _: UnsafeMutablePointer! - ) { fatalError() } - func _create_function( - _: JavaScriptHostFuncRef, - _: UnsafePointer! - ) { fatalError() } - func _destroy_ref(_: JavaScriptObjectRef) { fatalError() } +func _set_prop( + _ _this: JavaScriptObjectRef, + _ prop: UnsafePointer!, _ length: Int32, + _ rawJSValue: UnsafePointer!) { fatalError() } +func _get_prop( + _ _this: JavaScriptObjectRef, + _ prop: UnsafePointer!, _ length: Int32, + _ rawJSValue: UnsafeMutablePointer!) { fatalError() } +func _set_subscript( + _ _this: JavaScriptObjectRef, + _ index: Int32, + _ rawJSValue: UnsafePointer!) { fatalError() } +func _get_subscript( + _ _this: JavaScriptObjectRef, + _ index: Int32, + _ rawJSValue: UnsafeMutablePointer!) { fatalError() } +func _load_string( + _ ref: JavaScriptObjectRef, + _ buffer: UnsafeMutablePointer!) { fatalError() } +func _call_function( + _ ref: JavaScriptObjectRef, + _ argv: UnsafePointer!, _ argc: Int32, + _ result_kind: UnsafeMutablePointer!, + _ result_payload1: UnsafeMutablePointer!, + _ result_payload2: UnsafeMutablePointer!) { fatalError() } +func _call_function_with_this( + _ _this: JavaScriptObjectRef, + _ func_ref: JavaScriptObjectRef, + _ argv: UnsafePointer!, _ argc: Int32, + _ result_kind: UnsafeMutablePointer!, + _ result_payload1: UnsafeMutablePointer!, + _ result_payload2: UnsafeMutablePointer!) { fatalError() } +func _call_new( + _ ref: JavaScriptObjectRef, + _ argv: UnsafePointer!, _ argc: Int32, + _ result_obj: UnsafeMutablePointer!) { fatalError() } +func _create_function( + _ host_func_id: JavaScriptHostFuncRef, + _ func_ref_ptr: UnsafePointer!) { fatalError() } +func _destroy_ref(_ ref: JavaScriptObjectRef) { fatalError() } +func _instance_of( + _ ref: JavaScriptObjectRef, + _ constructorName: UnsafePointer!, + _ constructorLength: Int32, + _ rawJSValue: UnsafeMutablePointer!) { fatalError() } #endif diff --git a/Sources/_CJavaScriptKit/dummy.c b/Sources/_CJavaScriptKit/dummy.c index 8b1378917..ff2c17895 100644 --- a/Sources/_CJavaScriptKit/dummy.c +++ b/Sources/_CJavaScriptKit/dummy.c @@ -1 +1,2 @@ +const unsigned int _JS_Predef_Value_Global = 0; diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index bc54ba345..a97a354f7 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -28,32 +28,27 @@ typedef struct { JavaScriptPayload3 payload3; } RawJSValue; -#if __wasm32__ +extern const unsigned int _JS_Predef_Value_Global; + __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_set_prop"))) extern void _set_prop(const JavaScriptObjectRef _this, const char *prop, const int length, - const JavaScriptValueKind kind, const JavaScriptPayload1 payload1, - const JavaScriptPayload2 payload2, const JavaScriptPayload3 payload3); + const RawJSValue *rawJSValue); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_get_prop"))) extern void _get_prop(const JavaScriptObjectRef _this, const char *prop, const int length, - JavaScriptValueKind *kind, JavaScriptPayload1 *payload1, - JavaScriptPayload2 *payload2, JavaScriptPayload3 *payload3); + RawJSValue *rawJSValue); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_set_subscript"))) extern void _set_subscript(const JavaScriptObjectRef _this, const int length, - const JavaScriptValueKind kind, - const JavaScriptPayload1 payload1, - const JavaScriptPayload2 payload2, - const JavaScriptPayload3 payload3); + const RawJSValue *rawJSValue); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_get_subscript"))) extern void _get_subscript(const JavaScriptObjectRef _this, const int length, - JavaScriptValueKind *kind, JavaScriptPayload1 *payload1, - JavaScriptPayload2 *payload2, JavaScriptPayload3 *payload3); + RawJSValue *rawJSValue); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_load_string"))) extern void @@ -62,25 +57,19 @@ _load_string(const JavaScriptObjectRef ref, unsigned char *buffer); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_call_function"))) extern void _call_function(const JavaScriptObjectRef ref, const RawJSValue *argv, - const int argc, JavaScriptValueKind *result_kind, - JavaScriptPayload1 *result_payload1, - JavaScriptPayload2 *result_payload2, - JavaScriptPayload3 *result_payload3); + const int argc, RawJSValue *rawJSValue); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_call_function_with_this"))) extern void _call_function_with_this(const JavaScriptObjectRef _this, const JavaScriptObjectRef func_ref, const RawJSValue *argv, const int argc, - JavaScriptValueKind *result_kind, - JavaScriptPayload1 *result_payload1, - JavaScriptPayload2 *result_payload2, - JavaScriptPayload3 *result_payload3); + RawJSValue *rawJSValue); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_call_new"))) extern void _call_new(const JavaScriptObjectRef ref, const RawJSValue *argv, const int argc, - JavaScriptObjectRef *result_obj); + JavaScriptPayload *result_obj); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_create_function"))) extern void @@ -91,6 +80,16 @@ __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_destroy_ref"))) extern void _destroy_ref(const JavaScriptObjectRef ref); -#endif +__attribute__((__import_module__("javascript_kit"), + __import_name__("swjs_instance_of"))) extern void +_instance_of(const JavaScriptObjectRef _this, const char *constructor, + const int length, RawJSValue *rawJSValue + +); + +__attribute__((__import_module__("javascript_kit"), + __import_name__("swjs_copy_typed_array_content"))) extern void +_copy_typed_array_content(const JavaScriptObjectRef _this, + const void *elementsPtr, const int length); #endif /* _CJavaScriptKit_h */