@fluffylabs/anan-as 1.2.0 → 1.3.0-5cbd3aa
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/index.js +138 -5
- package/dist/bin/src/fuzz.js +2 -2
- package/dist/bin/src/test-json.js +2 -6
- package/dist/bin/src/trace-parse.js +1 -0
- package/dist/bin/src/trace-replay.js +14 -9
- package/dist/bin/src/tracer.js +16 -13
- package/dist/bin/src/utils.js +2 -2
- package/dist/build/compiler-inline.js +1 -1
- package/dist/build/compiler.d.ts +17 -13
- package/dist/build/compiler.js +13 -21
- package/dist/build/compiler.wasm +0 -0
- package/dist/build/debug-inline.js +1 -1
- package/dist/build/debug-raw-inline.js +1 -1
- package/dist/build/debug-raw.d.ts +50 -112
- package/dist/build/debug-raw.js +78 -139
- package/dist/build/debug-raw.wasm +0 -0
- package/dist/build/debug.d.ts +50 -112
- package/dist/build/debug.js +81 -147
- package/dist/build/debug.wasm +0 -0
- package/dist/build/js/assembly/api-debugger.d.ts +55 -0
- package/dist/build/js/assembly/api-debugger.js +245 -0
- package/dist/build/js/assembly/api-internal.d.ts +13 -0
- package/dist/build/js/assembly/api-internal.js +191 -0
- package/dist/build/js/assembly/api-types.d.ts +45 -0
- package/dist/build/js/assembly/api-types.js +52 -0
- package/dist/build/js/assembly/api-utils.d.ts +79 -0
- package/dist/build/js/assembly/api-utils.js +221 -0
- package/dist/build/js/assembly/arguments.d.ts +44 -0
- package/dist/build/js/assembly/arguments.js +164 -0
- package/dist/build/js/assembly/codec.d.ts +24 -0
- package/dist/build/js/assembly/codec.js +139 -0
- package/dist/build/js/assembly/gas.d.ts +11 -0
- package/dist/build/js/assembly/gas.js +33 -0
- package/dist/build/js/assembly/index-shared.d.ts +4 -0
- package/dist/build/js/assembly/index-shared.js +4 -0
- package/dist/build/js/assembly/instructions/bit.d.ts +11 -0
- package/dist/build/js/assembly/instructions/bit.js +53 -0
- package/dist/build/js/assembly/instructions/branch.d.ts +17 -0
- package/dist/build/js/assembly/instructions/branch.js +120 -0
- package/dist/build/js/assembly/instructions/jump.d.ts +5 -0
- package/dist/build/js/assembly/instructions/jump.js +21 -0
- package/dist/build/js/assembly/instructions/load.d.ts +17 -0
- package/dist/build/js/assembly/instructions/load.js +134 -0
- package/dist/build/js/assembly/instructions/logic.d.ts +10 -0
- package/dist/build/js/assembly/instructions/logic.js +47 -0
- package/dist/build/js/assembly/instructions/math.d.ts +28 -0
- package/dist/build/js/assembly/instructions/math.js +225 -0
- package/dist/build/js/assembly/instructions/misc.d.ts +6 -0
- package/dist/build/js/assembly/instructions/misc.js +22 -0
- package/dist/build/js/assembly/instructions/mov.d.ts +6 -0
- package/dist/build/js/assembly/instructions/mov.js +35 -0
- package/dist/build/js/assembly/instructions/outcome.d.ts +30 -0
- package/dist/build/js/assembly/instructions/outcome.js +88 -0
- package/dist/build/js/assembly/instructions/rot.d.ts +15 -0
- package/dist/build/js/assembly/instructions/rot.js +66 -0
- package/dist/build/js/assembly/instructions/set.d.ts +7 -0
- package/dist/build/js/assembly/instructions/set.js +36 -0
- package/dist/build/js/assembly/instructions/shift.d.ts +19 -0
- package/dist/build/js/assembly/instructions/shift.js +121 -0
- package/dist/build/js/assembly/instructions/store.d.ts +17 -0
- package/dist/build/js/assembly/instructions/store.js +101 -0
- package/dist/build/js/assembly/instructions/utils.d.ts +25 -0
- package/dist/build/js/assembly/instructions/utils.js +91 -0
- package/dist/build/js/assembly/instructions-exe.d.ts +2 -0
- package/dist/build/js/assembly/instructions-exe.js +245 -0
- package/dist/build/js/assembly/instructions.d.ts +10 -0
- package/dist/build/js/assembly/instructions.js +252 -0
- package/dist/build/js/assembly/interpreter.d.ts +28 -0
- package/dist/build/js/assembly/interpreter.js +221 -0
- package/dist/build/js/assembly/math.d.ts +6 -0
- package/dist/build/js/assembly/math.js +22 -0
- package/dist/build/js/assembly/memory-page.d.ts +36 -0
- package/dist/build/js/assembly/memory-page.js +74 -0
- package/dist/build/js/assembly/memory.d.ts +83 -0
- package/dist/build/js/assembly/memory.js +482 -0
- package/dist/build/js/assembly/portable.d.ts +24 -0
- package/dist/build/js/assembly/portable.js +363 -0
- package/dist/build/js/assembly/program-build.d.ts +2 -0
- package/dist/build/js/assembly/program-build.js +104 -0
- package/dist/build/js/assembly/program.d.ts +85 -0
- package/dist/build/js/assembly/program.js +340 -0
- package/dist/build/js/assembly/registers.d.ts +6 -0
- package/dist/build/js/assembly/registers.js +9 -0
- package/dist/build/js/assembly/spi.d.ts +92 -0
- package/dist/build/js/assembly/spi.js +152 -0
- package/dist/build/js/portable/bootstrap.d.ts +1 -0
- package/dist/build/js/portable/bootstrap.js +6 -0
- package/dist/build/js/portable/index.d.ts +4 -0
- package/dist/build/js/portable/index.js +6 -0
- package/dist/build/js/portable-bundle.js +4497 -0
- package/dist/build/release-inline.js +1 -1
- package/dist/build/release-mini-inline.js +1 -1
- package/dist/build/release-mini.d.ts +50 -112
- package/dist/build/release-mini.js +81 -147
- package/dist/build/release-mini.wasm +0 -0
- package/dist/build/release-stub-inline.js +1 -1
- package/dist/build/release-stub.d.ts +50 -112
- package/dist/build/release-stub.js +81 -147
- package/dist/build/release-stub.wasm +0 -0
- package/dist/build/release.d.ts +50 -112
- package/dist/build/release.js +81 -147
- package/dist/build/release.wasm +0 -0
- package/dist/build/test-inline.js +1 -1
- package/dist/build/test.wasm +0 -0
- package/dist/test/test-gas-cost.js +2 -3
- package/dist/test/test-trace-format.js +166 -0
- package/dist/test/test-w3f-common.js +125 -0
- package/dist/test/test-w3f-portable.js +5 -0
- package/dist/test/test-w3f.js +3 -120
- package/package.json +22 -11
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { buildMemory, getAssembly, vmDestroy, vmExecute, vmInit, vmRunOnce } from "./api-internal";
|
|
2
|
+
import { VmInput, VmPause, VmRunOptions } from "./api-types";
|
|
3
|
+
import { MaybePageFault, MemoryBuilder } from "./memory";
|
|
4
|
+
import { deblob, extractCodeAndMetadata, liftBytes } from "./program";
|
|
5
|
+
import { NO_OF_REGISTERS, newRegisters } from "./registers";
|
|
6
|
+
import { decodeSpi, StandardProgram } from "./spi";
|
|
7
|
+
export var InputKind;
|
|
8
|
+
(function (InputKind) {
|
|
9
|
+
InputKind[InputKind["Generic"] = 0] = "Generic";
|
|
10
|
+
InputKind[InputKind["SPI"] = 1] = "SPI";
|
|
11
|
+
})(InputKind || (InputKind = {}));
|
|
12
|
+
export var HasMetadata;
|
|
13
|
+
(function (HasMetadata) {
|
|
14
|
+
HasMetadata[HasMetadata["Yes"] = 0] = "Yes";
|
|
15
|
+
HasMetadata[HasMetadata["No"] = 1] = "No";
|
|
16
|
+
})(HasMetadata || (HasMetadata = {}));
|
|
17
|
+
class BlockGasCost {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.pc = 0;
|
|
20
|
+
this.gas = 0;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function getBlockGasCosts(input, kind, withMetadata) {
|
|
24
|
+
const program = prepareProgram(kind, withMetadata, input, [], [], [], [], 0, true);
|
|
25
|
+
const blockCosts = [];
|
|
26
|
+
const costs = program.program.gasCosts.codeAndGas;
|
|
27
|
+
for (let n = 0; n < costs.length; n += 1) {
|
|
28
|
+
const gas = costs[n] >> 8;
|
|
29
|
+
if (gas !== 0) {
|
|
30
|
+
const x = new BlockGasCost();
|
|
31
|
+
x.pc = n;
|
|
32
|
+
x.gas = costs[n];
|
|
33
|
+
blockCosts.push(x);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return blockCosts;
|
|
37
|
+
}
|
|
38
|
+
export function disassemble(input, kind, withMetadata) {
|
|
39
|
+
const program = prepareProgram(kind, withMetadata, input, [], [], [], [], 0, false);
|
|
40
|
+
let output = "";
|
|
41
|
+
if (withMetadata === HasMetadata.Yes) {
|
|
42
|
+
output = "Metadata: \n";
|
|
43
|
+
output += "0x";
|
|
44
|
+
output += program.metadata.reduce((acc, x) => acc + x.toString(16).padStart(2, "0"), "");
|
|
45
|
+
output += "\n\n";
|
|
46
|
+
}
|
|
47
|
+
output += getAssembly(program.program);
|
|
48
|
+
return output;
|
|
49
|
+
}
|
|
50
|
+
export function prepareProgram(kind, hasMetadata, program,
|
|
51
|
+
/** NOTE: ignored in case of SPI. */
|
|
52
|
+
initialRegisters,
|
|
53
|
+
/** NOTE: ignored in case of SPI. */
|
|
54
|
+
initialPageMap,
|
|
55
|
+
/** NOTE: ignored in case of SPI. */
|
|
56
|
+
initialMemory,
|
|
57
|
+
/** NOTE: ONLY needed for SPI. */
|
|
58
|
+
args,
|
|
59
|
+
/** Preallocate a bunch of memory pages for faster execution. */
|
|
60
|
+
preallocateMemoryPages,
|
|
61
|
+
/** Compute gas per-block instead of per-instruction. */
|
|
62
|
+
useBlockGas) {
|
|
63
|
+
let code = liftBytes(program);
|
|
64
|
+
let metadata = new Uint8Array(0);
|
|
65
|
+
if (hasMetadata === HasMetadata.Yes) {
|
|
66
|
+
const data = extractCodeAndMetadata(code);
|
|
67
|
+
// @ts-ignore: TS 5.9 Uint8Array generic parameter mismatch
|
|
68
|
+
code = data.code;
|
|
69
|
+
// @ts-ignore: TS 5.9 Uint8Array generic parameter mismatch
|
|
70
|
+
metadata = data.metadata;
|
|
71
|
+
}
|
|
72
|
+
if (kind === InputKind.Generic) {
|
|
73
|
+
const program = deblob(code, useBlockGas);
|
|
74
|
+
const builder = new MemoryBuilder(preallocateMemoryPages);
|
|
75
|
+
const memory = buildMemory(builder, initialPageMap, initialMemory);
|
|
76
|
+
const registers = newRegisters();
|
|
77
|
+
const safeLen = initialRegisters.length < NO_OF_REGISTERS ? initialRegisters.length : NO_OF_REGISTERS;
|
|
78
|
+
for (let r = 0; r < safeLen; r++) {
|
|
79
|
+
registers[r] = initialRegisters[r];
|
|
80
|
+
}
|
|
81
|
+
const exe = new StandardProgram(program, memory, registers);
|
|
82
|
+
exe.metadata = metadata;
|
|
83
|
+
return exe;
|
|
84
|
+
}
|
|
85
|
+
if (kind === InputKind.SPI) {
|
|
86
|
+
const exe = decodeSpi(code, liftBytes(args), preallocateMemoryPages);
|
|
87
|
+
exe.metadata = metadata;
|
|
88
|
+
return exe;
|
|
89
|
+
}
|
|
90
|
+
throw new Error(`Unknown kind: ${kind}`);
|
|
91
|
+
}
|
|
92
|
+
/** Execute PVM program and stop. */
|
|
93
|
+
export function runProgram(program, initialGas = 0, programCounter = 0, logs = false, dumpMemory = false) {
|
|
94
|
+
const vmInput = new VmInput(program.program, program.memory, program.registers);
|
|
95
|
+
vmInput.gas = i64(initialGas);
|
|
96
|
+
vmInput.pc = programCounter;
|
|
97
|
+
const vmOptions = new VmRunOptions();
|
|
98
|
+
vmOptions.logs = logs;
|
|
99
|
+
vmOptions.dumpMemory = dumpMemory;
|
|
100
|
+
return vmRunOnce(vmInput, vmOptions);
|
|
101
|
+
}
|
|
102
|
+
/** Next available pvm id. */
|
|
103
|
+
let nextPvmId = 0;
|
|
104
|
+
/** Currently allocated pvms. */
|
|
105
|
+
const pvms = new Map();
|
|
106
|
+
/**
|
|
107
|
+
* Allocate new PVM instance to execute given program.
|
|
108
|
+
*
|
|
109
|
+
* NOTE: the PVM MUST be de-allocated using `pvmDestroy`.
|
|
110
|
+
*/
|
|
111
|
+
export function pvmStart(program) {
|
|
112
|
+
const vmInput = new VmInput(program.program, program.memory, program.registers);
|
|
113
|
+
nextPvmId += 1;
|
|
114
|
+
pvms.set(nextPvmId, vmInit(vmInput));
|
|
115
|
+
return nextPvmId;
|
|
116
|
+
}
|
|
117
|
+
/** Deallocate PVM resources. */
|
|
118
|
+
export function pvmDestroy(pvmId) {
|
|
119
|
+
if (pvms.has(pvmId)) {
|
|
120
|
+
const int = pvms.get(pvmId);
|
|
121
|
+
pvms.delete(pvmId);
|
|
122
|
+
return vmDestroy(int, false);
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
/** Set register values of a paused PVM. */
|
|
127
|
+
export function pvmSetRegisters(pvmId, registers) {
|
|
128
|
+
if (pvms.has(pvmId)) {
|
|
129
|
+
const int = pvms.get(pvmId);
|
|
130
|
+
const safeIter = registers.length < NO_OF_REGISTERS ? registers.length : NO_OF_REGISTERS;
|
|
131
|
+
for (let i = 0; i < safeIter; i++) {
|
|
132
|
+
int.registers[i] = registers[i];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Read a continuous chunk of memory from given PVM instance.
|
|
138
|
+
*
|
|
139
|
+
* @deprecated Use `pvmGetPagePointer` instead to read memory directly from WASM linear memory
|
|
140
|
+
* on the JS side with no additional WASM-side allocations.
|
|
141
|
+
*/
|
|
142
|
+
export function pvmReadMemory(pvmId, address, length) {
|
|
143
|
+
if (pvms.has(pvmId)) {
|
|
144
|
+
const int = pvms.get(pvmId);
|
|
145
|
+
const faultRes = new MaybePageFault();
|
|
146
|
+
const result = int.memory.getMemory(faultRes, address, length);
|
|
147
|
+
if (!faultRes.isFault) {
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Returns the WASM linear memory pointer (byte offset) for the backing buffer of the page at `page`
|
|
155
|
+
* in the given PVM instance.
|
|
156
|
+
*
|
|
157
|
+
* Returns `0` if the PVM does not exist, the page does not exist, or the page is not readable.
|
|
158
|
+
*
|
|
159
|
+
* Use this instead of `pvmReadMemory` to read memory efficiently from the JS side:
|
|
160
|
+
* ```ts
|
|
161
|
+
* let pagesRead = 0;
|
|
162
|
+
* for (let address = start; address < end; address += PAGE_SIZE) {
|
|
163
|
+
* const page = address >> PAGE_SIZE_SHIFT;
|
|
164
|
+
* const ptr = pvmGetPagePointer(pvmId, page);
|
|
165
|
+
* if (ptr === 0) {
|
|
166
|
+
* throw new Error(`Page fault at ${page << PAGE_SIZE_SHIFT}`);
|
|
167
|
+
* }
|
|
168
|
+
* destination.set(
|
|
169
|
+
* new Uint8Array(wasm.instance.exports.memory.buffer, ptr, Math.min(end - address, PAGE_SIZE)),
|
|
170
|
+
* pagesRead << PAGE_SIZE_SHIFT,
|
|
171
|
+
* );
|
|
172
|
+
* pagesRead += 1;
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export function pvmGetPagePointer(pvmId, page) {
|
|
177
|
+
if (pvms.has(pvmId)) {
|
|
178
|
+
const int = pvms.get(pvmId);
|
|
179
|
+
return int.memory.getPagePointer(page);
|
|
180
|
+
}
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
/** Write a chunk of memory to given PVM instance. */
|
|
184
|
+
export function pvmWriteMemory(pvmId, address, data) {
|
|
185
|
+
if (pvms.has(pvmId)) {
|
|
186
|
+
const int = pvms.get(pvmId);
|
|
187
|
+
const faultRes = new MaybePageFault();
|
|
188
|
+
// Preflight: verify the entire target range is accessible before writing
|
|
189
|
+
const tempBuffer = new Uint8Array(data.length);
|
|
190
|
+
int.memory.bytesRead(faultRes, address, tempBuffer, 0);
|
|
191
|
+
if (faultRes.isFault) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
// Now perform the actual write
|
|
195
|
+
faultRes.isFault = false;
|
|
196
|
+
faultRes.isAccess = false;
|
|
197
|
+
int.memory.bytesWrite(faultRes, address, data, 0);
|
|
198
|
+
if (!faultRes.isFault) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
/** Resume execution of paused VM. */
|
|
205
|
+
export function pvmResume(pvmId, gas, pc, logs = false) {
|
|
206
|
+
if (pvms.has(pvmId)) {
|
|
207
|
+
const int = pvms.get(pvmId);
|
|
208
|
+
int.nextPc = pc;
|
|
209
|
+
int.gas.set(gas);
|
|
210
|
+
vmExecute(int, logs);
|
|
211
|
+
const pause = new VmPause();
|
|
212
|
+
pause.status = int.status;
|
|
213
|
+
pause.exitCode = int.exitCode;
|
|
214
|
+
pause.pc = int.pc;
|
|
215
|
+
pause.nextPc = int.nextPc;
|
|
216
|
+
pause.gas = int.gas.get();
|
|
217
|
+
pause.registers = int.registers.slice(0);
|
|
218
|
+
return pause;
|
|
219
|
+
}
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare enum Arguments {
|
|
2
|
+
Zero = 0,
|
|
3
|
+
OneImm = 1,
|
|
4
|
+
TwoImm = 2,
|
|
5
|
+
OneOff = 3,
|
|
6
|
+
OneRegOneImm = 4,
|
|
7
|
+
OneRegOneExtImm = 5,
|
|
8
|
+
OneRegTwoImm = 6,
|
|
9
|
+
OneRegOneImmOneOff = 7,
|
|
10
|
+
TwoReg = 8,
|
|
11
|
+
TwoRegOneImm = 9,
|
|
12
|
+
TwoRegOneOff = 10,
|
|
13
|
+
TwoRegTwoImm = 11,
|
|
14
|
+
ThreeReg = 12
|
|
15
|
+
}
|
|
16
|
+
/** How many numbers in `Args` is relevant for given `Arguments`. */
|
|
17
|
+
export declare const RELEVANT_ARGS: StaticArray<i32>;
|
|
18
|
+
/** How many bytes is required by given `Arguments`. */
|
|
19
|
+
export declare const REQUIRED_BYTES: StaticArray<i32>;
|
|
20
|
+
export declare class Args {
|
|
21
|
+
fill(a: u32, b?: u32, c?: u32, d?: u32): Args;
|
|
22
|
+
/**
|
|
23
|
+
* TwoReg: `omega_A`
|
|
24
|
+
* TwoRegOneOff: `omega_B`
|
|
25
|
+
* ThreeReg: `omega_B`
|
|
26
|
+
*/
|
|
27
|
+
a: u32;
|
|
28
|
+
/**
|
|
29
|
+
* TwoReg: `omega'_D`
|
|
30
|
+
* TwoRegOneOff: `omega'_A`
|
|
31
|
+
* ThreeReg: `omega_A`
|
|
32
|
+
*/
|
|
33
|
+
b: u32;
|
|
34
|
+
/**
|
|
35
|
+
* ThreeReg: `omega'_D`
|
|
36
|
+
*/
|
|
37
|
+
c: u32;
|
|
38
|
+
d: u32;
|
|
39
|
+
}
|
|
40
|
+
type ArgsDecoder = (args: Args, code: StaticArray<u8>, offset: u32, end: u32) => Args;
|
|
41
|
+
export declare const DECODERS: StaticArray<ArgsDecoder>;
|
|
42
|
+
export declare function lowNibble(byte: u8): u8;
|
|
43
|
+
export declare function higNibble(byte: u8): u8;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { IntMath } from "./math";
|
|
2
|
+
import { portable } from "./portable";
|
|
3
|
+
export var Arguments;
|
|
4
|
+
(function (Arguments) {
|
|
5
|
+
Arguments[Arguments["Zero"] = 0] = "Zero";
|
|
6
|
+
Arguments[Arguments["OneImm"] = 1] = "OneImm";
|
|
7
|
+
Arguments[Arguments["TwoImm"] = 2] = "TwoImm";
|
|
8
|
+
Arguments[Arguments["OneOff"] = 3] = "OneOff";
|
|
9
|
+
Arguments[Arguments["OneRegOneImm"] = 4] = "OneRegOneImm";
|
|
10
|
+
Arguments[Arguments["OneRegOneExtImm"] = 5] = "OneRegOneExtImm";
|
|
11
|
+
Arguments[Arguments["OneRegTwoImm"] = 6] = "OneRegTwoImm";
|
|
12
|
+
Arguments[Arguments["OneRegOneImmOneOff"] = 7] = "OneRegOneImmOneOff";
|
|
13
|
+
Arguments[Arguments["TwoReg"] = 8] = "TwoReg";
|
|
14
|
+
Arguments[Arguments["TwoRegOneImm"] = 9] = "TwoRegOneImm";
|
|
15
|
+
Arguments[Arguments["TwoRegOneOff"] = 10] = "TwoRegOneOff";
|
|
16
|
+
Arguments[Arguments["TwoRegTwoImm"] = 11] = "TwoRegTwoImm";
|
|
17
|
+
Arguments[Arguments["ThreeReg"] = 12] = "ThreeReg";
|
|
18
|
+
})(Arguments || (Arguments = {}));
|
|
19
|
+
/** How many numbers in `Args` is relevant for given `Arguments`. */
|
|
20
|
+
export const RELEVANT_ARGS = StaticArray.fromArray([0, 1, 2, 1, 2, 3, 3, 3, 2, 3, 3, 4, 3]);
|
|
21
|
+
/** How many bytes is required by given `Arguments`. */
|
|
22
|
+
export const REQUIRED_BYTES = StaticArray.fromArray([0, 0, 1, 0, 1, 9, 1, 1, 1, 1, 1, 2, 2]);
|
|
23
|
+
// @unmanaged
|
|
24
|
+
export class Args {
|
|
25
|
+
constructor() {
|
|
26
|
+
/**
|
|
27
|
+
* TwoReg: `omega_A`
|
|
28
|
+
* TwoRegOneOff: `omega_B`
|
|
29
|
+
* ThreeReg: `omega_B`
|
|
30
|
+
*/
|
|
31
|
+
this.a = 0;
|
|
32
|
+
/**
|
|
33
|
+
* TwoReg: `omega'_D`
|
|
34
|
+
* TwoRegOneOff: `omega'_A`
|
|
35
|
+
* ThreeReg: `omega_A`
|
|
36
|
+
*/
|
|
37
|
+
this.b = 0;
|
|
38
|
+
/**
|
|
39
|
+
* ThreeReg: `omega'_D`
|
|
40
|
+
*/
|
|
41
|
+
this.c = 0;
|
|
42
|
+
this.d = 0;
|
|
43
|
+
}
|
|
44
|
+
fill(a, b = 0, c = 0, d = 0) {
|
|
45
|
+
this.a = a;
|
|
46
|
+
this.b = b;
|
|
47
|
+
this.c = c;
|
|
48
|
+
this.d = d;
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function twoImm(args, code, offset, end) {
|
|
53
|
+
const low = lowNibble(portable.staticArrayAt(code, offset));
|
|
54
|
+
const split = IntMath.minI32(4, low) + 1;
|
|
55
|
+
const first = decodeI32(code, offset + 1, offset + split);
|
|
56
|
+
const second = decodeI32(code, offset + split, end);
|
|
57
|
+
return args.fill(first, second, 0, 0);
|
|
58
|
+
}
|
|
59
|
+
export const DECODERS = StaticArray.fromArray([
|
|
60
|
+
// DECODERS[Arguments.Zero] =
|
|
61
|
+
(args, _d, _o, _l) => {
|
|
62
|
+
return args.fill(0, 0, 0, 0);
|
|
63
|
+
},
|
|
64
|
+
// DECODERS[Arguments.OneImm] =
|
|
65
|
+
(args, data, o, lim) => {
|
|
66
|
+
return args.fill(decodeI32(data, o, lim), 0, 0, 0);
|
|
67
|
+
},
|
|
68
|
+
// DECODERS[Arguments.TwoImm] =
|
|
69
|
+
(args, data, o, lim) => twoImm(args, data, o, lim),
|
|
70
|
+
// DECODERS[Arguments.OneOff] =
|
|
71
|
+
(args, data, o, lim) => {
|
|
72
|
+
return args.fill(decodeI32(data, o, lim), 0, 0, 0);
|
|
73
|
+
},
|
|
74
|
+
// DECODERS[Arguments.OneRegOneImm] =
|
|
75
|
+
(args, data, o, lim) => {
|
|
76
|
+
return args.fill(lowNibble(data[o]), decodeI32(data, o + 1, lim), 0, 0);
|
|
77
|
+
},
|
|
78
|
+
// DECODERS[Arguments.OneRegOneExtImm] =
|
|
79
|
+
(args, data, o, _lim) => {
|
|
80
|
+
const a = lowNibble(data[o]);
|
|
81
|
+
const b = decodeU32(data, o + 1);
|
|
82
|
+
const c = decodeU32(data, o + 5);
|
|
83
|
+
return args.fill(a, b, c, 0);
|
|
84
|
+
},
|
|
85
|
+
//DECODERS[Arguments.OneRegTwoImm] =
|
|
86
|
+
(args, data, o, lim) => {
|
|
87
|
+
const h = higNibble(data[o]);
|
|
88
|
+
const l = lowNibble(data[o]);
|
|
89
|
+
const split = IntMath.minI32(4, h) + 1;
|
|
90
|
+
const immA = decodeI32(data, o + 1, o + split);
|
|
91
|
+
const immB = decodeI32(data, o + split, lim);
|
|
92
|
+
return args.fill(l, immA, immB, 0);
|
|
93
|
+
},
|
|
94
|
+
// DECODERS[Arguments.OneRegOneImmOneOff] =
|
|
95
|
+
(args, data, o, lim) => {
|
|
96
|
+
const h = higNibble(data[o]);
|
|
97
|
+
const l = lowNibble(data[o]);
|
|
98
|
+
const split = IntMath.minI32(4, h) + 1;
|
|
99
|
+
const immA = decodeI32(data, o + 1, o + split);
|
|
100
|
+
const offs = decodeI32(data, o + split, lim);
|
|
101
|
+
return args.fill(l, immA, offs, 0);
|
|
102
|
+
},
|
|
103
|
+
// DECODERS[Arguments.TwoReg] =
|
|
104
|
+
(args, data, o, _lim) => {
|
|
105
|
+
return args.fill(higNibble(data[o]), lowNibble(data[o]), 0, 0);
|
|
106
|
+
},
|
|
107
|
+
// DECODERS[Arguments.TwoRegOneImm] =
|
|
108
|
+
(args, data, o, lim) => {
|
|
109
|
+
const hig = higNibble(data[o]);
|
|
110
|
+
const low = lowNibble(data[o]);
|
|
111
|
+
return args.fill(hig, low, decodeI32(data, o + 1, lim), 0);
|
|
112
|
+
},
|
|
113
|
+
// DECODERS[Arguments.TwoRegOneOff] =
|
|
114
|
+
(args, data, o, lim) => {
|
|
115
|
+
const hig = higNibble(data[o]);
|
|
116
|
+
const low = lowNibble(data[o]);
|
|
117
|
+
return args.fill(hig, low, decodeI32(data, o + 1, lim), 0);
|
|
118
|
+
},
|
|
119
|
+
// DECODERS[Arguments.TwoRegTwoImm] =
|
|
120
|
+
(args, data, o, lim) => {
|
|
121
|
+
const hig = higNibble(data[o]);
|
|
122
|
+
const low = lowNibble(data[o]);
|
|
123
|
+
const result = twoImm(args, data, o + 1, lim);
|
|
124
|
+
return args.fill(hig, low, result.a, result.b);
|
|
125
|
+
},
|
|
126
|
+
// DECODERS[Arguments.ThreeReg] =
|
|
127
|
+
(args, data, o, _lim) => {
|
|
128
|
+
const hig = higNibble(data[o]);
|
|
129
|
+
const low = lowNibble(data[o]);
|
|
130
|
+
const b = lowNibble(data[o + 1]);
|
|
131
|
+
return args.fill(hig, low, b, 0);
|
|
132
|
+
},
|
|
133
|
+
]);
|
|
134
|
+
// @inline
|
|
135
|
+
export function lowNibble(byte) {
|
|
136
|
+
return byte & 0xf;
|
|
137
|
+
}
|
|
138
|
+
export function higNibble(byte) {
|
|
139
|
+
return byte >> 4;
|
|
140
|
+
}
|
|
141
|
+
//@inline
|
|
142
|
+
function decodeI32(input, start, end) {
|
|
143
|
+
if (end <= start) {
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
const l = end - start;
|
|
147
|
+
const len = l < 4 ? l : 4;
|
|
148
|
+
let num = 0x0;
|
|
149
|
+
for (let i = 0; i < len; i++) {
|
|
150
|
+
num |= u32(input[start + i]) << (i * 8);
|
|
151
|
+
}
|
|
152
|
+
const msb = portable.staticArrayAt(input, start + len - 1) & 0x80;
|
|
153
|
+
if (len < 4 && msb > 0) {
|
|
154
|
+
num |= 4294967295 << (len * 8);
|
|
155
|
+
}
|
|
156
|
+
return num;
|
|
157
|
+
}
|
|
158
|
+
function decodeU32(data, offset) {
|
|
159
|
+
let num = u32(data[offset + 0]);
|
|
160
|
+
num |= u32(data[offset + 1]) << 8;
|
|
161
|
+
num |= u32(data[offset + 2]) << 16;
|
|
162
|
+
num |= u32(data[offset + 3]) << 24;
|
|
163
|
+
return portable.asU32(num);
|
|
164
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare class Decoder {
|
|
2
|
+
private readonly source;
|
|
3
|
+
private offset;
|
|
4
|
+
constructor(source: Uint8Array, offset?: i32);
|
|
5
|
+
isExhausted(): boolean;
|
|
6
|
+
private ensureBytes;
|
|
7
|
+
finish(): void;
|
|
8
|
+
varU32(): u32;
|
|
9
|
+
u8(): u8;
|
|
10
|
+
u16(): u16;
|
|
11
|
+
u24(): u32;
|
|
12
|
+
u32(): u32;
|
|
13
|
+
bytes(len: i32): Uint8Array;
|
|
14
|
+
/** Read remaining bytes into Uint8Array */
|
|
15
|
+
remainingBytes(): Uint8Array;
|
|
16
|
+
}
|
|
17
|
+
export declare class ValOffset<T> {
|
|
18
|
+
readonly value: T;
|
|
19
|
+
readonly offset: i32;
|
|
20
|
+
constructor(value: T, offset: i32);
|
|
21
|
+
}
|
|
22
|
+
/** Read variable-length u32 and return number of bytes read. */
|
|
23
|
+
export declare function decodeVarU32(data: Uint8Array): ValOffset<u32>;
|
|
24
|
+
export declare function encodeVarU32(v: u64): Uint8Array;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const MASKS = [0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80];
|
|
2
|
+
const variableLength = (firstByte) => {
|
|
3
|
+
const len = MASKS.length;
|
|
4
|
+
for (let i = 0; i < len; i++) {
|
|
5
|
+
if (firstByte >= MASKS[i]) {
|
|
6
|
+
return 8 - i;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return 0;
|
|
10
|
+
};
|
|
11
|
+
export class Decoder {
|
|
12
|
+
constructor(source, offset = 0) {
|
|
13
|
+
this.source = source;
|
|
14
|
+
this.offset = offset;
|
|
15
|
+
}
|
|
16
|
+
isExhausted() {
|
|
17
|
+
return this.offset >= this.source.length;
|
|
18
|
+
}
|
|
19
|
+
ensureBytes(need) {
|
|
20
|
+
if (this.offset + need > this.source.length) {
|
|
21
|
+
throw new Error(`Not enough bytes left. Need: ${need}, left: ${this.source.length - this.offset}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
finish() {
|
|
25
|
+
if (!this.isExhausted()) {
|
|
26
|
+
throw new Error(`Expecting to use all bytes from the decoder. Left: ${this.source.length - this.offset}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
varU32() {
|
|
30
|
+
this.ensureBytes(1);
|
|
31
|
+
const v = decodeVarU32(this.source.subarray(this.offset));
|
|
32
|
+
this.offset += v.offset;
|
|
33
|
+
return v.value;
|
|
34
|
+
}
|
|
35
|
+
u8() {
|
|
36
|
+
this.ensureBytes(1);
|
|
37
|
+
const v = this.source[this.offset];
|
|
38
|
+
this.offset += 1;
|
|
39
|
+
return v;
|
|
40
|
+
}
|
|
41
|
+
u16() {
|
|
42
|
+
this.ensureBytes(2);
|
|
43
|
+
let v = this.source[this.offset];
|
|
44
|
+
v |= u16(this.source[this.offset + 1]) << 8;
|
|
45
|
+
this.offset += 2;
|
|
46
|
+
return v;
|
|
47
|
+
}
|
|
48
|
+
u24() {
|
|
49
|
+
this.ensureBytes(3);
|
|
50
|
+
let v = this.source[this.offset];
|
|
51
|
+
v |= u32(this.source[this.offset + 1]) << 8;
|
|
52
|
+
v |= u32(this.source[this.offset + 2]) << 16;
|
|
53
|
+
this.offset += 3;
|
|
54
|
+
return v;
|
|
55
|
+
}
|
|
56
|
+
u32() {
|
|
57
|
+
this.ensureBytes(4);
|
|
58
|
+
let v = this.source[this.offset];
|
|
59
|
+
v |= u32(this.source[this.offset + 1]) << 8;
|
|
60
|
+
v |= u32(this.source[this.offset + 2]) << 16;
|
|
61
|
+
v |= u32(this.source[this.offset + 3]) << 24;
|
|
62
|
+
this.offset += 4;
|
|
63
|
+
return v;
|
|
64
|
+
}
|
|
65
|
+
bytes(len) {
|
|
66
|
+
this.ensureBytes(len);
|
|
67
|
+
const v = this.source.subarray(this.offset, this.offset + len);
|
|
68
|
+
this.offset += len;
|
|
69
|
+
return v;
|
|
70
|
+
}
|
|
71
|
+
/** Read remaining bytes into Uint8Array */
|
|
72
|
+
remainingBytes() {
|
|
73
|
+
const v = this.source.subarray(this.offset);
|
|
74
|
+
this.offset += v.length;
|
|
75
|
+
return v;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// @unmanaged
|
|
79
|
+
export class ValOffset {
|
|
80
|
+
constructor(value, offset) {
|
|
81
|
+
this.value = value;
|
|
82
|
+
this.offset = offset;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Read variable-length u32 and return number of bytes read. */
|
|
86
|
+
export function decodeVarU32(data) {
|
|
87
|
+
const length = i32(variableLength(data[0]));
|
|
88
|
+
const first = u32(data[0]);
|
|
89
|
+
if (length === 0) {
|
|
90
|
+
return new ValOffset(first, 1);
|
|
91
|
+
}
|
|
92
|
+
if (data.length < length) {
|
|
93
|
+
throw new Error(`Not enough bytes to decode 'varU32'. Need ${length}, got: ${data.length}`);
|
|
94
|
+
}
|
|
95
|
+
const msb = (first + 2 ** (8 - length) - 2 ** 8) << (length * 8);
|
|
96
|
+
let number = 0;
|
|
97
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
98
|
+
number = (number << 8) + data[1 + i];
|
|
99
|
+
}
|
|
100
|
+
number += msb;
|
|
101
|
+
return new ValOffset(number, 1 + length);
|
|
102
|
+
}
|
|
103
|
+
export function encodeVarU32(v) {
|
|
104
|
+
v = u64(v);
|
|
105
|
+
if (v === u64(0)) {
|
|
106
|
+
return new Uint8Array(1);
|
|
107
|
+
}
|
|
108
|
+
// handle the biggest case
|
|
109
|
+
let maxEncoded = u64(2 ** (7 * 8));
|
|
110
|
+
if (v >= maxEncoded) {
|
|
111
|
+
const dest = new Uint8Array(9);
|
|
112
|
+
dest[0] = 0xff;
|
|
113
|
+
const dataView = new DataView(dest.buffer);
|
|
114
|
+
dataView.setUint64(1, v, true);
|
|
115
|
+
return dest;
|
|
116
|
+
}
|
|
117
|
+
// let's look for the correct range
|
|
118
|
+
let minEncoded = maxEncoded >> u64(7);
|
|
119
|
+
for (let l = 7; l >= 0; l -= 1) {
|
|
120
|
+
if (v >= minEncoded) {
|
|
121
|
+
const dest = new Uint8Array(l + 1);
|
|
122
|
+
// encode the first byte
|
|
123
|
+
const maxVal = u64(2 ** (8 * l));
|
|
124
|
+
const byte = (u32(2 ** 8 - 2 ** (8 - l)) + u32(v / maxVal)) & 4294967295;
|
|
125
|
+
dest[0] = u8(byte);
|
|
126
|
+
// now encode the rest of bytes of len `l`
|
|
127
|
+
let rest = v % maxVal;
|
|
128
|
+
for (let i = 1; i < 1 + l; i += 1) {
|
|
129
|
+
dest[i] = u8(rest);
|
|
130
|
+
rest >>= u64(8);
|
|
131
|
+
}
|
|
132
|
+
return dest;
|
|
133
|
+
}
|
|
134
|
+
// move one power down
|
|
135
|
+
maxEncoded = minEncoded;
|
|
136
|
+
minEncoded >>= u64(7);
|
|
137
|
+
}
|
|
138
|
+
throw new Error(`Unhandled number encoding: ${v}`);
|
|
139
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Gas type. */
|
|
2
|
+
export type Gas = u64;
|
|
3
|
+
/** Create a new gas counter instance. */
|
|
4
|
+
export declare function gasCounter(gas: Gas): GasCounter;
|
|
5
|
+
export declare class GasCounter {
|
|
6
|
+
private gas;
|
|
7
|
+
constructor(gas: Gas);
|
|
8
|
+
set(g: Gas): void;
|
|
9
|
+
get(): Gas;
|
|
10
|
+
sub(g: u32): boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
/** Create a new gas counter instance. */
|
|
8
|
+
export function gasCounter(gas) {
|
|
9
|
+
return new GasCounter(gas);
|
|
10
|
+
}
|
|
11
|
+
export class GasCounter {
|
|
12
|
+
constructor(gas) {
|
|
13
|
+
this.gas = gas;
|
|
14
|
+
}
|
|
15
|
+
set(g) {
|
|
16
|
+
this.gas = g;
|
|
17
|
+
}
|
|
18
|
+
get() {
|
|
19
|
+
return this.gas;
|
|
20
|
+
}
|
|
21
|
+
sub(g) {
|
|
22
|
+
const cost = u64(g);
|
|
23
|
+
if (cost > this.gas) {
|
|
24
|
+
this.gas = u64(0);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
this.gas = this.gas - cost;
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
__decorate([
|
|
32
|
+
inline
|
|
33
|
+
], GasCounter.prototype, "sub", null);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InstructionRun } from "./outcome";
|
|
2
|
+
export declare const count_set_bits_64: InstructionRun;
|
|
3
|
+
export declare const count_set_bits_32: InstructionRun;
|
|
4
|
+
export declare const leading_zero_bits_64: InstructionRun;
|
|
5
|
+
export declare const leading_zero_bits_32: InstructionRun;
|
|
6
|
+
export declare const trailing_zero_bits_64: InstructionRun;
|
|
7
|
+
export declare const trailing_zero_bits_32: InstructionRun;
|
|
8
|
+
export declare const sign_extend_8: InstructionRun;
|
|
9
|
+
export declare const sign_extend_16: InstructionRun;
|
|
10
|
+
export declare const zero_extend_16: InstructionRun;
|
|
11
|
+
export declare const reverse_bytes: InstructionRun;
|