mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-26 15:32:16 +00:00
Minor refactoring; Fix n-body TS build
This commit is contained in:
parent
2aea14b518
commit
8b5d1d7f74
2
dist/asc.js
vendored
2
dist/asc.js
vendored
File diff suppressed because one or more lines are too long
2
dist/asc.js.map
vendored
2
dist/asc.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -175,7 +175,7 @@ function asmFunc(global, env, buffer) {
|
|||||||
function assembly_index_NBodySystem_constructor($0, $1) {
|
function assembly_index_NBodySystem_constructor($0, $1) {
|
||||||
$0 = $0 | 0;
|
$0 = $0 | 0;
|
||||||
$1 = $1 | 0;
|
$1 = $1 | 0;
|
||||||
var $2 = 0, $3 = 0, $4 = 0.0, $5 = 0.0, $6 = 0.0, $7 = 0.0, $8 = 0, $8 = 0, $10 = 0;
|
var $2 = 0, $3 = 0, $4 = 0.0, $5 = 0.0, $6 = 0.0, $7 = 0.0, $8 = 0, $9 = 0;
|
||||||
$2 = $1;
|
$2 = $1;
|
||||||
$8 = HEAP32[($2 + 4 | 0) >> 2] | 0;
|
$8 = HEAP32[($2 + 4 | 0) >> 2] | 0;
|
||||||
continue_0 : do {
|
continue_0 : do {
|
||||||
@ -193,17 +193,16 @@ function asmFunc(global, env, buffer) {
|
|||||||
} while (1);
|
} while (1);
|
||||||
$2 = $1;
|
$2 = $1;
|
||||||
$2 = HEAPU32[$2 >> 2] | 0;
|
$2 = HEAPU32[$2 >> 2] | 0;
|
||||||
if (0 >>> 0 < ((HEAP32[$2 >> 2] | 0) >>> 2 | 0) >>> 0) $10 = HEAPU32[(($2 + 0 | 0) + 8 | 0) >> 2] | 0; else abort();
|
if (0 >>> 0 < ((HEAP32[$2 >> 2] | 0) >>> 2 | 0) >>> 0) $9 = HEAPU32[(($2 + 0 | 0) + 8 | 0) >> 2] | 0; else abort();
|
||||||
$2 = $10;
|
$2 = $9;
|
||||||
HEAPF64[($2 + 24 | 0) >> 3] = -$5 / 39.47841760435743;
|
HEAPF64[($2 + 24 | 0) >> 3] = -$5 / 39.47841760435743;
|
||||||
HEAPF64[($2 + 32 | 0) >> 3] = -$6 / 39.47841760435743;
|
HEAPF64[($2 + 32 | 0) >> 3] = -$6 / 39.47841760435743;
|
||||||
HEAPF64[($2 + 40 | 0) >> 3] = -$7 / 39.47841760435743;
|
HEAPF64[($2 + 40 | 0) >> 3] = -$7 / 39.47841760435743;
|
||||||
if ($0) $8 = $0; else {
|
if (($0 | 0) == (0 | 0)) {
|
||||||
$0 = $lib_allocator_arena_allocate_memory(4 | 0) | 0;
|
$0 = $lib_allocator_arena_allocate_memory(4 | 0) | 0;
|
||||||
HEAP32[$0 >> 2] = $1;
|
HEAP32[$0 >> 2] = $1;
|
||||||
$8 = $0;
|
|
||||||
}
|
}
|
||||||
return $8 | 0;
|
return $0 | 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function assembly_index_init() {
|
function assembly_index_init() {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
require("allocator/arena");
|
require("allocator/arena");
|
||||||
|
// From The Computer Language Benchmarks Game
|
||||||
|
// http://benchmarksgame.alioth.debian.org
|
||||||
const SOLAR_MASS = 4.0 * Math.PI * Math.PI;
|
const SOLAR_MASS = 4.0 * Math.PI * Math.PI;
|
||||||
const DAYS_PER_YEAR = 365.24;
|
const DAYS_PER_YEAR = 365.24;
|
||||||
class Body {
|
class Body {
|
||||||
@ -37,25 +39,27 @@ function Neptune() {
|
|||||||
}
|
}
|
||||||
class NBodySystem {
|
class NBodySystem {
|
||||||
constructor(bodies) {
|
constructor(bodies) {
|
||||||
|
this.bodies = bodies;
|
||||||
var px = 0.0;
|
var px = 0.0;
|
||||||
var py = 0.0;
|
var py = 0.0;
|
||||||
var pz = 0.0;
|
var pz = 0.0;
|
||||||
var size = bodies.length;
|
var size = bodies.length;
|
||||||
for (let i = 0; i < size; i++) {
|
for (let i = 0; i < size; i++) {
|
||||||
let b = bodies[i];
|
let b = unchecked(bodies[i]);
|
||||||
let m = b.mass;
|
let m = b.mass;
|
||||||
px += b.vx * m;
|
px += b.vx * m;
|
||||||
py += b.vy * m;
|
py += b.vy * m;
|
||||||
pz += b.vz * m;
|
pz += b.vz * m;
|
||||||
}
|
}
|
||||||
this.bodies = bodies;
|
bodies[0].offsetMomentum(px, py, pz);
|
||||||
this.bodies[0].offsetMomentum(px, py, pz);
|
|
||||||
}
|
}
|
||||||
advance(dt) {
|
advance(dt) {
|
||||||
var bodies = this.bodies;
|
var bodies = this.bodies;
|
||||||
var size = bodies.length;
|
var size = bodies.length;
|
||||||
|
// var buffer = changetype<usize>(bodies.buffer_);
|
||||||
for (let i = 0; i < size; ++i) {
|
for (let i = 0; i < size; ++i) {
|
||||||
let bodyi = bodies[i];
|
let bodyi = unchecked(bodies[i]);
|
||||||
|
// let bodyi = load<Body>(buffer + i * sizeof<Body>(), 8);
|
||||||
let ix = bodyi.x;
|
let ix = bodyi.x;
|
||||||
let iy = bodyi.y;
|
let iy = bodyi.y;
|
||||||
let iz = bodyi.z;
|
let iz = bodyi.z;
|
||||||
@ -64,7 +68,8 @@ class NBodySystem {
|
|||||||
let bivz = bodyi.vz;
|
let bivz = bodyi.vz;
|
||||||
let bodyim = bodyi.mass;
|
let bodyim = bodyi.mass;
|
||||||
for (let j = i + 1; j < size; ++j) {
|
for (let j = i + 1; j < size; ++j) {
|
||||||
let bodyj = bodies[j];
|
let bodyj = unchecked(bodies[j]);
|
||||||
|
// let bodyj = load<Body>(buffer + j * sizeof<Body>(), 8);
|
||||||
let dx = ix - bodyj.x;
|
let dx = ix - bodyj.x;
|
||||||
let dy = iy - bodyj.y;
|
let dy = iy - bodyj.y;
|
||||||
let dz = iz - bodyj.z;
|
let dz = iz - bodyj.z;
|
||||||
@ -91,9 +96,8 @@ class NBodySystem {
|
|||||||
energy() {
|
energy() {
|
||||||
var e = 0.0;
|
var e = 0.0;
|
||||||
var bodies = this.bodies;
|
var bodies = this.bodies;
|
||||||
var size = bodies.length;
|
for (let i = 0, size = bodies.length; i < size; ++i) {
|
||||||
for (let i = 0; i < size; ++i) {
|
let bodyi = unchecked(bodies[i]);
|
||||||
let bodyi = bodies[i];
|
|
||||||
let ix = bodyi.x;
|
let ix = bodyi.x;
|
||||||
let iy = bodyi.y;
|
let iy = bodyi.y;
|
||||||
let iz = bodyi.z;
|
let iz = bodyi.z;
|
||||||
|
Binary file not shown.
@ -706,21 +706,20 @@
|
|||||||
(f64.const 39.47841760435743)
|
(f64.const 39.47841760435743)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(if (result i32)
|
(if
|
||||||
(get_local $0)
|
(i32.eqz
|
||||||
(get_local $0)
|
|
||||||
(block (result i32)
|
|
||||||
(i32.store
|
|
||||||
(tee_local $0
|
|
||||||
(call $~lib/allocator/arena/allocate_memory
|
|
||||||
(i32.const 4)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(get_local $1)
|
|
||||||
)
|
|
||||||
(get_local $0)
|
(get_local $0)
|
||||||
)
|
)
|
||||||
|
(i32.store
|
||||||
|
(tee_local $0
|
||||||
|
(call $~lib/allocator/arena/allocate_memory
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
(get_local $0)
|
||||||
)
|
)
|
||||||
(func $assembly/index/init (; 6 ;) (type $v)
|
(func $assembly/index/init (; 6 ;) (type $v)
|
||||||
(local $0 i32)
|
(local $0 i32)
|
||||||
|
@ -25,7 +25,12 @@ var nbodyASMJS = eval("0," + src)({
|
|||||||
|
|
||||||
// Load JS version
|
// Load JS version
|
||||||
var src = fs.readFileSync(__dirname + "/../build/index.js", "utf8");
|
var src = fs.readFileSync(__dirname + "/../build/index.js", "utf8");
|
||||||
var nbodyJS = (new Function("require", "exports", src + " return exports;"))(function() {}, {});
|
var scopeJS = {
|
||||||
|
require: function() {},
|
||||||
|
exports: {},
|
||||||
|
unchecked: function(expr) { return expr }
|
||||||
|
};
|
||||||
|
var nbodyJS = new Function(...Object.keys(scopeJS).concat(src + "\nreturn exports"))(...Object.values(scopeJS));
|
||||||
|
|
||||||
function test(nbody, steps) {
|
function test(nbody, steps) {
|
||||||
nbody.init();
|
nbody.init();
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Compiler,
|
Compiler,
|
||||||
ConversionKind,
|
ConversionKind
|
||||||
|
|
||||||
makeSmallIntegerWrap
|
|
||||||
} from "./compiler";
|
} from "./compiler";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -383,10 +381,9 @@ export function compileCall(
|
|||||||
case TypeKind.U8:
|
case TypeKind.U8:
|
||||||
case TypeKind.U16:
|
case TypeKind.U16:
|
||||||
case TypeKind.BOOL: {
|
case TypeKind.BOOL: {
|
||||||
ret = makeSmallIntegerWrap(
|
ret = compiler.makeSmallIntegerWrap(
|
||||||
module.createBinary(BinaryOp.RotlI32, arg0, arg1),
|
module.createBinary(BinaryOp.RotlI32, arg0, arg1),
|
||||||
compiler.currentType,
|
compiler.currentType
|
||||||
module
|
|
||||||
);
|
);
|
||||||
// fall-through
|
// fall-through
|
||||||
}
|
}
|
||||||
@ -469,10 +466,9 @@ export function compileCall(
|
|||||||
case TypeKind.U8:
|
case TypeKind.U8:
|
||||||
case TypeKind.U16:
|
case TypeKind.U16:
|
||||||
case TypeKind.BOOL: {
|
case TypeKind.BOOL: {
|
||||||
ret = makeSmallIntegerWrap(
|
ret = compiler.makeSmallIntegerWrap(
|
||||||
module.createBinary(BinaryOp.RotrI32, arg0, arg1),
|
module.createBinary(BinaryOp.RotrI32, arg0, arg1),
|
||||||
compiler.currentType,
|
compiler.currentType
|
||||||
module
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
517
src/compiler.ts
517
src/compiler.ts
@ -886,7 +886,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
stmt = module.createBlock(null, [
|
stmt = module.createBlock(null, [
|
||||||
stmt,
|
stmt,
|
||||||
module.createTeeLocal(0,
|
module.createTeeLocal(0,
|
||||||
makeConditionalAllocate(this, <Class>parent, declaration.name)
|
this.makeConditionalAllocate(<Class>parent, declaration.name)
|
||||||
)
|
)
|
||||||
], nativeSizeType);
|
], nativeSizeType);
|
||||||
}
|
}
|
||||||
@ -1421,9 +1421,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.options.sourceMap) {
|
if (this.options.sourceMap) this.addDebugLocation(expr, statement.range);
|
||||||
addDebugLocation(expr, statement.range, module, this.currentFunction);
|
|
||||||
}
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1529,10 +1527,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
flow.continueLabel = previousContinueLabel;
|
flow.continueLabel = previousContinueLabel;
|
||||||
|
|
||||||
var module = this.module;
|
var module = this.module;
|
||||||
var condExpr = makeIsTrueish(
|
var condExpr = this.makeIsTrueish(
|
||||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||||
this.currentType,
|
this.currentType
|
||||||
module
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// No need to eliminate the condition in generic contexts as the statement is executed anyway.
|
// No need to eliminate the condition in generic contexts as the statement is executed anyway.
|
||||||
@ -1628,10 +1625,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var ifFalse = statement.ifFalse;
|
var ifFalse = statement.ifFalse;
|
||||||
|
|
||||||
// The condition doesn't initiate a branch yet
|
// The condition doesn't initiate a branch yet
|
||||||
var condExpr = makeIsTrueish(
|
var condExpr = this.makeIsTrueish(
|
||||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||||
this.currentType,
|
this.currentType
|
||||||
module
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -1652,10 +1648,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// Otherwise recompile to the original and let the optimizer decide
|
// Otherwise recompile to the original and let the optimizer decide
|
||||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||||
condExpr = makeIsTrueish(
|
condExpr = this.makeIsTrueish(
|
||||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||||
this.currentType,
|
this.currentType
|
||||||
module
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1995,10 +1990,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var module = this.module;
|
var module = this.module;
|
||||||
|
|
||||||
// The condition does not yet initialize a branch
|
// The condition does not yet initialize a branch
|
||||||
var condExpr = makeIsTrueish(
|
var condExpr = this.makeIsTrueish(
|
||||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||||
this.currentType,
|
this.currentType
|
||||||
module
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -2015,10 +2009,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// Otherwise recompile to the original and let the optimizer decide
|
// Otherwise recompile to the original and let the optimizer decide
|
||||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||||
condExpr = makeIsTrueish(
|
condExpr = this.makeIsTrueish(
|
||||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||||
this.currentType,
|
this.currentType
|
||||||
module
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2246,9 +2239,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
this.currentType = contextualType;
|
this.currentType = contextualType;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.sourceMap) {
|
if (this.options.sourceMap) this.addDebugLocation(expr, expression.range);
|
||||||
addDebugLocation(expr, expression.range, this.module, this.currentFunction);
|
|
||||||
}
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2359,14 +2350,14 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
expr = module.createUnary(UnaryOp.TruncF32ToI64, expr);
|
expr = module.createUnary(UnaryOp.TruncF32ToI64, expr);
|
||||||
} else {
|
} else {
|
||||||
expr = module.createUnary(UnaryOp.TruncF32ToI32, expr);
|
expr = module.createUnary(UnaryOp.TruncF32ToI32, expr);
|
||||||
if (toType.is(TypeFlags.SHORT)) expr = makeSmallIntegerWrap(expr, toType, module);
|
if (toType.is(TypeFlags.SHORT)) expr = this.makeSmallIntegerWrap(expr, toType);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (toType.is(TypeFlags.LONG)) {
|
if (toType.is(TypeFlags.LONG)) {
|
||||||
expr = module.createUnary(UnaryOp.TruncF32ToU64, expr);
|
expr = module.createUnary(UnaryOp.TruncF32ToU64, expr);
|
||||||
} else {
|
} else {
|
||||||
expr = module.createUnary(UnaryOp.TruncF32ToU32, expr);
|
expr = module.createUnary(UnaryOp.TruncF32ToU32, expr);
|
||||||
if (toType.is(TypeFlags.SHORT)) expr = makeSmallIntegerWrap(expr, toType, module);
|
if (toType.is(TypeFlags.SHORT)) expr = this.makeSmallIntegerWrap(expr, toType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2377,14 +2368,14 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
expr = module.createUnary(UnaryOp.TruncF64ToI64, expr);
|
expr = module.createUnary(UnaryOp.TruncF64ToI64, expr);
|
||||||
} else {
|
} else {
|
||||||
expr = module.createUnary(UnaryOp.TruncF64ToI32, expr);
|
expr = module.createUnary(UnaryOp.TruncF64ToI32, expr);
|
||||||
if (toType.is(TypeFlags.SHORT)) expr = makeSmallIntegerWrap(expr, toType, module);
|
if (toType.is(TypeFlags.SHORT)) expr = this.makeSmallIntegerWrap(expr, toType);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (toType.is(TypeFlags.LONG)) {
|
if (toType.is(TypeFlags.LONG)) {
|
||||||
expr = module.createUnary(UnaryOp.TruncF64ToU64, expr);
|
expr = module.createUnary(UnaryOp.TruncF64ToU64, expr);
|
||||||
} else {
|
} else {
|
||||||
expr = module.createUnary(UnaryOp.TruncF64ToU32, expr);
|
expr = module.createUnary(UnaryOp.TruncF64ToU32, expr);
|
||||||
if (toType.is(TypeFlags.SHORT)) expr = makeSmallIntegerWrap(expr, toType, module);
|
if (toType.is(TypeFlags.SHORT)) expr = this.makeSmallIntegerWrap(expr, toType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2442,7 +2433,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
// i64 to i32
|
// i64 to i32
|
||||||
if (!toType.is(TypeFlags.LONG)) {
|
if (!toType.is(TypeFlags.LONG)) {
|
||||||
expr = module.createUnary(UnaryOp.WrapI64, expr); // discards upper bits
|
expr = module.createUnary(UnaryOp.WrapI64, expr); // discards upper bits
|
||||||
if (toType.is(TypeFlags.SHORT)) expr = makeSmallIntegerWrap(expr, toType, module);
|
if (toType.is(TypeFlags.SHORT)) expr = this.makeSmallIntegerWrap(expr, toType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// i32 to i64
|
// i32 to i64
|
||||||
@ -2460,7 +2451,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
expr = makeSmallIntegerWrap(expr, toType, module);
|
expr = this.makeSmallIntegerWrap(expr, toType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise (smaller) i32/u32 to (same size) i32/u32
|
// otherwise (smaller) i32/u32 to (same size) i32/u32
|
||||||
@ -4123,7 +4114,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
possiblyOverflows = this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER);
|
possiblyOverflows = this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER);
|
||||||
condExpr = makeIsTrueish(leftExpr, this.currentType, module);
|
condExpr = this.makeIsTrueish(leftExpr, this.currentType);
|
||||||
|
|
||||||
// simplify when cloning left without side effects was successful
|
// simplify when cloning left without side effects was successful
|
||||||
if (expr) {
|
if (expr) {
|
||||||
@ -4169,7 +4160,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
possiblyOverflows = this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER); // if right did
|
possiblyOverflows = this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER); // if right did
|
||||||
condExpr = makeIsTrueish(leftExpr, this.currentType, module);
|
condExpr = this.makeIsTrueish(leftExpr, this.currentType);
|
||||||
|
|
||||||
// simplify when cloning left without side effects was successful
|
// simplify when cloning left without side effects was successful
|
||||||
if (expr) {
|
if (expr) {
|
||||||
@ -4205,7 +4196,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
if (possiblyOverflows && wrapSmallIntegers) {
|
if (possiblyOverflows && wrapSmallIntegers) {
|
||||||
assert(this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER)); // must be a small int
|
assert(this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER)); // must be a small int
|
||||||
expr = makeSmallIntegerWrap(expr, this.currentType, module);
|
expr = this.makeSmallIntegerWrap(expr, this.currentType);
|
||||||
}
|
}
|
||||||
return compound
|
return compound
|
||||||
? this.compileAssignmentWithValue(left, expr, contextualType != Type.void)
|
? this.compileAssignmentWithValue(left, expr, contextualType != Type.void)
|
||||||
@ -5425,7 +5416,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
// must be conditional because `this` could have been provided by a derived class
|
// must be conditional because `this` could have been provided by a derived class
|
||||||
this.currentType = thisType;
|
this.currentType = thisType;
|
||||||
return module.createTeeLocal(0,
|
return module.createTeeLocal(0,
|
||||||
makeConditionalAllocate(this, <Class>parent, expression)
|
this.makeConditionalAllocate(<Class>parent, expression)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5965,7 +5956,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// otherwise simply allocate a new instance and initialize its fields
|
// otherwise simply allocate a new instance and initialize its fields
|
||||||
} else {
|
} else {
|
||||||
expr = makeAllocate(this, classInstance, expression);
|
expr = this.makeAllocate(classInstance, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentType = classInstance.type;
|
this.currentType = classInstance.type;
|
||||||
@ -6092,10 +6083,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var ifElse = expression.ifElse;
|
var ifElse = expression.ifElse;
|
||||||
var currentFunction = this.currentFunction;
|
var currentFunction = this.currentFunction;
|
||||||
|
|
||||||
var condExpr = makeIsTrueish(
|
var condExpr = this.makeIsTrueish(
|
||||||
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
||||||
this.currentType,
|
this.currentType
|
||||||
this.module
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -6114,10 +6104,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// Otherwise recompile to the original and let the optimizer decide
|
// Otherwise recompile to the original and let the optimizer decide
|
||||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||||
condExpr = makeIsTrueish(
|
condExpr = this.makeIsTrueish(
|
||||||
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
||||||
this.currentType,
|
this.currentType
|
||||||
this.module
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6347,7 +6336,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
if (possiblyOverflows) {
|
if (possiblyOverflows) {
|
||||||
assert(currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER));
|
assert(currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER));
|
||||||
setValue = makeSmallIntegerWrap(setValue, currentType, module);
|
setValue = this.makeSmallIntegerWrap(setValue, currentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue = this.compileAssignmentWithValue(expression.operand, setValue, false);
|
setValue = this.compileAssignmentWithValue(expression.operand, setValue, false);
|
||||||
@ -6373,15 +6362,13 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
wrapSmallIntegers: bool = true
|
wrapSmallIntegers: bool = true
|
||||||
): ExpressionRef {
|
): ExpressionRef {
|
||||||
var module = this.module;
|
var module = this.module;
|
||||||
var currentType = this.currentType;
|
|
||||||
|
|
||||||
var possiblyOverflows = false;
|
var possiblyOverflows = false;
|
||||||
var compound = false;
|
var compound = false;
|
||||||
var expr: ExpressionRef;
|
var expr: ExpressionRef;
|
||||||
|
|
||||||
switch (expression.operator) {
|
switch (expression.operator) {
|
||||||
case Token.PLUS: {
|
case Token.PLUS: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6396,12 +6383,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
ConversionKind.NONE,
|
ConversionKind.NONE,
|
||||||
false // wrapped below
|
false // wrapped below
|
||||||
);
|
);
|
||||||
currentType = this.currentType;
|
possiblyOverflows = this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER); // if operand already did
|
||||||
possiblyOverflows = currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER); // if operand already did
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Token.MINUS: {
|
case Token.MINUS: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6414,11 +6400,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
)) {
|
)) {
|
||||||
// implicitly negate integer and float literals. also enables proper checking of literal ranges.
|
// implicitly negate integer and float literals. also enables proper checking of literal ranges.
|
||||||
expr = this.compileLiteralExpression(<LiteralExpression>expression.operand, contextualType, true);
|
expr = this.compileLiteralExpression(<LiteralExpression>expression.operand, contextualType, true);
|
||||||
if (this.options.sourceMap) {
|
// compileExpression normally does this:
|
||||||
// compileExpression normally does this
|
if (this.options.sourceMap) this.addDebugLocation(expr, expression.range);
|
||||||
addDebugLocation(expr, expression.range, module, this.currentFunction);
|
|
||||||
}
|
|
||||||
currentType = this.currentType;
|
|
||||||
} else {
|
} else {
|
||||||
expr = this.compileExpression(
|
expr = this.compileExpression(
|
||||||
expression.operand,
|
expression.operand,
|
||||||
@ -6428,8 +6411,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
ConversionKind.NONE,
|
ConversionKind.NONE,
|
||||||
false // wrapped below
|
false // wrapped below
|
||||||
);
|
);
|
||||||
currentType = this.currentType;
|
switch (this.currentType.kind) {
|
||||||
switch (currentType.kind) {
|
|
||||||
case TypeKind.I8:
|
case TypeKind.I8:
|
||||||
case TypeKind.I16:
|
case TypeKind.I16:
|
||||||
case TypeKind.U8:
|
case TypeKind.U8:
|
||||||
@ -6440,7 +6422,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeKind.USIZE: {
|
case TypeKind.USIZE: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6454,7 +6436,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
this.options.isWasm64
|
this.options.isWasm64
|
||||||
? BinaryOp.SubI64
|
? BinaryOp.SubI64
|
||||||
: BinaryOp.SubI32,
|
: BinaryOp.SubI32,
|
||||||
currentType.toNativeZero(module),
|
this.currentType.toNativeZero(module),
|
||||||
expr
|
expr
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -6477,7 +6459,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Token.PLUS_PLUS: {
|
case Token.PLUS_PLUS: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6493,8 +6475,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
ConversionKind.NONE,
|
ConversionKind.NONE,
|
||||||
false // wrapped below
|
false // wrapped below
|
||||||
);
|
);
|
||||||
currentType = this.currentType;
|
switch (this.currentType.kind) {
|
||||||
switch (currentType.kind) {
|
|
||||||
case TypeKind.I8:
|
case TypeKind.I8:
|
||||||
case TypeKind.I16:
|
case TypeKind.I16:
|
||||||
case TypeKind.U8:
|
case TypeKind.U8:
|
||||||
@ -6505,7 +6486,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeKind.USIZE: {
|
case TypeKind.USIZE: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6520,7 +6501,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
? BinaryOp.AddI64
|
? BinaryOp.AddI64
|
||||||
: BinaryOp.AddI32,
|
: BinaryOp.AddI32,
|
||||||
expr,
|
expr,
|
||||||
currentType.toNativeOne(module)
|
this.currentType.toNativeOne(module)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6541,7 +6522,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Token.MINUS_MINUS: {
|
case Token.MINUS_MINUS: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6557,8 +6538,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
ConversionKind.NONE,
|
ConversionKind.NONE,
|
||||||
false // wrapped below
|
false // wrapped below
|
||||||
);
|
);
|
||||||
currentType = this.currentType;
|
switch (this.currentType.kind) {
|
||||||
switch (currentType.kind) {
|
|
||||||
case TypeKind.I8:
|
case TypeKind.I8:
|
||||||
case TypeKind.I16:
|
case TypeKind.I16:
|
||||||
case TypeKind.U8:
|
case TypeKind.U8:
|
||||||
@ -6569,7 +6549,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeKind.USIZE: {
|
case TypeKind.USIZE: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6584,7 +6564,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
? BinaryOp.SubI64
|
? BinaryOp.SubI64
|
||||||
: BinaryOp.SubI32,
|
: BinaryOp.SubI32,
|
||||||
expr,
|
expr,
|
||||||
currentType.toNativeOne(module)
|
this.currentType.toNativeOne(module)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6613,12 +6593,12 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
ConversionKind.NONE,
|
ConversionKind.NONE,
|
||||||
true // must wrap small integers
|
true // must wrap small integers
|
||||||
);
|
);
|
||||||
expr = makeIsFalseish(expr, this.currentType, module);
|
expr = this.makeIsFalseish(expr, this.currentType);
|
||||||
this.currentType = Type.bool;
|
this.currentType = Type.bool;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Token.TILDE: {
|
case Token.TILDE: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6637,8 +6617,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
: ConversionKind.IMPLICIT,
|
: ConversionKind.IMPLICIT,
|
||||||
false // retains low bits of small integers
|
false // retains low bits of small integers
|
||||||
);
|
);
|
||||||
currentType = this.currentType;
|
switch (this.currentType.kind) {
|
||||||
switch (currentType.kind) {
|
|
||||||
case TypeKind.I8:
|
case TypeKind.I8:
|
||||||
case TypeKind.I16:
|
case TypeKind.I16:
|
||||||
case TypeKind.U8:
|
case TypeKind.U8:
|
||||||
@ -6649,7 +6628,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeKind.USIZE: {
|
case TypeKind.USIZE: {
|
||||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
expression.range
|
expression.range
|
||||||
@ -6664,7 +6643,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
? BinaryOp.XorI64
|
? BinaryOp.XorI64
|
||||||
: BinaryOp.XorI32,
|
: BinaryOp.XorI32,
|
||||||
expr,
|
expr,
|
||||||
currentType.toNativeNegOne(module)
|
this.currentType.toNativeNegOne(module)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6698,13 +6677,208 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (possiblyOverflows && wrapSmallIntegers) {
|
if (possiblyOverflows && wrapSmallIntegers) {
|
||||||
assert(currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER));
|
assert(this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER));
|
||||||
expr = makeSmallIntegerWrap(expr, currentType, module);
|
expr = this.makeSmallIntegerWrap(expr, this.currentType);
|
||||||
}
|
}
|
||||||
return compound
|
return compound
|
||||||
? this.compileAssignmentWithValue(expression.operand, expr, contextualType != Type.void)
|
? this.compileAssignmentWithValue(expression.operand, expr, contextualType != Type.void)
|
||||||
: expr;
|
: expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Makes sure that a 32-bit integer value is wrapped to a valid value of the specified type. */
|
||||||
|
makeSmallIntegerWrap(expr: ExpressionRef, type: Type): ExpressionRef {
|
||||||
|
var module = this.module;
|
||||||
|
switch (type.kind) {
|
||||||
|
case TypeKind.I8: { // TODO: Use 'i32.extend8_s' once sign-extension-ops lands
|
||||||
|
expr = module.createBinary(BinaryOp.ShrI32,
|
||||||
|
module.createBinary(BinaryOp.ShlI32,
|
||||||
|
expr,
|
||||||
|
module.createI32(24)
|
||||||
|
),
|
||||||
|
module.createI32(24)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeKind.I16: { // TODO: Use 'i32.extend16_s' once sign-extension-ops lands
|
||||||
|
expr = module.createBinary(BinaryOp.ShrI32,
|
||||||
|
module.createBinary(BinaryOp.ShlI32,
|
||||||
|
expr,
|
||||||
|
module.createI32(16)
|
||||||
|
),
|
||||||
|
module.createI32(16)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeKind.U8: {
|
||||||
|
expr = module.createBinary(BinaryOp.AndI32,
|
||||||
|
expr,
|
||||||
|
module.createI32(0xff)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeKind.U16: {
|
||||||
|
expr = module.createBinary(BinaryOp.AndI32,
|
||||||
|
expr,
|
||||||
|
module.createI32(0xffff)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeKind.BOOL: {
|
||||||
|
expr = module.createBinary(BinaryOp.AndI32,
|
||||||
|
expr,
|
||||||
|
module.createI32(0x1)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a comparison whether an expression is 'false' in a broader sense. */
|
||||||
|
makeIsFalseish(expr: ExpressionRef, type: Type): ExpressionRef {
|
||||||
|
var module = this.module;
|
||||||
|
switch (type.kind) {
|
||||||
|
default: { // any native i32
|
||||||
|
return module.createUnary(UnaryOp.EqzI32, expr);
|
||||||
|
}
|
||||||
|
case TypeKind.I64:
|
||||||
|
case TypeKind.U64: {
|
||||||
|
return module.createUnary(UnaryOp.EqzI64, expr);
|
||||||
|
}
|
||||||
|
case TypeKind.USIZE: // TODO: strings?
|
||||||
|
case TypeKind.ISIZE: {
|
||||||
|
return module.createUnary(type.size == 64 ? UnaryOp.EqzI64 : UnaryOp.EqzI32, expr);
|
||||||
|
}
|
||||||
|
case TypeKind.F32: {
|
||||||
|
return module.createBinary(BinaryOp.EqF32, expr, module.createF32(0));
|
||||||
|
}
|
||||||
|
case TypeKind.F64: {
|
||||||
|
return module.createBinary(BinaryOp.EqF64, expr, module.createF64(0));
|
||||||
|
}
|
||||||
|
case TypeKind.VOID: {
|
||||||
|
assert(false);
|
||||||
|
return module.createI32(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a comparison whether an expression is 'true' in a broader sense. */
|
||||||
|
makeIsTrueish(expr: ExpressionRef, type: Type): ExpressionRef {
|
||||||
|
var module = this.module;
|
||||||
|
switch (type.kind) {
|
||||||
|
default: { // any native i32
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
case TypeKind.I64:
|
||||||
|
case TypeKind.U64: {
|
||||||
|
return module.createBinary(BinaryOp.NeI64, expr, module.createI64(0));
|
||||||
|
}
|
||||||
|
case TypeKind.USIZE: // TODO: strings?
|
||||||
|
case TypeKind.ISIZE: {
|
||||||
|
return type.size == 64
|
||||||
|
? module.createBinary(BinaryOp.NeI64, expr, module.createI64(0))
|
||||||
|
: expr;
|
||||||
|
}
|
||||||
|
case TypeKind.F32: {
|
||||||
|
return module.createBinary(BinaryOp.NeF32, expr, module.createF32(0));
|
||||||
|
}
|
||||||
|
case TypeKind.F64: {
|
||||||
|
return module.createBinary(BinaryOp.NeF64, expr, module.createF64(0));
|
||||||
|
}
|
||||||
|
case TypeKind.VOID: {
|
||||||
|
assert(false);
|
||||||
|
return module.createI32(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes an allocation expression for an instance of the specified class. */
|
||||||
|
makeAllocate(classInstance: Class, reportNode: Node): ExpressionRef {
|
||||||
|
var module = this.module;
|
||||||
|
var currentFunction = this.currentFunction;
|
||||||
|
var nativeSizeType = this.options.nativeSizeType;
|
||||||
|
|
||||||
|
// allocate the necessary memory and tee the pointer to a temp. local for reuse
|
||||||
|
var tempLocal = currentFunction.getTempLocal(classInstance.type);
|
||||||
|
var initializers = new Array<ExpressionRef>();
|
||||||
|
initializers.push(
|
||||||
|
module.createSetLocal(tempLocal.index,
|
||||||
|
compileBuiltinAllocate(this, classInstance, reportNode)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// apply field initializers
|
||||||
|
if (classInstance.members) {
|
||||||
|
for (let member of classInstance.members.values()) {
|
||||||
|
if (member.kind == ElementKind.FIELD) {
|
||||||
|
let field = <Field>member;
|
||||||
|
let fieldType = field.type;
|
||||||
|
let nativeFieldType = fieldType.toNativeType();
|
||||||
|
let fieldDeclaration = field.prototype.declaration;
|
||||||
|
assert(!field.isAny(CommonFlags.CONST));
|
||||||
|
if (fieldDeclaration.initializer) { // use initializer
|
||||||
|
initializers.push(module.createStore(fieldType.byteSize,
|
||||||
|
module.createGetLocal(tempLocal.index, nativeSizeType),
|
||||||
|
this.compileExpression(fieldDeclaration.initializer, fieldType), // reports
|
||||||
|
nativeFieldType,
|
||||||
|
field.memoryOffset
|
||||||
|
));
|
||||||
|
} else { // initialize with zero
|
||||||
|
// TODO: might be unnecessary if the ctor initializes the field
|
||||||
|
let parameterIndex = (<FieldDeclaration>field.prototype.declaration).parameterIndex;
|
||||||
|
initializers.push(module.createStore(fieldType.byteSize,
|
||||||
|
module.createGetLocal(tempLocal.index, nativeSizeType),
|
||||||
|
parameterIndex >= 0 // initialized via parameter
|
||||||
|
? module.createGetLocal(1 + parameterIndex, nativeFieldType)
|
||||||
|
: fieldType.toNativeZero(module),
|
||||||
|
nativeFieldType,
|
||||||
|
field.memoryOffset
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return `this`
|
||||||
|
initializers.push(
|
||||||
|
module.createGetLocal(tempLocal.index, nativeSizeType)
|
||||||
|
);
|
||||||
|
|
||||||
|
currentFunction.freeTempLocal(tempLocal);
|
||||||
|
this.currentType = classInstance.type;
|
||||||
|
return module.createBlock(null, initializers, nativeSizeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes a conditional allocation expression inside of the constructor of the specified class. */
|
||||||
|
makeConditionalAllocate(classInstance: Class, reportNode: Node): ExpressionRef {
|
||||||
|
// requires that `this` is the first local
|
||||||
|
var module = this.module;
|
||||||
|
var nativeSizeType = this.options.nativeSizeType;
|
||||||
|
this.currentType = classInstance.type;
|
||||||
|
return module.createIf(
|
||||||
|
nativeSizeType == NativeType.I64
|
||||||
|
? module.createBinary(
|
||||||
|
BinaryOp.NeI64,
|
||||||
|
module.createGetLocal(0, NativeType.I64),
|
||||||
|
module.createI64(0)
|
||||||
|
)
|
||||||
|
: module.createGetLocal(0, NativeType.I32),
|
||||||
|
module.createGetLocal(0, nativeSizeType),
|
||||||
|
module.createTeeLocal(0,
|
||||||
|
this.makeAllocate(classInstance, reportNode)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds the debug location of the specified expression at the specified range to the source map. */
|
||||||
|
addDebugLocation(expr: ExpressionRef, range: Range): void {
|
||||||
|
var currentFunction = this.currentFunction;
|
||||||
|
var source = range.source;
|
||||||
|
if (source.debugInfoIndex < 0) source.debugInfoIndex = this.module.addDebugInfoFile(source.normalizedPath);
|
||||||
|
range.debugInfoRef = expr;
|
||||||
|
if (!currentFunction.debugLocations) currentFunction.debugLocations = [];
|
||||||
|
currentFunction.debugLocations.push(range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
@ -6752,200 +6926,3 @@ function mangleExportName(element: Element, explicitSimpleName: string | null =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Adds the debug location of the specified expression at the specified range to the source map. */
|
|
||||||
function addDebugLocation(expr: ExpressionRef, range: Range, module: Module, currentFunction: Function): void {
|
|
||||||
var source = range.source;
|
|
||||||
if (source.debugInfoIndex < 0) {
|
|
||||||
source.debugInfoIndex = module.addDebugInfoFile(source.normalizedPath);
|
|
||||||
}
|
|
||||||
range.debugInfoRef = expr;
|
|
||||||
if (!currentFunction.debugLocations) currentFunction.debugLocations = [];
|
|
||||||
currentFunction.debugLocations.push(range);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Wraps a 32-bit integer expression so it evaluates to a valid value of the specified type. */
|
|
||||||
export function makeSmallIntegerWrap(expr: ExpressionRef, type: Type, module: Module): ExpressionRef {
|
|
||||||
switch (type.kind) {
|
|
||||||
case TypeKind.I8: {
|
|
||||||
return module.createBinary(BinaryOp.ShrI32,
|
|
||||||
module.createBinary(BinaryOp.ShlI32,
|
|
||||||
expr,
|
|
||||||
module.createI32(24)
|
|
||||||
),
|
|
||||||
module.createI32(24)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case TypeKind.I16: {
|
|
||||||
return module.createBinary(BinaryOp.ShrI32,
|
|
||||||
module.createBinary(BinaryOp.ShlI32,
|
|
||||||
expr,
|
|
||||||
module.createI32(16)
|
|
||||||
),
|
|
||||||
module.createI32(16)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case TypeKind.U8: {
|
|
||||||
return module.createBinary(BinaryOp.AndI32,
|
|
||||||
expr,
|
|
||||||
module.createI32(0xff)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case TypeKind.U16: {
|
|
||||||
return module.createBinary(BinaryOp.AndI32,
|
|
||||||
expr,
|
|
||||||
module.createI32(0xffff)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case TypeKind.BOOL: {
|
|
||||||
return module.createBinary(BinaryOp.AndI32,
|
|
||||||
expr,
|
|
||||||
module.createI32(0x1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
assert(false);
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates a comparison whether an expression is not 'true' in a broader sense. */
|
|
||||||
export function makeIsFalseish(expr: ExpressionRef, type: Type, module: Module): ExpressionRef {
|
|
||||||
switch (type.kind) {
|
|
||||||
default: { // any native i32
|
|
||||||
return module.createUnary(UnaryOp.EqzI32, expr);
|
|
||||||
}
|
|
||||||
case TypeKind.I64:
|
|
||||||
case TypeKind.U64: {
|
|
||||||
return module.createUnary(UnaryOp.EqzI64, expr);
|
|
||||||
}
|
|
||||||
case TypeKind.USIZE: // TODO: strings?
|
|
||||||
case TypeKind.ISIZE: {
|
|
||||||
return module.createUnary(type.size == 64 ? UnaryOp.EqzI64 : UnaryOp.EqzI32, expr);
|
|
||||||
}
|
|
||||||
case TypeKind.F32: {
|
|
||||||
return module.createBinary(BinaryOp.EqF32, expr, module.createF32(0));
|
|
||||||
}
|
|
||||||
case TypeKind.F64: {
|
|
||||||
return module.createBinary(BinaryOp.EqF64, expr, module.createF64(0));
|
|
||||||
}
|
|
||||||
case TypeKind.VOID: {
|
|
||||||
assert(false);
|
|
||||||
return module.createI32(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates a comparison whether an expression is 'true' in a broader sense. */
|
|
||||||
export function makeIsTrueish(expr: ExpressionRef, type: Type, module: Module): ExpressionRef {
|
|
||||||
switch (type.kind) {
|
|
||||||
default: { // any native i32
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
case TypeKind.I64:
|
|
||||||
case TypeKind.U64: {
|
|
||||||
return module.createBinary(BinaryOp.NeI64, expr, module.createI64(0));
|
|
||||||
}
|
|
||||||
case TypeKind.USIZE: // TODO: strings?
|
|
||||||
case TypeKind.ISIZE: {
|
|
||||||
return type.size == 64
|
|
||||||
? module.createBinary(BinaryOp.NeI64, expr, module.createI64(0))
|
|
||||||
: expr;
|
|
||||||
}
|
|
||||||
case TypeKind.F32: {
|
|
||||||
return module.createBinary(BinaryOp.NeF32, expr, module.createF32(0));
|
|
||||||
}
|
|
||||||
case TypeKind.F64: {
|
|
||||||
return module.createBinary(BinaryOp.NeF64, expr, module.createF64(0));
|
|
||||||
}
|
|
||||||
case TypeKind.VOID: {
|
|
||||||
assert(false);
|
|
||||||
return module.createI32(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Makes an allocation expression for an instance of the specified class. */
|
|
||||||
export function makeAllocate(compiler: Compiler, classInstance: Class, reportNode: Node): ExpressionRef {
|
|
||||||
var module = compiler.module;
|
|
||||||
var currentFunction = compiler.currentFunction;
|
|
||||||
var nativeSizeType = compiler.options.nativeSizeType;
|
|
||||||
|
|
||||||
var tempLocal = currentFunction.getTempLocal(classInstance.type);
|
|
||||||
|
|
||||||
// allocate the necessary memory
|
|
||||||
var initializers = new Array<ExpressionRef>();
|
|
||||||
initializers.push(
|
|
||||||
module.createSetLocal(tempLocal.index,
|
|
||||||
compileBuiltinAllocate(compiler, classInstance, reportNode)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// apply field initializers
|
|
||||||
if (classInstance.members) {
|
|
||||||
for (let member of classInstance.members.values()) {
|
|
||||||
if (member.kind == ElementKind.FIELD) {
|
|
||||||
let field = <Field>member;
|
|
||||||
let fieldType = field.type;
|
|
||||||
let nativeFieldType = fieldType.toNativeType();
|
|
||||||
let fieldDeclaration = field.prototype.declaration;
|
|
||||||
assert(!field.isAny(CommonFlags.CONST));
|
|
||||||
if (fieldDeclaration.initializer) { // use initializer
|
|
||||||
initializers.push(module.createStore(fieldType.byteSize,
|
|
||||||
module.createGetLocal(tempLocal.index, nativeSizeType),
|
|
||||||
compiler.compileExpression(fieldDeclaration.initializer, fieldType), // reports
|
|
||||||
nativeFieldType,
|
|
||||||
field.memoryOffset
|
|
||||||
));
|
|
||||||
} else { // initialize with zero
|
|
||||||
// TODO: might be unnecessary if the ctor initializes the field
|
|
||||||
let parameterIndex = (<FieldDeclaration>field.prototype.declaration).parameterIndex;
|
|
||||||
initializers.push(module.createStore(fieldType.byteSize,
|
|
||||||
module.createGetLocal(tempLocal.index, nativeSizeType),
|
|
||||||
parameterIndex >= 0 // initialized via parameter
|
|
||||||
? module.createGetLocal(1 + parameterIndex, nativeFieldType)
|
|
||||||
: fieldType.toNativeZero(module),
|
|
||||||
nativeFieldType,
|
|
||||||
field.memoryOffset
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return `this`
|
|
||||||
initializers.push(
|
|
||||||
module.createGetLocal(tempLocal.index, nativeSizeType)
|
|
||||||
);
|
|
||||||
|
|
||||||
currentFunction.freeTempLocal(tempLocal);
|
|
||||||
compiler.currentType = classInstance.type;
|
|
||||||
return module.createBlock(null, initializers, nativeSizeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Makes a conditional allocation expression inside of the constructor of the specified class. */
|
|
||||||
export function makeConditionalAllocate(compiler: Compiler, classInstance: Class, reportNode: Node): ExpressionRef {
|
|
||||||
// requires that `this` is the first local
|
|
||||||
var module = compiler.module;
|
|
||||||
var nativeSizeType = compiler.options.nativeSizeType;
|
|
||||||
compiler.currentType = classInstance.type;
|
|
||||||
return module.createIf(
|
|
||||||
nativeSizeType == NativeType.I64
|
|
||||||
? module.createBinary(
|
|
||||||
BinaryOp.NeI64,
|
|
||||||
module.createGetLocal(0, NativeType.I64),
|
|
||||||
module.createI64(0)
|
|
||||||
)
|
|
||||||
: module.createGetLocal(0, NativeType.I32),
|
|
||||||
module.createGetLocal(0, nativeSizeType),
|
|
||||||
module.createTeeLocal(0,
|
|
||||||
makeAllocate(compiler, classInstance, reportNode)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isI32Const(expr: ExpressionRef): bool {
|
|
||||||
return _BinaryenExpressionGetId(expr) == ExpressionId.Const
|
|
||||||
&& _BinaryenExpressionGetType(expr) == NativeType.I32;
|
|
||||||
}
|
|
||||||
|
2
std/portable.d.ts
vendored
2
std/portable.d.ts
vendored
@ -183,6 +183,8 @@ declare function bswap16<T = i16 | u16 | i32 | u32>(value: T): T;
|
|||||||
|
|
||||||
/** Changes the type of any value of `usize` kind to another one of `usize` kind. Useful for casting class instances to their pointer values and vice-versa. Beware that this is unsafe.*/
|
/** Changes the type of any value of `usize` kind to another one of `usize` kind. Useful for casting class instances to their pointer values and vice-versa. Beware that this is unsafe.*/
|
||||||
declare function changetype<T>(value: any): T;
|
declare function changetype<T>(value: any): T;
|
||||||
|
/** Explicitly requests no bounds checks on the provided expression. Useful for array accesses. */
|
||||||
|
declare function unchecked<T>(value: T): T;
|
||||||
/** Tests if a 32-bit or 64-bit float is `NaN`. */
|
/** Tests if a 32-bit or 64-bit float is `NaN`. */
|
||||||
declare function isNaN<T = f32 | f64>(value: T): bool;
|
declare function isNaN<T = f32 | f64>(value: T): bool;
|
||||||
/** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */
|
/** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */
|
||||||
|
@ -202,6 +202,10 @@ globalScope["isString"] = function isString(arg) {
|
|||||||
|
|
||||||
globalScope["isArray"] = Array.isArray;
|
globalScope["isArray"] = Array.isArray;
|
||||||
|
|
||||||
|
globalScope["unchecked"] = function(expr) {
|
||||||
|
return expr;
|
||||||
|
};
|
||||||
|
|
||||||
globalScope["fmod"] = function fmod(x, y) {
|
globalScope["fmod"] = function fmod(x, y) {
|
||||||
return x % y;
|
return x % y;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user