Skip to content

Commit

Permalink
Add doc comments for Runtime library interface
Browse files Browse the repository at this point in the history
  • Loading branch information
kateinoigakukun committed Sep 22, 2020
1 parent 2ba20d2 commit 10bfff2
Show file tree
Hide file tree
Showing 2 changed files with 225 additions and 61 deletions.
35 changes: 35 additions & 0 deletions Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,41 @@ public class JSClosure: JSFunction {
}
}


// MARK: - `JSClosure` mechanism note
//
// 1. Create thunk function in JavaScript world, that has a reference
// to Swift Closure.
// ┌─────────────────────┬──────────────────────────┐
// │ Swift side │ JavaScript side │
// │ │ │
// │ │ │
// │ │ ┌──[Thunk function]──┐ │
// │ ┌ ─ ─ ─ ─ ─│─ ─│─ ─ ─ ─ ─ ┐ │ │
// │ ↓ │ │ │ │ │
// │ [Swift Closure] │ │ Host Function ID │ │
// │ │ │ │ │
// │ │ └────────────────────┘ │
// └─────────────────────┴──────────────────────────┘
//
// 2. When thunk function is invoked, it calls Swift Closure via
// `_call_host_function` and callback the result through callback func
// ┌─────────────────────┬──────────────────────────┐
// │ Swift side │ JavaScript side │
// │ │ │
// │ │ │
// │ Apply ┌──[Thunk function]──┐ │
// │ ┌ ─ ─ ─ ─ ─│─ ─│─ ─ ─ ─ ─ ┐ │ │
// │ ↓ │ │ │ │ │
// │ [Swift Closure] │ │ Host Function ID │ │
// │ │ │ │ │ │
// │ │ │ └────────────────────┘ │
// │ │ │ ↑ │
// │ │ Apply │ │
// │ └─[Result]─┼───>[Callback func]─┘ │
// │ │ │
// └─────────────────────┴──────────────────────────┘

@_cdecl("swjs_prepare_host_function_call")
func _prepare_host_function_call(_ argc: Int32) -> UnsafeMutableRawPointer {
let argumentSize = MemoryLayout<RawJSValue>.size * Int(argc)
Expand Down
251 changes: 190 additions & 61 deletions Sources/_CJavaScriptKit/include/_CJavaScriptKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
#include <stdlib.h>
#include <stdbool.h>

/// `JavaScriptObjectRef` represents JavaScript object reference that is referenced by Swift side.
/// This value is an address of `SwiftRuntimeHeap`.
typedef unsigned int JavaScriptObjectRef;
/// `JavaScriptHostFuncRef` represents Swift closure that is referenced by JavaScript side.
/// This value is produced by `JSClosure`.
typedef unsigned int JavaScriptHostFuncRef;

/// `JavaScriptValueKind` represents the kind of JavaScript primitive value.
typedef enum __attribute__((enum_extensibility(closed))) {
JavaScriptValueKindInvalid = -1,
JavaScriptValueKindBoolean = 0,
Expand All @@ -21,90 +26,214 @@ typedef enum __attribute__((enum_extensibility(closed))) {
typedef unsigned JavaScriptPayload1;
typedef double JavaScriptPayload2;

/// `RawJSValue` is abstract representaion of JavaScript primitive value.
///
/// For boolean value:
/// payload1: 1 or 0
/// payload2: 0
///
/// For string value:
/// payload1: `JavaScriptObjectRef` of string
/// payload2: 0
///
/// For number value:
/// payload1: 0
/// payload2: double number
///
/// For object value:
/// payload1: `JavaScriptObjectRef`
/// payload2: 0
/// For null value:
/// payload1: 0
/// payload2: 0
///
/// For undefined value:
/// payload1: 0
/// payload2: 0
///
/// For function value:
/// payload1: the target `JavaScriptHostFuncRef`
/// payload2: 0
///
typedef struct {
JavaScriptValueKind kind;
JavaScriptPayload1 payload1;
JavaScriptPayload2 payload2;
} RawJSValue;

#if __wasm32__
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_set_prop"))) extern void
_set_prop(const JavaScriptObjectRef _this, const JavaScriptObjectRef prop,
const JavaScriptValueKind kind, const JavaScriptPayload1 payload1,
const JavaScriptPayload2 payload2);

/// `_set_prop` sets a value of `_this` JavaScript object.
///
/// @param _this The target JavaScript object to set the given value.
/// @param prop A JavaScript string object to reference a member of `_this` object.
/// @param kind A kind of JavaScript value to set the target object.
/// @param payload1 The first payload of JavaScript value to set the target object.
/// @param payload2 The second payload of JavaScript value to set the target object.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_get_prop"))) extern void
_get_prop(const JavaScriptObjectRef _this, const JavaScriptObjectRef prop,
JavaScriptValueKind *kind, JavaScriptPayload1 *payload1,
JavaScriptPayload2 *payload2);

__import_name__("swjs_set_prop")))
extern void _set_prop(const JavaScriptObjectRef _this,
const JavaScriptObjectRef prop,
const JavaScriptValueKind kind,
const JavaScriptPayload1 payload1,
const JavaScriptPayload2 payload2);

/// `_get_prop` gets a value of `_this` JavaScript object.
///
/// @param _this The target JavaScript object to get its member value.
/// @param prop A JavaScript string object to reference a member of `_this` object.
/// @param kind A result pointer of JavaScript value kind to get.
/// @param payload1 A result pointer of first payload of JavaScript value to set the target object.
/// @param payload2 A result pointer of second payload of JavaScript value to set the target object.
__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);

__import_name__("swjs_get_prop")))
extern void _get_prop(const JavaScriptObjectRef _this,
const JavaScriptObjectRef prop,
JavaScriptValueKind *kind,
JavaScriptPayload1 *payload1,
JavaScriptPayload2 *payload2);

/// `_set_subscript` sets a value of `_this` JavaScript object.
///
/// @param _this The target JavaScript object to set its member value.
/// @param index A subscript index to set value.
/// @param kind A kind of JavaScript value to set the target object.
/// @param payload1 The first payload of JavaScript value to set the target object.
/// @param payload2 The second payload of JavaScript value to set the target object.
__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);

__import_name__("swjs_set_subscript")))
extern void _set_subscript(const JavaScriptObjectRef _this,
const int index,
const JavaScriptValueKind kind,
const JavaScriptPayload1 payload1,
const JavaScriptPayload2 payload2);

/// `_get_subscript` gets a value of `_this` JavaScript object.
///
/// @param _this The target JavaScript object to get its member value.
/// @param index A subscript index to get value.
/// @param kind A result pointer of JavaScript value kind to get.
/// @param payload1 A result pointer of first payload of JavaScript value to get the target object.
/// @param payload2 A result pointer of second payload of JavaScript value to get the target object.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_encode_string"))) extern int
_encode_string(const JavaScriptObjectRef str_obj, JavaScriptObjectRef *bytes_ptr_result);

__import_name__("swjs_get_subscript")))
extern void _get_subscript(const JavaScriptObjectRef _this,
const int index,
JavaScriptValueKind *kind,
JavaScriptPayload1 *payload1,
JavaScriptPayload2 *payload2);

/// `_encode_string` encodes the `str_obj` to bytes sequence and returns the length of bytes.
///
/// @param str_obj A JavaScript string object ref to encode.
/// @param bytes_result A result pointer of bytes sequence representation in JavaScript.
/// This value will be used to load the actual bytes using `_load_string`.
/// @result The length of bytes sequence. This value will be used to allocate Swift side string buffer to load the actual bytes.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_decode_string"))) extern JavaScriptObjectRef
_decode_string(const unsigned char *bytes_ptr, const int length);

__import_name__("swjs_encode_string")))
extern int _encode_string(const JavaScriptObjectRef str_obj, JavaScriptObjectRef *bytes_result);

/// `_decode_string` decodes the given bytes sequence into JavaScript string object.
///
/// @param bytes_ptr A `uint8_t` byte sequence to decode.
/// @param length The length of `bytes_ptr`.
/// @result The decoded JavaScript string object.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_load_string"))) extern void
_load_string(const JavaScriptObjectRef ref, unsigned char *buffer);
__import_name__("swjs_decode_string")))
extern JavaScriptObjectRef _decode_string(const unsigned char *bytes_ptr, const int length);

/// `_load_string` loads the actual bytes sequence of `bytes` into `buffer` which is a Swift side memory address.
///
/// @param bytes A bytes sequence representation in JavaScript to load. This value should be derived from `_encode_string`.
/// @param buffer A Swift side string buffer to load the bytes.
__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);

__import_name__("swjs_load_string")))
extern void _load_string(const JavaScriptObjectRef bytes, unsigned char *buffer);

/// `_call_function` calls JavaScript function with given arguments list.
///
/// @param ref The target JavaScript function to call.
/// @param argv A list of `RawJSValue` arguments to apply.
/// @param argc The length of `argv``.
/// @param result_kind A result pointer of JavaScript value kind to get.
/// @param result_payload1 A result pointer of first payload of JavaScript value to set the target object.
/// @param result_payload2 A result pointer of second payload of JavaScript value to set the target object.
__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);

__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);

/// `_call_function_with_this` calls JavaScript function with given arguments list and given `_this`.
///
/// @param _this The value of `this` provided for the call to `func_ref`.
/// @param func_ref The target JavaScript function to call.
/// @param argv A list of `RawJSValue` arguments to apply.
/// @param argc The length of `argv``.
/// @param result_kind A result pointer of JavaScript value kind to get.
/// @param result_payload1 A result pointer of first payload of JavaScript value to set the target object.
/// @param result_payload2 A result pointer of second payload of JavaScript value to set the target object.
__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);

__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);

/// `_call_new` calls JavaScript object constructor with given arguments list.
///
/// @param ref The target JavaScript constructor to call.
/// @param argv A list of `RawJSValue` arguments to apply.
/// @param argc The length of `argv``.
/// @param result_obj A result pointer of the constructed object.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_instanceof"))) extern bool
_instanceof(const JavaScriptObjectRef obj,
const JavaScriptObjectRef constructor);

__import_name__("swjs_call_new")))
extern void _call_new(const JavaScriptObjectRef ref,
const RawJSValue *argv, const int argc,
JavaScriptObjectRef *result_obj);

/// `_instanceof` acts like JavaScript `instanceof` operator.
///
/// @param obj The target object to check its prototype chain.
/// @param constructor The `constructor` object to check against.
/// @result Return `true` if `constructor` appears anywhere in the prototype chain of `obj`. Return `false` if not.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_create_function"))) extern void
_create_function(const JavaScriptHostFuncRef host_func_id,
const JavaScriptObjectRef *func_ref_ptr);

__import_name__("swjs_instanceof")))
extern bool _instanceof(const JavaScriptObjectRef obj,
const JavaScriptObjectRef constructor);

/// `_create_function` creates a JavaScript thunk function that calls Swift side closure.
/// See also comments on JSFunction.swift
///
/// @param host_func_id The target Swift side function called by the created thunk function.
/// @param func_ref_ptr A result pointer of created thunk function.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_release"))) extern void
_release(const JavaScriptObjectRef ref);
__import_name__("swjs_create_function")))
extern void _create_function(const JavaScriptHostFuncRef host_func_id,
const JavaScriptObjectRef *func_ref_ptr);

/// Decrements reference count of `ref` retained by `SwiftRuntimeHeap` in JavaScript side.
///
/// @param ref The target JavaScript object.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_release")))
extern void _release(const JavaScriptObjectRef ref);

/// Instantiate a new `TypedArray` object with given elements
/// This is used to provide an efficient way to create `TypedArray`.
///
/// @param constructor The `TypedArray` constructor.
/// @param elements_ptr The elements pointer to initialize. They are assumed to be the same size of `constructor` elements size.
/// @param length The length of `elements_ptr`
/// @param result_obj A result pointer of the constructed object.
__attribute__((__import_module__("javascript_kit"),
__import_name__("swjs_create_typed_array"))) extern void
_create_typed_array(const JavaScriptObjectRef constructor,
const void *elementsPtr, const int length,
JavaScriptObjectRef *result_obj);
__import_name__("swjs_create_typed_array")))
extern void _create_typed_array(const JavaScriptObjectRef constructor,
const void *elements_ptr, const int length,
JavaScriptObjectRef *result_obj);

#endif

Expand Down

0 comments on commit 10bfff2

Please sign in to comment.