diff --git a/examples/n-body/assembly/index.ts b/examples/n-body/assembly/index.ts
index 4173cb117b..4fe1ddf626 100644
--- a/examples/n-body/assembly/index.ts
+++ b/examples/n-body/assembly/index.ts
@@ -82,7 +82,7 @@ function Neptune(): Body {
class NBodySystem {
- constructor(public bodies: Body[]) {
+ constructor(public bodies: StaticArray
) {
var px: float = 0.0;
var py: float = 0.0;
var pz: float = 0.0;
diff --git a/examples/n-body/build/index.asm.js b/examples/n-body/build/index.asm.js
index a34219ace4..5b3416dec5 100644
--- a/examples/n-body/build/index.asm.js
+++ b/examples/n-body/build/index.asm.js
@@ -58,20 +58,20 @@ function asmFunc(global, env, buffer) {
function assembly_index_NBodySystem_constructor($0) {
var $1 = 0, $2 = 0, $3 = 0.0, $4 = 0.0, $5 = 0.0, $6 = 0.0, $7 = 0;
- $7 = HEAP32[($0 + 12 | 0) >> 2];
- loop_0 : while (1) {
+ $7 = HEAP32[(($0 - 16 | 0) + 12 | 0) >> 2] >>> 2 | 0;
+ for_loop_0 : while (1) {
if (($1 | 0) < ($7 | 0)) {
- $2 = HEAP32[(HEAP32[($0 + 4 | 0) >> 2] + ($1 << 2 | 0) | 0) >> 2];
+ $2 = HEAP32[(($1 << 2 | 0) + $0 | 0) >> 2];
$3 = HEAPF64[($2 + 48 | 0) >> 3];
$4 = $4 + HEAPF64[($2 + 24 | 0) >> 3] * $3;
$5 = $5 + HEAPF64[($2 + 32 | 0) >> 3] * $3;
$6 = $6 + HEAPF64[($2 + 40 | 0) >> 3] * $3;
$1 = $1 + 1 | 0;
- continue loop_0;
+ continue for_loop_0;
}
- break loop_0;
+ break for_loop_0;
};
- $1 = HEAP32[HEAP32[($0 + 4 | 0) >> 2] >> 2];
+ $1 = HEAP32[$0 >> 2];
HEAPF64[($1 + 24 | 0) >> 3] = -$4 / 39.47841760435743;
HEAPF64[($1 + 32 | 0) >> 3] = -$5 / 39.47841760435743;
HEAPF64[($1 + 40 | 0) >> 3] = -$6 / 39.47841760435743;
@@ -93,36 +93,24 @@ function asmFunc(global, env, buffer) {
return $7;
}
- function $lib_rt___allocArray() {
- var $0 = 0, $1 = 0;
- $0 = $lib_rt_stub___alloc(16, 5);
- $1 = $lib_rt_stub___alloc(20, 0);
- HEAP32[$0 >> 2] = $1;
- HEAP32[($0 + 4 | 0) >> 2] = $1;
- HEAP32[($0 + 8 | 0) >> 2] = 20;
- HEAP32[($0 + 12 | 0) >> 2] = 5;
- return $0;
- }
-
function assembly_index_init() {
- var $0 = 0, $1 = 0, wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
- $1 = $lib_rt___allocArray();
- $0 = HEAP32[($1 + 4 | 0) >> 2];
+ var $0 = 0, wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
+ $0 = $lib_rt_stub___alloc(20, 5);
(wasm2js_i32$0 = $0, wasm2js_i32$1 = assembly_index_Body_constructor(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 39.47841760435743)), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1;
(wasm2js_i32$0 = $0, wasm2js_i32$1 = assembly_index_Body_constructor(4.841431442464721, -1.1603200440274284, -.10362204447112311, .606326392995832, 2.81198684491626, -.02521836165988763, .03769367487038949)), HEAP32[(wasm2js_i32$0 + 4 | 0) >> 2] = wasm2js_i32$1;
(wasm2js_i32$0 = $0, wasm2js_i32$1 = assembly_index_Body_constructor(8.34336671824458, 4.124798564124305, -.4035234171143214, -1.0107743461787924, 1.8256623712304119, .008415761376584154, .011286326131968767)), HEAP32[(wasm2js_i32$0 + 8 | 0) >> 2] = wasm2js_i32$1;
(wasm2js_i32$0 = $0, wasm2js_i32$1 = assembly_index_Body_constructor(12.894369562139131, -15.111151401698631, -.22330757889265573, 1.0827910064415354, .8687130181696082, -.010832637401363636, 1.7237240570597112e-03)), HEAP32[(wasm2js_i32$0 + 12 | 0) >> 2] = wasm2js_i32$1;
(wasm2js_i32$0 = $0, wasm2js_i32$1 = assembly_index_Body_constructor(15.379697114850917, -25.919314609987964, .17925877295037118, .979090732243898, .5946989986476762, -.034755955504078104, 2.0336868699246304e-03)), HEAP32[(wasm2js_i32$0 + 16 | 0) >> 2] = wasm2js_i32$1;
- assembly_index_system = assembly_index_NBodySystem_constructor($1);
+ assembly_index_system = assembly_index_NBodySystem_constructor($0);
}
function assembly_index_NBodySystem_advance($0) {
var $1 = 0, $2 = 0.0, $3 = 0.0, $4 = 0, $5 = 0.0, $6 = 0.0, $7 = 0.0, $8 = 0, $9 = 0.0, $10 = 0.0, $11 = 0.0, $12 = 0, $13 = 0, $14 = 0.0, $15 = 0.0, $16 = 0.0, $17 = 0.0;
$12 = HEAP32[$0 >> 2];
- $13 = HEAP32[($12 + 12 | 0) >> 2];
- loop_0 : while (1) {
+ $13 = HEAP32[(($12 - 16 | 0) + 12 | 0) >> 2] >>> 2 | 0;
+ for_loop_0 : while (1) {
if ($4 >>> 0 < $13 >>> 0) {
- $0 = HEAP32[(HEAP32[($12 + 4 | 0) >> 2] + ($4 << 2 | 0) | 0) >> 2];
+ $0 = HEAP32[(($4 << 2 | 0) + $12 | 0) >> 2];
$14 = HEAPF64[$0 >> 3];
$15 = HEAPF64[($0 + 8 | 0) >> 3];
$16 = HEAPF64[($0 + 16 | 0) >> 3];
@@ -131,9 +119,9 @@ function asmFunc(global, env, buffer) {
$7 = HEAPF64[($0 + 40 | 0) >> 3];
$17 = HEAPF64[($0 + 48 | 0) >> 3];
$8 = $4 + 1 | 0;
- loop_1 : while (1) {
+ for_loop_1 : while (1) {
if ($8 >>> 0 < $13 >>> 0) {
- $1 = HEAP32[(HEAP32[($12 + 4 | 0) >> 2] + ($8 << 2 | 0) | 0) >> 2];
+ $1 = HEAP32[(($8 << 2 | 0) + $12 | 0) >> 2];
$2 = $14 - HEAPF64[$1 >> 3];
$9 = $15 - HEAPF64[($1 + 8 | 0) >> 3];
$10 = $16 - HEAPF64[($1 + 16 | 0) >> 3];
@@ -150,9 +138,9 @@ function asmFunc(global, env, buffer) {
HEAPF64[($1 + 32 | 0) >> 3] = HEAPF64[($1 + 32 | 0) >> 3] + $9 * $2;
HEAPF64[($1 + 40 | 0) >> 3] = HEAPF64[($1 + 40 | 0) >> 3] + $10 * $2;
$8 = $8 + 1 | 0;
- continue loop_1;
+ continue for_loop_1;
}
- break loop_1;
+ break for_loop_1;
};
HEAPF64[($0 + 24 | 0) >> 3] = $5;
HEAPF64[($0 + 32 | 0) >> 3] = $6;
@@ -161,19 +149,19 @@ function asmFunc(global, env, buffer) {
HEAPF64[($0 + 8 | 0) >> 3] = HEAPF64[($0 + 8 | 0) >> 3] + .01 * $6;
HEAPF64[($0 + 16 | 0) >> 3] = HEAPF64[($0 + 16 | 0) >> 3] + .01 * $7;
$4 = $4 + 1 | 0;
- continue loop_0;
+ continue for_loop_0;
}
- break loop_0;
+ break for_loop_0;
};
}
function assembly_index_NBodySystem_energy($0) {
var $1 = 0.0, $2 = 0.0, $3 = 0, $4 = 0, $5 = 0, $6 = 0.0, $7 = 0, $8 = 0.0, $9 = 0.0, $10 = 0.0, $11 = 0.0;
$5 = HEAP32[$0 >> 2];
- $7 = HEAP32[($5 + 12 | 0) >> 2];
- loop_0 : while (1) {
+ $7 = HEAP32[(($5 - 16 | 0) + 12 | 0) >> 2] >>> 2 | 0;
+ for_loop_0 : while (1) {
if ($3 >>> 0 < $7 >>> 0) {
- $0 = HEAP32[(HEAP32[($5 + 4 | 0) >> 2] + ($3 << 2 | 0) | 0) >> 2];
+ $0 = HEAP32[(($3 << 2 | 0) + $5 | 0) >> 2];
$9 = HEAPF64[$0 >> 3];
$10 = HEAPF64[($0 + 8 | 0) >> 3];
$11 = HEAPF64[($0 + 16 | 0) >> 3];
@@ -186,9 +174,9 @@ function asmFunc(global, env, buffer) {
$1 = HEAPF64[($0 + 40 | 0) >> 3];
$1 = $6 + .5 * $8 * ($2 + $1 * $1);
$0 = $3 + 1 | 0;
- loop_1 : while (1) {
+ for_loop_1 : while (1) {
if ($0 >>> 0 < $7 >>> 0) {
- $4 = HEAP32[(HEAP32[($5 + 4 | 0) >> 2] + ($0 << 2 | 0) | 0) >> 2];
+ $4 = HEAP32[(($0 << 2 | 0) + $5 | 0) >> 2];
$6 = $1;
$1 = $9 - HEAPF64[$4 >> 3];
$2 = $1 * $1;
@@ -197,14 +185,14 @@ function asmFunc(global, env, buffer) {
$1 = $11 - HEAPF64[($4 + 16 | 0) >> 3];
$1 = $6 - $8 * HEAPF64[($4 + 48 | 0) >> 3] / Math_sqrt($2 + $1 * $1);
$0 = $0 + 1 | 0;
- continue loop_1;
+ continue for_loop_1;
}
- break loop_1;
+ break for_loop_1;
};
$3 = $3 + 1 | 0;
- continue loop_0;
+ continue for_loop_0;
}
- break loop_0;
+ break for_loop_0;
};
return $1;
}
@@ -217,13 +205,13 @@ function asmFunc(global, env, buffer) {
function assembly_index_bench($0) {
$0 = $0 | 0;
var $1 = 0;
- loop_0 : while (1) {
+ for_loop_0 : while (1) {
if ($1 >>> 0 < $0 >>> 0) {
assembly_index_NBodySystem_advance(assembly_index_system);
$1 = $1 + 1 | 0;
- continue loop_0;
+ continue for_loop_0;
}
- break loop_0;
+ break for_loop_0;
};
}
@@ -231,15 +219,15 @@ function asmFunc(global, env, buffer) {
$0 = $0 | 0;
var $1 = 0;
$1 = HEAP32[assembly_index_system >> 2];
- if ($0 >>> 0 < HEAP32[($1 + 12 | 0) >> 2] >>> 0) {
- $0 = HEAP32[(HEAP32[($1 + 4 | 0) >> 2] + ($0 << 2 | 0) | 0) >> 2]
+ if ($0 >>> 0 < (HEAP32[(($1 - 16 | 0) + 12 | 0) >> 2] >>> 2 | 0) >>> 0) {
+ $0 = HEAP32[(($0 << 2 | 0) + $1 | 0) >> 2]
} else {
$0 = 0
}
return $0 | 0;
}
- function start() {
+ function $start() {
$lib_rt_stub_startOffset = 16;
$lib_rt_stub_offset = 16;
}
diff --git a/examples/n-body/build/index.js b/examples/n-body/build/index.js
index ca3ead7976..750fdd137a 100644
--- a/examples/n-body/build/index.js
+++ b/examples/n-body/build/index.js
@@ -1,6 +1,7 @@
"use strict";
+// From The Computer Language Benchmarks Game
+// http://benchmarksgame.alioth.debian.org
Object.defineProperty(exports, "__esModule", { value: true });
-require("allocator/arena");
const SOLAR_MASS = (4.0 * Math.PI * Math.PI);
const DAYS_PER_YEAR = 365.24;
class Body {
diff --git a/examples/n-body/build/optimized.wasm b/examples/n-body/build/optimized.wasm
index ed28ad53fd..7f29650667 100644
Binary files a/examples/n-body/build/optimized.wasm and b/examples/n-body/build/optimized.wasm differ
diff --git a/examples/n-body/build/optimized.wat b/examples/n-body/build/optimized.wat
index d9351098b8..92847d63c7 100644
--- a/examples/n-body/build/optimized.wat
+++ b/examples/n-body/build/optimized.wat
@@ -2,7 +2,6 @@
(type $i32_=>_none (func (param i32)))
(type $none_=>_none (func))
(type $i32_=>_i32 (func (param i32) (result i32)))
- (type $none_=>_i32 (func (result i32)))
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $f64_f64_f64_f64_f64_f64_f64_=>_i32 (func (param f64 f64 f64 f64 f64 f64 f64) (result i32)))
(type $none_=>_f64 (func (result f64)))
@@ -16,7 +15,7 @@
(export "step" (func $assembly/index/step))
(export "bench" (func $assembly/index/bench))
(export "getBody" (func $assembly/index/getBody))
- (start $start)
+ (start $~start)
(func $~lib/rt/stub/maybeGrowMemory (; 0 ;) (param $0 i32)
(local $1 i32)
(local $2 i32)
@@ -113,15 +112,18 @@
(local $6 f64)
(local $7 i32)
local.get $0
+ i32.const 16
+ i32.sub
i32.load offset=12
+ i32.const 2
+ i32.shr_u
local.set $7
- loop $loop|0
+ loop $for-loop|0
local.get $1
local.get $7
i32.lt_s
if
local.get $0
- i32.load offset=4
local.get $1
i32.const 2
i32.shl
@@ -155,11 +157,10 @@
i32.const 1
i32.add
local.set $1
- br $loop|0
+ br $for-loop|0
end
end
local.get $0
- i32.load offset=4
i32.load
local.tee $1
local.get $4
@@ -215,35 +216,11 @@
f64.store offset=48
local.get $7
)
- (func $~lib/rt/__allocArray (; 4 ;) (result i32)
+ (func $assembly/index/init (; 4 ;)
(local $0 i32)
- (local $1 i32)
- i32.const 16
- i32.const 5
- call $~lib/rt/stub/__alloc
- local.tee $0
i32.const 20
- i32.const 0
- call $~lib/rt/stub/__alloc
- local.tee $1
- i32.store
- local.get $0
- local.get $1
- i32.store offset=4
- local.get $0
- i32.const 20
- i32.store offset=8
- local.get $0
i32.const 5
- i32.store offset=12
- local.get $0
- )
- (func $assembly/index/init (; 5 ;)
- (local $0 i32)
- (local $1 i32)
- call $~lib/rt/__allocArray
- local.tee $1
- i32.load offset=4
+ call $~lib/rt/stub/__alloc
local.tee $0
f64.const 0
f64.const 0
@@ -294,11 +271,11 @@
f64.const 2.0336868699246304e-03
call $assembly/index/Body#constructor
i32.store offset=16
- local.get $1
+ local.get $0
call $assembly/index/NBodySystem#constructor
global.set $assembly/index/system
)
- (func $assembly/index/NBodySystem#advance (; 6 ;) (param $0 i32)
+ (func $assembly/index/NBodySystem#advance (; 5 ;) (param $0 i32)
(local $1 i32)
(local $2 f64)
(local $3 i32)
@@ -319,15 +296,18 @@
local.get $0
i32.load
local.tee $12
+ i32.const 16
+ i32.sub
i32.load offset=12
+ i32.const 2
+ i32.shr_u
local.set $13
- loop $loop|0
+ loop $for-loop|0
local.get $3
local.get $13
i32.lt_u
if
local.get $12
- i32.load offset=4
local.get $3
i32.const 2
i32.shl
@@ -358,14 +338,13 @@
i32.const 1
i32.add
local.set $7
- loop $loop|1
+ loop $for-loop|1
local.get $7
local.get $13
i32.lt_u
if
local.get $14
local.get $12
- i32.load offset=4
local.get $7
i32.const 2
i32.shl
@@ -454,7 +433,7 @@
i32.const 1
i32.add
local.set $7
- br $loop|1
+ br $for-loop|1
end
end
local.get $0
@@ -494,11 +473,11 @@
i32.const 1
i32.add
local.set $3
- br $loop|0
+ br $for-loop|0
end
end
)
- (func $assembly/index/NBodySystem#energy (; 7 ;) (param $0 i32) (result f64)
+ (func $assembly/index/NBodySystem#energy (; 6 ;) (param $0 i32) (result f64)
(local $1 f64)
(local $2 i32)
(local $3 i32)
@@ -512,15 +491,18 @@
local.get $0
i32.load
local.tee $4
+ i32.const 16
+ i32.sub
i32.load offset=12
+ i32.const 2
+ i32.shr_u
local.set $5
- loop $loop|0
+ loop $for-loop|0
local.get $2
local.get $5
i32.lt_u
if
local.get $4
- i32.load offset=4
local.get $2
i32.const 2
i32.shl
@@ -565,14 +547,13 @@
i32.const 1
i32.add
local.set $0
- loop $loop|1
+ loop $for-loop|1
local.get $0
local.get $5
i32.lt_u
if
local.get $7
local.get $4
- i32.load offset=4
local.get $0
i32.const 2
i32.shl
@@ -614,53 +595,55 @@
i32.const 1
i32.add
local.set $0
- br $loop|1
+ br $for-loop|1
end
end
local.get $2
i32.const 1
i32.add
local.set $2
- br $loop|0
+ br $for-loop|0
end
end
local.get $1
)
- (func $assembly/index/step (; 8 ;) (result f64)
+ (func $assembly/index/step (; 7 ;) (result f64)
global.get $assembly/index/system
call $assembly/index/NBodySystem#advance
global.get $assembly/index/system
call $assembly/index/NBodySystem#energy
)
- (func $assembly/index/bench (; 9 ;) (param $0 i32)
+ (func $assembly/index/bench (; 8 ;) (param $0 i32)
(local $1 i32)
- loop $loop|0
- block $break|0
- local.get $1
- local.get $0
- i32.ge_u
- br_if $break|0
+ loop $for-loop|0
+ local.get $1
+ local.get $0
+ i32.lt_u
+ if
global.get $assembly/index/system
call $assembly/index/NBodySystem#advance
local.get $1
i32.const 1
i32.add
local.set $1
- br $loop|0
+ br $for-loop|0
end
end
)
- (func $assembly/index/getBody (; 10 ;) (param $0 i32) (result i32)
+ (func $assembly/index/getBody (; 9 ;) (param $0 i32) (result i32)
(local $1 i32)
local.get $0
global.get $assembly/index/system
i32.load
local.tee $1
+ i32.const 16
+ i32.sub
i32.load offset=12
+ i32.const 2
+ i32.shr_u
i32.lt_u
if (result i32)
local.get $1
- i32.load offset=4
local.get $0
i32.const 2
i32.shl
@@ -670,7 +653,7 @@
i32.const 0
end
)
- (func $start (; 11 ;)
+ (func $~start (; 10 ;)
i32.const 16
global.set $~lib/rt/stub/startOffset
i32.const 16
diff --git a/examples/n-body/build/untouched.wat b/examples/n-body/build/untouched.wat
index 757af7936a..4ecd32c47b 100644
--- a/examples/n-body/build/untouched.wat
+++ b/examples/n-body/build/untouched.wat
@@ -6,7 +6,7 @@
(type $none_=>_none (func))
(type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
(type $i32_f64_=>_none (func (param i32 f64)))
- (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
(type $i32_f64_f64_f64_=>_i32 (func (param i32 f64 f64 f64) (result i32)))
(type $i32_f64_f64_f64_f64_f64_f64_f64_=>_i32 (func (param i32 f64 f64 f64 f64 f64 f64 f64) (result i32)))
(type $none_=>_f64 (func (result f64)))
@@ -26,17 +26,20 @@
(export "step" (func $assembly/index/step))
(export "bench" (func $assembly/index/bench))
(export "getBody" (func $assembly/index/getBody))
- (start $start)
+ (start $~start)
(func $~lib/rt/stub/__retain (; 0 ;) (param $0 i32) (result i32)
local.get $0
)
- (func $~lib/array/Array#get:length (; 1 ;) (param $0 i32) (result i32)
+ (func $~lib/staticarray/StaticArray#get:length (; 1 ;) (param $0 i32) (result i32)
local.get $0
+ i32.const 16
+ i32.sub
i32.load offset=12
+ i32.const 2
+ i32.shr_u
)
- (func $~lib/array/Array#__unchecked_get (; 2 ;) (param $0 i32) (param $1 i32) (result i32)
+ (func $~lib/staticarray/StaticArray#__unchecked_get (; 2 ;) (param $0 i32) (param $1 i32) (result i32)
local.get $0
- i32.load offset=4
local.get $1
i32.const 2
i32.shl
@@ -184,7 +187,8 @@
(local $6 i32)
(local $7 i32)
(local $8 i32)
- (local $9 f64)
+ (local $9 i32)
+ (local $10 f64)
local.get $1
call $~lib/rt/stub/__retain
local.set $1
@@ -195,62 +199,61 @@
f64.const 0
local.set $4
local.get $1
- call $~lib/array/Array#get:length
+ call $~lib/staticarray/StaticArray#get:length
local.set $5
- block $break|0
- i32.const 0
- local.set $6
- loop $loop|0
- local.get $6
- local.get $5
- i32.lt_s
- i32.eqz
- br_if $break|0
+ i32.const 0
+ local.set $6
+ loop $for-loop|0
+ local.get $6
+ local.get $5
+ i32.lt_s
+ local.set $7
+ local.get $7
+ if
local.get $1
local.get $6
- call $~lib/array/Array#__unchecked_get
- local.tee $7
+ call $~lib/staticarray/StaticArray#__unchecked_get
+ local.tee $8
call $~lib/rt/stub/__retain
- local.set $8
- local.get $8
- f64.load offset=48
local.set $9
+ local.get $9
+ f64.load offset=48
+ local.set $10
local.get $2
- local.get $8
- f64.load offset=24
local.get $9
+ f64.load offset=24
+ local.get $10
f64.mul
f64.add
local.set $2
local.get $3
- local.get $8
- f64.load offset=32
local.get $9
+ f64.load offset=32
+ local.get $10
f64.mul
f64.add
local.set $3
local.get $4
- local.get $8
- f64.load offset=40
local.get $9
+ f64.load offset=40
+ local.get $10
f64.mul
f64.add
local.set $4
- local.get $7
- call $~lib/rt/stub/__release
local.get $8
call $~lib/rt/stub/__release
+ local.get $9
+ call $~lib/rt/stub/__release
local.get $6
i32.const 1
i32.add
local.set $6
- br $loop|0
+ br $for-loop|0
end
- unreachable
end
local.get $1
i32.const 0
- call $~lib/array/Array#__unchecked_get
+ call $~lib/staticarray/StaticArray#__unchecked_get
local.tee $6
local.get $2
local.get $3
@@ -400,39 +403,39 @@
(local $3 i32)
(local $4 i32)
(local $5 i32)
- block $break|0
- loop $continue|0
- local.get $2
- if (result i32)
- local.get $1
- i32.const 3
- i32.and
- else
- i32.const 0
- end
- i32.eqz
- br_if $break|0
+ (local $6 i32)
+ loop $while-continue|0
+ local.get $2
+ if (result i32)
+ local.get $1
+ i32.const 3
+ i32.and
+ else
+ i32.const 0
+ end
+ local.set $5
+ local.get $5
+ if
local.get $0
- local.tee $5
+ local.tee $6
i32.const 1
i32.add
local.set $0
- local.get $5
+ local.get $6
local.get $1
- local.tee $5
+ local.tee $6
i32.const 1
i32.add
local.set $1
- local.get $5
+ local.get $6
i32.load8_u
i32.store8
local.get $2
i32.const 1
i32.sub
local.set $2
- br $continue|0
+ br $while-continue|0
end
- unreachable
end
local.get $0
i32.const 3
@@ -440,13 +443,13 @@
i32.const 0
i32.eq
if
- block $break|1
- loop $continue|1
- local.get $2
- i32.const 16
- i32.ge_u
- i32.eqz
- br_if $break|1
+ loop $while-continue|1
+ local.get $2
+ i32.const 16
+ i32.ge_u
+ local.set $5
+ local.get $5
+ if
local.get $0
local.get $1
i32.load
@@ -487,9 +490,8 @@
i32.const 16
i32.sub
local.set $2
- br $continue|1
+ br $while-continue|1
end
- unreachable
end
local.get $2
i32.const 8
@@ -646,13 +648,13 @@
i32.const 3
i32.sub
local.set $2
- block $break|3
- loop $continue|3
- local.get $2
- i32.const 17
- i32.ge_u
- i32.eqz
- br_if $break|3
+ loop $while-continue|3
+ local.get $2
+ i32.const 17
+ i32.ge_u
+ local.set $5
+ local.get $5
+ if
local.get $1
i32.const 1
i32.add
@@ -727,9 +729,8 @@
i32.const 16
i32.sub
local.set $2
- br $continue|3
+ br $while-continue|3
end
- unreachable
end
br $break|2
end
@@ -768,13 +769,13 @@
i32.const 2
i32.sub
local.set $2
- block $break|4
- loop $continue|4
- local.get $2
- i32.const 18
- i32.ge_u
- i32.eqz
- br_if $break|4
+ loop $while-continue|4
+ local.get $2
+ i32.const 18
+ i32.ge_u
+ local.set $5
+ local.get $5
+ if
local.get $1
i32.const 2
i32.add
@@ -849,9 +850,8 @@
i32.const 16
i32.sub
local.set $2
- br $continue|4
+ br $while-continue|4
end
- unreachable
end
br $break|2
end
@@ -876,13 +876,13 @@
i32.const 1
i32.sub
local.set $2
- block $break|5
- loop $continue|5
- local.get $2
- i32.const 19
- i32.ge_u
- i32.eqz
- br_if $break|5
+ loop $while-continue|5
+ local.get $2
+ i32.const 19
+ i32.ge_u
+ local.set $5
+ local.get $5
+ if
local.get $1
i32.const 3
i32.add
@@ -957,9 +957,8 @@
i32.const 16
i32.sub
local.set $2
- br $continue|5
+ br $while-continue|5
end
- unreachable
end
br $break|2
end
@@ -1429,6 +1428,7 @@
(local $4 i32)
(local $5 i32)
(local $6 i32)
+ (local $7 i32)
block $~lib/util/memory/memmove|inlined.0
local.get $0
local.set $5
@@ -1475,13 +1475,13 @@
i32.and
i32.eq
if
- block $break|0
- loop $continue|0
- local.get $5
- i32.const 7
- i32.and
- i32.eqz
- br_if $break|0
+ loop $while-continue|0
+ local.get $5
+ i32.const 7
+ i32.and
+ local.set $6
+ local.get $6
+ if
local.get $3
i32.eqz
if
@@ -1492,30 +1492,29 @@
i32.sub
local.set $3
local.get $5
- local.tee $6
+ local.tee $7
i32.const 1
i32.add
local.set $5
- local.get $6
+ local.get $7
local.get $4
- local.tee $6
+ local.tee $7
i32.const 1
i32.add
local.set $4
- local.get $6
+ local.get $7
i32.load8_u
i32.store8
- br $continue|0
+ br $while-continue|0
end
- unreachable
end
- block $break|1
- loop $continue|1
- local.get $3
- i32.const 8
- i32.ge_u
- i32.eqz
- br_if $break|1
+ loop $while-continue|1
+ local.get $3
+ i32.const 8
+ i32.ge_u
+ local.set $6
+ local.get $6
+ if
local.get $5
local.get $4
i64.load
@@ -1532,37 +1531,35 @@
i32.const 8
i32.add
local.set $4
- br $continue|1
+ br $while-continue|1
end
- unreachable
end
end
- block $break|2
- loop $continue|2
- local.get $3
- i32.eqz
- br_if $break|2
+ loop $while-continue|2
+ local.get $3
+ local.set $6
+ local.get $6
+ if
local.get $5
- local.tee $6
+ local.tee $7
i32.const 1
i32.add
local.set $5
- local.get $6
+ local.get $7
local.get $4
- local.tee $6
+ local.tee $7
i32.const 1
i32.add
local.set $4
- local.get $6
+ local.get $7
i32.load8_u
i32.store8
local.get $3
i32.const 1
i32.sub
local.set $3
- br $continue|2
+ br $while-continue|2
end
- unreachable
end
else
local.get $4
@@ -1573,15 +1570,15 @@
i32.and
i32.eq
if
- block $break|3
- loop $continue|3
- local.get $5
- local.get $3
- i32.add
- i32.const 7
- i32.and
- i32.eqz
- br_if $break|3
+ loop $while-continue|3
+ local.get $5
+ local.get $3
+ i32.add
+ i32.const 7
+ i32.and
+ local.set $6
+ local.get $6
+ if
local.get $3
i32.eqz
if
@@ -1598,17 +1595,16 @@
i32.add
i32.load8_u
i32.store8
- br $continue|3
+ br $while-continue|3
end
- unreachable
end
- block $break|4
- loop $continue|4
- local.get $3
- i32.const 8
- i32.ge_u
- i32.eqz
- br_if $break|4
+ loop $while-continue|4
+ local.get $3
+ i32.const 8
+ i32.ge_u
+ local.set $6
+ local.get $6
+ if
local.get $3
i32.const 8
i32.sub
@@ -1621,16 +1617,15 @@
i32.add
i64.load
i64.store
- br $continue|4
+ br $while-continue|4
end
- unreachable
end
end
- block $break|5
- loop $continue|5
- local.get $3
- i32.eqz
- br_if $break|5
+ loop $while-continue|5
+ local.get $3
+ local.set $6
+ local.get $6
+ if
local.get $5
local.get $3
i32.const 1
@@ -1642,110 +1637,61 @@
i32.add
i32.load8_u
i32.store8
- br $continue|5
+ br $while-continue|5
end
- unreachable
end
end
end
)
- (func $~lib/rt/__allocArray (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
- (local $4 i32)
- (local $5 i32)
- (local $6 i32)
- i32.const 16
- local.get $2
- call $~lib/rt/stub/__alloc
- local.set $4
+ (func $~lib/rt/__allocBuffer (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+ (local $3 i32)
local.get $0
local.get $1
- i32.shl
- local.set $5
- local.get $5
- i32.const 0
call $~lib/rt/stub/__alloc
- local.set $6
- local.get $4
- local.get $6
- call $~lib/rt/stub/__retain
- i32.store
- local.get $4
- local.get $6
- i32.store offset=4
- local.get $4
- local.get $5
- i32.store offset=8
- local.get $4
- local.get $0
- i32.store offset=12
- local.get $3
+ local.set $3
+ local.get $2
if
- local.get $6
local.get $3
- local.get $5
+ local.get $2
+ local.get $0
call $~lib/memory/memory.copy
end
- local.get $4
+ local.get $3
)
(func $assembly/index/init (; 17 ;)
(local $0 i32)
(local $1 i32)
- (local $2 i32)
- (local $3 i32)
- (local $4 i32)
- (local $5 i32)
- (local $6 i32)
i32.const 0
- i32.const 5
- i32.const 2
+ i32.const 20
i32.const 5
i32.const 0
- call $~lib/rt/__allocArray
+ call $~lib/rt/__allocBuffer
+ call $~lib/rt/stub/__retain
local.set $0
local.get $0
- i32.load offset=4
- local.set $1
- local.get $1
call $assembly/index/Sun
- local.tee $2
- call $~lib/rt/stub/__retain
i32.store
- local.get $1
+ local.get $0
call $assembly/index/Jupiter
- local.tee $3
- call $~lib/rt/stub/__retain
i32.store offset=4
- local.get $1
+ local.get $0
call $assembly/index/Saturn
- local.tee $4
- call $~lib/rt/stub/__retain
i32.store offset=8
- local.get $1
+ local.get $0
call $assembly/index/Uranus
- local.tee $5
- call $~lib/rt/stub/__retain
i32.store offset=12
- local.get $1
+ local.get $0
call $assembly/index/Neptune
- local.tee $6
- call $~lib/rt/stub/__retain
i32.store offset=16
local.get $0
+ local.tee $0
call $assembly/index/NBodySystem#constructor
- local.set $0
+ local.set $1
global.get $assembly/index/system
call $~lib/rt/stub/__release
- local.get $0
+ local.get $1
global.set $assembly/index/system
- local.get $2
- call $~lib/rt/stub/__release
- local.get $3
- call $~lib/rt/stub/__release
- local.get $4
- call $~lib/rt/stub/__release
- local.get $5
- call $~lib/rt/stub/__release
- local.get $6
+ local.get $0
call $~lib/rt/stub/__release
)
(func $assembly/index/NBodySystem#advance (; 18 ;) (param $0 i32) (param $1 f64)
@@ -1754,229 +1700,229 @@
(local $4 i32)
(local $5 i32)
(local $6 i32)
- (local $7 f64)
+ (local $7 i32)
(local $8 f64)
(local $9 f64)
(local $10 f64)
(local $11 f64)
(local $12 f64)
(local $13 f64)
- (local $14 i32)
+ (local $14 f64)
(local $15 i32)
(local $16 i32)
- (local $17 f64)
- (local $18 f64)
+ (local $17 i32)
+ (local $18 i32)
(local $19 f64)
(local $20 f64)
(local $21 f64)
(local $22 f64)
(local $23 f64)
(local $24 f64)
+ (local $25 f64)
+ (local $26 f64)
local.get $0
i32.load
call $~lib/rt/stub/__retain
local.set $2
local.get $2
- call $~lib/array/Array#get:length
+ call $~lib/staticarray/StaticArray#get:length
local.set $3
- block $break|0
- i32.const 0
- local.set $4
- loop $loop|0
- local.get $4
- local.get $3
- i32.lt_u
- i32.eqz
- br_if $break|0
+ i32.const 0
+ local.set $4
+ loop $for-loop|0
+ local.get $4
+ local.get $3
+ i32.lt_u
+ local.set $5
+ local.get $5
+ if
local.get $2
local.get $4
- call $~lib/array/Array#__unchecked_get
- local.tee $5
+ call $~lib/staticarray/StaticArray#__unchecked_get
+ local.tee $6
call $~lib/rt/stub/__retain
- local.set $6
- local.get $6
- f64.load
local.set $7
- local.get $6
- f64.load offset=8
+ local.get $7
+ f64.load
local.set $8
- local.get $6
- f64.load offset=16
+ local.get $7
+ f64.load offset=8
local.set $9
- local.get $6
- f64.load offset=24
+ local.get $7
+ f64.load offset=16
local.set $10
- local.get $6
- f64.load offset=32
+ local.get $7
+ f64.load offset=24
local.set $11
- local.get $6
- f64.load offset=40
+ local.get $7
+ f64.load offset=32
local.set $12
- local.get $6
- f64.load offset=48
+ local.get $7
+ f64.load offset=40
local.set $13
- block $break|1
- local.get $4
- i32.const 1
- i32.add
- local.set $14
- loop $loop|1
- local.get $14
- local.get $3
- i32.lt_u
- i32.eqz
- br_if $break|1
+ local.get $7
+ f64.load offset=48
+ local.set $14
+ local.get $4
+ i32.const 1
+ i32.add
+ local.set $15
+ loop $for-loop|1
+ local.get $15
+ local.get $3
+ i32.lt_u
+ local.set $16
+ local.get $16
+ if
local.get $2
- local.get $14
- call $~lib/array/Array#__unchecked_get
- local.tee $15
+ local.get $15
+ call $~lib/staticarray/StaticArray#__unchecked_get
+ local.tee $17
call $~lib/rt/stub/__retain
- local.set $16
- local.get $7
- local.get $16
+ local.set $18
+ local.get $8
+ local.get $18
f64.load
f64.sub
- local.set $17
- local.get $8
- local.get $16
+ local.set $19
+ local.get $9
+ local.get $18
f64.load offset=8
f64.sub
- local.set $18
- local.get $9
- local.get $16
+ local.set $20
+ local.get $10
+ local.get $18
f64.load offset=16
f64.sub
- local.set $19
- local.get $17
- local.get $17
- f64.mul
- local.get $18
- local.get $18
- f64.mul
- f64.add
+ local.set $21
local.get $19
local.get $19
f64.mul
- f64.add
- local.set $20
local.get $20
- local.set $21
- local.get $21
- f64.sqrt
- local.set $21
- local.get $1
local.get $20
+ f64.mul
+ f64.add
+ local.get $21
local.get $21
f64.mul
- f64.div
+ f64.add
local.set $22
- local.get $13
local.get $22
- f64.mul
local.set $23
- local.get $16
- f64.load offset=48
+ local.get $23
+ f64.sqrt
+ local.set $23
+ local.get $1
local.get $22
+ local.get $23
f64.mul
+ f64.div
local.set $24
- local.get $10
- local.get $17
+ local.get $14
local.get $24
f64.mul
- f64.sub
- local.set $10
- local.get $11
+ local.set $25
local.get $18
+ f64.load offset=48
local.get $24
f64.mul
+ local.set $26
+ local.get $11
+ local.get $19
+ local.get $26
+ f64.mul
f64.sub
local.set $11
local.get $12
- local.get $19
- local.get $24
+ local.get $20
+ local.get $26
f64.mul
f64.sub
local.set $12
- local.get $16
- local.get $16
+ local.get $13
+ local.get $21
+ local.get $26
+ f64.mul
+ f64.sub
+ local.set $13
+ local.get $18
+ local.get $18
f64.load offset=24
- local.get $17
- local.get $23
+ local.get $19
+ local.get $25
f64.mul
f64.add
f64.store offset=24
- local.get $16
- local.get $16
- f64.load offset=32
local.get $18
- local.get $23
+ local.get $18
+ f64.load offset=32
+ local.get $20
+ local.get $25
f64.mul
f64.add
f64.store offset=32
- local.get $16
- local.get $16
+ local.get $18
+ local.get $18
f64.load offset=40
- local.get $19
- local.get $23
+ local.get $21
+ local.get $25
f64.mul
f64.add
f64.store offset=40
- local.get $15
+ local.get $17
call $~lib/rt/stub/__release
- local.get $16
+ local.get $18
call $~lib/rt/stub/__release
- local.get $14
+ local.get $15
i32.const 1
i32.add
- local.set $14
- br $loop|1
+ local.set $15
+ br $for-loop|1
end
- unreachable
end
- local.get $6
- local.get $10
- f64.store offset=24
- local.get $6
+ local.get $7
local.get $11
- f64.store offset=32
- local.get $6
+ f64.store offset=24
+ local.get $7
local.get $12
+ f64.store offset=32
+ local.get $7
+ local.get $13
f64.store offset=40
- local.get $6
- local.get $6
+ local.get $7
+ local.get $7
f64.load
local.get $1
- local.get $10
+ local.get $11
f64.mul
f64.add
f64.store
- local.get $6
- local.get $6
+ local.get $7
+ local.get $7
f64.load offset=8
local.get $1
- local.get $11
+ local.get $12
f64.mul
f64.add
f64.store offset=8
- local.get $6
- local.get $6
+ local.get $7
+ local.get $7
f64.load offset=16
local.get $1
- local.get $12
+ local.get $13
f64.mul
f64.add
f64.store offset=16
- local.get $5
- call $~lib/rt/stub/__release
local.get $6
call $~lib/rt/stub/__release
+ local.get $7
+ call $~lib/rt/stub/__release
local.get $4
i32.const 1
i32.add
local.set $4
- br $loop|0
+ br $for-loop|0
end
- unreachable
end
local.get $2
call $~lib/rt/stub/__release
@@ -1988,168 +1934,168 @@
(local $4 i32)
(local $5 i32)
(local $6 i32)
- (local $7 f64)
+ (local $7 i32)
(local $8 f64)
(local $9 f64)
(local $10 f64)
(local $11 f64)
(local $12 f64)
(local $13 f64)
- (local $14 i32)
+ (local $14 f64)
(local $15 i32)
(local $16 i32)
- (local $17 f64)
- (local $18 f64)
+ (local $17 i32)
+ (local $18 i32)
(local $19 f64)
(local $20 f64)
+ (local $21 f64)
+ (local $22 f64)
f64.const 0
local.set $1
local.get $0
i32.load
call $~lib/rt/stub/__retain
local.set $2
- block $break|0
- i32.const 0
- local.set $3
- local.get $2
- call $~lib/array/Array#get:length
- local.set $4
- loop $loop|0
- local.get $3
- local.get $4
- i32.lt_u
- i32.eqz
- br_if $break|0
+ i32.const 0
+ local.set $3
+ local.get $2
+ call $~lib/staticarray/StaticArray#get:length
+ local.set $4
+ loop $for-loop|0
+ local.get $3
+ local.get $4
+ i32.lt_u
+ local.set $5
+ local.get $5
+ if
local.get $2
local.get $3
- call $~lib/array/Array#__unchecked_get
- local.tee $5
+ call $~lib/staticarray/StaticArray#__unchecked_get
+ local.tee $6
call $~lib/rt/stub/__retain
- local.set $6
- local.get $6
- f64.load
local.set $7
- local.get $6
- f64.load offset=8
+ local.get $7
+ f64.load
local.set $8
- local.get $6
- f64.load offset=16
+ local.get $7
+ f64.load offset=8
local.set $9
- local.get $6
- f64.load offset=24
+ local.get $7
+ f64.load offset=16
local.set $10
- local.get $6
- f64.load offset=32
+ local.get $7
+ f64.load offset=24
local.set $11
- local.get $6
- f64.load offset=40
+ local.get $7
+ f64.load offset=32
local.set $12
- local.get $6
- f64.load offset=48
+ local.get $7
+ f64.load offset=40
local.set $13
+ local.get $7
+ f64.load offset=48
+ local.set $14
local.get $1
f64.const 0.5
- local.get $13
- f64.mul
- local.get $10
- local.get $10
+ local.get $14
f64.mul
local.get $11
local.get $11
f64.mul
- f64.add
local.get $12
local.get $12
f64.mul
f64.add
+ local.get $13
+ local.get $13
+ f64.mul
+ f64.add
f64.mul
f64.add
local.set $1
- block $break|1
- local.get $3
- i32.const 1
- i32.add
- local.set $14
- loop $loop|1
- local.get $14
- local.get $4
- i32.lt_u
- i32.eqz
- br_if $break|1
+ local.get $3
+ i32.const 1
+ i32.add
+ local.set $15
+ loop $for-loop|1
+ local.get $15
+ local.get $4
+ i32.lt_u
+ local.set $16
+ local.get $16
+ if
local.get $2
- local.get $14
- call $~lib/array/Array#__unchecked_get
- local.tee $15
+ local.get $15
+ call $~lib/staticarray/StaticArray#__unchecked_get
+ local.tee $17
call $~lib/rt/stub/__retain
- local.set $16
- local.get $7
- local.get $16
+ local.set $18
+ local.get $8
+ local.get $18
f64.load
f64.sub
- local.set $17
- local.get $8
- local.get $16
+ local.set $19
+ local.get $9
+ local.get $18
f64.load offset=8
f64.sub
- local.set $18
- local.get $9
- local.get $16
+ local.set $20
+ local.get $10
+ local.get $18
f64.load offset=16
f64.sub
- local.set $19
- local.get $17
- local.get $17
+ local.set $21
+ local.get $19
+ local.get $19
f64.mul
- local.get $18
- local.get $18
+ local.get $20
+ local.get $20
f64.mul
f64.add
- local.get $19
- local.get $19
+ local.get $21
+ local.get $21
f64.mul
f64.add
- local.set $20
- local.get $20
+ local.set $22
+ local.get $22
f64.sqrt
- local.set $20
+ local.set $22
local.get $1
- local.get $13
- local.get $16
+ local.get $14
+ local.get $18
f64.load offset=48
f64.mul
- local.get $20
+ local.get $22
f64.div
f64.sub
local.set $1
- local.get $15
+ local.get $17
call $~lib/rt/stub/__release
- local.get $16
+ local.get $18
call $~lib/rt/stub/__release
- local.get $14
+ local.get $15
i32.const 1
i32.add
- local.set $14
- br $loop|1
+ local.set $15
+ br $for-loop|1
end
- unreachable
end
- local.get $5
- call $~lib/rt/stub/__release
local.get $6
call $~lib/rt/stub/__release
+ local.get $7
+ call $~lib/rt/stub/__release
local.get $3
i32.const 1
i32.add
local.set $3
- br $loop|0
+ br $for-loop|0
end
- unreachable
end
local.get $1
- local.set $13
+ local.set $14
local.get $2
call $~lib/rt/stub/__release
- local.get $13
+ local.get $14
)
(func $assembly/index/step (; 20 ;) (result f64)
global.get $assembly/index/system
@@ -2160,15 +2106,16 @@
)
(func $assembly/index/bench (; 21 ;) (param $0 i32)
(local $1 i32)
- block $break|0
- i32.const 0
- local.set $1
- loop $loop|0
- local.get $1
- local.get $0
- i32.lt_u
- i32.eqz
- br_if $break|0
+ (local $2 i32)
+ i32.const 0
+ local.set $1
+ loop $for-loop|0
+ local.get $1
+ local.get $0
+ i32.lt_u
+ local.set $2
+ local.get $2
+ if
global.get $assembly/index/system
f64.const 0.01
call $assembly/index/NBodySystem#advance
@@ -2176,9 +2123,8 @@
i32.const 1
i32.add
local.set $1
- br $loop|0
+ br $for-loop|0
end
- unreachable
end
)
(func $assembly/index/getBody (; 22 ;) (param $0 i32) (result i32)
@@ -2190,12 +2136,12 @@
local.set $1
local.get $0
local.get $1
- call $~lib/array/Array#get:length
+ call $~lib/staticarray/StaticArray#get:length
i32.lt_u
if (result i32)
local.get $1
local.get $0
- call $~lib/array/Array#__unchecked_get
+ call $~lib/staticarray/StaticArray#__unchecked_get
local.tee $2
else
i32.const 0
@@ -2206,7 +2152,7 @@
call $~lib/rt/stub/__release
local.get $2
)
- (func $start (; 23 ;)
+ (func $~start (; 23 ;)
global.get $~lib/heap/__heap_base
i32.const 15
i32.add
diff --git a/src/ast.ts b/src/ast.ts
index 01dc394da8..009c756f58 100644
--- a/src/ast.ts
+++ b/src/ast.ts
@@ -860,12 +860,14 @@ export abstract class Node {
static createIndexSignatureDeclaration(
keyType: NamedTypeNode,
valueType: TypeNode,
+ flags: CommonFlags,
range: Range
): IndexSignatureDeclaration {
var elem = new IndexSignatureDeclaration();
elem.range = range;
elem.keyType = keyType;
elem.valueType = valueType;
+ elem.flags = flags;
return elem;
}
@@ -1339,7 +1341,8 @@ export class ArrayLiteralExpression extends LiteralExpression {
export enum AssertionKind {
PREFIX,
AS,
- NONNULL
+ NONNULL,
+ CONST
}
/** Represents an assertion expression. */
diff --git a/src/builtins.ts b/src/builtins.ts
index 72e9fd6d4d..2684afe098 100644
--- a/src/builtins.ts
+++ b/src/builtins.ts
@@ -4835,11 +4835,12 @@ export function compileVisitMembers(compiler: Compiler): void {
);
} else {
let visitSig = visitFunc.signature;
+ let visitThisType = assert(visitSig.thisType);
assert(
visitSig.parameterTypes.length == 1 &&
visitSig.parameterTypes[0] == Type.u32 &&
visitSig.returnType == Type.void &&
- visitSig.thisType == instance.type
+ instance.type.isStrictlyAssignableTo(visitThisType) // incl. implemented on super
);
code.push(
module.call(visitFunc.internalName, [
diff --git a/src/common.ts b/src/common.ts
index db286f4ae1..c50c49cd04 100644
--- a/src/common.ts
+++ b/src/common.ts
@@ -181,7 +181,7 @@ export namespace CommonNames {
export const Anyref = "Anyref";
export const String = "String";
export const Array = "Array";
- export const FixedArray = "FixedArray";
+ export const StaticArray = "StaticArray";
export const Set = "Set";
export const Map = "Map";
export const ArrayBufferView = "ArrayBufferView";
@@ -213,6 +213,7 @@ export namespace CommonNames {
export const typeinfo = "__typeinfo";
export const instanceof_ = "__instanceof";
export const visit = "__visit";
+ export const allocBuffer = "__allocBuffer";
export const allocArray = "__allocArray";
}
diff --git a/src/compiler.ts b/src/compiler.ts
index fc21184697..8ddfe85444 100644
--- a/src/compiler.ts
+++ b/src/compiler.ts
@@ -859,7 +859,7 @@ export class Compiler extends DiagnosticEmitter {
this.currentFlow = global.file.startFunction.flow;
}
initExpr = this.compileExpression(initializerNode, Type.auto, // reports
- Constraints.MUST_WRAP | Constraints.WILL_RETAIN
+ Constraints.MUST_WRAP | Constraints.WILL_RETAIN | Constraints.PREFER_STATIC
);
this.currentFlow = previousFlow;
if (this.currentType == Type.void) {
@@ -1549,7 +1549,7 @@ export class Compiler extends DiagnosticEmitter {
} else {
let length = stringValue.length;
let buffer = new Uint8Array(rtHeaderSize + (length << 1));
- program.writeRuntimeHeader(buffer, 0, stringInstance, length << 1);
+ program.writeRuntimeHeader(buffer, 0, stringInstance.id, length << 1);
for (let i = 0; i < length; ++i) {
writeI16(stringValue.charCodeAt(i), buffer, rtHeaderSize + (i << 1));
}
@@ -1567,16 +1567,15 @@ export class Compiler extends DiagnosticEmitter {
}
/** Adds a buffer to static memory and returns the created segment. */
- private addStaticBuffer(elementType: Type, values: ExpressionRef[]): MemorySegment {
+ addStaticBuffer(elementType: Type, values: ExpressionRef[], id: u32 = this.program.arrayBufferInstance.id): MemorySegment {
var program = this.program;
var length = values.length;
var byteSize = elementType.byteSize;
var byteLength = length * byteSize;
- var bufferInstance = assert(program.arrayBufferInstance);
var runtimeHeaderSize = program.runtimeHeaderSize;
var buf = new Uint8Array(runtimeHeaderSize + byteLength);
- program.writeRuntimeHeader(buf, 0, bufferInstance, byteLength);
+ program.writeRuntimeHeader(buf, 0, id, byteLength);
var pos = runtimeHeaderSize;
var nativeType = elementType.toNativeType();
switch (nativeType) {
@@ -1664,7 +1663,7 @@ export class Compiler extends DiagnosticEmitter {
var arrayLength = i32(bufferLength / elementType.byteSize);
var buf = new Uint8Array(runtimeHeaderSize + arrayInstanceSize);
- program.writeRuntimeHeader(buf, 0, arrayInstance, arrayInstanceSize);
+ program.writeRuntimeHeader(buf, 0, arrayInstance.id, arrayInstanceSize);
var bufferAddress32 = i64_low(bufferSegment.offset) + runtimeHeaderSize;
assert(!program.options.isWasm64); // TODO
@@ -3494,6 +3493,25 @@ export class Compiler extends DiagnosticEmitter {
this.currentType = type.nonNullableType;
return expr;
}
+ case AssertionKind.CONST: {
+ // TODO: decide on the layout of ReadonlyArray first
+ // let operand = expression.expression;
+ // if (operand.kind == NodeKind.LITERAL && (operand).literalKind == LiteralKind.ARRAY) {
+ // let element = this.resolver.lookupExpression(expression /* ! */, this.currentFlow, contextualType);
+ // if (!element) return this.module.unreachable();
+ // if (element.kind == ElementKind.CLASS) {
+ // let arrayInstance = element;
+ // if (arrayInstance.extends(this.program.readonlyArrayPrototype)) {
+ // return this.compileStaticArrayLiteral(operand, arrayInstance.type, constraints);
+ // }
+ // }
+ // }
+ this.error(
+ DiagnosticCode.Not_implemented,
+ expression.range
+ );
+ return this.module.unreachable();
+ }
default: assert(false);
}
return this.module.unreachable();
@@ -7893,6 +7911,7 @@ export class Compiler extends DiagnosticEmitter {
assert(!implicitlyNegate);
return this.compileArrayLiteral(
expression,
+ contextualType,
constraints
);
}
@@ -7961,27 +7980,36 @@ export class Compiler extends DiagnosticEmitter {
private compileArrayLiteral(
expression: ArrayLiteralExpression,
+ contextualType: Type,
constraints: Constraints
): ExpressionRef {
var module = this.module;
var flow = this.currentFlow;
+ var program = this.program;
- var arrayInstance = this.resolver.lookupExpression(expression, flow, this.currentType);
- if (!arrayInstance) return module.unreachable();
+ // handle static arrays
+ if (contextualType.is(TypeFlags.REFERENCE)) {
+ let classReference = contextualType.classReference;
+ if (classReference !== null && classReference.extends(program.staticArrayPrototype)) {
+ return this.compileStaticArrayLiteral(expression, contextualType, constraints);
+ }
+ }
- var program = this.program;
+ // handle normal arrays
+ var element = this.resolver.lookupExpression(expression, flow, this.currentType);
+ if (!element) return module.unreachable();
+ assert(element.kind == ElementKind.CLASS);
+ var arrayInstance = element;
+ var arrayType = arrayInstance.type;
+ var elementType = assert(arrayInstance.getTypeArgumentsTo(program.arrayPrototype))[0];
var arrayBufferInstance = assert(program.arrayBufferInstance);
// block those here so compiling expressions doesn't conflict
var tempThis = flow.getTempLocal(this.options.usizeType);
var tempDataStart = flow.getTempLocal(arrayBufferInstance.type);
- assert(arrayInstance.kind == ElementKind.CLASS);
- var arrayType = (arrayInstance).type;
- var elementType = assert((arrayInstance).getTypeArgumentsTo(this.program.arrayPrototype))[0];
- var expressions = expression.elementExpressions;
-
// compile value expressions and find out whether all are constant
+ var expressions = expression.elementExpressions;
var length = expressions.length;
var values = new Array(length);
var isStatic = true;
@@ -7991,7 +8019,7 @@ export class Compiler extends DiagnosticEmitter {
let expr = expression
? module.precomputeExpression(
this.compileExpression(expression, elementType,
- Constraints.CONV_IMPLICIT
+ Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN
)
)
: this.makeZero(elementType);
@@ -8024,7 +8052,7 @@ export class Compiler extends DiagnosticEmitter {
// otherwise allocate a new array header and make it wrap a copy of the static buffer
} else {
- // makeArray(length, alignLog2, classId, staticBuffer)
+ // __allocArray(length, alignLog2, classId, staticBuffer)
let expr = this.makeCallDirect(program.allocArrayInstance, [
module.i32(length),
program.options.isWasm64
@@ -8063,7 +8091,7 @@ export class Compiler extends DiagnosticEmitter {
var nativeArrayType = arrayType.toNativeType();
var stmts = new Array();
- // tempThis = makeArray(length, alignLog2, classId, source = 0)
+ // tempThis = __allocArray(length, alignLog2, classId, source = 0)
stmts.push(
module.local_set(tempThis.index,
this.makeRetain(
@@ -8097,7 +8125,9 @@ export class Compiler extends DiagnosticEmitter {
let valueExpr = values[i];
if (isManaged) {
// value = __retain(value)
- valueExpr = this.makeRetain(valueExpr);
+ if (!this.skippedAutoreleases.has(valueExpr)) {
+ valueExpr = this.makeRetain(valueExpr);
+ }
}
// store(tempData, value, immOffset)
stmts.push(
@@ -8118,10 +8148,168 @@ export class Compiler extends DiagnosticEmitter {
this.currentType = arrayType;
var expr = module.flatten(stmts, nativeArrayType);
if (arrayType.isManaged) {
- if (!(constraints & Constraints.WILL_RETAIN)) {
+ if (constraints & Constraints.WILL_RETAIN) {
+ this.skippedAutoreleases.add(expr);
+ } else {
expr = this.makeAutorelease(expr, arrayType, this.currentFlow);
+ }
+ }
+ return expr;
+ }
+
+ /** Compiles a special `fixed` array literal. */
+ private compileStaticArrayLiteral(
+ expression: ArrayLiteralExpression,
+ contextualType: Type,
+ constraints: Constraints
+ ): ExpressionRef {
+ var module = this.module;
+ var flow = this.currentFlow;
+ var program = this.program;
+
+ // make sure this method is only called with a valid contextualType
+ assert(contextualType.is(TypeFlags.REFERENCE));
+ var arrayInstance = assert(contextualType.classReference);
+ var arrayType = arrayInstance.type;
+ var elementType = assert(arrayInstance.getTypeArgumentsTo(program.staticArrayPrototype))[0];
+
+ // block those here so compiling expressions doesn't conflict
+ var tempThis = flow.getTempLocal(this.options.usizeType);
+
+ // compile value expressions and check if all are compile-time constants
+ var expressions = expression.elementExpressions;
+ var length = expressions.length;
+ var values = new Array(length);
+ var nativeElementType = elementType.toNativeType();
+ var isStatic = true;
+ for (let i = 0; i < length; ++i) {
+ let expression = expressions[i];
+ let expr: ExpressionRef;
+ if (expression) {
+ expr = module.precomputeExpression(
+ this.compileExpression(expression, elementType,
+ Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN
+ )
+ );
+ if (getExpressionId(expr) == ExpressionId.Const) {
+ assert(getExpressionType(expr) == nativeElementType);
+ } else {
+ isStatic = false;
+ }
} else {
+ expr = this.makeZero(elementType);
+ }
+ values[i] = expr;
+ }
+
+ var isWasm64 = this.options.isWasm64;
+ var bufferSize = values.length << elementType.alignLog2;
+
+ // if the array is static, make a static arraybuffer segment
+ if (isStatic) {
+ flow.freeTempLocal(tempThis);
+
+ let bufferSegment = this.addStaticBuffer(elementType, values, arrayInstance.id);
+ let bufferAddress = i64_add(bufferSegment.offset, i64_new(program.runtimeHeaderSize));
+
+ // return the static buffer directly if assigned to a global
+ if (constraints & Constraints.PREFER_STATIC) {
+ let expr = this.options.isWasm64
+ ? module.i64(i64_low(bufferAddress), i64_high(bufferAddress))
+ : module.i32(i64_low(bufferAddress));
+ if (constraints & Constraints.WILL_RETAIN) {
+ this.skippedAutoreleases.add(expr);
+ } else {
+ // not necessary since this is static data anyway
+ // expr = this.makeAutorelease(expr, arrayType, flow);
+ }
+ this.currentType = arrayType;
+ return expr;
+
+ // otherwise allocate a new chunk of memory and return a copy of the buffer
+ } else {
+ // __allocBuffer(bufferSize, id, buffer)
+ let expr = this.makeRetain(
+ this.makeCallDirect(program.allocBufferInstance, [
+ isWasm64
+ ? module.i64(bufferSize)
+ : module.i32(bufferSize),
+ module.i32(arrayInstance.id),
+ isWasm64
+ ? module.i64(i64_low(bufferAddress), i64_high(bufferAddress))
+ : module.i32(i64_low(bufferAddress))
+ ], expression)
+ );
+ if (arrayType.isManaged) {
+ if (constraints & Constraints.WILL_RETAIN) {
+ this.skippedAutoreleases.add(expr);
+ } else {
+ expr = this.makeAutorelease(expr, arrayType);
+ }
+ }
+ this.currentType = arrayType;
+ return expr;
+ }
+ }
+
+ // otherwise compile an explicit instantiation with indexed sets
+ var setter = arrayInstance.lookupOverload(OperatorKind.INDEXED_SET, true);
+ if (!setter) {
+ flow.freeTempLocal(tempThis);
+ this.error(
+ DiagnosticCode.Index_signature_in_type_0_only_permits_reading,
+ expression.range, arrayInstance.internalName
+ );
+ this.currentType = arrayType;
+ return module.unreachable();
+ }
+ var nativeArrayType = arrayType.toNativeType();
+
+ var stmts = new Array();
+ // tempThis = __allocBuffer(bufferSize, classId)
+ stmts.push(
+ module.local_set(tempThis.index,
+ this.makeRetain(
+ this.makeCallDirect(program.allocBufferInstance, [
+ isWasm64
+ ? module.i64(bufferSize)
+ : module.i32(bufferSize),
+ module.i32(arrayInstance.id)
+ ], expression)
+ )
+ )
+ );
+ var isManaged = elementType.isManaged;
+ for (let i = 0, alignLog2 = elementType.alignLog2; i < length; ++i) {
+ let valueExpr = values[i];
+ if (isManaged) {
+ // value = __retain(value)
+ if (!this.skippedAutoreleases.has(valueExpr)) {
+ valueExpr = this.makeRetain(valueExpr);
+ }
+ }
+ // store(tempThis, value, immOffset)
+ stmts.push(
+ module.store(elementType.byteSize,
+ module.local_get(tempThis.index, nativeArrayType),
+ valueExpr,
+ nativeElementType,
+ i << alignLog2
+ )
+ );
+ }
+ // -> tempThis
+ stmts.push(
+ module.local_get(tempThis.index, nativeArrayType)
+ );
+ flow.freeTempLocal(tempThis);
+ this.currentType = arrayType;
+ var expr = module.flatten(stmts, nativeArrayType);
+ if (arrayType.isManaged) {
+ if (constraints & Constraints.WILL_RETAIN) {
this.skippedAutoreleases.add(expr);
+ } else {
+ expr = this.makeAutorelease(expr, arrayType, this.currentFlow);
}
}
return expr;
diff --git a/src/extra/ast.ts b/src/extra/ast.ts
index da80807295..2b0d711419 100644
--- a/src/extra/ast.ts
+++ b/src/extra/ast.ts
@@ -529,6 +529,11 @@ export class ASTBuilder {
sb.push("!");
break;
}
+ case AssertionKind.CONST: {
+ this.visitNode(node.expression);
+ sb.push(" as const");
+ break;
+ }
default: assert(false);
}
}
diff --git a/src/parser.ts b/src/parser.ts
index f78b8e6232..a77639bd3f 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -1962,14 +1962,16 @@ export class Parser extends DiagnosticEmitter {
tn.range(abstractStart, abstractEnd), "abstract"
); // recoverable
}
- if (flags & CommonFlags.READONLY) {
- this.error(
- DiagnosticCode._0_modifier_cannot_be_used_here,
- tn.range(readonlyStart, readonlyEnd), "readonly"
- ); // recoverable
+ let retIndex = this.parseIndexSignatureDeclaration(tn, flags, decorators);
+ if (!retIndex) {
+ if (flags & CommonFlags.READONLY) {
+ this.error(
+ DiagnosticCode._0_modifier_cannot_be_used_here,
+ tn.range(readonlyStart, readonlyEnd), "readonly"
+ ); // recoverable
+ }
+ return null;
}
- let retIndex = this.parseIndexSignatureDeclaration(tn, decorators);
- if (!retIndex) return null;
tn.skip(Token.SEMICOLON);
return retIndex;
}
@@ -2199,7 +2201,11 @@ export class Parser extends DiagnosticEmitter {
return null;
}
- parseIndexSignatureDeclaration(tn: Tokenizer, decorators: DecoratorNode[] | null): IndexSignatureDeclaration | null {
+ parseIndexSignatureDeclaration(
+ tn: Tokenizer,
+ flags: CommonFlags,
+ decorators: DecoratorNode[] | null,
+ ): IndexSignatureDeclaration | null {
// at: '[': 'key' ':' Type ']' ':' Type
@@ -2228,7 +2234,7 @@ export class Parser extends DiagnosticEmitter {
if (tn.skip(Token.COLON)) {
let valueType = this.parseType(tn);
if (!valueType) return null;
- return Node.createIndexSignatureDeclaration(keyType, valueType, tn.range(start, tn.pos));
+ return Node.createIndexSignatureDeclaration(keyType, valueType, flags, tn.range(start, tn.pos));
} else {
this.error(
DiagnosticCode._0_expected,
@@ -3693,14 +3699,23 @@ export class Parser extends DiagnosticEmitter {
// AssertionExpression
case Token.AS: {
- let toType = this.parseType(tn); // reports
- if (!toType) return null;
- expr = Node.createAssertionExpression(
- AssertionKind.AS,
- expr,
- toType,
- tn.range(startPos, tn.pos)
- );
+ if (tn.skip(Token.CONST)) {
+ expr = Node.createAssertionExpression(
+ AssertionKind.CONST,
+ expr,
+ null,
+ tn.range(startPos, tn.pos)
+ );
+ } else {
+ let toType = this.parseType(tn); // reports
+ if (!toType) return null;
+ expr = Node.createAssertionExpression(
+ AssertionKind.AS,
+ expr,
+ toType,
+ tn.range(startPos, tn.pos)
+ );
+ }
break;
}
case Token.EXCLAMATION: {
diff --git a/src/program.ts b/src/program.ts
index cd7d486aa8..de57361697 100644
--- a/src/program.ts
+++ b/src/program.ts
@@ -413,12 +413,12 @@ export class Program extends DiagnosticEmitter {
arrayBufferInstance: Class;
/** Array prototype reference. */
arrayPrototype: ClassPrototype;
+ /** Static array prototype reference. */
+ staticArrayPrototype: ClassPrototype;
/** Set prototype reference. */
setPrototype: ClassPrototype;
/** Map prototype reference. */
mapPrototype: ClassPrototype;
- /** Fixed array prototype reference. */
- fixedArrayPrototype: ClassPrototype;
/** Int8Array prototype. */
i8ArrayPrototype: ClassPrototype;
/** Int16Array prototype. */
@@ -466,6 +466,8 @@ export class Program extends DiagnosticEmitter {
typeinfoInstance: Function;
/** RT `__instanceof(ptr: usize, superId: u32): bool` */
instanceofInstance: Function;
+ /** RT `__allocBuffer(size: usize, id: u32, data: usize = 0): usize` */
+ allocBufferInstance: Function;
/** RT `__allocArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize` */
allocArrayInstance: Function;
@@ -502,7 +504,7 @@ export class Program extends DiagnosticEmitter {
}
/** Writes a common runtime header to the specified buffer. */
- writeRuntimeHeader(buffer: Uint8Array, offset: i32, classInstance: Class, payloadSize: u32): void {
+ writeRuntimeHeader(buffer: Uint8Array, offset: i32, id: u32, payloadSize: u32): void {
// BLOCK {
// mmInfo: usize // WASM64 TODO
// gcInfo: u32
@@ -512,7 +514,7 @@ export class Program extends DiagnosticEmitter {
assert(payloadSize < (1 << 28)); // 1 bit BUFFERED + 3 bits color
writeI32(payloadSize, buffer, offset);
writeI32(1, buffer, offset + 4); // RC=1
- writeI32(classInstance.id, buffer, offset + 8);
+ writeI32(id, buffer, offset + 8);
writeI32(payloadSize, buffer, offset + 12);
}
@@ -962,7 +964,7 @@ export class Program extends DiagnosticEmitter {
// register stdlib components
this.arrayPrototype = this.require(CommonNames.Array, ElementKind.CLASS_PROTOTYPE);
- this.fixedArrayPrototype = this.require(CommonNames.FixedArray, ElementKind.CLASS_PROTOTYPE);
+ this.staticArrayPrototype = this.require(CommonNames.StaticArray, ElementKind.CLASS_PROTOTYPE);
this.setPrototype = this.require(CommonNames.Set, ElementKind.CLASS_PROTOTYPE);
this.mapPrototype = this.require(CommonNames.Map, ElementKind.CLASS_PROTOTYPE);
this.abortInstance = this.lookupFunction(CommonNames.abort); // can be disabled
@@ -975,6 +977,7 @@ export class Program extends DiagnosticEmitter {
this.typeinfoInstance = this.requireFunction(CommonNames.typeinfo);
this.instanceofInstance = this.requireFunction(CommonNames.instanceof_);
this.visitInstance = this.requireFunction(CommonNames.visit);
+ this.allocBufferInstance = this.requireFunction(CommonNames.allocBuffer);
this.allocArrayInstance = this.requireFunction(CommonNames.allocArray);
// mark module exports, i.e. to apply proper wrapping behavior on the boundaries
diff --git a/src/resolver.ts b/src/resolver.ts
index 723b02581c..0cd448561b 100644
--- a/src/resolver.ts
+++ b/src/resolver.ts
@@ -1583,26 +1583,47 @@ export class Resolver extends DiagnosticEmitter {
/** How to proceed with eventual diagnostics. */
reportMode: ReportMode = ReportMode.REPORT
): Element | null {
- if (node.assertionKind == AssertionKind.NONNULL) {
- return this.lookupExpression(node.expression, ctxFlow, ctxType, reportMode);
- }
- var type = this.resolveType(
- assert(node.toType), // must be set if not NONNULL
- ctxFlow.actualFunction,
- ctxFlow.contextualTypeArguments,
- reportMode
- );
- if (!type) return null;
- var element = this.getElementOfType(type);
- if (element) return element;
- if (reportMode == ReportMode.REPORT) {
- this.error(
- DiagnosticCode.Type_0_is_illegal_in_this_context,
- node.range, type.toString()
- );
+ switch (node.assertionKind) {
+ case AssertionKind.AS:
+ case AssertionKind.PREFIX: {
+ let type = this.resolveType(
+ assert(node.toType), // must be set if not NONNULL
+ ctxFlow.actualFunction,
+ ctxFlow.contextualTypeArguments,
+ reportMode
+ );
+ if (!type) return null;
+ let element = this.getElementOfType(type);
+ if (element) return element;
+ if (reportMode == ReportMode.REPORT) {
+ this.error(
+ DiagnosticCode.Type_0_is_illegal_in_this_context,
+ node.range, type.toString()
+ );
+ }
+ this.currentThisExpression = null;
+ this.currentElementExpression = null;
+ return null;
+ }
+ case AssertionKind.NONNULL: {
+ return this.lookupExpression(node.expression, ctxFlow, ctxType, reportMode);
+ }
+ case AssertionKind.CONST: {
+ // TODO: decide on the layout of ReadonlyArray first
+ // let element = this.lookupExpression(node.expression, ctxFlow, ctxType, reportMode);
+ // if (!element) return null;
+ // if (element.kind == ElementKind.CLASS && (element).extends(this.program.arrayPrototype)) {
+ // let elementType = assert((element).getTypeArgumentsTo(this.program.arrayPrototype))[0];
+ // return this.resolveClass(this.program.readonlyArrayPrototype, [ elementType ]);
+ // }
+ this.error(
+ DiagnosticCode.Not_implemented,
+ node.range
+ );
+ return null;
+ }
+ default: assert(false);
}
- this.currentThisExpression = null;
- this.currentElementExpression = null;
return null;
}
@@ -1617,16 +1638,37 @@ export class Resolver extends DiagnosticEmitter {
/** How to proceed with eventual diagnostics. */
reportMode: ReportMode = ReportMode.REPORT
): Type | null {
- if (node.assertionKind == AssertionKind.NONNULL) {
- let type = this.resolveExpression(node.expression, ctxFlow, ctxType, reportMode);
- return type ? type.nonNullableType : null;
- }
- return this.resolveType(
- assert(node.toType), // must be set if not NONNULL
- ctxFlow.actualFunction,
- ctxFlow.contextualTypeArguments,
- reportMode
- );
+ switch (node.assertionKind) {
+ case AssertionKind.AS:
+ case AssertionKind.PREFIX: {
+ return this.resolveType(
+ assert(node.toType),
+ ctxFlow.actualFunction,
+ ctxFlow.contextualTypeArguments,
+ reportMode
+ );
+ }
+ case AssertionKind.NONNULL: {
+ let type = this.resolveExpression(node.expression, ctxFlow, ctxType, reportMode);
+ return type ? type.nonNullableType : null;
+ }
+ case AssertionKind.CONST: {
+ let element = this.lookupExpression(node, ctxFlow, ctxType, reportMode);
+ if (!element) return null;
+ let type = this.getTypeOfElement(element);
+ if (!type) {
+ if (reportMode == ReportMode.REPORT) {
+ this.error(
+ DiagnosticCode.Expression_cannot_be_represented_by_a_type,
+ node.range
+ );
+ }
+ }
+ return type;
+ }
+ default: assert(false);
+ }
+ return null;
}
/** Looks up the program element the specified unary prefix expression refers to. */
diff --git a/std/assembly/fixedarray.ts b/std/assembly/fixedarray.ts
deleted file mode 100644
index 9e6570acf0..0000000000
--- a/std/assembly/fixedarray.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-///
-
-import { BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "./rt/common";
-import { idof } from "./builtins";
-import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_HOLEYARRAY } from "./util/error";
-
-// NOTE: DO NOT USE YET!
-
-// TODO: FixedArray with S being the static size, i.e. `new FixedArray`.
-// Then hard-wire this special type to the compiler and do static length checks instead :)
-
-export class FixedArray {
- [key: number]: T;
-
- constructor(length: i32) {
- if (length > BLOCK_MAXSIZE >>> alignof()) throw new RangeError(E_INVALIDLENGTH);
- var outSize = length << alignof();
- var out = __alloc(outSize, idof>());
- memory.fill(out, 0, outSize);
- return changetype>(out); // retains
- }
-
- get length(): i32 {
- return changetype(changetype(this) - BLOCK_OVERHEAD).rtSize >>> alignof();
- }
-
- @operator("[]") private __get(index: i32): T {
- if (index >= this.length) throw new RangeError(E_INDEXOUTOFRANGE);
- var value = this.__unchecked_get(index);
- if (isReference()) {
- if (!isNullable()) {
- if (!changetype(value)) throw new Error(E_HOLEYARRAY);
- }
- }
- return value;
- }
-
- @unsafe @operator("{}") private __unchecked_get(index: i32): T {
- return load(changetype(this) + (index << alignof()));
- }
-
- @operator("[]=") private __set(index: i32, value: T): void {
- if (index >= this.length) throw new RangeError(E_INDEXOUTOFRANGE);
- this.__unchecked_set(index, value);
- }
-
- @unsafe @operator("{}=") private __unchecked_set(index: i32, value: T): void {
- if (isManaged()) {
- let offset = changetype(this) + (index << alignof());
- let oldRef = load(offset);
- if (changetype(value) != oldRef) {
- store(offset, __retain(changetype(value)));
- __release(changetype(oldRef));
- }
- } else {
- store(changetype(this) + (index << alignof()), value);
- }
- }
-
- // RT integration
-
- @unsafe private __visit_impl(cookie: u32): void {
- if (isManaged()) {
- let cur = changetype(this);
- let end = cur + changetype(changetype(this) - BLOCK_OVERHEAD).rtSize;
- while (cur < end) {
- let val = load(cur);
- if (val) __visit(val, cookie);
- cur += sizeof();
- }
- }
- }
-}
diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts
index a0fd2064be..02af3d2ee7 100644
--- a/std/assembly/index.d.ts
+++ b/std/assembly/index.d.ts
@@ -1398,11 +1398,21 @@ declare class Array {
toString(): string;
}
-/** Class representing a fixed sequence of values of type `T`. */
-declare class FixedArray {
+/** Class representing a static (not resizable) sequence of values of type `T`. */
+declare abstract class StaticArray {
[key: number]: T;
+ static fromArray(source: Array): StaticArray;
+ static concat(source: StaticArray, other: StaticArray): StaticArray;
+ static slice(source: StaticArray, start?: i32, end?: i32): StaticArray;
readonly length: i32;
- constructor(capacity?: i32);
+ constructor(length?: i32);
+ includes(searchElement: T, fromIndex?: i32): bool;
+ indexOf(searchElement: T, fromIndex?: i32): i32;
+ lastIndexOf(searchElement: T, fromIndex?: i32): i32;
+ concat(items: Array): Array;
+ slice(from: i32, to?: i32): Array;
+ join(separator?: string): string;
+ toString(): string;
}
/** Class representing a sequence of characters. */
diff --git a/std/assembly/math.ts b/std/assembly/math.ts
index 73203c083a..57986c45d7 100644
--- a/std/assembly/math.ts
+++ b/std/assembly/math.ts
@@ -36,8 +36,8 @@ var rempio2_y0: f64,
/** @internal */
// @ts-ignore: decorator
-@lazy
-const PIO2_TABLE: u64[] = [
+@lazy @inline
+const PIO2_TABLE: StaticArray = [
0x00000000A2F9836E, 0x4E441529FC2757D1, 0xF534DDC0DB629599, 0x3C439041FE5163AB,
0xDEBBC561B7246E3A, 0x424DD2E006492EEA, 0x09D1921CFE1DEB1C, 0xB129A73EE88235F5,
0x2EBB4484E99C7026, 0xB45F7E413991D639, 0x835339F49C845F8B, 0xBDF9283B1FF897FF,
@@ -135,7 +135,7 @@ function umuldi(u: u64, v: u64): u64 {
/** @internal */
function pio2_large_quot(x: f64, u: i64): i32 { // see: jdh8/metallic/blob/master/src/math/double/rem_pio2.c
- const bits = PIO2_TABLE.dataStart;
+ const bits = changetype(PIO2_TABLE);
var magnitude = u & 0x7FFFFFFFFFFFFFFF;
var offset = (magnitude >> 52) - 1045;
@@ -1749,8 +1749,8 @@ export namespace NativeMath {
var rempio2f_y: f64;
// @ts-ignore: decorator
-@lazy
-const PIO2F_TABLE: u64[] = [
+@lazy @inline
+const PIO2F_TABLE: StaticArray = [
0xA2F9836E4E441529,
0xFC2757D1F534DDC0,
0xDB6295993C439041,
@@ -1782,7 +1782,7 @@ function expo2f(x: f32): f32 { // exp(x)/2 for x >= log(DBL_MAX)
@inline
function pio2f_large_quot(x: f32, u: i32): i32 { // see: jdh8/metallic/blob/master/src/math/float/rem_pio2f.c
const coeff = reinterpret(0x3BF921FB54442D18); // π * 0x1p-65 = 8.51530395021638647334e-20
- const bits = PIO2F_TABLE.dataStart;
+ const bits = changetype(PIO2F_TABLE);
var offset = (u >> 23) - 152;
var shift = (offset & 63);
diff --git a/std/assembly/rt.ts b/std/assembly/rt.ts
index bf63760b3d..0c9d3d7795 100644
--- a/std/assembly/rt.ts
+++ b/std/assembly/rt.ts
@@ -35,17 +35,24 @@ export function __instanceof(ref: usize, superId: u32): bool { // keyword
return false;
}
+// @ts-ignore: decorator
+@unsafe
+export function __allocBuffer(size: usize, id: u32, data: usize = 0): usize {
+ var buffer = __alloc(size, id);
+ if (data) memory.copy(buffer, data, size);
+ return buffer;
+}
+
// @ts-ignore: decorator
@unsafe
export function __allocArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize {
var array = __alloc(offsetof(), id);
var bufferSize = length << alignLog2;
- var buffer = __alloc(bufferSize, idof());
+ var buffer = __allocBuffer(bufferSize, idof(), data);
store(array, __retain(buffer), offsetof("buffer"));
store(array, buffer, offsetof("dataStart"));
- store(array, bufferSize, offsetof("byteLength"));
+ store(array, bufferSize, offsetof("byteLength"));
store(array, length, offsetof("length_"));
- if (data) memory.copy(buffer, data, bufferSize);
return array;
}
diff --git a/std/assembly/rt/index.d.ts b/std/assembly/rt/index.d.ts
index b594fcca37..b8d1c74f3c 100644
--- a/std/assembly/rt/index.d.ts
+++ b/std/assembly/rt/index.d.ts
@@ -10,6 +10,7 @@ declare function __instanceof(ref: usize, superId: u32): bool;
declare function __visit(ref: usize, cookie: i32): void;
declare function __visit_globals(cookie: u32): void;
declare function __visit_members(ref: usize, cookie: u32): void;
+declare function __allocBuffer(size: usize, id: u32, data?: usize): usize;
declare function __allocArray(length: i32, alignLog2: usize, id: u32, data?: usize): usize;
declare const ASC_RTRACE: bool;
declare const __GC_ALL_ACYCLIC: bool;
diff --git a/std/assembly/staticarray.ts b/std/assembly/staticarray.ts
new file mode 100644
index 0000000000..8a3bbcb06c
--- /dev/null
+++ b/std/assembly/staticarray.ts
@@ -0,0 +1,246 @@
+///
+
+import { BLOCK, BLOCK_MAXSIZE, BLOCK_OVERHEAD } from "./rt/common";
+import { idof } from "./builtins";
+import { Array } from "./array";
+import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_HOLEYARRAY } from "./util/error";
+import { joinBooleanArray, joinIntegerArray, joinFloatArray, joinStringArray, joinReferenceArray } from "./util/string";
+
+@sealed
+export class StaticArray {
+ [key: number]: T;
+
+ // Note that the interface of StaticArray instances must be a semantically
+ // compatible subset of Array in order for syntax highlighting to work
+ // properly, for instance when creating static arrays from array literals.
+ // The additionally provided static methods take care of dealing with static
+ // arrays exclusively, without having to convert to Array first.
+
+ static fromArray(source: Array): StaticArray {
+ var length = source.length;
+ var outSize = length << alignof();
+ var out = __alloc(outSize, idof>());
+ if (isManaged()) {
+ let sourcePtr = source.dataStart;
+ for (let i = 0; i < length; ++i) {
+ let off = i << alignof();
+ store(out + off, __retain(load(sourcePtr + off)));
+ }
+ } else {
+ memory.copy(out, source.dataStart, outSize);
+ }
+ return changetype>(out);
+ }
+
+ static concat(source: StaticArray, other: StaticArray): StaticArray {
+ var sourceLen = source.length;
+ var otherLen = select(0, other.length, other === null);
+ var outLen = sourceLen + otherLen;
+ if (outLen > BLOCK_MAXSIZE >>> alignof()) throw new Error(E_INVALIDLENGTH);
+ var out = changetype>(__alloc(outLen << alignof(), idof>())); // retains
+ var outStart = changetype(out);
+ var sourceSize = sourceLen << alignof();
+ if (isManaged()) {
+ for (let offset: usize = 0; offset < sourceSize; offset += sizeof()) {
+ let ref = load(changetype(source) + offset);
+ store(outStart + offset, __retain(ref));
+ }
+ outStart += sourceSize;
+ let otherSize = otherLen << alignof();
+ for (let offset: usize = 0; offset < otherSize; offset += sizeof()) {
+ let ref = load(changetype(other) + offset);
+ store(outStart + offset, __retain(ref));
+ }
+ } else {
+ memory.copy(outStart, changetype(source), sourceSize);
+ memory.copy(outStart + sourceSize, changetype(other), otherLen << alignof());
+ }
+ return out;
+ }
+
+ static slice(source: StaticArray, start: i32 = 0, end: i32 = i32.MAX_VALUE): StaticArray {
+ var length = source.length;
+ start = start < 0 ? max(start + length, 0) : min(start, length);
+ end = end < 0 ? max(end + length, 0) : min(end , length);
+ length = max(end - start, 0);
+ var sliceSize = length << alignof();
+ var slice = changetype>(__alloc(sliceSize, idof>())); // retains
+ var sourcePtr = changetype(source) + (start << alignof());
+ if (isManaged()) {
+ let off: usize = 0;
+ while (off < sliceSize) {
+ let ref = load(sourcePtr + off);
+ store(changetype(slice) + off, __retain(ref));
+ off += sizeof();
+ }
+ } else {
+ memory.copy(changetype(slice), sourcePtr, sliceSize);
+ }
+ return slice;
+ }
+
+ constructor(length: i32) {
+ if (length > BLOCK_MAXSIZE >>> alignof()) throw new RangeError(E_INVALIDLENGTH);
+ var outSize = length << alignof();
+ var out = __alloc(outSize, idof>());
+ memory.fill(out, 0, outSize);
+ return changetype>(out); // retains
+ }
+
+ get length(): i32 {
+ return changetype(changetype(this) - BLOCK_OVERHEAD).rtSize >>> alignof();
+ }
+
+ @operator("[]") private __get(index: i32): T {
+ if (index >= this.length) throw new RangeError(E_INDEXOUTOFRANGE);
+ var value = this.__unchecked_get(index);
+ if (isReference()) {
+ if (!isNullable()) {
+ if (!changetype(value)) throw new Error(E_HOLEYARRAY);
+ }
+ }
+ return value;
+ }
+
+ @unsafe @operator("{}") private __unchecked_get(index: i32): T {
+ return load(changetype(this) + (index << alignof()));
+ }
+
+ @operator("[]=") private __set(index: i32, value: T): void {
+ if (index >= this.length) throw new RangeError(E_INDEXOUTOFRANGE);
+ this.__unchecked_set(index, value);
+ }
+
+ @unsafe @operator("{}=") private __unchecked_set(index: i32, value: T): void {
+ if (isManaged()) {
+ let offset = changetype(this) + (index << alignof());
+ let oldRef = load(offset);
+ if (changetype(value) != oldRef) {
+ store(offset, __retain(changetype(value)));
+ __release(changetype(oldRef));
+ }
+ } else {
+ store(changetype(this) + (index << alignof()), value);
+ }
+ }
+
+ includes(value: T, fromIndex: i32 = 0): bool {
+ if (isFloat()) {
+ let length = this.length;
+ if (length == 0 || fromIndex >= length) return false;
+ if (fromIndex < 0) fromIndex = max(length + fromIndex, 0);
+ while (fromIndex < length) {
+ let elem = load(changetype(this) + (fromIndex << alignof()));
+ // @ts-ignore
+ if (elem == value || isNaN(elem) & isNaN(value)) return true;
+ ++fromIndex;
+ }
+ return false;
+ } else {
+ return this.indexOf(value, fromIndex) >= 0;
+ }
+ }
+
+ indexOf(value: T, fromIndex: i32 = 0): i32 {
+ var length = this.length;
+ if (length == 0 || fromIndex >= length) return -1;
+ if (fromIndex < 0) fromIndex = max(length + fromIndex, 0);
+ while (fromIndex < length) {
+ if (load(changetype(this) + (fromIndex << alignof())) == value) return fromIndex;
+ ++fromIndex;
+ }
+ return -1;
+ }
+
+ lastIndexOf(value: T, fromIndex: i32 = this.length): i32 {
+ var length = this.length;
+ if (length == 0) return -1;
+ if (fromIndex < 0) fromIndex = length + fromIndex;
+ else if (fromIndex >= length) fromIndex = length - 1;
+ while (fromIndex >= 0) {
+ if (load(changetype(this) + (fromIndex << alignof())) == value) return fromIndex;
+ --fromIndex;
+ }
+ return -1;
+ }
+
+ concat(other: Array): Array {
+ var thisLen = this.length;
+ var otherLen = select(0, other.length, other === null);
+ var outLen = thisLen + otherLen;
+ if (outLen > BLOCK_MAXSIZE >>> alignof()) throw new Error(E_INVALIDLENGTH);
+ var out = changetype>(__allocArray(outLen, alignof(), idof>())); // retains
+ var outStart = out.dataStart;
+ var thisSize = thisLen << alignof();
+ if (isManaged()) {
+ let thisStart = changetype(this);
+ for (let offset: usize = 0; offset < thisSize; offset += sizeof()) {
+ let ref = load(thisStart + offset);
+ store(outStart + offset, __retain(ref));
+ }
+ outStart += thisSize;
+ let otherStart = other.dataStart;
+ let otherSize = otherLen << alignof();
+ for (let offset: usize = 0; offset < otherSize; offset += sizeof