Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Shanks0224 committed Feb 20, 2024
2 parents 49fded7 + cda461d commit ae6576a
Show file tree
Hide file tree
Showing 28 changed files with 2,665 additions and 661 deletions.
136 changes: 124 additions & 12 deletions doc/developer-guide/wasmType_usage.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,68 @@
# Use wasmType in typescript
## wasmType declaration
Now we support use wasmType directly in typescript, and the types must be explicitly specified:
Now we support use wasmType directly in typescript, these below types are supported:
### wasm basic type
- `i32`
- `i64`
- `f32`
- `f64`
- `anyref`
### wasm heap type
- `array`
- `struct`

## wasmType usage
### For basic type
During usage, we must follow some rules. And the wasm basic type rules is differ from wasm heap type rules.
### wasm basic type
We can use the wasm basic type as ts type name directly.
### wasm heap type
We should set a special comment to indicate that a wasm heap type structure will be created.

1. For `array`, we use `comment + array type alias` to represent the raw wasm array type.
```ts
// Wasmnizer-ts: @WASMArray@ <Not_Packed, Mutable, Nullable>
type arrayType1 = string[];
---> will create a raw wasm array type: array<stringref>

// Wasmnizer-ts: @WASMArray@
type arrayType2 = i32[];
---> will create a raw wasm array type: array<i32>
```
**Hint: `// Wasmnizer-ts: @WASMArray@ ` is necessary, and `<Not_Packed, Mutable, Nullable>` is optional. The latter shows that `if the array element is packed`, `if the array element is mutable`, `if the array is nullable`. The default value is `Not_Packed`, `Mutable` and `Nullable`.**

2. For `struct`, we use `comment + tuple type alias` to represent the raw wasm struct type.
```ts
// Wasmnizer-ts: @WASMStruct@ <[Not_Packed, Not_Packed], [Mutable, Mutable], Nullable, NULL>
type structType1 = [arrayType1, i64];
---> will create a raw wasm struct type: struct[array<stringref>, i64]

// Wasmnizer-ts: @WASMStruct@
type structType2 = [i64, i32];
---> will create a raw wasm struct type: struct[i64, i32]
```
**Hint: `// Wasmnizer-ts: @WASMStruct@ ` is necessary, and `<[Not_Packed, ...], [Mutable, ...], Nullable, BaseTypeName>` is optional. The latter shows that `if the struct fields are packed`, `if the struct fields are mutable`, `if the struct is nullable`, `the struct's base type name`. The default value is `[Not_Packed, ...]`, `[Mutable, ...]`, `Nullable` and `NULL`.**

The comments' optional attributes can be one of these enum value:
```ts
export enum PackedTypeKind {
Not_Packed = 'Not_Packed',
I8 = 'I8',
I16 = 'I16',
}

export enum MutabilityKind {
Immutable = 'Immutable',
Mutable = 'Mutable',
}

export enum NullabilityKind {
NonNullable = 'NonNullable',
Nullable = 'Nullable',
}
```

## Example
### Used as basic type
If we define the wasmtype for variables, and the right value is LiteralValue or variables with the same wasmtype, the **no cast** will be generated.
```ts
const a: i32 = 100;
Expand All @@ -32,6 +88,27 @@ const a: f64 = 100;
(f64.const 100)
```

```ts
// Wasmnizer-ts: @WASMArray@
type arrayType2 = i32[];
const a: arrayType2 = [100];
-->
(array.new_fixed $array0 1
(i32.const 100)
)
```

```ts
// Wasmnizer-ts: @WASMStruct@
type structType2 = [i64, i32];
const a: structType2 = [100, 200]
--->
(struct.new $45
(i64.const 100)
(i32.const 200)
)
```

If we don't define the wasmtype explicitly, then the variable will be regard as `number` type, **one cast** will be occurs.
```ts
const a = 100 as i32;
Expand All @@ -42,12 +119,21 @@ const a = 100 as i32;
```


### For array type
### Used as array element type
The array type should be explicitly specified too.
```ts
const a: i32[] = [1, 2];
-->
a will be regarded as i32[], the elements in right value are both i32.
since we use struct to represent ts array, so the wasm structure is struct[array<i32>, i32].
```
```ts
const x: arrayType2 = [100];
const y: arrayType2 = [200];
const a: arrayType2[] = [x, y];
-->
a will be regarded as arrayType2[], the elements in right value are both arrayType2.
since we use struct to represent ts array, so the wasm structure is struct[array<array<i32>>, i32].
```
If array's type is not explicitly specified, then left value is regarded as number[], compilation error will occur.
```ts
Expand All @@ -58,19 +144,20 @@ let a = [a1, a2];
a will be regarded as number[], compile will fail.
```

### For class type
### Used as class property type
Each property's wasm type should be explicitly specified.
```ts
class A {
a: i32 = 1;
b: i64 = 2;
c: f32 = 3;
d: f64 = 4;
e: arrayType2 = [5];
}
-->
The properties type are i32, i64, f32, f64 type.
The properties type are i32, i64, f32, f64, array<i32> type.
```
If property's type is not explicitly specified, they will be regarded as number type, and **one cast** will occur.
If property's type is not explicitly specified, they will be regarded as original ts type, and **one cast** will occur.
```ts
class A {
a = 1 as i32;
Expand All @@ -81,31 +168,42 @@ class A {
-->
The properties type are both number type, and a, b, c all will be cast to f64.
```
Wasm heap type can not be used as casted target since the ts original type `number[]` can not be casted to `WASMArrayType`:
```ts
class A {
e = [5] as arrayType2
}
-->
Will cause compilation error since `cannot make cast value from "Array<NUMBER(6)(OBJECT)>(-1)" to "WASM_ARRAY(58)"`
```

### For interface type
### Used as interface property type
Each property's wasm type should be explicitly specified.
```ts
interface I {
a: i32;
b: i64;
c: f32;
d: f64;
e: arrayType2;
}
-->
The properties type are i32, i64, f32, f64 type.
The properties type are i32, i64, f32, f64, array<i32> type.
```

### For object literal type
### Used as object literal property type
Since object literal's properties' type can not be defined, we only provide its value, so we judge properties' type by its real value type.
```ts
const x: arrayType2 = [5];
const obj = {
a: 1 as i32,
b: 2 as i64,
c: 3 as f32,
d: 4 as f64,
e: x as arrayType2,
}
-->
The properties type are i32, i64, f32, f64 type.
The properties type are i32, i64, f32, f64, array<i32> type.
```

So, if we assign the obj's type to an interface type which has wasmtype, then we should ensure that the properties' value type should be wasmtype too.
Expand All @@ -115,12 +213,15 @@ interface I {
b: i64;
c: f32;
d: f64;
e: arrayType2;
}
const x: arrayType2 = [5];
const obj: I = {
a: 1 as i32,
b: 2 as i64,
c: 3 as f32,
d: 4 as f64,
e: x as arrayType2,
}
--->
compile success
Expand All @@ -131,18 +232,20 @@ interface I {
b: i64;
c: f32;
d: f64;
e: arrayType2;
}
const obj: I = {
a: 1,
b: 2,
c: 3,
d: 4,
e: [5],
}
--->
compile fail
```

### For funtion type
### Used as funtion param type & return type
The parameter's type and return type should be explicitly specified when using wasmtype.
```ts
function test(): i32 {
Expand All @@ -165,7 +268,16 @@ One cast will occur, the return type is number.
)
```

### binary operations
```ts
function test(): arrayType2 {
const x: arrayType2 = [100];
return x;
}
-->
The return type is array<i32>.
```

### type casting in binary operations
If two operators with wasm type operate binary operations, they will cast to the larger type, and operate.
```ts
const a: i32 = 100;
Expand Down
1 change: 1 addition & 0 deletions lib/builtin/builtin_name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export namespace BuiltinNames {
export const findPropertyFlagAndIndex = 'find_property_flag_and_index';
export const findPropertyType = 'find_property_type';
export const getInfcProperty = 'get_infc_property';
export const getTupleField = 'get_tuple_field';

// builtin globals
export const builtinTypeManglePrefix = 'lib/builtin/lib.type.d';
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
},
"lint-staged": {
"*.ts": [
"eslint --ignore-path .eslintignore --config .eslintrc.json --fix '**/*.ts'",
"eslint --ignore-path .eslintignore --config .eslintrc.json --fix --quiet '**/*.ts'",
"prettier --ignore-path .prettierignore --config .prettierrc.json --write '**/*.ts'"
]
},
Expand Down
22 changes: 11 additions & 11 deletions runtime-library/stdlib/lib_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ array_concat_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
return NULL;
}

wasm_runtime_push_local_object_ref(exec_env, &local_ref);
wasm_runtime_push_local_obj_ref(exec_env, &local_ref);
local_ref.val = (wasm_obj_t)new_arr;
create_new_array = true;

Expand All @@ -183,7 +183,7 @@ array_concat_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,

fail:
if (create_new_array) {
wasm_runtime_pop_local_object_ref(exec_env);
wasm_runtime_pop_local_obj_ref(exec_env);
}

return new_arr_struct;
Expand Down Expand Up @@ -305,7 +305,7 @@ array_slice_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
return NULL;
}

wasm_runtime_push_local_object_ref(exec_env, &local_ref);
wasm_runtime_push_local_obj_ref(exec_env, &local_ref);
local_ref.val = (wasm_obj_t)new_arr;

for (i = start; i < end; i++) {
Expand All @@ -326,7 +326,7 @@ array_slice_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
wasm_struct_obj_set_field(new_arr_struct, 1, &tmp_val);

end:
wasm_runtime_pop_local_object_ref(exec_env);
wasm_runtime_pop_local_obj_ref(exec_env);
return new_arr_struct;
}

Expand Down Expand Up @@ -500,7 +500,7 @@ array_splice_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
goto end1;
}

wasm_runtime_push_local_object_ref(exec_env, &local_ref);
wasm_runtime_push_local_obj_ref(exec_env, &local_ref);
local_ref.val = (wasm_obj_t)delete_arr;

/* Copy deleted elements to delete_arr*/
Expand Down Expand Up @@ -551,7 +551,7 @@ array_splice_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
tmp_val.u32 = delete_count;
wasm_struct_obj_set_field(new_arr_struct, 1, &tmp_val);

wasm_runtime_pop_local_object_ref(exec_env);
wasm_runtime_pop_local_obj_ref(exec_env);
return new_arr_struct;

end1:
Expand All @@ -560,7 +560,7 @@ array_splice_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
return NULL;

end2:
wasm_runtime_pop_local_object_ref(exec_env);
wasm_runtime_pop_local_obj_ref(exec_env);
wasm_runtime_set_exception(wasm_runtime_get_module_inst(exec_env),
"alloc memory failed");
return NULL;
Expand Down Expand Up @@ -1059,7 +1059,7 @@ array_map_generic(wasm_exec_env_t exec_env, void *ctx, void *obj, void *closure)
"alloc memory failed");
return NULL;
}
wasm_runtime_push_local_object_ref(exec_env, &local_ref);
wasm_runtime_push_local_obj_ref(exec_env, &local_ref);
local_ref.val = (wasm_obj_t)new_arr;

/* get current array element type */
Expand Down Expand Up @@ -1110,7 +1110,7 @@ array_map_generic(wasm_exec_env_t exec_env, void *ctx, void *obj, void *closure)
wasm_struct_obj_set_field(new_arr_struct, 1, &tmp_val);

end:
wasm_runtime_pop_local_object_ref(exec_env);
wasm_runtime_pop_local_obj_ref(exec_env);
return new_arr_struct;
}

Expand Down Expand Up @@ -1190,7 +1190,7 @@ array_filter_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
"alloc memory failed");
goto end1;
}
wasm_runtime_push_local_object_ref(exec_env, &local_ref);
wasm_runtime_push_local_obj_ref(exec_env, &local_ref);
local_ref.val = (wasm_obj_t)new_arr;

for (i = 0; i < new_arr_len; i++) {
Expand All @@ -1211,7 +1211,7 @@ array_filter_generic(wasm_exec_env_t exec_env, void *ctx, void *obj,
wasm_struct_obj_set_field(new_arr_struct, 1, &tmp_val);

end2:
wasm_runtime_pop_local_object_ref(exec_env);
wasm_runtime_pop_local_obj_ref(exec_env);

end1:
if (include_refs) {
Expand Down
4 changes: 2 additions & 2 deletions runtime-library/utils/object_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ call_wasm_func_with_boxing(wasm_exec_env_t exec_env, dyn_ctx_t ctx,
) {
/* unbox_value_from_any will create anyref for any-objects, we must
* hold its reference to avoid it being claimed */
wasm_runtime_push_local_object_ref(exec_env,
wasm_runtime_push_local_obj_ref(exec_env,
&local_refs[local_ref_count]);
local_refs[local_ref_count++].val = tmp_param.gc_obj;
}
Expand All @@ -454,7 +454,7 @@ call_wasm_func_with_boxing(wasm_exec_env_t exec_env, dyn_ctx_t ctx,
}

if (local_ref_count) {
wasm_runtime_pop_local_object_refs(exec_env, local_ref_count);
wasm_runtime_pop_local_obj_refs(exec_env, local_ref_count);
}

is_success =
Expand Down
Loading

0 comments on commit ae6576a

Please sign in to comment.