From bf7dd1a64f350be7711f058bbd1424d66a4f3f4f Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Fri, 30 Nov 2018 01:12:01 +0100 Subject: [PATCH] Document the use of two type parameters in loadUnsafe, TypedArray etc., see #349 --- std/assembly/internal/arraybuffer.ts | 34 +++++++++++++++---- std/assembly/internal/typedarray.ts | 19 ++++++----- tests/compiler/std/dataview.optimized.wat | 2 +- tests/compiler/std/dataview.untouched.wat | 4 +-- tests/compiler/std/typedarray.optimized.wat | 22 ++++++------- tests/compiler/std/typedarray.untouched.wat | 36 ++++++++++----------- 6 files changed, 71 insertions(+), 46 deletions(-) diff --git a/std/assembly/internal/arraybuffer.ts b/std/assembly/internal/arraybuffer.ts index 8484e8f6..9833116a 100644 --- a/std/assembly/internal/arraybuffer.ts +++ b/std/assembly/internal/arraybuffer.ts @@ -64,18 +64,40 @@ export function reallocateUnsafe(buffer: ArrayBuffer, newByteLength: i32): Array return buffer; } -@inline export function loadUnsafe(buffer: ArrayBuffer, index: i32): V { - return load(changetype(buffer) + (index << alignof()), HEADER_SIZE); +// The helpers below use two different types in order to emit loads and stores that load respectively +// store one type to/from memory while returning/taking the desired output/input type. This allows to +// emit instructions like +// +// * `i32.load8` ^= `load(...)` that reads an i8 but returns an i32, or +// * `i64.load32_s` ^= `load(...)`) that reads a 32-bit as a 64-bit integer +// +// without having to emit an additional instruction for conversion purposes. This is useful for +// small integers only of course. When dealing with reference types like classes, both parameters +// are usually the same, even though it looks ugly. +// +// TODO: is there a better way to model this? + +@inline export function loadUnsafe(buffer: ArrayBuffer, index: i32): TOut { + return load(changetype(buffer) + (index << alignof()), HEADER_SIZE); } -@inline export function storeUnsafe(buffer: ArrayBuffer, index: i32, value: V): void { +@inline export function storeUnsafe(buffer: ArrayBuffer, index: i32, value: TIn): void { store(changetype(buffer) + (index << alignof()), value, HEADER_SIZE); } -@inline export function loadUnsafeWithOffset(buffer: ArrayBuffer, index: i32, byteOffset: i32): V { - return load(changetype(buffer) + byteOffset + (index << alignof()), HEADER_SIZE); +@inline export function loadUnsafeWithOffset( + buffer: ArrayBuffer, + index: i32, + byteOffset: i32 +): TOut { + return load(changetype(buffer) + byteOffset + (index << alignof()), HEADER_SIZE); } -@inline export function storeUnsafeWithOffset(buffer: ArrayBuffer, index: i32, value: V, byteOffset: i32): void { +@inline export function storeUnsafeWithOffset( + buffer: ArrayBuffer, + index: i32, + value: TIn, + byteOffset: i32 +): void { store(changetype(buffer) + byteOffset + (index << alignof()), value, HEADER_SIZE); } diff --git a/std/assembly/internal/typedarray.ts b/std/assembly/internal/typedarray.ts index e901267a..61ab7203 100644 --- a/std/assembly/internal/typedarray.ts +++ b/std/assembly/internal/typedarray.ts @@ -12,8 +12,11 @@ import { defaultComparator } from "./array"; +// The internal TypedArray class uses two type parameters for the same reason as `loadUnsafe` and +// `storeUnsafe` in 'internal/arraybuffer.ts'. See the documentation there for details. + /** Typed array base class. Not a global object. */ -export abstract class TypedArray { +export abstract class TypedArray { readonly buffer: ArrayBuffer; readonly byteOffset: i32; @@ -47,19 +50,19 @@ export abstract class TypedArray { } @operator("[]=") - protected __set(index: i32, value: V): void { + protected __set(index: i32, value: TNative): void { if (index >= (this.byteLength >>> alignof())) throw new Error("Index out of bounds"); - storeUnsafeWithOffset(this.buffer, index, value, this.byteOffset); + storeUnsafeWithOffset(this.buffer, index, value, this.byteOffset); } @inline @operator("{}=") - protected __unchecked_set(index: i32, value: V): void { - storeUnsafeWithOffset(this.buffer, index, value, this.byteOffset); + protected __unchecked_set(index: i32, value: TNative): void { + storeUnsafeWithOffset(this.buffer, index, value, this.byteOffset); } // copyWithin(target: i32, start: i32, end: i32 = this.length): this - fill(value: V, start: i32 = 0, end: i32 = i32.MAX_VALUE): this { + fill(value: TNative, start: i32 = 0, end: i32 = i32.MAX_VALUE): this { var buffer = this.buffer; var byteOffset = this.byteOffset; var len = this.length; @@ -75,14 +78,14 @@ export abstract class TypedArray { } } else { for (; start < end; ++start) { - storeUnsafeWithOffset(buffer, start, value, byteOffset); + storeUnsafeWithOffset(buffer, start, value, byteOffset); } } return this; } @inline - subarray(begin: i32 = 0, end: i32 = i32.MAX_VALUE): TypedArray { + subarray(begin: i32 = 0, end: i32 = i32.MAX_VALUE): TypedArray { var length = this.length; if (begin < 0) begin = max(length + begin, 0); else begin = min(begin, length); diff --git a/tests/compiler/std/dataview.optimized.wat b/tests/compiler/std/dataview.optimized.wat index 45e697b0..1ff3bedd 100644 --- a/tests/compiler/std/dataview.optimized.wat +++ b/tests/compiler/std/dataview.optimized.wat @@ -379,7 +379,7 @@ if i32.const 0 i32.const 8 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable diff --git a/tests/compiler/std/dataview.untouched.wat b/tests/compiler/std/dataview.untouched.wat index 109ac035..422adc3f 100644 --- a/tests/compiler/std/dataview.untouched.wat +++ b/tests/compiler/std/dataview.untouched.wat @@ -426,7 +426,7 @@ if i32.const 0 i32.const 8 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -492,7 +492,7 @@ if i32.const 0 i32.const 8 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable diff --git a/tests/compiler/std/typedarray.optimized.wat b/tests/compiler/std/typedarray.optimized.wat index f0ec2665..4812dfbf 100644 --- a/tests/compiler/std/typedarray.optimized.wat +++ b/tests/compiler/std/typedarray.optimized.wat @@ -398,7 +398,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -442,7 +442,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -489,7 +489,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -536,7 +536,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -1015,7 +1015,7 @@ if i32.const 0 i32.const 48 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable @@ -1042,7 +1042,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable @@ -1133,7 +1133,7 @@ if i32.const 0 i32.const 48 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable @@ -1696,7 +1696,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable @@ -1720,7 +1720,7 @@ if i32.const 0 i32.const 48 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable @@ -1761,7 +1761,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable @@ -1860,7 +1860,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable diff --git a/tests/compiler/std/typedarray.untouched.wat b/tests/compiler/std/typedarray.untouched.wat index 93c186f7..abeb77ae 100644 --- a/tests/compiler/std/typedarray.untouched.wat +++ b/tests/compiler/std/typedarray.untouched.wat @@ -472,7 +472,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -537,7 +537,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -602,7 +602,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -667,7 +667,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -732,7 +732,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -797,7 +797,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -862,7 +862,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -927,7 +927,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -992,7 +992,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -1057,7 +1057,7 @@ if i32.const 0 i32.const 48 - i32.const 24 + i32.const 27 i32.const 34 call $~lib/env/abort unreachable @@ -1675,7 +1675,7 @@ if i32.const 0 i32.const 48 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable @@ -1708,7 +1708,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable @@ -1841,7 +1841,7 @@ if i32.const 0 i32.const 48 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable @@ -2666,7 +2666,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable @@ -2700,7 +2700,7 @@ if i32.const 0 i32.const 48 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable @@ -2755,7 +2755,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable @@ -2789,7 +2789,7 @@ if i32.const 0 i32.const 48 - i32.const 51 + i32.const 54 i32.const 63 call $~lib/env/abort unreachable @@ -2914,7 +2914,7 @@ if i32.const 0 i32.const 48 - i32.const 40 + i32.const 43 i32.const 63 call $~lib/env/abort unreachable