一、限制

将无类型的JavaScript编译为WebAssembly没有意义,因为它最终会导致运行其中较慢的一个JavaScript。

相反,AssemblyScript专注于WebAssembly擅长的地方,并且不支持回退到无法提前有效编译的JavaScript的动态特性:

1.强制类型

  • 比 TypeScript 多了很多更细致的内置类型,以优化性能和内存占用,详情文档;
  • 没有联合类型,因为所有内容都必须按设计进行静态类型化;
  • 不能使用 any 和 undefined 类型,以及枚举类型;
  • 可空类型的变量必须是引用类型,例如 ClassType | null,而不能是基本数据类型如 string、number、boolean;
  • 函数中的可选参数必须提供默认值,函数必须有返回类型,无返回值的函数返回类型需要是 void;
  • 如果初始化是整数字面量,则假定i32适合32位,否则假设为i64。
  • 如果初始化是浮点数,则假定为f64。
  • 否则,将评估初始化程序以获取其类型。

总体来说 AssemblyScript 比 TypeScript 又多了很多限制,编写起来会觉得局限性很大; 用 AssemblyScript 来写 WebAssembly 经常会出现 tsc 编译通过但运行 WebAssembly 时出错的情况,这很可能就是你没有遵守以上限制导致的;但 AssemblyScript 通过修改 TypeScript 编译器默认配置能在编译阶段找出大多错误。

AssemblyScript 的实现原理其实也借助了 LLVM,它通过 TypeScript 编译器把 TS 源码解析成 AST,再把 AST 翻译成 IR,再通过 LLVM 编译成 WebAssembly 字节码实现; 上面提到的各种限制都是为了方便把 AST 转换成 LLVM IR。

2.详细说明

  • const和static readonly关键字当前与其他语言中的static const类似,需要编译时常量初始化程序,否则会回退到可变变量。
  • 在JavaScript中,类的静态字段在定义时始终进行求值,而在AssemblyScript中,内置树抖动时会在引用时懒惰地编译静态字段。

当调用一个从Js中导出的可变参数长度的WebAssembly函数时,例如:



1 export function add(a: i32 = 1, b: i32 = 2): i32 {
2   return a + b;
3 }



必须明确指定调用的实际参数数量,因为WebAssembly端没有与arguments.length等效的内容。 例如:



1 exports._setargc(0);
2 exports.sum(); // 3
3 
4 exports._setargc(1);
5 exports.sum(2); // 4
6 
7 exports._setargc(2);
8 exports.sum(2, 3); // 5



二、类型

与在JS中使用各种数值的数字类型不同,AssemblyScript将它们拆分为更精确的整数和浮点类型,这些类型直接映射到WebAssembly类型。

1.原生类型

  • i32/u32  一个32位有符号/无符号整数。
  • i64/u64  一个64位有符号/无符号整数。
  • f32  一个32为浮点数。
  • f64 一个64位浮点数。

2.模拟类型

  • i8/u8  一个8字节的有符号/无符号整数。
  • i16/u16  一个16字节的有符号/无符号整数。
  • bool  一个1字节无符号整数。

注意:模拟类型被隐式符号扩展,分别被屏蔽以处理溢出。 在进行大量数学运算时,建议在计算中使用原生类型,然后将值存储回模拟类型,上面的"位"即byte,字节。

3.针对特定类型

  • isize/usize  当目标是32位WebAssembly时,一个32位有符号/无符号整数;当目标是64位WebAssembly时,一个64位有符号/无符号整数。在其他语言中相当于void*, size_t等。

注意,使用目标特定类型可能需要也可能不需要显式强制类型,具体取决于目标。

注意,WASM64是未来的功能?,现在在任何地方都不受支持。

4.特殊类型

  • void  表示函数无返回值。

5.范围限制

为方便起见,以下范围限制作为全局常量出现:

Constant

Value

i8.MIN_VALUE: i8

-128

i8.MAX_VALUE: i8

127

i16.MIN_VALUE: i16

-32768

i16.MAX_VALUE: i16

32767

i32.MIN_VALUE: i32

-2147483648

i32.MAX_VALUE: i32

2147483647

i64.MIN_VALUE: i64

-9223372036854775808

i64.MAX_VALUE: i64

9223372036854775807

isize.MIN_VALUE: isize

target specific: either i32.MIN_VALUE or i64.MIN_VALUE

isize.MAX_VALUE: isize

target specific: either i32.MAX_VALUE or i64.MAX_VALUE

u8.MIN_VALUE: u8

0

u8.MAX_VALUE: u8

255

u16.MIN_VALUE: u16

0

u16.MAX_VALUE: u16

65535

u32.MIN_VALUE: u32

0

u32.MAX_VALUE: u32

4294967295

u64.MIN_VALUE: u64

0

u64.MAX_VALUE: u64

18446744073709551615

usize.MIN_VALUE: usize

0

usize.MAX_VALUE: usize

target specific: either u32.MAX_VALUE or u64.MAX_VALUE

bool.MIN_VALUE: bool

0

bool.MAX_VALUE: bool

1

f32.MIN_VALUE: f32

-3.40282347e+38

f32.MAX_VALUE: f32

3.40282347e+38

f32.MIN_SAFE_INTEGER: f32

-16777215

f32.MAX_SAFE_INTEGER: f32

16777215

f32.EPSILON: f32

1.19209290e-07

f64.MIN_VALUE: f64

-1.7976931348623157e+308

f64.MAX_VALUE: f64

1.7976931348623157e+308

f64.MIN_SAFE_INTEGER: f64

-9007199254740991

f64.MAX_SAFE_INTEGER: f64

9007199254740991

f64.EPSILON: f64

2.2204460492503131e-16

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 6.可转换性

 将一种类型的值分配给另一种类型的目标可以在没有显式强制转换的情况下执行,其中可以在目标类型中表示完整范围的可能值,而不管解释/签名:


bool

i8/u8

i16/u16

i32/u32

i64/u64

f32

f64

bool








i8/u8

 







i16/u16

 

 






i32/u32

 

 

 



 


i64/u64

 

 

 

 


 

 

f32

 

 

 

 

 



f64

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

  

注意,如果目标是WASM32,则isize / usize的行为与i32 / u32相同,如果目标是WASM64,则分别为i64 / u64。

例如:



1 var i8val  : i8  = -128;  // 0x80
2 var u8val  : u8  = i8val; // becomes 128 (0x80)
3 var i16val : i16 = i8val; // becomes -128 through sign-extension (0xFF80)
4 var u16val : u16 = i8val; // becomes 65408 through masking (0xFF80)
5 var f32val : f32 = i8val; // becomes -128.0



7.可比性

可以在可分配性中概述的相同规则下执行比较不同类型的两个值而无需显式转换

1.如果比较是绝对的 (==!=)

2.如果比较是相对的  (><>=<=)  并且两种类型都具有相同的签名

因为WebAssembly对签名和未签名的比较具有不同的操作。 比较使用较大的类型并返回一个bool。

8.除法和余数

划分或取出除以不同类型的两个值的余数,可以在可转让性中概述的相同规则下进行显式转换。

  • 如果两种类型都具有相同的签名

因为WebAssembly对有符号和无符号除法和余数有不同的操作。 结果是更大的类型。

9.位运算

位运算(<<,>>)的结果是左类型,右类型隐式转换为左类型,如果左类型是有符号的,则执行算术移位;如果左类型是无符号,则执行逻辑移位。

无符号右移(>>>)的结果是左类型(保留了符号),右类型隐式转换为左类型,但始终执行逻辑移位。

如果左类型是浮点数,则会发出错误。

WebAssembly基本概念到此结束,虽然有很多不理解的东西,但还是先记录在此,慢慢学习。