Skip to content

Commit dadfc3d

Browse files
WIP
1 parent 90d6937 commit dadfc3d

File tree

7 files changed

+117
-111
lines changed

7 files changed

+117
-111
lines changed

IntegrationTests/JavaScriptKitExec/Sources/JavaScriptKitExec/main.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ Object_Conversion: do {
6767
print(error)
6868
}
6969

70+
Value_Construction: do {
71+
let globalObject1 = getJSValue(this: .global, name: "globalObject1")
72+
let globalObject1Ref = try expectObject(globalObject1)
73+
let prop_7 = getJSValue(this: globalObject1Ref, name: "prop_7")
74+
print(prop_7)
75+
try expectEqual(Double.construct(from: prop_7), 3.14)
76+
try expectEqual(Float.construct(from: prop_7), 3.14)
77+
} catch {
78+
print(error)
79+
}
80+
7081
Function_Call: do {
7182
// Notes: globalObject1 is defined in JavaScript environment
7283
//

IntegrationTests/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ global.globalObject1 = {
4141
"call_host_1": () => {
4242
return global.globalObject1.prop_6.host_func_1()
4343
}
44-
}
44+
},
45+
"prop_7": 3.14,
4546
}
4647

4748
global.Animal = function(name, age, isCat) {

Runtime/src/index.ts

Lines changed: 58 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,8 @@ export class SwiftRuntime {
102102
const argv = exports.swjs_prepare_host_function_call(argc)
103103
for (let index = 0; index < args.length; index++) {
104104
const argument = args[index]
105-
const value = encodeValue(argument)
106-
const base = argv + 12 * index
107-
writeUint32(base, value.kind)
108-
writeUint32(base + 4, value.payload1)
109-
writeUint32(base + 8, value.payload2)
105+
const base = argv + 16 * index
106+
writeValue(argument, base, base + 4, base + 12)
110107
}
111108
let output: any;
112109
const callback_func_ref = this.heap.allocHeap(function (result: any) {
@@ -142,6 +139,11 @@ export class SwiftRuntime {
142139
+ (uint8Memory[ptr + 3] << 24)
143140
}
144141

142+
const readFloat64 = (ptr: pointer) => {
143+
const dataView = new DataView(memory().buffer);
144+
return dataView.getFloat64(ptr, true);
145+
}
146+
145147
const writeUint32 = (ptr: pointer, value: number) => {
146148
const uint8Memory = new Uint8Array(memory().buffer);
147149
uint8Memory[ptr + 0] = (value & 0x000000ff) >> 0
@@ -150,25 +152,30 @@ export class SwiftRuntime {
150152
uint8Memory[ptr + 3] = (value & 0xff000000) >> 24
151153
}
152154

155+
const writeFloat64 = (ptr: pointer, value: number) => {
156+
const dataView = new DataView(memory().buffer);
157+
dataView.setFloat64(ptr, value, true);
158+
}
159+
153160
const decodeValue = (
154161
kind: JavaScriptValueKind,
155-
payload1: number, payload2: number
162+
payload1_ptr: pointer, payload2_ptr: pointer
156163
) => {
157164
switch (kind) {
158165
case JavaScriptValueKind.Boolean: {
159-
switch (payload1) {
166+
switch (readUInt32(payload1_ptr)) {
160167
case 0: return false
161168
case 1: return true
162169
}
163170
}
164171
case JavaScriptValueKind.Number: {
165-
return payload1
172+
return readFloat64(payload1_ptr);
166173
}
167174
case JavaScriptValueKind.String: {
168-
return readString(payload1, payload2)
175+
return readString(readUInt32(payload1_ptr), readUInt32(payload2_ptr))
169176
}
170177
case JavaScriptValueKind.Object: {
171-
return this.heap.referenceHeap(payload1)
178+
return this.heap.referenceHeap(readUInt32(payload1_ptr))
172179
}
173180
case JavaScriptValueKind.Null: {
174181
return null
@@ -177,80 +184,76 @@ export class SwiftRuntime {
177184
return undefined
178185
}
179186
case JavaScriptValueKind.Function: {
180-
return this.heap.referenceHeap(payload1)
187+
return this.heap.referenceHeap(readUInt32(payload1_ptr))
181188
}
182189
default:
183190
throw new Error(`Type kind "${kind}" is not supported`)
184191
}
185192
}
186193

187-
const encodeValue = (value: any) => {
194+
const writeValue = (
195+
value: any, kind_ptr: pointer,
196+
payload1_ptr: pointer, payload2_ptr: pointer
197+
) => {
188198
if (value === null) {
189-
return {
190-
kind: JavaScriptValueKind.Null,
191-
payload1: 0,
192-
payload2: 0,
193-
}
199+
writeUint32(kind_ptr, JavaScriptValueKind.Null);
200+
writeUint32(payload1_ptr, 0);
201+
writeUint32(payload2_ptr, 0);
194202
}
195203
switch (typeof value) {
196204
case "boolean": {
197-
return {
198-
kind: JavaScriptValueKind.Boolean,
199-
payload1: value ? 1 : 0,
200-
payload2: 0,
201-
}
205+
writeUint32(kind_ptr, JavaScriptValueKind.Boolean);
206+
writeUint32(payload1_ptr, value ? 1 : 0);
207+
writeUint32(payload2_ptr, 0);
208+
break;
202209
}
203210
case "number": {
204-
return {
205-
kind: JavaScriptValueKind.Number,
206-
payload1: value,
207-
payload2: 0,
208-
}
211+
writeUint32(kind_ptr, JavaScriptValueKind.Number);
212+
writeFloat64(payload1_ptr, value);
213+
writeUint32(payload2_ptr, 0);
214+
break;
209215
}
210216
case "string": {
217+
// FIXME: currently encode twice
211218
const bytes = textEncoder.encode(value);
212-
return {
213-
kind: JavaScriptValueKind.String,
214-
payload1: this.heap.allocHeap(value),
215-
payload2: bytes.length,
216-
}
219+
writeUint32(kind_ptr, JavaScriptValueKind.String);
220+
writeUint32(payload1_ptr, this.heap.allocHeap(value));
221+
writeUint32(payload2_ptr, bytes.length);
222+
break;
217223
}
218224
case "undefined": {
219-
return {
220-
kind: JavaScriptValueKind.Undefined,
221-
payload1: 0,
222-
payload2: 0,
223-
}
225+
writeUint32(kind_ptr, JavaScriptValueKind.Undefined);
226+
writeUint32(payload1_ptr, 0);
227+
writeUint32(payload2_ptr, 0);
228+
break;
224229
}
225230
case "object": {
226-
return {
227-
kind: JavaScriptValueKind.Object,
228-
payload1: this.heap.allocHeap(value),
229-
payload2: 0,
230-
}
231+
writeUint32(kind_ptr, JavaScriptValueKind.Object);
232+
writeUint32(payload1_ptr, this.heap.allocHeap(value));
233+
writeUint32(payload2_ptr, 0);
234+
break;
231235
}
232236
case "function": {
233-
return {
234-
kind: JavaScriptValueKind.Function,
235-
payload1: this.heap.allocHeap(value),
236-
payload2: 0,
237-
}
237+
writeUint32(kind_ptr, JavaScriptValueKind.Function);
238+
writeUint32(payload1_ptr, this.heap.allocHeap(value));
239+
writeUint32(payload2_ptr, 0);
240+
break;
238241
}
239242
default:
240243
throw new Error(`Type "${typeof value}" is not supported yet`)
241244
}
242245
}
243246

244247
// Note:
245-
// `decodeValues` assumes that the size of RawJSValue is 12
248+
// `decodeValues` assumes that the size of RawJSValue is 16
246249
// and the alignment of it is 4
247250
const decodeValues = (ptr: pointer, length: number) => {
248251
let result = []
249252
for (let index = 0; index < length; index++) {
250-
const base = ptr + 12 * index
253+
const base = ptr + 16 * index
251254
const kind = readUInt32(base)
252-
const payload1 = readUInt32(base + 4)
253-
const payload2 = readUInt32(base + 8)
255+
const payload1 = readFloat64(base + 4)
256+
const payload2 = readUInt32(base + 12)
254257
result.push(decodeValue(kind, payload1, payload2))
255258
}
256259
return result
@@ -272,10 +275,7 @@ export class SwiftRuntime {
272275
) => {
273276
const obj = this.heap.referenceHeap(ref);
274277
const result = Reflect.get(obj, readString(name, length));
275-
const { kind, payload1, payload2 } = encodeValue(result);
276-
writeUint32(kind_ptr, kind);
277-
writeUint32(payload1_ptr, payload1);
278-
writeUint32(payload2_ptr, payload2);
278+
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr);
279279
},
280280
swjs_set_subscript: (
281281
ref: ref, index: number,
@@ -292,10 +292,7 @@ export class SwiftRuntime {
292292
) => {
293293
const obj = this.heap.referenceHeap(ref);
294294
const result = Reflect.get(obj, index);
295-
const { kind, payload1, payload2 } = encodeValue(result);
296-
writeUint32(kind_ptr, kind);
297-
writeUint32(payload1_ptr, payload1);
298-
writeUint32(payload2_ptr, payload2);
295+
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr);
299296
},
300297
swjs_load_string: (ref: ref, buffer: pointer) => {
301298
const string = this.heap.referenceHeap(ref);
@@ -308,10 +305,7 @@ export class SwiftRuntime {
308305
) => {
309306
const func = this.heap.referenceHeap(ref)
310307
const result = Reflect.apply(func, undefined, decodeValues(argv, argc))
311-
const { kind, payload1, payload2 } = encodeValue(result);
312-
writeUint32(kind_ptr, kind);
313-
writeUint32(payload1_ptr, payload1);
314-
writeUint32(payload2_ptr, payload2);
308+
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr);
315309
},
316310
swjs_call_function_with_this: (
317311
obj_ref: ref, func_ref: ref,
@@ -322,10 +316,7 @@ export class SwiftRuntime {
322316
const obj = this.heap.referenceHeap(obj_ref)
323317
const func = this.heap.referenceHeap(func_ref)
324318
const result = Reflect.apply(func, obj, decodeValues(argv, argc))
325-
const { kind, payload1, payload2 } = encodeValue(result);
326-
writeUint32(kind_ptr, kind);
327-
writeUint32(payload1_ptr, payload1);
328-
writeUint32(payload2_ptr, payload2);
319+
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr);
329320
},
330321
swjs_create_function: (
331322
host_func_id: number,

Sources/JavaScriptKit/JSFunction.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class JSFunctionRef: JSObjectRef {
4444
rawValues.withUnsafeBufferPointer { bufferPointer in
4545
let argv = bufferPointer.baseAddress
4646
let argc = bufferPointer.count
47-
var resultObj = JavaScriptPayload()
47+
var resultObj = JavaScriptObjectRef()
4848
_call_new(
4949
self.id, argv, Int32(argc),
5050
&resultObj
@@ -85,7 +85,7 @@ public func _cleanup_host_function_call(_ pointer: UnsafeMutableRawPointer) {
8585
public func _call_host_function(
8686
_ hostFuncRef: JavaScriptHostFuncRef,
8787
_ argv: UnsafePointer<RawJSValue>, _ argc: Int32,
88-
_ callbackFuncRef: JavaScriptPayload) {
88+
_ callbackFuncRef: JavaScriptObjectRef) {
8989
let hostFunc = JSFunctionRef.sharedFunctions[Int(hostFuncRef)]
9090
let args = UnsafeBufferPointer(start: argv, count: Int(argc)).map {
9191
$0.jsValue()

Sources/JavaScriptKit/JSValueConvertible.swift

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,24 @@ extension RawJSValue: JSValueConvertible {
6969
case JavaScriptValueKind_Boolean:
7070
return .boolean(payload1 != 0)
7171
case JavaScriptValueKind_Number:
72-
return .number(Int32(bitPattern: payload1))
72+
fatalError("unimplemented yet")
73+
// return .number(Int32(bitPattern: payload1))
7374
case JavaScriptValueKind_String:
7475
// +1 for null terminator
7576
let buffer = malloc(Int(payload2 + 1))!.assumingMemoryBound(to: UInt8.self)
7677
defer { free(buffer) }
77-
_load_string(payload1 as JavaScriptObjectRef, buffer)
78+
_load_string(JavaScriptObjectRef(payload1), buffer)
7879
buffer[Int(payload2)] = 0
7980
let string = String(decodingCString: UnsafePointer(buffer), as: UTF8.self)
8081
return .string(string)
8182
case JavaScriptValueKind_Object:
82-
return .object(JSObjectRef(id: payload1))
83+
return .object(JSObjectRef(id: UInt32(payload1)))
8384
case JavaScriptValueKind_Null:
8485
return .null
8586
case JavaScriptValueKind_Undefined:
8687
return .undefined
8788
case JavaScriptValueKind_Function:
88-
return .function(JSFunctionRef(id: payload1))
89+
return .function(JSFunctionRef(id: UInt32(payload1)))
8990
default:
9091
fatalError("unreachable")
9192
}
@@ -95,27 +96,28 @@ extension RawJSValue: JSValueConvertible {
9596
extension JSValue {
9697
func withRawJSValue<T>(_ body: (RawJSValue) -> T) -> T {
9798
let kind: JavaScriptValueKind
98-
let payload1: JavaScriptPayload
99-
let payload2: JavaScriptPayload
99+
let payload1: JavaScriptPayload1
100+
let payload2: JavaScriptPayload2
100101
switch self {
101102
case let .boolean(boolValue):
102103
kind = JavaScriptValueKind_Boolean
103104
payload1 = boolValue ? 1 : 0
104105
payload2 = 0
105106
case let .number(numberValue):
106-
kind = JavaScriptValueKind_Number
107-
payload1 = JavaScriptPayload(bitPattern: numberValue)
108-
payload2 = 0
107+
fatalError("unimplemented yet")
108+
// kind = JavaScriptValueKind_Number
109+
// payload1 = JavaScriptPayload1(bitPattern: numberValue)
110+
// payload2 = 0
109111
case var .string(stringValue):
110112
kind = JavaScriptValueKind_String
111113
return stringValue.withUTF8 { bufferPtr in
112114
let ptrValue = UInt32(UInt(bitPattern: bufferPtr.baseAddress!))
113-
let rawValue = RawJSValue(kind: kind, payload1: ptrValue, payload2: JavaScriptPayload(bufferPtr.count))
115+
let rawValue = RawJSValue(kind: kind, payload1: JavaScriptPayload1(ptrValue), payload2: JavaScriptPayload2(bufferPtr.count))
114116
return body(rawValue)
115117
}
116118
case let .object(ref):
117119
kind = JavaScriptValueKind_Object
118-
payload1 = ref.id
120+
payload1 = JavaScriptPayload1(ref.id)
119121
payload2 = 0
120122
case .null:
121123
kind = JavaScriptValueKind_Null
@@ -127,7 +129,7 @@ extension JSValue {
127129
payload2 = 0
128130
case let .function(functionRef):
129131
kind = JavaScriptValueKind_Function
130-
payload1 = functionRef.id
132+
payload1 = JavaScriptPayload1(functionRef.id)
131133
payload2 = 0
132134
}
133135
let rawValue = RawJSValue(kind: kind, payload1: payload1, payload2: payload2)

0 commit comments

Comments
 (0)