Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"test": "npm run test:all",
"test:all": "npm run test:prebuild && npm run test:ava",
"test:ava": "ava",
"test:integration": "npx ts-node ./tests/integration/precision.ts",
"test:example": "npx ts-node ./tests/examples/example.ts",
"coverage:test:ava": "c8 --src src/ --all ava"
},
Expand Down
11 changes: 8 additions & 3 deletions src/messaging/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {SourceMap} from '../sourcemap/SourceMap';
import {readFileSync} from 'fs';
import {CompileOutput, CompilerFactory} from '../manage/Compiler';
import {WABT} from '../util/env';
import {encodeSLEB128, encodeULEB128} from '@thi.ng/leb128';
import Interrupt = WARDuino.Interrupt;
import State = WARDuino.State;
import Value = WASM.Value;
Expand Down Expand Up @@ -139,7 +140,7 @@ export namespace Message {
export function updateModule(wasm: string): Request<Ack> {
function payload(binary: Buffer): string {
const w = new Uint8Array(binary);
const sizeHex: string = WASM.leb128(BigInt(w.length));
const sizeHex = Buffer.from(encodeULEB128(w.length)).toString('hex');
const sizeBuffer = Buffer.allocUnsafe(4);
sizeBuffer.writeUint32BE(w.length);
const wasmHex = Buffer.from(w).toString('hex');
Expand Down Expand Up @@ -181,16 +182,20 @@ export namespace Message {
const buff = Buffer.alloc(arg.type === Float.f32 ? 4 : 8);
write(buff, Number(arg.value), 0, true, arg.type === Float.f32 ? 23 : 52, buff.length); // todo fix precision loss
payload += buff.toString('hex');
} else if (arg.type === WASM.Integer.i32 || arg.type === WASM.Integer.i64) {
payload += Buffer.from(encodeSLEB128((arg.value as WASM.WasmInt).toBigInt())).toString('hex');
} else if (arg.type === WASM.Integer.u32 || arg.type === WASM.Integer.u64) {
payload += Buffer.from(encodeULEB128((arg.value as WASM.WasmInt).toBigInt())).toString('hex');
} else {
payload += WASM.leb128(<number>arg.value);
throw Error(`Cannot invoke a function with a ${arg.type} argument.`);
}
});
return payload;
}

return {
type: Interrupt.invoke,
payload: (map: SourceMap.Mapping) => `${WASM.leb128(BigInt(fidx(map, func)))}${convert(args)}`,
payload: (map: SourceMap.Mapping) => `${Buffer.from(encodeULEB128(fidx(map, func))).toString('hex')}${convert(args)}`,
parser: invokeParser
}
}
Expand Down
20 changes: 1 addition & 19 deletions src/sourcemap/Wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,22 +178,4 @@ export namespace WASM {
bytes: Uint8Array;
}

export function leb128(value: bigint | number): string { // TODO can only handle 32 bit
let a = Number(value);
a |= 0;
const result = [];
while (true) {
const byte_ = a & 0x7f;
a >>= 7;
if (
(a === 0 && (byte_ & 0x40) === 0) ||
(a === -1 && (byte_ & 0x40) !== 0)
) {
result.push(byte_.toString(16).padStart(2, '0'));
return result.join('').toUpperCase();
}
result.push((byte_ | 0x80).toString(16).padStart(2, '0'));
}
}

}
}
28 changes: 28 additions & 0 deletions tests/integration/precision.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
EmulatorSpecification,
Framework,
Invoker,
Verbosity,
WASM
} from '../../src/index';

const framework = Framework.getImplementation();

const precision = framework.suite('Test i64 precision');

precision.testee('emulator[:8100]', new EmulatorSpecification(8100));

precision.test({
title: 'i64 rem_s returns zero for INT64_MIN modulo -1',
program: 'tests/integration/precision.wast',
dependencies: [],
steps: [
new Invoker('rem_s', [
WASM.i64(-9223372036854775808n),
WASM.i64(-1n)
], WASM.i64(0n))
]
});

framework.reporter.verbosity(Verbosity.more);
framework.analyse([precision]);
37 changes: 37 additions & 0 deletions tests/integration/precision.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
(module
(func (export "add") (param $x i64) (param $y i64) (result i64) (i64.add (local.get $x) (local.get $y)))
(func (export "sub") (param $x i64) (param $y i64) (result i64) (i64.sub (local.get $x) (local.get $y)))
(func (export "mul") (param $x i64) (param $y i64) (result i64) (i64.mul (local.get $x) (local.get $y)))
(func (export "div_s") (param $x i64) (param $y i64) (result i64) (i64.div_s (local.get $x) (local.get $y)))
(func (export "div_u") (param $x i64) (param $y i64) (result i64) (i64.div_u (local.get $x) (local.get $y)))
(func (export "rem_s") (param $x i64) (param $y i64) (result i64) (i64.rem_s (local.get $x) (local.get $y)))
(func (export "rem_u") (param $x i64) (param $y i64) (result i64) (i64.rem_u (local.get $x) (local.get $y)))
(func (export "and") (param $x i64) (param $y i64) (result i64) (i64.and (local.get $x) (local.get $y)))
(func (export "or") (param $x i64) (param $y i64) (result i64) (i64.or (local.get $x) (local.get $y)))
(func (export "xor") (param $x i64) (param $y i64) (result i64) (i64.xor (local.get $x) (local.get $y)))
(func (export "shl") (param $x i64) (param $y i64) (result i64) (i64.shl (local.get $x) (local.get $y)))
(func (export "shr_s") (param $x i64) (param $y i64) (result i64) (i64.shr_s (local.get $x) (local.get $y)))
(func (export "shr_u") (param $x i64) (param $y i64) (result i64) (i64.shr_u (local.get $x) (local.get $y)))
(func (export "rotl") (param $x i64) (param $y i64) (result i64) (i64.rotl (local.get $x) (local.get $y)))
(func (export "rotr") (param $x i64) (param $y i64) (result i64) (i64.rotr (local.get $x) (local.get $y)))
(func (export "clz") (param $x i64) (result i64) (i64.clz (local.get $x)))
(func (export "ctz") (param $x i64) (result i64) (i64.ctz (local.get $x)))
(func (export "popcnt") (param $x i64) (result i64) (i64.popcnt (local.get $x)))
(func (export "extend8_s") (param $x i64) (result i64) (i64.extend8_s (local.get $x)))
(func (export "extend16_s") (param $x i64) (result i64) (i64.extend16_s (local.get $x)))
(func (export "extend32_s") (param $x i64) (result i64) (i64.extend32_s (local.get $x)))
(func (export "eqz") (param $x i64) (result i32) (i64.eqz (local.get $x)))
(func (export "eq") (param $x i64) (param $y i64) (result i32) (i64.eq (local.get $x) (local.get $y)))
(func (export "ne") (param $x i64) (param $y i64) (result i32) (i64.ne (local.get $x) (local.get $y)))
(func (export "lt_s") (param $x i64) (param $y i64) (result i32) (i64.lt_s (local.get $x) (local.get $y)))
(func (export "lt_u") (param $x i64) (param $y i64) (result i32) (i64.lt_u (local.get $x) (local.get $y)))
(func (export "le_s") (param $x i64) (param $y i64) (result i32) (i64.le_s (local.get $x) (local.get $y)))
(func (export "le_u") (param $x i64) (param $y i64) (result i32) (i64.le_u (local.get $x) (local.get $y)))
(func (export "gt_s") (param $x i64) (param $y i64) (result i32) (i64.gt_s (local.get $x) (local.get $y)))
(func (export "gt_u") (param $x i64) (param $y i64) (result i32) (i64.gt_u (local.get $x) (local.get $y)))
(func (export "ge_s") (param $x i64) (param $y i64) (result i32) (i64.ge_s (local.get $x) (local.get $y)))
(func (export "ge_u") (param $x i64) (param $y i64) (result i32) (i64.ge_u (local.get $x) (local.get $y)))
(func (export "i64_get_max") (result i64) (i64.const 9223372036854775807))
(func (export "i64_eq_max") (param i64) (result i32) (i64.eq (local.get 0) (i64.const 9223372036854775807)))
(func (export "i64_eq_max_wrong") (param i64) (result i32) (i64.eq (local.get 0) (i64.const 9223372036854776000)))
)
20 changes: 19 additions & 1 deletion tests/unit/messaging.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import test from 'ava';
import {MessageQueue} from '../../src/messaging/MessageQueue';
import {Message} from '../../src/messaging/Message';
import {WASM} from '../../src/sourcemap/Wasm';
import {SourceMap} from '../../src/sourcemap/SourceMap';

const alphanumerical = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');

test('[Message.invoke] : encode 64-bit integer arguments without precision loss', t => {
const mapping = new SourceMap.Mapping().init([], [{
index: 0,
name: 'rem_s',
arguments: [],
locals: []
}], [], []);
const request = Message.invoke('rem_s', [
WASM.i64(-9223372036854775808n),
WASM.i64(-1n)
]);

t.is(request.payload!(mapping), '008080808080808080807f7f');
});

test('[MessageQueue] : test EOM detection', t => {
const fuzzer = fuzzy(alphanumerical);
const newline = new MessageQueue('\n');
Expand Down Expand Up @@ -75,4 +93,4 @@ const fuzzy = (characters: string[]): (n: number) => string => {
}
return result;
};
}
}
16 changes: 1 addition & 15 deletions tests/unit/sourcemap.test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import test from 'ava';
import {WASM} from '../../src/sourcemap/Wasm';
import {WatMapper} from '../../src/sourcemap/SourceMapper';
import {SourceMap} from '../../src/sourcemap/SourceMap';
import {WABT} from '../../src/util/env';
import {copyFileSync, mkdtempSync, readFileSync, rmSync} from 'fs';

const artifacts = `${__dirname}/../../../tests/artifacts`;

/**
* Check LEB 128 encoding
*/
test('[leb128] : test encoding', t => {
t.is(WASM.leb128(0n), '00');
t.is(WASM.leb128(1n), '01');
t.is(WASM.leb128(8n), '08');
t.is(WASM.leb128(32n), '20');
t.is(WASM.leb128(64n), 'C000');
t.is(WASM.leb128(128n), '8001');
t.is(WASM.leb128(1202n), 'B209');
});

test('[extractLineInfo] : test against artifacts (1)', async t => {
await check(`${artifacts}/compile.output`, (mapping: SourceMap.Mapping) => {
// check line information
Expand Down Expand Up @@ -81,4 +67,4 @@ function initialize(): string {
const tmp: string = mkdtempSync('test');
copyFileSync(`${artifacts}/upload.wasm`, `${tmp}/upload.wasm`);
return tmp;
}
}
Loading