mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +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) {
|
||||
$0 = $0 | 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;
|
||||
$8 = HEAP32[($2 + 4 | 0) >> 2] | 0;
|
||||
continue_0 : do {
|
||||
@ -193,17 +193,16 @@ function asmFunc(global, env, buffer) {
|
||||
} while (1);
|
||||
$2 = $1;
|
||||
$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();
|
||||
$2 = $10;
|
||||
if (0 >>> 0 < ((HEAP32[$2 >> 2] | 0) >>> 2 | 0) >>> 0) $9 = HEAPU32[(($2 + 0 | 0) + 8 | 0) >> 2] | 0; else abort();
|
||||
$2 = $9;
|
||||
HEAPF64[($2 + 24 | 0) >> 3] = -$5 / 39.47841760435743;
|
||||
HEAPF64[($2 + 32 | 0) >> 3] = -$6 / 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;
|
||||
HEAP32[$0 >> 2] = $1;
|
||||
$8 = $0;
|
||||
}
|
||||
return $8 | 0;
|
||||
return $0 | 0;
|
||||
}
|
||||
|
||||
function assembly_index_init() {
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
require("allocator/arena");
|
||||
// From The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org
|
||||
const SOLAR_MASS = 4.0 * Math.PI * Math.PI;
|
||||
const DAYS_PER_YEAR = 365.24;
|
||||
class Body {
|
||||
@ -37,25 +39,27 @@ function Neptune() {
|
||||
}
|
||||
class NBodySystem {
|
||||
constructor(bodies) {
|
||||
this.bodies = bodies;
|
||||
var px = 0.0;
|
||||
var py = 0.0;
|
||||
var pz = 0.0;
|
||||
var size = bodies.length;
|
||||
for (let i = 0; i < size; i++) {
|
||||
let b = bodies[i];
|
||||
let b = unchecked(bodies[i]);
|
||||
let m = b.mass;
|
||||
px += b.vx * m;
|
||||
py += b.vy * m;
|
||||
pz += b.vz * m;
|
||||
}
|
||||
this.bodies = bodies;
|
||||
this.bodies[0].offsetMomentum(px, py, pz);
|
||||
bodies[0].offsetMomentum(px, py, pz);
|
||||
}
|
||||
advance(dt) {
|
||||
var bodies = this.bodies;
|
||||
var size = bodies.length;
|
||||
// var buffer = changetype<usize>(bodies.buffer_);
|
||||
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 iy = bodyi.y;
|
||||
let iz = bodyi.z;
|
||||
@ -64,7 +68,8 @@ class NBodySystem {
|
||||
let bivz = bodyi.vz;
|
||||
let bodyim = bodyi.mass;
|
||||
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 dy = iy - bodyj.y;
|
||||
let dz = iz - bodyj.z;
|
||||
@ -91,9 +96,8 @@ class NBodySystem {
|
||||
energy() {
|
||||
var e = 0.0;
|
||||
var bodies = this.bodies;
|
||||
var size = bodies.length;
|
||||
for (let i = 0; i < size; ++i) {
|
||||
let bodyi = bodies[i];
|
||||
for (let i = 0, size = bodies.length; i < size; ++i) {
|
||||
let bodyi = unchecked(bodies[i]);
|
||||
let ix = bodyi.x;
|
||||
let iy = bodyi.y;
|
||||
let iz = bodyi.z;
|
||||
|
Binary file not shown.
@ -706,21 +706,20 @@
|
||||
(f64.const 39.47841760435743)
|
||||
)
|
||||
)
|
||||
(if (result i32)
|
||||
(get_local $0)
|
||||
(get_local $0)
|
||||
(block (result i32)
|
||||
(i32.store
|
||||
(tee_local $0
|
||||
(call $~lib/allocator/arena/allocate_memory
|
||||
(i32.const 4)
|
||||
)
|
||||
)
|
||||
(get_local $1)
|
||||
)
|
||||
(if
|
||||
(i32.eqz
|
||||
(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)
|
||||
(local $0 i32)
|
||||
|
@ -25,7 +25,12 @@ var nbodyASMJS = eval("0," + src)({
|
||||
|
||||
// Load JS version
|
||||
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) {
|
||||
nbody.init();
|
||||
|
@ -5,9 +5,7 @@
|
||||
|
||||
import {
|
||||
Compiler,
|
||||
ConversionKind,
|
||||
|
||||
makeSmallIntegerWrap
|
||||
ConversionKind
|
||||
} from "./compiler";
|
||||
|
||||
import {
|
||||
@ -383,10 +381,9 @@ export function compileCall(
|
||||
case TypeKind.U8:
|
||||
case TypeKind.U16:
|
||||
case TypeKind.BOOL: {
|
||||
ret = makeSmallIntegerWrap(
|
||||
ret = compiler.makeSmallIntegerWrap(
|
||||
module.createBinary(BinaryOp.RotlI32, arg0, arg1),
|
||||
compiler.currentType,
|
||||
module
|
||||
compiler.currentType
|
||||
);
|
||||
// fall-through
|
||||
}
|
||||
@ -469,10 +466,9 @@ export function compileCall(
|
||||
case TypeKind.U8:
|
||||
case TypeKind.U16:
|
||||
case TypeKind.BOOL: {
|
||||
ret = makeSmallIntegerWrap(
|
||||
ret = compiler.makeSmallIntegerWrap(
|
||||
module.createBinary(BinaryOp.RotrI32, arg0, arg1),
|
||||
compiler.currentType,
|
||||
module
|
||||
compiler.currentType
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
517
src/compiler.ts
517
src/compiler.ts
@ -886,7 +886,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
stmt = module.createBlock(null, [
|
||||
stmt,
|
||||
module.createTeeLocal(0,
|
||||
makeConditionalAllocate(this, <Class>parent, declaration.name)
|
||||
this.makeConditionalAllocate(<Class>parent, declaration.name)
|
||||
)
|
||||
], nativeSizeType);
|
||||
}
|
||||
@ -1421,9 +1421,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.options.sourceMap) {
|
||||
addDebugLocation(expr, statement.range, module, this.currentFunction);
|
||||
}
|
||||
if (this.options.sourceMap) this.addDebugLocation(expr, statement.range);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -1529,10 +1527,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
flow.continueLabel = previousContinueLabel;
|
||||
|
||||
var module = this.module;
|
||||
var condExpr = makeIsTrueish(
|
||||
var condExpr = this.makeIsTrueish(
|
||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
module
|
||||
this.currentType
|
||||
);
|
||||
|
||||
// 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;
|
||||
|
||||
// The condition doesn't initiate a branch yet
|
||||
var condExpr = makeIsTrueish(
|
||||
var condExpr = this.makeIsTrueish(
|
||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
module
|
||||
this.currentType
|
||||
);
|
||||
|
||||
if (
|
||||
@ -1652,10 +1648,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// Otherwise recompile to the original and let the optimizer decide
|
||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||
condExpr = makeIsTrueish(
|
||||
condExpr = this.makeIsTrueish(
|
||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
module
|
||||
this.currentType
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1995,10 +1990,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var module = this.module;
|
||||
|
||||
// The condition does not yet initialize a branch
|
||||
var condExpr = makeIsTrueish(
|
||||
var condExpr = this.makeIsTrueish(
|
||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
module
|
||||
this.currentType
|
||||
);
|
||||
|
||||
if (
|
||||
@ -2015,10 +2009,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// Otherwise recompile to the original and let the optimizer decide
|
||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||
condExpr = makeIsTrueish(
|
||||
condExpr = this.makeIsTrueish(
|
||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
module
|
||||
this.currentType
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -2246,9 +2239,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.currentType = contextualType;
|
||||
}
|
||||
|
||||
if (this.options.sourceMap) {
|
||||
addDebugLocation(expr, expression.range, this.module, this.currentFunction);
|
||||
}
|
||||
if (this.options.sourceMap) this.addDebugLocation(expr, expression.range);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -2359,14 +2350,14 @@ export class Compiler extends DiagnosticEmitter {
|
||||
expr = module.createUnary(UnaryOp.TruncF32ToI64, expr);
|
||||
} else {
|
||||
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 {
|
||||
if (toType.is(TypeFlags.LONG)) {
|
||||
expr = module.createUnary(UnaryOp.TruncF32ToU64, expr);
|
||||
} else {
|
||||
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);
|
||||
} else {
|
||||
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 {
|
||||
if (toType.is(TypeFlags.LONG)) {
|
||||
expr = module.createUnary(UnaryOp.TruncF64ToU64, expr);
|
||||
} else {
|
||||
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
|
||||
if (!toType.is(TypeFlags.LONG)) {
|
||||
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
|
||||
@ -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
|
||||
@ -4123,7 +4114,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
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
|
||||
if (expr) {
|
||||
@ -4169,7 +4160,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
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
|
||||
if (expr) {
|
||||
@ -4205,7 +4196,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
if (possiblyOverflows && wrapSmallIntegers) {
|
||||
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
|
||||
? 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
|
||||
this.currentType = thisType;
|
||||
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
|
||||
} else {
|
||||
expr = makeAllocate(this, classInstance, expression);
|
||||
expr = this.makeAllocate(classInstance, expression);
|
||||
}
|
||||
|
||||
this.currentType = classInstance.type;
|
||||
@ -6092,10 +6083,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var ifElse = expression.ifElse;
|
||||
var currentFunction = this.currentFunction;
|
||||
|
||||
var condExpr = makeIsTrueish(
|
||||
var condExpr = this.makeIsTrueish(
|
||||
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
this.module
|
||||
this.currentType
|
||||
);
|
||||
|
||||
if (
|
||||
@ -6114,10 +6104,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// Otherwise recompile to the original and let the optimizer decide
|
||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||
condExpr = makeIsTrueish(
|
||||
condExpr = this.makeIsTrueish(
|
||||
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
this.module
|
||||
this.currentType
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -6347,7 +6336,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
if (possiblyOverflows) {
|
||||
assert(currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER));
|
||||
setValue = makeSmallIntegerWrap(setValue, currentType, module);
|
||||
setValue = this.makeSmallIntegerWrap(setValue, currentType);
|
||||
}
|
||||
|
||||
setValue = this.compileAssignmentWithValue(expression.operand, setValue, false);
|
||||
@ -6373,15 +6362,13 @@ export class Compiler extends DiagnosticEmitter {
|
||||
wrapSmallIntegers: bool = true
|
||||
): ExpressionRef {
|
||||
var module = this.module;
|
||||
var currentType = this.currentType;
|
||||
|
||||
var possiblyOverflows = false;
|
||||
var compound = false;
|
||||
var expr: ExpressionRef;
|
||||
|
||||
switch (expression.operator) {
|
||||
case Token.PLUS: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6396,12 +6383,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
ConversionKind.NONE,
|
||||
false // wrapped below
|
||||
);
|
||||
currentType = this.currentType;
|
||||
possiblyOverflows = currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER); // if operand already did
|
||||
possiblyOverflows = this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER); // if operand already did
|
||||
break;
|
||||
}
|
||||
case Token.MINUS: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6414,11 +6400,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
)) {
|
||||
// implicitly negate integer and float literals. also enables proper checking of literal ranges.
|
||||
expr = this.compileLiteralExpression(<LiteralExpression>expression.operand, contextualType, true);
|
||||
if (this.options.sourceMap) {
|
||||
// compileExpression normally does this
|
||||
addDebugLocation(expr, expression.range, module, this.currentFunction);
|
||||
}
|
||||
currentType = this.currentType;
|
||||
// compileExpression normally does this:
|
||||
if (this.options.sourceMap) this.addDebugLocation(expr, expression.range);
|
||||
} else {
|
||||
expr = this.compileExpression(
|
||||
expression.operand,
|
||||
@ -6428,8 +6411,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
ConversionKind.NONE,
|
||||
false // wrapped below
|
||||
);
|
||||
currentType = this.currentType;
|
||||
switch (currentType.kind) {
|
||||
switch (this.currentType.kind) {
|
||||
case TypeKind.I8:
|
||||
case TypeKind.I16:
|
||||
case TypeKind.U8:
|
||||
@ -6440,7 +6422,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
case TypeKind.USIZE: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6454,7 +6436,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.options.isWasm64
|
||||
? BinaryOp.SubI64
|
||||
: BinaryOp.SubI32,
|
||||
currentType.toNativeZero(module),
|
||||
this.currentType.toNativeZero(module),
|
||||
expr
|
||||
);
|
||||
break;
|
||||
@ -6477,7 +6459,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
case Token.PLUS_PLUS: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6493,8 +6475,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
ConversionKind.NONE,
|
||||
false // wrapped below
|
||||
);
|
||||
currentType = this.currentType;
|
||||
switch (currentType.kind) {
|
||||
switch (this.currentType.kind) {
|
||||
case TypeKind.I8:
|
||||
case TypeKind.I16:
|
||||
case TypeKind.U8:
|
||||
@ -6505,7 +6486,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
case TypeKind.USIZE: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6520,7 +6501,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
? BinaryOp.AddI64
|
||||
: BinaryOp.AddI32,
|
||||
expr,
|
||||
currentType.toNativeOne(module)
|
||||
this.currentType.toNativeOne(module)
|
||||
);
|
||||
break;
|
||||
}
|
||||
@ -6541,7 +6522,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
case Token.MINUS_MINUS: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6557,8 +6538,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
ConversionKind.NONE,
|
||||
false // wrapped below
|
||||
);
|
||||
currentType = this.currentType;
|
||||
switch (currentType.kind) {
|
||||
switch (this.currentType.kind) {
|
||||
case TypeKind.I8:
|
||||
case TypeKind.I16:
|
||||
case TypeKind.U8:
|
||||
@ -6569,7 +6549,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
case TypeKind.USIZE: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6584,7 +6564,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
? BinaryOp.SubI64
|
||||
: BinaryOp.SubI32,
|
||||
expr,
|
||||
currentType.toNativeOne(module)
|
||||
this.currentType.toNativeOne(module)
|
||||
);
|
||||
break;
|
||||
}
|
||||
@ -6613,12 +6593,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
ConversionKind.NONE,
|
||||
true // must wrap small integers
|
||||
);
|
||||
expr = makeIsFalseish(expr, this.currentType, module);
|
||||
expr = this.makeIsFalseish(expr, this.currentType);
|
||||
this.currentType = Type.bool;
|
||||
break;
|
||||
}
|
||||
case Token.TILDE: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6637,8 +6617,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
: ConversionKind.IMPLICIT,
|
||||
false // retains low bits of small integers
|
||||
);
|
||||
currentType = this.currentType;
|
||||
switch (currentType.kind) {
|
||||
switch (this.currentType.kind) {
|
||||
case TypeKind.I8:
|
||||
case TypeKind.I16:
|
||||
case TypeKind.U8:
|
||||
@ -6649,7 +6628,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
}
|
||||
case TypeKind.USIZE: {
|
||||
if (currentType.is(TypeFlags.REFERENCE)) {
|
||||
if (this.currentType.is(TypeFlags.REFERENCE)) {
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
expression.range
|
||||
@ -6664,7 +6643,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
? BinaryOp.XorI64
|
||||
: BinaryOp.XorI32,
|
||||
expr,
|
||||
currentType.toNativeNegOne(module)
|
||||
this.currentType.toNativeNegOne(module)
|
||||
);
|
||||
break;
|
||||
}
|
||||
@ -6698,13 +6677,208 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
if (possiblyOverflows && wrapSmallIntegers) {
|
||||
assert(currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER));
|
||||
expr = makeSmallIntegerWrap(expr, currentType, module);
|
||||
assert(this.currentType.is(TypeFlags.SHORT | TypeFlags.INTEGER));
|
||||
expr = this.makeSmallIntegerWrap(expr, this.currentType);
|
||||
}
|
||||
return compound
|
||||
? this.compileAssignmentWithValue(expression.operand, expr, contextualType != Type.void)
|
||||
: 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
|
||||
@ -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.*/
|
||||
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`. */
|
||||
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`. */
|
||||
|
@ -202,6 +202,10 @@ globalScope["isString"] = function isString(arg) {
|
||||
|
||||
globalScope["isArray"] = Array.isArray;
|
||||
|
||||
globalScope["unchecked"] = function(expr) {
|
||||
return expr;
|
||||
};
|
||||
|
||||
globalScope["fmod"] = function fmod(x, y) {
|
||||
return x % y;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user