@typeberry/lib 0.2.0-c96e8ef → 0.2.0-eae807e

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.
Files changed (4) hide show
  1. package/index.cjs +2500 -1911
  2. package/index.d.ts +1956 -1864
  3. package/index.js +2498 -1909
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@ declare enum GpVersion {
2
2
  V0_6_7 = "0.6.7",
3
3
  V0_7_0 = "0.7.0",
4
4
  V0_7_1 = "0.7.1",
5
- V0_7_2 = "0.7.2-preview",
5
+ V0_7_2 = "0.7.2",
6
6
  }
7
7
 
8
8
  declare enum TestSuite {
@@ -10,43 +10,39 @@ declare enum TestSuite {
10
10
  JAMDUNA = "jamduna",
11
11
  }
12
12
 
13
+ declare const ALL_VERSIONS_IN_ORDER = [GpVersion.V0_6_7, GpVersion.V0_7_0, GpVersion.V0_7_1, GpVersion.V0_7_2];
14
+
13
15
  declare const DEFAULT_SUITE = TestSuite.W3F_DAVXY;
14
- declare const DEFAULT_VERSION = GpVersion.V0_7_1;
16
+ declare const DEFAULT_VERSION = GpVersion.V0_7_2;
15
17
  declare let CURRENT_VERSION = parseCurrentVersion(env.GP_VERSION) ?? DEFAULT_VERSION;
16
18
  declare let CURRENT_SUITE = parseCurrentSuite(env.TEST_SUITE) ?? DEFAULT_SUITE;
17
19
 
18
- declare const ALL_VERSIONS_IN_ORDER = [GpVersion.V0_6_7, GpVersion.V0_7_0, GpVersion.V0_7_1, GpVersion.V0_7_2];
19
-
20
20
  declare function parseCurrentVersion(env?: string): GpVersion | undefined {
21
21
  if (env === undefined) {
22
22
  return undefined;
23
23
  }
24
- switch (env) {
25
- case GpVersion.V0_6_7:
26
- case GpVersion.V0_7_0:
27
- case GpVersion.V0_7_1:
28
- case GpVersion.V0_7_2:
29
- return env;
30
- default:
31
- throw new Error(
32
- `Configured environment variable GP_VERSION is unknown: '${env}'. Use one of: ${ALL_VERSIONS_IN_ORDER}`,
33
- );
24
+ for (const v of Object.values(GpVersion)) {
25
+ if (env === v) {
26
+ return v;
27
+ }
34
28
  }
29
+ throw new Error(
30
+ `Configured environment variable GP_VERSION is unknown: '${env}'. Use one of: ${ALL_VERSIONS_IN_ORDER}`,
31
+ );
35
32
  }
36
33
 
37
34
  declare function parseCurrentSuite(env?: string): TestSuite | undefined {
38
35
  if (env === undefined) {
39
36
  return undefined;
40
37
  }
41
- switch (env) {
42
- case TestSuite.W3F_DAVXY:
43
- case TestSuite.JAMDUNA:
44
- return env;
45
- default:
46
- throw new Error(
47
- `Configured environment variable TEST_SUITE is unknown: '${env}'. Use one of: ${Object.values(TestSuite)}`,
48
- );
38
+ for (const s of Object.values(TestSuite)) {
39
+ if (env === s) {
40
+ return s;
41
+ }
49
42
  }
43
+ throw new Error(
44
+ `Configured environment variable TEST_SUITE is unknown: '${env}'. Use one of: ${Object.values(TestSuite)}`,
45
+ );
50
46
  }
51
47
 
52
48
  declare class Compatibility {
@@ -5117,6 +5113,17 @@ declare class Bootnode implements PeerAddress {
5117
5113
  }
5118
5114
  }
5119
5115
 
5116
+ /** Implemented PVM Backends names in THE SAME ORDER as enum. */
5117
+ declare const PvmBackendNames = ["built-in", "ananas"];
5118
+
5119
+ /** Implemented PVM Backends to choose from. */
5120
+ declare enum PvmBackend {
5121
+ /** Built-in aka. Typeberry 🫐 interpreter. */
5122
+ BuiltIn = 0,
5123
+ /** Ananas 🍍 interpreter. */
5124
+ Ananas = 1,
5125
+ }
5126
+
5120
5127
  type index$m_Bootnode = Bootnode;
5121
5128
  declare const index$m_Bootnode: typeof Bootnode;
5122
5129
  type index$m_ChainSpec = ChainSpec;
@@ -5128,10 +5135,13 @@ declare const index$m_EST_VALIDATORS: typeof EST_VALIDATORS;
5128
5135
  declare const index$m_EST_VALIDATORS_SUPER_MAJORITY: typeof EST_VALIDATORS_SUPER_MAJORITY;
5129
5136
  type index$m_PeerAddress = PeerAddress;
5130
5137
  type index$m_PeerId = PeerId;
5138
+ type index$m_PvmBackend = PvmBackend;
5139
+ declare const index$m_PvmBackend: typeof PvmBackend;
5140
+ declare const index$m_PvmBackendNames: typeof PvmBackendNames;
5131
5141
  declare const index$m_fullChainSpec: typeof fullChainSpec;
5132
5142
  declare const index$m_tinyChainSpec: typeof tinyChainSpec;
5133
5143
  declare namespace index$m {
5134
- export { index$m_Bootnode as Bootnode, index$m_ChainSpec as ChainSpec, index$m_EC_SEGMENT_SIZE as EC_SEGMENT_SIZE, index$m_EST_CORES as EST_CORES, index$m_EST_EPOCH_LENGTH as EST_EPOCH_LENGTH, index$m_EST_VALIDATORS as EST_VALIDATORS, index$m_EST_VALIDATORS_SUPER_MAJORITY as EST_VALIDATORS_SUPER_MAJORITY, index$m_fullChainSpec as fullChainSpec, index$m_tinyChainSpec as tinyChainSpec };
5144
+ export { index$m_Bootnode as Bootnode, index$m_ChainSpec as ChainSpec, index$m_EC_SEGMENT_SIZE as EC_SEGMENT_SIZE, index$m_EST_CORES as EST_CORES, index$m_EST_EPOCH_LENGTH as EST_EPOCH_LENGTH, index$m_EST_VALIDATORS as EST_VALIDATORS, index$m_EST_VALIDATORS_SUPER_MAJORITY as EST_VALIDATORS_SUPER_MAJORITY, index$m_PvmBackend as PvmBackend, index$m_PvmBackendNames as PvmBackendNames, index$m_fullChainSpec as fullChainSpec, index$m_tinyChainSpec as tinyChainSpec };
5135
5145
  export type { index$m_PeerAddress as PeerAddress, index$m_PeerId as PeerId };
5136
5146
  }
5137
5147
 
@@ -8155,6 +8165,7 @@ declare const DEFAULT_CONFIG = "default";
8155
8165
  declare const NODE_DEFAULTS = {
8156
8166
  name: isBrowser() ? "browser" : os.hostname(),
8157
8167
  config: DEFAULT_CONFIG,
8168
+ pvm: PvmBackend.BuiltIn,
8158
8169
  };
8159
8170
 
8160
8171
  /** Chain spec chooser. */
@@ -12247,6 +12258,18 @@ declare class StateEntries {
12247
12258
  return Object.fromEntries(this.entries);
12248
12259
  }
12249
12260
 
12261
+ /** Dump state entries to JSON string (format compatible with stf vectors). */
12262
+ toString() {
12263
+ return JSON.stringify(
12264
+ Array.from(this.entries.entries()).map(([key, value]) => ({
12265
+ key,
12266
+ value,
12267
+ })),
12268
+ null,
12269
+ 2,
12270
+ );
12271
+ }
12272
+
12250
12273
  [Symbol.iterator]() {
12251
12274
  return this.entries[Symbol.iterator]();
12252
12275
  }
@@ -14322,48 +14345,133 @@ declare class PendingTransfer {
14322
14345
  }
14323
14346
  }
14324
14347
 
14325
- /** Gas measuring type. Can be either U64 or U32 for performance reasons. */
14326
- type Gas = BigGas | SmallGas;
14327
14348
  /** A U64 version of `Gas`. */
14328
14349
  type BigGas = Opaque<U64, "BigGas[U64]">;
14329
14350
  /** A U32 version of `Gas`. */
14330
14351
  type SmallGas = Opaque<U32, "SmallGas[U32]">;
14331
-
14332
- /** Attempt to convert given number into U32 gas representation. */
14333
- declare const tryAsSmallGas = (v: number): SmallGas => asOpaqueType(tryAsU32(v));
14334
-
14335
- /** Attempt to convert given number into U64 gas representation. */
14336
- declare const tryAsBigGas = (v: number | bigint): BigGas => asOpaqueType(tryAsU64(v));
14337
-
14338
- /** Attempt to convert given number into gas. */
14339
- declare const tryAsGas = (v: number | bigint): Gas =>
14340
- typeof v === "number" && v < 2 ** 32 ? tryAsSmallGas(v) : tryAsBigGas(v);
14341
-
14342
- /** Create a new gas counter instance depending on the gas value. */
14343
- declare function gasCounter(gas: Gas): GasCounter {
14344
- return new GasCounterU64(tryAsU64(gas));
14345
- }
14352
+ /** Gas measuring type. Can be either U64 or U32 for performance reasons. */
14353
+ type Gas = BigGas | SmallGas;
14346
14354
 
14347
14355
  /** An abstraction over gas counter.
14348
14356
  *
14349
14357
  * It can be optimized to use numbers instead of bigint in case of small gas.
14350
14358
  */
14351
- interface GasCounter {
14359
+ interface IGasCounter {
14360
+ /**
14361
+ * Set during initialization of GasCounter.
14362
+ *
14363
+ * NOTE: Needed to calculate `used()` gas.
14364
+ */
14365
+ initialGas: Gas;
14366
+
14352
14367
  /** Return remaining gas. */
14353
14368
  get(): Gas;
14354
14369
 
14355
- /** Overwrite remaining gas. Prefer sub method instead. */
14370
+ /**
14371
+ * Overwrite remaining gas.
14372
+ *
14373
+ * NOTE: Could cause `used()` gas calculation to be incorrect.
14374
+ *
14375
+ * @see
14376
+ * Prefer sub method instead.
14377
+ */
14356
14378
  set(g: Gas): void;
14357
14379
 
14358
14380
  /** Returns true if there was an underflow. */
14359
14381
  sub(g: Gas): boolean;
14382
+
14383
+ /**
14384
+ * Calculates used gas since creation of GasCounter.
14385
+ *
14386
+ * The interface does not handle negative or more than `initialGas` values.
14387
+ *
14388
+ * NOTE: We can use at most `initialGas` and as little as `0`.
14389
+ */
14390
+ used(): Gas;
14391
+ }
14392
+
14393
+ type PageFault$1 = {
14394
+ address: U32;
14395
+ };
14396
+
14397
+ /** Allows store and read segments of memory. */
14398
+ interface IMemory {
14399
+ /** Store bytes into memory at given address. */
14400
+ store(address: U32, bytes: Uint8Array): Result$2<OK, PageFault$1>;
14401
+
14402
+ /** Load bytes from memory from given address into given buffer. */
14403
+ read(address: U32, result: Uint8Array): Result$2<OK, PageFault$1>;
14360
14404
  }
14361
14405
 
14362
14406
  declare const NO_OF_REGISTERS$1 = 13;
14363
14407
 
14408
+ /** Allow to set and get all registers encoded into little-endian bytes. */
14409
+ interface IRegisters {
14410
+ /**
14411
+ * Get all registers encoded into little-endian bytes.
14412
+ *
14413
+ * NOTE: Total length of bytes must be NO_OF_REGISTERS * REGISTER_BYTE_SIZE.
14414
+ */
14415
+ getAllEncoded(): Uint8Array;
14416
+ /**
14417
+ * Set all registers from little-endian encoded bytes.
14418
+ *
14419
+ * NOTE: Total length of bytes must be NO_OF_REGISTERS * REGISTER_BYTE_SIZE.
14420
+ */
14421
+ setAllEncoded(bytes: Uint8Array): void;
14422
+ }
14423
+
14424
+ /**
14425
+ * Result codes for the PVM execution.
14426
+ *
14427
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/2e43002e4300?v=0.7.2
14428
+ */
14429
+ declare enum Status {
14430
+ /** Continue */
14431
+ OK = 255,
14432
+ /** Finished */
14433
+ HALT = 0,
14434
+ /** Panic */
14435
+ PANIC = 1,
14436
+ /** Page-fault */
14437
+ FAULT = 2,
14438
+ /** Host-call */
14439
+ HOST = 3,
14440
+ /** Out of gas */
14441
+ OOG = 4,
14442
+ }
14443
+
14444
+ interface IPvmInterpreter {
14445
+ /** Manipulate gas. */
14446
+ readonly gas: IGasCounter;
14447
+
14448
+ /** Manipulate registers. */
14449
+ readonly registers: IRegisters;
14450
+
14451
+ /** Manipulate memory. */
14452
+ readonly memory: IMemory;
14453
+
14454
+ /** Prepare SPI program to be executed. */
14455
+ resetJam(program: Uint8Array, args: Uint8Array, pc: number, gas: Gas): void;
14456
+
14457
+ /** Execute loaded program. */
14458
+ runProgram(): void;
14459
+
14460
+ /** Get current Status. */
14461
+ getStatus(): Status;
14462
+
14463
+ /** Get current Program Counter. */
14464
+ getPC(): number;
14465
+
14466
+ /** Get exit args. Needed in case of HOST or FAULT. */
14467
+ getExitParam(): U32 | null;
14468
+ }
14469
+
14470
+ // x << 3 === x * 8
14471
+
14364
14472
  type RegisterIndex = Opaque<number, "register index">;
14365
14473
 
14366
- declare class Registers {
14474
+ declare class Registers implements IRegisters {
14367
14475
  private asSigned: BigInt64Array;
14368
14476
  private asUnsigned: BigUint64Array;
14369
14477
 
@@ -14373,6 +14481,15 @@ declare class Registers {
14373
14481
  this.asUnsigned = new BigUint64Array(bytes.buffer, bytes.byteOffset);
14374
14482
  }
14375
14483
 
14484
+ getAllEncoded(): Uint8Array {
14485
+ return this.bytes;
14486
+ }
14487
+
14488
+ setAllEncoded(bytes: Uint8Array): void {
14489
+ check`${bytes.length === this.bytes.length} Incorrect size of input registers. Got: ${bytes.length}, need: ${this.bytes.length}`;
14490
+ this.bytes.set(bytes, 0);
14491
+ }
14492
+
14376
14493
  static fromBytes(bytes: Uint8Array) {
14377
14494
  check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
14378
14495
  return new Registers(bytes);
@@ -14383,10 +14500,6 @@ declare class Registers {
14383
14500
  return this.bytes.subarray(offset, offset + len);
14384
14501
  }
14385
14502
 
14386
- getAllBytesAsLittleEndian() {
14387
- return this.bytes;
14388
- }
14389
-
14390
14503
  copyFrom(regs: Registers | BigUint64Array) {
14391
14504
  const array = regs instanceof BigUint64Array ? regs : regs.asUnsigned;
14392
14505
  this.asUnsigned.set(array);
@@ -14435,1493 +14548,1856 @@ declare class Registers {
14435
14548
  }
14436
14549
  }
14437
14550
 
14438
- /**
14439
- * Mask class is an implementation of skip function defined in GP.
14440
- *
14441
- * https://graypaper.fluffylabs.dev/#/5f542d7/237201239801
14442
- */
14443
- declare class Mask {
14551
+ declare class HostCallMemory {
14552
+ constructor(private readonly memory: IMemory) {}
14553
+
14444
14554
  /**
14445
- * The lookup table will have `0` at the index which corresponds to an instruction on the same index in the bytecode.
14446
- * In case the value is non-zero it signifies the offset to the index with next instruction.
14555
+ * Save some bytes into memory under given address.
14447
14556
  *
14448
- * Example:
14449
- * ```
14450
- * 0..1..2..3..4..5..6..7..8..9 # Indices
14451
- * 0..2..1..0..1..0..3..2..1..0 # lookupTable forward values
14452
- * ```
14453
- * There are instructions at indices `0, 3, 5, 9`.
14557
+ * NOTE: Given address is U64 (pure register value),
14558
+ * but we use only lower 32-bits.
14454
14559
  */
14455
- private lookupTableForward: Uint8Array;
14456
-
14457
- constructor(mask: BitVec) {
14458
- this.lookupTableForward = this.buildLookupTableForward(mask);
14459
- }
14460
-
14461
- isInstruction(index: number) {
14462
- return this.lookupTableForward[index] === 0;
14463
- }
14560
+ storeFrom(regAddress: U64, bytes: Uint8Array): Result$2<OK, PageFault$1> {
14561
+ if (bytes.length === 0) {
14562
+ return Result.ok(OK);
14563
+ }
14464
14564
 
14465
- getNoOfBytesToNextInstruction(index: number) {
14466
- check`${index >= 0} index (${index}) cannot be a negative number`;
14467
- return Math.min(this.lookupTableForward[index] ?? 0, MAX_INSTRUCTION_DISTANCE);
14565
+ // NOTE: We always take lower 32 bits from register value.
14566
+ //
14567
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/25ed0025ed00?v=0.7.2
14568
+ const address = tryAsU32(Number(regAddress & 0xffff_ffffn));
14569
+ return this.memory.store(address, bytes);
14468
14570
  }
14469
14571
 
14470
- private buildLookupTableForward(mask: BitVec) {
14471
- const table = safeAllocUint8Array(mask.bitLength);
14472
- let lastInstructionOffset = 0;
14473
- for (let i = mask.bitLength - 1; i >= 0; i--) {
14474
- if (mask.isSet(i)) {
14475
- lastInstructionOffset = 0;
14476
- } else {
14477
- lastInstructionOffset++;
14478
- }
14479
- table[i] = lastInstructionOffset;
14572
+ /**
14573
+ * Read some bytes from memory under given address.
14574
+ *
14575
+ * NOTE: Given address is U64 (pure register value),
14576
+ * but we use only lower 32-bits.
14577
+ */
14578
+ loadInto(output: Uint8Array, regAddress: U64): Result$2<OK, PageFault$1> {
14579
+ if (output.length === 0) {
14580
+ return Result.ok(OK);
14480
14581
  }
14481
- return table;
14482
- }
14483
14582
 
14484
- static empty() {
14485
- return new Mask(BitVec.empty(0));
14583
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/25ed0025ed00?v=0.7.2
14584
+ //
14585
+ // NOTE we are taking the the lower U32 part of the register, hence it's safe.
14586
+ const address = tryAsU32(Number(regAddress & 0xffff_ffffn));
14587
+ return this.memory.read(address, output);
14486
14588
  }
14487
14589
  }
14488
14590
 
14489
- declare enum ArgumentType {
14490
- NO_ARGUMENTS = 0,
14491
- ONE_IMMEDIATE = 1,
14492
- TWO_IMMEDIATES = 2,
14493
- ONE_OFFSET = 3,
14494
- ONE_REGISTER_ONE_IMMEDIATE = 4,
14495
- ONE_REGISTER_TWO_IMMEDIATES = 5,
14496
- ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET = 6,
14497
- TWO_REGISTERS = 7,
14498
- TWO_REGISTERS_ONE_IMMEDIATE = 8,
14499
- TWO_REGISTERS_ONE_OFFSET = 9,
14500
- TWO_REGISTERS_TWO_IMMEDIATES = 10,
14501
- THREE_REGISTERS = 11,
14502
- ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE = 12,
14503
- }
14504
-
14505
- declare class ExtendedWitdthImmediateDecoder {
14506
- private unsignedImmediate: BigUint64Array;
14507
- private bytes: Uint8Array;
14591
+ declare class HostCallRegisters {
14592
+ private readonly registers: DataView;
14508
14593
 
14509
- constructor() {
14510
- const buffer = new ArrayBuffer(IMMEDIATE_SIZE);
14511
- this.unsignedImmediate = new BigUint64Array(buffer);
14512
- this.bytes = new Uint8Array(buffer);
14594
+ constructor(private readonly bytes: Uint8Array) {
14595
+ this.registers = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
14513
14596
  }
14514
14597
 
14515
- setBytes(bytes: Uint8Array) {
14516
- let i = 0;
14517
- for (; i < bytes.length; i++) {
14518
- this.bytes[i] = bytes[i];
14519
- }
14520
-
14521
- for (; i < IMMEDIATE_SIZE; i++) {
14522
- this.bytes[i] = 0;
14523
- }
14598
+ /** Get U64 register value. */
14599
+ get(registerIndex: number): U64 {
14600
+ return tryAsU64(this.registers.getBigUint64(registerIndex * REGISTER_BYTE_SIZE, true));
14524
14601
  }
14525
14602
 
14526
- getValue() {
14527
- return this.unsignedImmediate[0];
14603
+ /** Set U64 register value. */
14604
+ set(registerIndex: number, value: U64) {
14605
+ this.registers.setBigUint64(registerIndex * REGISTER_BYTE_SIZE, value, true);
14528
14606
  }
14529
14607
 
14530
- getBytesAsLittleEndian() {
14531
- return this.bytes.subarray(0, IMMEDIATE_SIZE);
14608
+ /** Get all registers encoded into little-endian bytes. */
14609
+ getEncoded(): Uint8Array {
14610
+ return this.bytes;
14532
14611
  }
14533
14612
  }
14534
14613
 
14535
- declare class ImmediateDecoder {
14536
- private u32: Uint32Array;
14537
- private i32: Int32Array;
14538
- private u64: BigUint64Array;
14539
- private i64: BigInt64Array;
14540
- private view: DataView;
14541
- private bytes: Uint8Array;
14542
-
14543
- constructor() {
14544
- const buffer = new ArrayBuffer(BUFFER_SIZE);
14545
- this.u32 = new Uint32Array(buffer);
14546
- this.i32 = new Int32Array(buffer);
14547
- this.u64 = new BigUint64Array(buffer);
14548
- this.i64 = new BigInt64Array(buffer);
14549
- this.view = new DataView(buffer);
14550
- this.bytes = new Uint8Array(buffer);
14551
- }
14614
+ /** Strictly-typed host call index. */
14615
+ type HostCallIndex = Opaque<U32, "HostCallIndex[U32]">;
14616
+ /** Attempt to convert a number into `HostCallIndex`. */
14617
+ declare const tryAsHostCallIndex = (v: number): HostCallIndex => asOpaqueType(tryAsU32(v));
14552
14618
 
14553
- setBytes(bytes: Uint8Array) {
14554
- const n = bytes.length;
14555
- const msb = n > 0 ? bytes[n - 1] & 0x80 : 0;
14556
- const noOfBytes = Math.min(n, BUFFER_SIZE);
14557
- const prefix = msb !== 0 ? 0xff : 0x00;
14619
+ /**
14620
+ * Host-call exit reason.
14621
+ *
14622
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
14623
+ */
14624
+ declare enum PvmExecution {
14625
+ Halt = 0,
14626
+ Panic = 1,
14627
+ OOG = 2, // out-of-gas
14628
+ }
14558
14629
 
14559
- for (let i = 0; i < noOfBytes; i++) {
14560
- this.view.setUint8(i, bytes[i]);
14561
- }
14630
+ /** A utility function to easily trace a bunch of registers. */
14631
+ declare function traceRegisters(...regs: number[]) {
14632
+ return regs.map(tryAsRegisterIndex);
14633
+ }
14562
14634
 
14563
- for (let i = n; i < BUFFER_SIZE; i++) {
14564
- this.view.setUint8(i, prefix);
14565
- }
14566
- }
14635
+ /** An interface for a host call implementation */
14636
+ interface HostCallHandler {
14637
+ /** Index of that host call (i.e. what PVM invokes via `ecalli`) */
14638
+ readonly index: HostCallIndex;
14567
14639
 
14568
14640
  /**
14569
- * @deprecated Use getU32 instead
14641
+ * The gas cost of invocation of that host call.
14642
+ *
14643
+ * NOTE: `((reg: HostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
14570
14644
  */
14571
- getUnsigned() {
14572
- return this.u32[U32_INDEX];
14573
- }
14645
+ readonly basicGasCost: SmallGas | ((reg: HostCallRegisters) => Gas);
14646
+
14647
+ /** Currently executing service id. */
14648
+ readonly currentServiceId: U32;
14649
+
14650
+ /** Input&Output registers that we should add to tracing log. */
14651
+ readonly tracedRegisters: RegisterIndex[];
14574
14652
 
14575
14653
  /**
14576
- * @deprecated Use getI32 instead
14654
+ * Actually execute the host call.
14655
+ *
14656
+ * NOTE the call is ALLOWED and expected to modify registers and memory.
14577
14657
  */
14578
- getSigned() {
14579
- return this.i32[U32_INDEX];
14580
- }
14581
-
14582
- getU32(): number {
14583
- return this.u32[U32_INDEX];
14584
- }
14658
+ execute(gas: IGasCounter, regs: HostCallRegisters, memory: HostCallMemory): Promise<undefined | PvmExecution>;
14659
+ }
14585
14660
 
14586
- getI32(): number {
14587
- return this.i32[U32_INDEX];
14588
- }
14661
+ /** Container for all available host calls. */
14662
+ declare class HostCallsManager {
14663
+ private readonly hostCalls = new Map<HostCallIndex, HostCallHandler>();
14664
+ private readonly missing;
14589
14665
 
14590
- getU64(): bigint {
14591
- return this.u64[U64_INDEX];
14592
- }
14666
+ constructor({
14667
+ missing,
14668
+ handlers = [],
14669
+ }: {
14670
+ missing: HostCallHandler;
14671
+ handlers?: HostCallHandler[];
14672
+ }) {
14673
+ this.missing = missing;
14593
14674
 
14594
- getI64(): bigint {
14595
- return this.i64[U64_INDEX];
14675
+ for (const handler of handlers) {
14676
+ check`${this.hostCalls.get(handler.index) === undefined} Overwriting host call handler at index ${handler.index}`;
14677
+ this.hostCalls.set(handler.index, handler);
14678
+ }
14596
14679
  }
14597
14680
 
14598
- getBytesAsLittleEndian() {
14599
- return this.bytes.subarray(0, IMMEDIATE_SIZE);
14681
+ /** Get a host call by index. */
14682
+ get(hostCallIndex: HostCallIndex): HostCallHandler {
14683
+ return this.hostCalls.get(hostCallIndex) ?? this.missing;
14600
14684
  }
14601
14685
 
14602
- getExtendedBytesAsLittleEndian() {
14603
- return this.bytes;
14686
+ traceHostCall(
14687
+ context: string,
14688
+ hostCallIndex: HostCallIndex,
14689
+ hostCallHandler: HostCallHandler,
14690
+ registers: HostCallRegisters,
14691
+ gas: Gas,
14692
+ ) {
14693
+ const { currentServiceId } = hostCallHandler;
14694
+ const requested = hostCallIndex !== hostCallHandler.index ? ` (${hostCallIndex})` : "";
14695
+ const name = `${hostCallHandler.constructor.name}:${hostCallHandler.index}`;
14696
+ const registerValues = hostCallHandler.tracedRegisters
14697
+ .map((idx) => [idx.toString().padStart(2, "0"), registers.get(idx)] as const)
14698
+ .filter((v) => v[1] !== 0n)
14699
+ .map(([idx, value]) => {
14700
+ return `r${idx}=${value} (0x${value.toString(16)})`;
14701
+ })
14702
+ .join(", ");
14703
+ logger.insane`[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
14604
14704
  }
14605
14705
  }
14606
14706
 
14607
- declare class NibblesDecoder {
14608
- private byte = new Int8Array(1);
14707
+ /** Create a new gas counter instance depending on the gas value. */
14708
+ declare function gasCounter(gas: Gas): IGasCounter {
14709
+ return new GasCounterU64(tryAsU64(gas));
14710
+ }
14609
14711
 
14610
- setByte(byte: number) {
14611
- this.byte[0] = byte;
14712
+ type MemoryIndex = Opaque<number, "memory index">;
14713
+
14714
+ declare const tryAsMemoryIndex = (index: number): MemoryIndex => {
14715
+ check`${index >= 0 && index <= MAX_MEMORY_INDEX} Incorrect memory index: ${index}!`;
14716
+ return asOpaqueType(index);
14717
+ };
14718
+
14719
+ type SbrkIndex = Opaque<number, "sbrk index">;
14720
+
14721
+ declare const tryAsSbrkIndex = (index: number): SbrkIndex => {
14722
+ check`${index >= 0 && index <= MAX_MEMORY_INDEX + 1} Incorrect sbrk index: ${index}!`;
14723
+ return asOpaqueType(index);
14724
+ };
14725
+
14726
+ type PageIndex = Opaque<number, "memory page index">;
14727
+ type PageNumber = Opaque<number, "memory page number">;
14728
+
14729
+ declare class PageFault implements PageFault$1 {
14730
+ private constructor(
14731
+ public address: U32,
14732
+ public isAccessFault = true,
14733
+ ) {}
14734
+
14735
+ static fromPageNumber(maybePageNumber: number, isAccessFault = false) {
14736
+ const pageNumber = tryAsPageNumber(maybePageNumber);
14737
+ const startPageIndex = getStartPageIndexFromPageNumber(pageNumber);
14738
+ return new PageFault(tryAsU32(startPageIndex), isAccessFault);
14612
14739
  }
14613
14740
 
14614
- getHighNibble() {
14615
- return (this.byte[0] & 0xf0) >>> 4;
14741
+ static fromMemoryIndex(maybeMemoryIndex: number, isAccessFault = false) {
14742
+ const memoryIndex = tryAsMemoryIndex(maybeMemoryIndex % MEMORY_SIZE);
14743
+ const startPageIndex = getStartPageIndex(memoryIndex);
14744
+ return new PageFault(tryAsU32(startPageIndex), isAccessFault);
14616
14745
  }
14746
+ }
14617
14747
 
14618
- getLowNibble() {
14619
- return this.byte[0] & 0x0f;
14748
+ /**
14749
+ * A representation of open-ended range of consecutive indices in memory,
14750
+ * possibly empty or wrapping around.
14751
+ *
14752
+ * `[start, start + length)`
14753
+ */
14754
+ declare class MemoryRange {
14755
+ /**
14756
+ * Exclusive end index of the range.
14757
+ *
14758
+ * NOTE: The index may be wrapped around and smaller than `start`!
14759
+ */
14760
+ public readonly end: MemoryIndex;
14761
+ /**
14762
+ * Inclusive last index of the range (present unless the range is empty).
14763
+ *
14764
+ * NOTE: the index may be wrapped around and smaller than `start`!
14765
+ */
14766
+ public readonly lastIndex: MemoryIndex | null = null;
14767
+
14768
+ private constructor(
14769
+ public readonly start: MemoryIndex,
14770
+ public readonly length: number,
14771
+ ) {
14772
+ this.end = tryAsMemoryIndex((this.start + this.length) % MEMORY_SIZE);
14773
+
14774
+ if (length > 0) {
14775
+ this.lastIndex = tryAsMemoryIndex((this.end - 1 + MEMORY_SIZE) % MEMORY_SIZE);
14776
+ }
14620
14777
  }
14621
14778
 
14622
- getHighNibbleAsRegisterIndex() {
14623
- return Math.min(this.getHighNibble(), MAX_REGISTER_INDEX);
14779
+ /** Creates a memory range from given starting point and length */
14780
+ static fromStartAndLength(start: MemoryIndex, length: number) {
14781
+ if (!Number.isInteger(length) || length < 0 || length > MEMORY_SIZE) {
14782
+ throw new TypeError(`length must be a non-negative integer and less than ${MEMORY_SIZE}, got ${length}`);
14783
+ }
14784
+
14785
+ return new MemoryRange(start, length);
14624
14786
  }
14625
14787
 
14626
- getLowNibbleAsRegisterIndex() {
14627
- return Math.min(this.getLowNibble(), MAX_REGISTER_INDEX);
14788
+ /** Checks if a range is empty (`length === 0`) */
14789
+ isEmpty() {
14790
+ return this.length === 0;
14628
14791
  }
14629
14792
 
14630
- getHighNibbleAsLength() {
14631
- return Math.min(this.getHighNibble(), MAX_LENGTH);
14793
+ /** Returns true if the range is wrapped (`start` >= `end`) and is not empty */
14794
+ isWrapped() {
14795
+ return this.start >= this.end && !this.isEmpty();
14632
14796
  }
14633
14797
 
14634
- getLowNibbleAsLength() {
14635
- return Math.min(this.getLowNibble(), MAX_LENGTH);
14798
+ /** Checks if given memory address is within the range */
14799
+ isInRange(address: MemoryIndex) {
14800
+ if (this.isWrapped()) {
14801
+ return address >= this.start || address < this.end;
14802
+ }
14803
+
14804
+ return address >= this.start && address < this.end;
14805
+ }
14806
+
14807
+ /** Checks if this range overlaps with another range */
14808
+ overlapsWith(other: MemoryRange) {
14809
+ if (this.lastIndex === null || other.lastIndex === null) {
14810
+ return false;
14811
+ }
14812
+
14813
+ return (
14814
+ this.isInRange(other.start) ||
14815
+ this.isInRange(other.lastIndex) ||
14816
+ other.isInRange(this.start) ||
14817
+ other.isInRange(this.lastIndex)
14818
+ );
14636
14819
  }
14637
14820
  }
14638
14821
 
14639
- type EmptyArgs = {
14640
- type: ArgumentType.NO_ARGUMENTS;
14641
- noOfBytesToSkip: number;
14642
- };
14822
+ declare abstract class MemoryPage {
14823
+ public start: MemoryIndex;
14643
14824
 
14644
- type OneImmediateArgs = {
14645
- type: ArgumentType.ONE_IMMEDIATE;
14646
- noOfBytesToSkip: number;
14647
- /** V_X */
14648
- immediateDecoder: ImmediateDecoder;
14649
- };
14825
+ constructor(pageNumber: PageNumber) {
14826
+ this.start = getStartPageIndexFromPageNumber(pageNumber);
14827
+ }
14650
14828
 
14651
- type ThreeRegistersArgs = {
14652
- type: ArgumentType.THREE_REGISTERS;
14653
- noOfBytesToSkip: number;
14654
- /** W_A */
14655
- firstRegisterIndex: number;
14656
- /** W_B */
14657
- secondRegisterIndex: number;
14658
- /** W_D */
14659
- thirdRegisterIndex: number;
14660
- };
14829
+ /** Returns `true` if the page is writeable. */
14830
+ abstract isWriteable(): boolean;
14661
14831
 
14662
- type TwoRegistersArgs = {
14663
- type: ArgumentType.TWO_REGISTERS;
14664
- noOfBytesToSkip: number;
14665
- /** W_A */
14666
- firstRegisterIndex: number;
14667
- /** W_D */
14668
- secondRegisterIndex: number;
14669
- };
14832
+ /**
14833
+ * Load exactly `length` bytes from memory page, starting at index `address`
14834
+ * into the `res` array.
14835
+ *
14836
+ * Note that the `res` might be bigger than the number of bytes length, but cannot be smaller.
14837
+ *
14838
+ * Returns `null` if copying was successful and [`PageFault`] otherwise.
14839
+ * NOTE That the `result` might be partially modified in case `PageFault` occurs!
14840
+ */
14841
+ abstract loadInto(res: Uint8Array, address: PageIndex, length: number): Result$2<OK, PageFault>;
14670
14842
 
14671
- type TwoRegistersOneImmediateArgs = {
14672
- type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
14673
- noOfBytesToSkip: number;
14674
- /** W_A */
14675
- firstRegisterIndex: number;
14676
- /** W_B */
14677
- secondRegisterIndex: number;
14678
- /** V_X */
14679
- immediateDecoder: ImmediateDecoder;
14680
- };
14843
+ /**
14844
+ * Copy all bytes from the `data` into the page at index `address`.
14845
+ *
14846
+ * Returns `null` if copying was successful and [`PageFault`] otherwise.
14847
+ */
14848
+ abstract storeFrom(address: PageIndex, data: Uint8Array): Result$2<OK, PageFault>;
14849
+ /**
14850
+ * Get dump of the entire page. Should only be used for the debugger-adapter because it
14851
+ * might be inefficient.
14852
+ */
14853
+ abstract getPageDump(): Uint8Array;
14681
14854
 
14682
- type OneRegisterOneImmediateArgs = {
14683
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
14684
- noOfBytesToSkip: number;
14685
- /** W_A */
14686
- registerIndex: number;
14687
- /** V_X */
14688
- immediateDecoder: ImmediateDecoder;
14689
- };
14855
+ abstract setData(pageIndex: PageIndex, data: Uint8Array): void;
14856
+ }
14690
14857
 
14691
- type OneRegisterOneExtendedWidthImmediateArgs = {
14692
- type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
14693
- noOfBytesToSkip: number;
14694
- /** W_A */
14695
- registerIndex: number;
14696
- /** V_X */
14697
- immediateDecoder: ExtendedWitdthImmediateDecoder;
14858
+ /**
14859
+ * I had to extend ArrayBuffer type to use resizable ArrayBuffer.
14860
+ * We will be able to remove it when this is merged: https://github.com/microsoft/TypeScript/pull/58573
14861
+ * And then a new version of TypeScript is released.
14862
+ */
14863
+ declare global {
14864
+ interface ArrayBufferConstructor {
14865
+ new (length: number, options?: {
14866
+ maxByteLength: number;
14867
+ }): ArrayBuffer;
14868
+ }
14869
+ interface ArrayBuffer {
14870
+ resize(length: number): void;
14871
+ }
14872
+ }
14873
+
14874
+ type InitialMemoryState = {
14875
+ memory: Map<PageNumber, MemoryPage>;
14876
+ sbrkIndex: SbrkIndex;
14877
+ endHeapIndex: SbrkIndex;
14698
14878
  };
14699
14879
 
14700
- type TwoRegistersTwoImmediatesArgs = {
14701
- type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
14702
- noOfBytesToSkip: number;
14703
- /** W_A */
14704
- firstRegisterIndex: number;
14705
- /** W_B */
14706
- secondRegisterIndex: number;
14707
- /** V_X */
14708
- firstImmediateDecoder: ImmediateDecoder;
14709
- /** V_Y */
14710
- secondImmediateDecoder: ImmediateDecoder;
14711
- };
14880
+ declare enum AccessType {
14881
+ READ = 0,
14882
+ WRITE = 1,
14883
+ }
14712
14884
 
14713
- type TwoImmediatesArgs = {
14714
- type: ArgumentType.TWO_IMMEDIATES;
14715
- noOfBytesToSkip: number;
14716
- /** V_X */
14717
- firstImmediateDecoder: ImmediateDecoder;
14718
- /** V_Y */
14719
- secondImmediateDecoder: ImmediateDecoder;
14720
- };
14885
+ declare class Memory implements IMemory {
14886
+ static fromInitialMemory(initialMemoryState: InitialMemoryState) {
14887
+ return new Memory(
14888
+ initialMemoryState?.sbrkIndex,
14889
+ initialMemoryState?.sbrkIndex,
14890
+ initialMemoryState?.endHeapIndex,
14891
+ initialMemoryState?.memory,
14892
+ );
14893
+ }
14721
14894
 
14722
- type TwoRegistersOneOffsetArgs = {
14723
- type: ArgumentType.TWO_REGISTERS_ONE_OFFSET;
14724
- noOfBytesToSkip: number;
14725
- /** W_A */
14726
- firstRegisterIndex: number;
14727
- /** W_B */
14728
- secondRegisterIndex: number;
14729
- nextPc: number;
14730
- };
14895
+ constructor(
14896
+ private sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
14897
+ private virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
14898
+ private endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX),
14899
+ private memory = new Map<PageNumber, MemoryPage>(),
14900
+ ) {}
14731
14901
 
14732
- type OneRegisterOneImmediateOneOffsetArgs = {
14733
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
14734
- noOfBytesToSkip: number;
14735
- /** W_A */
14736
- registerIndex: number;
14737
- /** V_X */
14738
- immediateDecoder: ImmediateDecoder;
14739
- /** V_Y */
14740
- nextPc: number;
14741
- };
14902
+ store(address: U32, bytes: Uint8Array): Result$2<OK, PageFault$1> {
14903
+ return this.storeFrom(tryAsMemoryIndex(address), bytes);
14904
+ }
14742
14905
 
14743
- type OneRegisterTwoImmediatesArgs = {
14744
- type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
14745
- noOfBytesToSkip: number;
14746
- /** W_A */
14747
- registerIndex: number;
14748
- /** V_X */
14749
- firstImmediateDecoder: ImmediateDecoder;
14750
- /** V_Y */
14751
- secondImmediateDecoder: ImmediateDecoder;
14752
- };
14906
+ read(address: U32, output: Uint8Array): Result$2<OK, PageFault$1> {
14907
+ return this.loadInto(output, tryAsMemoryIndex(address));
14908
+ }
14753
14909
 
14754
- type OneOffsetArgs = {
14755
- type: ArgumentType.ONE_OFFSET;
14756
- noOfBytesToSkip: number;
14757
- /** V_X */
14758
- nextPc: number;
14759
- };
14910
+ reset() {
14911
+ this.sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
14912
+ this.virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
14913
+ this.endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX);
14914
+ this.memory = new Map<PageNumber, MemoryPage>(); // TODO [MaSi]: We should keep allocated pages somewhere and reuse it when it is possible
14915
+ }
14760
14916
 
14761
- type Args =
14762
- | EmptyArgs
14763
- | OneImmediateArgs
14764
- | TwoRegistersArgs
14765
- | ThreeRegistersArgs
14766
- | TwoRegistersOneImmediateArgs
14767
- | TwoRegistersTwoImmediatesArgs
14768
- | OneRegisterOneImmediateOneOffsetArgs
14769
- | TwoRegistersOneOffsetArgs
14770
- | OneRegisterOneImmediateArgs
14771
- | OneOffsetArgs
14772
- | TwoImmediatesArgs
14773
- | OneRegisterTwoImmediatesArgs
14774
- | OneRegisterOneExtendedWidthImmediateArgs;
14917
+ copyFrom(memory: Memory) {
14918
+ this.sbrkIndex = memory.sbrkIndex;
14919
+ this.virtualSbrkIndex = memory.virtualSbrkIndex;
14920
+ this.endHeapIndex = memory.endHeapIndex;
14921
+ this.memory = memory.memory;
14922
+ }
14775
14923
 
14776
- declare class ArgsDecoder {
14777
- private nibblesDecoder = new NibblesDecoder();
14778
- private offsetDecoder = new ImmediateDecoder();
14779
- private code: Uint8Array = new Uint8Array();
14780
- private mask: Mask = Mask.empty();
14924
+ storeFrom(address: MemoryIndex, bytes: Uint8Array): Result$2<OK, PageFault> {
14925
+ if (bytes.length === 0) {
14926
+ return Result.ok(OK);
14927
+ }
14781
14928
 
14782
- reset(code: Uint8Array, mask: Mask) {
14783
- this.code = code;
14784
- this.mask = mask;
14785
- }
14929
+ logger.insane`MEM[${address}] <- ${BytesBlob.blobFrom(bytes)}`;
14930
+ const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
14786
14931
 
14787
- fillArgs<T extends Args>(pc: number, result: T): void {
14788
- const nextInstructionDistance = 1 + this.mask.getNoOfBytesToNextInstruction(pc + 1);
14789
- result.noOfBytesToSkip = nextInstructionDistance;
14932
+ if (pagesResult.isError) {
14933
+ return Result.error(pagesResult.error, pagesResult.details);
14934
+ }
14790
14935
 
14791
- switch (result.type) {
14792
- case ArgumentType.NO_ARGUMENTS:
14793
- break;
14936
+ const pages = pagesResult.ok;
14937
+ let currentPosition: number = address;
14938
+ let bytesLeft = bytes.length;
14794
14939
 
14795
- case ArgumentType.ONE_IMMEDIATE: {
14796
- const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
14797
- const argsStartIndex = pc + 1;
14798
- result.immediateDecoder.setBytes(this.code.subarray(argsStartIndex, argsStartIndex + immediateLength));
14799
- break;
14800
- }
14940
+ for (const page of pages) {
14941
+ const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
14942
+ const bytesToWrite = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
14943
+ const sourceStartIndex = currentPosition - address;
14944
+ const source = bytes.subarray(sourceStartIndex, sourceStartIndex + bytesToWrite);
14801
14945
 
14802
- case ArgumentType.THREE_REGISTERS: {
14803
- const firstByte = this.code[pc + 1];
14804
- const secondByte = this.code[pc + 2];
14805
- this.nibblesDecoder.setByte(firstByte);
14806
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14807
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14808
- this.nibblesDecoder.setByte(secondByte);
14809
- result.thirdRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14810
- break;
14811
- }
14946
+ page.storeFrom(pageStartIndex, source);
14812
14947
 
14813
- case ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE: {
14814
- const firstByte = this.code[pc + 1];
14815
- this.nibblesDecoder.setByte(firstByte);
14816
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14817
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14948
+ currentPosition += bytesToWrite;
14949
+ bytesLeft -= bytesToWrite;
14950
+ }
14951
+ return Result.ok(OK);
14952
+ }
14818
14953
 
14819
- const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
14820
- const immediateStartIndex = pc + 2;
14821
- const immediateEndIndex = immediateStartIndex + immediateLength;
14822
- result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
14823
- break;
14824
- }
14954
+ private getPages(startAddress: MemoryIndex, length: number, accessType: AccessType): Result$2<MemoryPage[], PageFault> {
14955
+ if (length === 0) {
14956
+ return Result.ok([]);
14957
+ }
14825
14958
 
14826
- case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET: {
14827
- const firstByte = this.code[pc + 1];
14828
- this.nibblesDecoder.setByte(firstByte);
14829
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14959
+ const memoryRange = MemoryRange.fromStartAndLength(startAddress, length);
14960
+ const pageRange = PageRange.fromMemoryRange(memoryRange);
14830
14961
 
14831
- const immediateLength = this.nibblesDecoder.getHighNibbleAsLength();
14832
- const immediateStartIndex = pc + 2;
14833
- const immediateEndIndex = immediateStartIndex + immediateLength;
14834
- result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
14962
+ const pages: MemoryPage[] = [];
14835
14963
 
14836
- const offsetLength = Math.min(
14837
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14838
- Math.max(0, nextInstructionDistance - 2 - immediateLength),
14964
+ for (const pageNumber of pageRange) {
14965
+ if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
14966
+ return Result.error(
14967
+ PageFault.fromPageNumber(pageNumber, true),
14968
+ () => `Page fault: attempted to access reserved page ${pageNumber}`,
14839
14969
  );
14840
- const offsetStartIndex = pc + 2 + immediateLength;
14841
- const offsetEndIndex = offsetStartIndex + offsetLength;
14842
- this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
14843
-
14844
- result.nextPc = pc + this.offsetDecoder.getSigned();
14845
- break;
14846
14970
  }
14847
14971
 
14848
- case ArgumentType.TWO_REGISTERS_ONE_OFFSET: {
14849
- const firstByte = this.code[pc + 1];
14850
- this.nibblesDecoder.setByte(firstByte);
14851
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14852
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14853
-
14854
- const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
14855
- const offsetStartIndex = pc + 2;
14856
- const offsetEndIndex = offsetStartIndex + offsetLength;
14857
- this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
14972
+ const page = this.memory.get(pageNumber);
14858
14973
 
14859
- result.nextPc = pc + this.offsetDecoder.getSigned();
14860
- break;
14974
+ if (page === undefined) {
14975
+ return Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
14861
14976
  }
14862
14977
 
14863
- case ArgumentType.TWO_REGISTERS: {
14864
- const firstByte = this.code[pc + 1];
14865
- this.nibblesDecoder.setByte(firstByte);
14866
- result.firstRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14867
- result.secondRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14868
- break;
14978
+ if (accessType === AccessType.WRITE && !page.isWriteable()) {
14979
+ return Result.error(
14980
+ PageFault.fromPageNumber(pageNumber, true),
14981
+ () => `Page fault: attempted to write to read-only page ${pageNumber}`,
14982
+ );
14869
14983
  }
14870
14984
 
14871
- case ArgumentType.ONE_OFFSET: {
14872
- const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
14873
- const offsetStartIndex = pc + 1;
14874
- const offsetEndIndex = offsetStartIndex + offsetLength;
14875
- const offsetBytes = this.code.subarray(offsetStartIndex, offsetEndIndex);
14876
- this.offsetDecoder.setBytes(offsetBytes);
14877
- const offsetValue = this.offsetDecoder.getSigned();
14878
- result.nextPc = pc + offsetValue;
14879
- break;
14880
- }
14985
+ pages.push(page);
14986
+ }
14881
14987
 
14882
- case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE: {
14883
- const firstByte = this.code[pc + 1];
14884
- this.nibblesDecoder.setByte(firstByte);
14885
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14988
+ return Result.ok(pages);
14989
+ }
14990
+ /**
14991
+ * Read content of the memory at `[address, address + result.length)` and
14992
+ * write the result into the `result` buffer.
14993
+ *
14994
+ * Returns `null` if the data was read successfully or `PageFault` otherwise.
14995
+ */
14996
+ loadInto(result: Uint8Array, startAddress: MemoryIndex): Result$2<OK, PageFault> {
14997
+ if (result.length === 0) {
14998
+ return Result.ok(OK);
14999
+ }
14886
15000
 
14887
- const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
14888
- const immediateStartIndex = pc + 2;
14889
- const immediateEndIndex = immediateStartIndex + immediateLength;
14890
- const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
14891
- result.immediateDecoder.setBytes(immediateBytes);
14892
- break;
14893
- }
15001
+ const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
14894
15002
 
14895
- case ArgumentType.TWO_IMMEDIATES: {
14896
- const firstByte = this.code[pc + 1];
14897
- this.nibblesDecoder.setByte(firstByte);
14898
- const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
14899
- const firstImmediateStartIndex = pc + 2;
14900
- const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
14901
- const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
14902
- result.firstImmediateDecoder.setBytes(firstImmediateBytes);
14903
-
14904
- const secondImmediateLength = Math.min(
14905
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14906
- Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
14907
- );
14908
- const secondImmediateStartIndex = firstImmediateEndIndex;
14909
- const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
14910
- const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
14911
- result.secondImmediateDecoder.setBytes(secondImmediateBytes);
14912
- break;
14913
- }
15003
+ if (pagesResult.isError) {
15004
+ return Result.error(pagesResult.error, pagesResult.details);
15005
+ }
14914
15006
 
14915
- case ArgumentType.ONE_REGISTER_TWO_IMMEDIATES: {
14916
- const firstByte = this.code[pc + 1];
14917
- this.nibblesDecoder.setByte(firstByte);
14918
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15007
+ const pages = pagesResult.ok;
14919
15008
 
14920
- const firstImmediateLength = this.nibblesDecoder.getHighNibbleAsLength();
14921
- const firstImmediateStartIndex = pc + 2;
14922
- const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
14923
- const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
14924
- result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15009
+ let currentPosition: number = startAddress;
15010
+ let bytesLeft = result.length;
14925
15011
 
14926
- const secondImmediateLength = Math.min(
14927
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14928
- Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
14929
- );
14930
- const secondImmediateStartIndex = firstImmediateEndIndex;
14931
- const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
14932
- const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
14933
- result.secondImmediateDecoder.setBytes(secondImmediateBytes);
14934
- break;
14935
- }
15012
+ for (const page of pages) {
15013
+ const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
15014
+ const bytesToRead = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
15015
+ const destinationStartIndex = currentPosition - startAddress;
15016
+ const destination = result.subarray(destinationStartIndex);
14936
15017
 
14937
- case ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES: {
14938
- const firstByte = this.code[pc + 1];
14939
- this.nibblesDecoder.setByte(firstByte);
14940
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14941
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15018
+ page.loadInto(destination, pageStartIndex, bytesToRead);
14942
15019
 
14943
- const secondByte = this.code[pc + 2];
14944
- this.nibblesDecoder.setByte(secondByte);
14945
- const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
14946
- const firstImmediateStartIndex = pc + 3;
14947
- const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
14948
- const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
14949
- result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15020
+ currentPosition += bytesToRead;
15021
+ bytesLeft -= bytesToRead;
15022
+ }
14950
15023
 
14951
- const secondImmediateLength = Math.min(
14952
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14953
- Math.max(0, nextInstructionDistance - 3 - firstImmediateLength),
14954
- );
14955
- const secondImmediateStartIndex = firstImmediateEndIndex;
14956
- const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
14957
- const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
14958
- result.secondImmediateDecoder.setBytes(secondImmediateBytes);
14959
- break;
14960
- }
15024
+ logger.insane`MEM[${startAddress}] => ${BytesBlob.blobFrom(result)}`;
15025
+ return Result.ok(OK);
15026
+ }
14961
15027
 
14962
- case ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE: {
14963
- const firstByte = this.code[pc + 1];
14964
- this.nibblesDecoder.setByte(firstByte);
14965
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15028
+ sbrk(length: number): SbrkIndex {
15029
+ const currentSbrkIndex = this.sbrkIndex;
15030
+ const currentVirtualSbrkIndex = this.virtualSbrkIndex;
14966
15031
 
14967
- const immediateStartIndex = pc + 2;
14968
- const immediateEndIndex = immediateStartIndex + 8;
14969
- const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
14970
- result.immediateDecoder.setBytes(immediateBytes);
14971
- break;
14972
- }
15032
+ // new sbrk index is bigger than 2 ** 32 or endHeapIndex
15033
+ if (MAX_MEMORY_INDEX < currentVirtualSbrkIndex + length || currentVirtualSbrkIndex + length > this.endHeapIndex) {
15034
+ throw new OutOfMemory();
14973
15035
  }
14974
- }
14975
- }
14976
15036
 
14977
- declare const createResults = () => {
14978
- const results = new Array(ARGUMENT_TYPE_LENGTH) as Results;
15037
+ const newVirtualSbrkIndex = tryAsSbrkIndex(this.virtualSbrkIndex + length);
14979
15038
 
14980
- results[ArgumentType.NO_ARGUMENTS] = {
14981
- type: ArgumentType.NO_ARGUMENTS,
14982
- noOfBytesToSkip: 1,
14983
- };
15039
+ // no alllocation needed
15040
+ if (newVirtualSbrkIndex <= currentSbrkIndex) {
15041
+ this.virtualSbrkIndex = newVirtualSbrkIndex;
15042
+ return currentVirtualSbrkIndex;
15043
+ }
14984
15044
 
14985
- results[ArgumentType.ONE_IMMEDIATE] = {
14986
- type: ArgumentType.ONE_IMMEDIATE,
14987
- noOfBytesToSkip: 1,
14988
- immediateDecoder: new ImmediateDecoder(),
14989
- };
15045
+ // standard allocation using "Writeable" pages
15046
+ const newSbrkIndex = tryAsSbrkIndex(alignToPageSize(newVirtualSbrkIndex));
15047
+ // TODO [MaSi]: `getPageNumber` works incorrectly for SbrkIndex. Sbrk index should be changed to MemoryIndex
15048
+ const firstPageNumber = getPageNumber(currentSbrkIndex);
15049
+ const pagesToAllocate = (newSbrkIndex - currentSbrkIndex) / PAGE_SIZE;
15050
+ const rangeToAllocate = PageRange.fromStartAndLength(firstPageNumber, pagesToAllocate);
14990
15051
 
14991
- results[ArgumentType.TWO_REGISTERS] = {
14992
- type: ArgumentType.TWO_REGISTERS,
14993
- noOfBytesToSkip: 1,
14994
- firstRegisterIndex: 0,
14995
- secondRegisterIndex: 0,
14996
- };
15052
+ for (const pageNumber of rangeToAllocate) {
15053
+ const page = new WriteablePage(pageNumber);
15054
+ this.memory.set(pageNumber, page);
15055
+ }
14997
15056
 
14998
- results[ArgumentType.THREE_REGISTERS] = {
14999
- type: ArgumentType.THREE_REGISTERS,
15000
- noOfBytesToSkip: 1,
15001
- firstRegisterIndex: 0,
15002
- secondRegisterIndex: 0,
15003
- thirdRegisterIndex: 0,
15004
- };
15057
+ this.virtualSbrkIndex = newVirtualSbrkIndex;
15058
+ this.sbrkIndex = newSbrkIndex;
15059
+ return currentVirtualSbrkIndex;
15060
+ }
15005
15061
 
15006
- results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET] = {
15007
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET,
15008
- noOfBytesToSkip: 1,
15009
- registerIndex: 0,
15010
- immediateDecoder: new ImmediateDecoder(),
15011
- nextPc: 0,
15012
- };
15062
+ getPageDump(pageNumber: PageNumber) {
15063
+ const page = this.memory.get(pageNumber);
15064
+ return page?.getPageDump() ?? null;
15065
+ }
15013
15066
 
15014
- results[ArgumentType.TWO_REGISTERS_ONE_OFFSET] = {
15015
- type: ArgumentType.TWO_REGISTERS_ONE_OFFSET,
15016
- noOfBytesToSkip: 1,
15017
- firstRegisterIndex: 0,
15018
- secondRegisterIndex: 0,
15019
- nextPc: 0,
15020
- };
15067
+ getDirtyPages() {
15068
+ return this.memory.keys();
15069
+ }
15070
+ }
15021
15071
 
15022
- results[ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE] = {
15023
- type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE,
15024
- noOfBytesToSkip: 1,
15025
- firstRegisterIndex: 0,
15026
- secondRegisterIndex: 0,
15027
- immediateDecoder: new ImmediateDecoder(),
15028
- };
15072
+ declare class MemoryBuilder {
15073
+ private readonly initialMemory: Map<PageNumber, MemoryPage> = new Map();
15074
+ private isFinalized = false;
15029
15075
 
15030
- results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE] = {
15031
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE,
15032
- noOfBytesToSkip: 1,
15033
- registerIndex: 0,
15034
- immediateDecoder: new ImmediateDecoder(),
15035
- };
15076
+ private ensureNotFinalized() {
15077
+ if (this.isFinalized) {
15078
+ throw new FinalizedBuilderModification();
15079
+ }
15080
+ }
15036
15081
 
15037
- results[ArgumentType.ONE_REGISTER_TWO_IMMEDIATES] = {
15038
- type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES,
15039
- noOfBytesToSkip: 1,
15040
- registerIndex: 0,
15041
- firstImmediateDecoder: new ImmediateDecoder(),
15042
- secondImmediateDecoder: new ImmediateDecoder(),
15043
- };
15082
+ private ensureNoReservedMemoryUsage(range: MemoryRange) {
15083
+ if (range.overlapsWith(RESERVED_MEMORY_RANGE)) {
15084
+ throw new ReservedMemoryFault();
15085
+ }
15086
+ }
15044
15087
 
15045
- results[ArgumentType.ONE_OFFSET] = {
15046
- type: ArgumentType.ONE_OFFSET,
15047
- noOfBytesToSkip: 1,
15048
- nextPc: 0,
15049
- };
15088
+ /**
15089
+ * Create entire readable pages to handle the `[start, end)` range.
15090
+ *
15091
+ * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15092
+ * they need to be the start indices of the pages.
15093
+ *
15094
+ * The data passed will be placed at `start`, but might be shorter than the requested range,
15095
+ * prepend it with zeros if you don't wish to have it at the beginning of the page.
15096
+ */
15097
+ setReadablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15098
+ this.ensureNotFinalized();
15099
+ check`${start < end} end has to be bigger than start`;
15100
+ check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15101
+ check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15102
+ check`${data.length <= end - start} the initial data is longer than address range`;
15050
15103
 
15051
- results[ArgumentType.TWO_IMMEDIATES] = {
15052
- type: ArgumentType.TWO_IMMEDIATES,
15053
- noOfBytesToSkip: 1,
15054
- firstImmediateDecoder: new ImmediateDecoder(),
15055
- secondImmediateDecoder: new ImmediateDecoder(),
15056
- };
15104
+ const length = end - start;
15105
+ const range = MemoryRange.fromStartAndLength(start, length);
15057
15106
 
15058
- results[ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES] = {
15059
- type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES,
15060
- noOfBytesToSkip: 1,
15061
- firstImmediateDecoder: new ImmediateDecoder(),
15062
- secondImmediateDecoder: new ImmediateDecoder(),
15063
- firstRegisterIndex: 0,
15064
- secondRegisterIndex: 0,
15065
- };
15107
+ this.ensureNoReservedMemoryUsage(range);
15066
15108
 
15067
- results[ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE] = {
15068
- type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE,
15069
- noOfBytesToSkip: 9,
15070
- registerIndex: 0,
15071
- immediateDecoder: new ExtendedWitdthImmediateDecoder(),
15072
- };
15109
+ const pages = Array.from(PageRange.fromMemoryRange(range));
15110
+ const noOfPages = pages.length;
15073
15111
 
15074
- return results;
15075
- };
15112
+ for (let i = 0; i < noOfPages; i++) {
15113
+ const pageNumber = pages[i];
15114
+ const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15115
+ const page = new ReadablePage(pageNumber, dataChunk);
15116
+ this.initialMemory.set(pageNumber, page);
15117
+ }
15076
15118
 
15077
- declare enum Instruction {
15078
- TRAP = 0,
15079
- FALLTHROUGH = 1,
15080
- ECALLI = 10,
15081
- LOAD_IMM_64 = 20,
15082
- STORE_IMM_U8 = 30,
15083
- STORE_IMM_U16 = 31,
15084
- STORE_IMM_U32 = 32,
15085
- STORE_IMM_U64 = 33,
15086
- JUMP = 40,
15087
- JUMP_IND = 50,
15088
- LOAD_IMM = 51,
15089
- LOAD_U8 = 52,
15090
- LOAD_I8 = 53,
15091
- LOAD_U16 = 54,
15092
- LOAD_I16 = 55,
15093
- LOAD_U32 = 56,
15094
- LOAD_I32 = 57,
15095
- LOAD_U64 = 58,
15096
- STORE_U8 = 59,
15097
- STORE_U16 = 60,
15098
- STORE_U32 = 61,
15099
- STORE_U64 = 62,
15100
- STORE_IMM_IND_U8 = 70,
15101
- STORE_IMM_IND_U16 = 71,
15102
- STORE_IMM_IND_U32 = 72,
15103
- STORE_IMM_IND_U64 = 73,
15104
- LOAD_IMM_JUMP = 80,
15105
- BRANCH_EQ_IMM = 81,
15106
- BRANCH_NE_IMM = 82,
15107
- BRANCH_LT_U_IMM = 83,
15108
- BRANCH_LE_U_IMM = 84,
15109
- BRANCH_GE_U_IMM = 85,
15110
- BRANCH_GT_U_IMM = 86,
15111
- BRANCH_LT_S_IMM = 87,
15112
- BRANCH_LE_S_IMM = 88,
15113
- BRANCH_GE_S_IMM = 89,
15114
- BRANCH_GT_S_IMM = 90,
15115
- MOVE_REG = 100,
15116
- SBRK = 101,
15117
- COUNT_SET_BITS_64 = 102,
15118
- COUNT_SET_BITS_32 = 103,
15119
- LEADING_ZERO_BITS_64 = 104,
15120
- LEADING_ZERO_BITS_32 = 105,
15121
- TRAILING_ZERO_BITS_64 = 106,
15122
- TRAILING_ZERO_BITS_32 = 107,
15123
- SIGN_EXTEND_8 = 108,
15124
- SIGN_EXTEND_16 = 109,
15125
- ZERO_EXTEND_16 = 110,
15126
- REVERSE_BYTES = 111,
15127
- STORE_IND_U8 = 120,
15128
- STORE_IND_U16 = 121,
15129
- STORE_IND_U32 = 122,
15130
- STORE_IND_U64 = 123,
15131
- LOAD_IND_U8 = 124,
15132
- LOAD_IND_I8 = 125,
15133
- LOAD_IND_U16 = 126,
15134
- LOAD_IND_I16 = 127,
15135
- LOAD_IND_U32 = 128,
15136
- LOAD_IND_I32 = 129,
15137
- LOAD_IND_U64 = 130,
15138
- ADD_IMM_32 = 131,
15139
- AND_IMM = 132,
15140
- XOR_IMM = 133,
15141
- OR_IMM = 134,
15142
- MUL_IMM_32 = 135,
15143
- SET_LT_U_IMM = 136,
15144
- SET_LT_S_IMM = 137,
15145
- SHLO_L_IMM_32 = 138,
15146
- SHLO_R_IMM_32 = 139,
15147
- SHAR_R_IMM_32 = 140,
15148
- NEG_ADD_IMM_32 = 141,
15149
- SET_GT_U_IMM = 142,
15150
- SET_GT_S_IMM = 143,
15151
- SHLO_L_IMM_ALT_32 = 144,
15152
- SHLO_R_IMM_ALT_32 = 145,
15153
- SHAR_R_IMM_ALT_32 = 146,
15154
- CMOV_IZ_IMM = 147,
15155
- CMOV_NZ_IMM = 148,
15156
- ADD_IMM_64 = 149,
15157
- MUL_IMM_64 = 150,
15158
- SHLO_L_IMM_64 = 151,
15159
- SHLO_R_IMM_64 = 152,
15160
- SHAR_R_IMM_64 = 153,
15161
- NEG_ADD_IMM_64 = 154,
15162
- SHLO_L_IMM_ALT_64 = 155,
15163
- SHLO_R_IMM_ALT_64 = 156,
15164
- SHAR_R_IMM_ALT_64 = 157,
15165
- ROT_R_64_IMM = 158,
15166
- ROT_R_64_IMM_ALT = 159,
15167
- ROT_R_32_IMM = 160,
15168
- ROT_R_32_IMM_ALT = 161,
15169
- BRANCH_EQ = 170,
15170
- BRANCH_NE = 171,
15171
- BRANCH_LT_U = 172,
15172
- BRANCH_LT_S = 173,
15173
- BRANCH_GE_U = 174,
15174
- BRANCH_GE_S = 175,
15175
- LOAD_IMM_JUMP_IND = 180,
15176
- ADD_32 = 190,
15177
- SUB_32 = 191,
15178
- MUL_32 = 192,
15179
- DIV_U_32 = 193,
15180
- DIV_S_32 = 194,
15181
- REM_U_32 = 195,
15182
- REM_S_32 = 196,
15183
- SHLO_L_32 = 197,
15184
- SHLO_R_32 = 198,
15185
- SHAR_R_32 = 199,
15186
- ADD_64 = 200,
15187
- SUB_64 = 201,
15188
- MUL_64 = 202,
15189
- DIV_U_64 = 203,
15190
- DIV_S_64 = 204,
15191
- REM_U_64 = 205,
15192
- REM_S_64 = 206,
15193
- SHLO_L_64 = 207,
15194
- SHLO_R_64 = 208,
15195
- SHAR_R_64 = 209,
15196
- AND = 210,
15197
- XOR = 211,
15198
- OR = 212,
15199
- MUL_UPPER_S_S = 213,
15200
- MUL_UPPER_U_U = 214,
15201
- MUL_UPPER_S_U = 215,
15202
- SET_LT_U = 216,
15203
- SET_LT_S = 217,
15204
- CMOV_IZ = 218,
15205
- CMOV_NZ = 219,
15206
- ROT_L_64 = 220,
15207
- ROT_L_32 = 221,
15208
- ROT_R_64 = 222,
15209
- ROT_R_32 = 223,
15210
- AND_INV = 224,
15211
- OR_INV = 225,
15212
- XNOR = 226,
15213
- MAX = 227,
15214
- MAX_U = 228,
15215
- MIN = 229,
15216
- MIN_U = 230,
15119
+ return this;
15120
+ }
15121
+
15122
+ /**
15123
+ * Create entire writeable pages to handle the `[start, end)` range.
15124
+ *
15125
+ * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15126
+ * they need to be the start indices of the pages.
15127
+ *
15128
+ * The data passed will be placed at `start`, but might be shorter than the requested range,
15129
+ * prepend it with zeros if you don't wish to have it at the beginning of the page.
15130
+ */
15131
+ setWriteablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15132
+ this.ensureNotFinalized();
15133
+ check`${start < end} end has to be bigger than start`;
15134
+ check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15135
+ check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15136
+ check`${data.length <= end - start} the initial data is longer than address range`;
15137
+
15138
+ const length = end - start;
15139
+ const range = MemoryRange.fromStartAndLength(start, length);
15140
+
15141
+ this.ensureNoReservedMemoryUsage(range);
15142
+
15143
+ const pages = Array.from(PageRange.fromMemoryRange(range));
15144
+ const noOfPages = pages.length;
15145
+
15146
+ for (let i = 0; i < noOfPages; i++) {
15147
+ const pageNumber = pages[i];
15148
+ const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15149
+ const page = new WriteablePage(pageNumber, dataChunk);
15150
+ this.initialMemory.set(pageNumber, page);
15151
+ }
15152
+
15153
+ return this;
15154
+ }
15155
+
15156
+ /**
15157
+ * This function can be useful when page map and initial memory data are provided separatelly.
15158
+ * You can use setWriteablePages/setReadablePages to create empty pages and then setData to fill them
15159
+ */
15160
+ setData(start: MemoryIndex, data: Uint8Array) {
15161
+ this.ensureNotFinalized();
15162
+ const pageOffset = start % PAGE_SIZE;
15163
+ const remainingSpaceOnPage = PAGE_SIZE - pageOffset;
15164
+ check`${data.length <= remainingSpaceOnPage} The data has to fit into a single page.`;
15165
+
15166
+ const length = data.length;
15167
+ const range = MemoryRange.fromStartAndLength(start, length);
15168
+
15169
+ this.ensureNoReservedMemoryUsage(range);
15170
+
15171
+ const pageNumber = getPageNumber(start);
15172
+ const page = this.initialMemory.get(pageNumber);
15173
+
15174
+ if (page === undefined) {
15175
+ throw new PageNotExist();
15176
+ }
15177
+
15178
+ const startPageIndex = tryAsPageIndex(start - page.start);
15179
+ page.setData(startPageIndex, data);
15180
+
15181
+ return this;
15182
+ }
15183
+
15184
+ finalize(startHeapIndex: MemoryIndex, endHeapIndex: SbrkIndex): Memory {
15185
+ check`
15186
+ ${startHeapIndex <= endHeapIndex}
15187
+ startHeapIndex (${startHeapIndex}) has to be less than or equal to endHeapIndex (${endHeapIndex})
15188
+ `;
15189
+ this.ensureNotFinalized();
15190
+
15191
+ const heapRange = MemoryRange.fromStartAndLength(startHeapIndex, endHeapIndex - startHeapIndex);
15192
+ const heapPagesRange = PageRange.fromMemoryRange(heapRange);
15193
+ const initializedPageNumbers = Array.from(this.initialMemory.keys());
15194
+
15195
+ for (const pageNumber of initializedPageNumbers) {
15196
+ if (heapPagesRange.isInRange(pageNumber)) {
15197
+ throw new IncorrectSbrkIndex();
15198
+ }
15199
+ }
15200
+
15201
+ const memory = Memory.fromInitialMemory({
15202
+ memory: this.initialMemory,
15203
+ sbrkIndex: tryAsSbrkIndex(startHeapIndex),
15204
+ endHeapIndex,
15205
+ });
15206
+
15207
+ this.isFinalized = true;
15208
+ return memory;
15209
+ }
15217
15210
  }
15218
15211
 
15219
- declare const instructionArgumentTypeMap = (() => {
15220
- const instructionArgumentTypeMap = new Array<ArgumentType>(HIGHEST_INSTRUCTION_NUMBER + 1);
15212
+ declare const NO_OF_REGISTERS = 13;
15221
15213
 
15222
- instructionArgumentTypeMap[Instruction.TRAP] = ArgumentType.NO_ARGUMENTS;
15223
- instructionArgumentTypeMap[Instruction.FALLTHROUGH] = ArgumentType.NO_ARGUMENTS;
15214
+ declare class MemorySegment extends WithDebug {
15215
+ static from({ start, end, data }: Omit<MemorySegment, never>) {
15216
+ return new MemorySegment(start, end, data);
15217
+ }
15218
+
15219
+ constructor(
15220
+ public readonly start: number,
15221
+ public readonly end: number,
15222
+ public readonly data: Uint8Array | null,
15223
+ ) {
15224
+ super();
15225
+ }
15226
+ }
15227
+ declare class SpiMemory extends WithDebug {
15228
+ constructor(
15229
+ public readonly readable: MemorySegment[],
15230
+ public readonly writeable: MemorySegment[],
15231
+ public readonly sbrkIndex: number,
15232
+ public readonly heapEnd: number,
15233
+ ) {
15234
+ super();
15235
+ }
15236
+ }
15237
+
15238
+ declare class SpiProgram extends WithDebug {
15239
+ constructor(
15240
+ public readonly code: Uint8Array,
15241
+ public readonly memory: SpiMemory,
15242
+ public readonly registers: BigUint64Array,
15243
+ ) {
15244
+ super();
15245
+ }
15246
+ }
15247
+
15248
+ /**
15249
+ * program = E_3(|o|) ++ E_3(|w|) ++ E_2(z) ++ E_3(s) ++ o ++ w ++ E_4(|c|) ++ c
15250
+ *
15251
+ * E_n - little endian encoding, n - length
15252
+ * o - initial read only data
15253
+ * w - initial heap
15254
+ * z - heap pages filled with zeros
15255
+ * s - stack size
15256
+ * c - program code
15257
+ *
15258
+ * https://graypaper.fluffylabs.dev/#/579bd12/2b92022b9202
15259
+ */
15260
+ declare function decodeStandardProgram(program: Uint8Array, args: Uint8Array) {
15261
+ const decoder = Decoder.fromBlob(program);
15262
+ const oLength = decoder.u24();
15263
+ const wLength = decoder.u24();
15264
+ check`${args.length <= DATA_LENGTH} Incorrect arguments length`;
15265
+ check`${oLength <= DATA_LENGTH} Incorrect readonly segment length`;
15266
+ const readOnlyLength = oLength;
15267
+ check`${wLength <= DATA_LENGTH} Incorrect heap segment length`;
15268
+ const heapLength = wLength;
15269
+ const noOfHeapZerosPages = decoder.u16();
15270
+ const stackSize = decoder.u24();
15271
+ const readOnlyMemory = decoder.bytes(readOnlyLength).raw;
15272
+ const initialHeap = decoder.bytes(heapLength).raw;
15273
+ const codeLength = decoder.u32();
15274
+ const code = decoder.bytes(codeLength).raw;
15275
+ decoder.finish();
15276
+
15277
+ const readonlyDataStart = SEGMENT_SIZE;
15278
+ const readonlyDataEnd = SEGMENT_SIZE + alignToPageSize(readOnlyLength);
15279
+ const heapDataStart = 2 * SEGMENT_SIZE + alignToSegmentSize(readOnlyLength);
15280
+ const heapDataEnd = heapDataStart + alignToPageSize(heapLength);
15281
+ const heapZerosEnd = heapDataStart + alignToPageSize(heapLength) + noOfHeapZerosPages * PAGE_SIZE;
15282
+ const stackStart = STACK_SEGMENT - alignToPageSize(stackSize);
15283
+ const stackEnd = STACK_SEGMENT;
15284
+ const argsStart = ARGS_SEGMENT;
15285
+ const argsEnd = argsStart + alignToPageSize(args.length);
15286
+ const argsZerosEnd = argsEnd + alignToPageSize(args.length);
15287
+
15288
+ function nonEmpty(s: MemorySegment | false): s is MemorySegment {
15289
+ return s !== false;
15290
+ }
15291
+
15292
+ const readableMemory = [
15293
+ readOnlyLength > 0 && getMemorySegment(readonlyDataStart, readonlyDataEnd, readOnlyMemory),
15294
+ args.length > 0 && getMemorySegment(argsStart, argsEnd, args),
15295
+ argsEnd < argsZerosEnd && getMemorySegment(argsEnd, argsZerosEnd),
15296
+ ].filter(nonEmpty);
15297
+ const writeableMemory = [
15298
+ heapLength > 0 && getMemorySegment(heapDataStart, heapDataEnd, initialHeap),
15299
+ heapDataEnd < heapZerosEnd && getMemorySegment(heapDataEnd, heapZerosEnd),
15300
+ stackStart < stackEnd && getMemorySegment(stackStart, stackEnd),
15301
+ ].filter(nonEmpty);
15302
+
15303
+ return new SpiProgram(
15304
+ code,
15305
+ new SpiMemory(readableMemory, writeableMemory, heapZerosEnd, stackStart),
15306
+ getRegisters(args.length),
15307
+ );
15308
+ }
15309
+
15310
+ declare function getMemorySegment(start: number, end: number, data: Uint8Array | null = null) {
15311
+ return new MemorySegment(start, end, data);
15312
+ }
15313
+
15314
+ declare function getRegisters(argsLength: number) {
15315
+ const regs = new BigUint64Array(NO_OF_REGISTERS);
15316
+
15317
+ // GP reference: https://graypaper.fluffylabs.dev/#/579bd12/2c7c012cb101
15318
+ regs[0] = BigInt(LAST_PAGE);
15319
+ regs[1] = BigInt(STACK_SEGMENT);
15320
+ regs[7] = BigInt(ARGS_SEGMENT);
15321
+ regs[8] = BigInt(argsLength);
15322
+
15323
+ return regs;
15324
+ }
15325
+
15326
+ type index$8_MemorySegment = MemorySegment;
15327
+ declare const index$8_MemorySegment: typeof MemorySegment;
15328
+ declare const index$8_NO_OF_REGISTERS: typeof NO_OF_REGISTERS;
15329
+ type index$8_SpiMemory = SpiMemory;
15330
+ declare const index$8_SpiMemory: typeof SpiMemory;
15331
+ type index$8_SpiProgram = SpiProgram;
15332
+ declare const index$8_SpiProgram: typeof SpiProgram;
15333
+ declare const index$8_decodeStandardProgram: typeof decodeStandardProgram;
15334
+ declare const index$8_getMemorySegment: typeof getMemorySegment;
15335
+ declare const index$8_getRegisters: typeof getRegisters;
15336
+ declare namespace index$8 {
15337
+ export {
15338
+ index$8_MemorySegment as MemorySegment,
15339
+ index$8_NO_OF_REGISTERS as NO_OF_REGISTERS,
15340
+ index$8_SpiMemory as SpiMemory,
15341
+ index$8_SpiProgram as SpiProgram,
15342
+ index$8_decodeStandardProgram as decodeStandardProgram,
15343
+ index$8_getMemorySegment as getMemorySegment,
15344
+ index$8_getRegisters as getRegisters,
15345
+ };
15346
+ }
15347
+
15348
+ declare class Program {
15349
+ static fromSpi(blob: Uint8Array, args: Uint8Array, hasMetadata: boolean) {
15350
+ const { code: spiCode, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
15351
+ const { code, memory: rawMemory, registers } = decodeStandardProgram(spiCode, args);
15352
+ const regs = new Registers();
15353
+ regs.copyFrom(registers);
15354
+ const memoryBuilder = new MemoryBuilder();
15355
+
15356
+ for (const { start, end, data } of rawMemory.readable) {
15357
+ const startIndex = tryAsMemoryIndex(start);
15358
+ const endIndex = tryAsMemoryIndex(end);
15359
+ memoryBuilder.setReadablePages(startIndex, endIndex, data ?? new Uint8Array());
15360
+ }
15361
+
15362
+ for (const { start, end, data } of rawMemory.writeable) {
15363
+ const startIndex = tryAsMemoryIndex(start);
15364
+ const endIndex = tryAsMemoryIndex(end);
15365
+ memoryBuilder.setWriteablePages(startIndex, endIndex, data ?? new Uint8Array());
15366
+ }
15367
+
15368
+ const heapStart = tryAsMemoryIndex(rawMemory.sbrkIndex);
15369
+ const heapEnd = tryAsSbrkIndex(rawMemory.heapEnd);
15370
+ const memory = memoryBuilder.finalize(heapStart, heapEnd);
15371
+
15372
+ return new Program(code, regs, memory, metadata);
15373
+ }
15374
+
15375
+ static fromGeneric(blob: Uint8Array, hasMetadata: boolean) {
15376
+ const { code, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
15377
+ const regs = new Registers();
15378
+ const memory = new Memory();
15379
+ return new Program(code, regs, memory, metadata);
15380
+ }
15381
+
15382
+ private constructor(
15383
+ public readonly code: Uint8Array,
15384
+ public readonly registers: Registers,
15385
+ public readonly memory: Memory,
15386
+ public metadata: Uint8Array = new Uint8Array(),
15387
+ ) {}
15388
+ }
15389
+
15390
+ /**
15391
+ * A function that splits preimage into metadata and code.
15392
+ *
15393
+ * https://graypaper.fluffylabs.dev/#/cc517d7/109a01109a01?v=0.6.5
15394
+ */
15395
+ declare function extractCodeAndMetadata(blobWithMetadata: Uint8Array) {
15396
+ const decoder = Decoder.fromBlob(blobWithMetadata);
15397
+ const metadata = decoder.bytesBlob().raw;
15398
+ const code = decoder.remainingBytes().raw;
15399
+ return { metadata, code };
15400
+ }
15401
+
15402
+ type index$7_Program = Program;
15403
+ declare const index$7_Program: typeof Program;
15404
+ declare const index$7_extractCodeAndMetadata: typeof extractCodeAndMetadata;
15405
+ declare namespace index$7 {
15406
+ export {
15407
+ index$7_Program as Program,
15408
+ index$7_extractCodeAndMetadata as extractCodeAndMetadata,
15409
+ };
15410
+ }
15411
+
15412
+ /**
15413
+ * Mask class is an implementation of skip function defined in GP.
15414
+ *
15415
+ * https://graypaper.fluffylabs.dev/#/5f542d7/237201239801
15416
+ */
15417
+ declare class Mask {
15418
+ /**
15419
+ * The lookup table will have `0` at the index which corresponds to an instruction on the same index in the bytecode.
15420
+ * In case the value is non-zero it signifies the offset to the index with next instruction.
15421
+ *
15422
+ * Example:
15423
+ * ```
15424
+ * 0..1..2..3..4..5..6..7..8..9 # Indices
15425
+ * 0..2..1..0..1..0..3..2..1..0 # lookupTable forward values
15426
+ * ```
15427
+ * There are instructions at indices `0, 3, 5, 9`.
15428
+ */
15429
+ private lookupTableForward: Uint8Array;
15430
+
15431
+ constructor(mask: BitVec) {
15432
+ this.lookupTableForward = this.buildLookupTableForward(mask);
15433
+ }
15434
+
15435
+ isInstruction(index: number) {
15436
+ return this.lookupTableForward[index] === 0;
15437
+ }
15438
+
15439
+ getNoOfBytesToNextInstruction(index: number) {
15440
+ check`${index >= 0} index (${index}) cannot be a negative number`;
15441
+ return Math.min(this.lookupTableForward[index] ?? 0, MAX_INSTRUCTION_DISTANCE);
15442
+ }
15443
+
15444
+ private buildLookupTableForward(mask: BitVec) {
15445
+ const table = safeAllocUint8Array(mask.bitLength);
15446
+ let lastInstructionOffset = 0;
15447
+ for (let i = mask.bitLength - 1; i >= 0; i--) {
15448
+ if (mask.isSet(i)) {
15449
+ lastInstructionOffset = 0;
15450
+ } else {
15451
+ lastInstructionOffset++;
15452
+ }
15453
+ table[i] = lastInstructionOffset;
15454
+ }
15455
+ return table;
15456
+ }
15224
15457
 
15225
- instructionArgumentTypeMap[Instruction.ECALLI] = ArgumentType.ONE_IMMEDIATE;
15458
+ static empty() {
15459
+ return new Mask(BitVec.empty(0));
15460
+ }
15461
+ }
15226
15462
 
15227
- instructionArgumentTypeMap[Instruction.LOAD_IMM_64] = ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
15463
+ declare enum ArgumentType {
15464
+ NO_ARGUMENTS = 0,
15465
+ ONE_IMMEDIATE = 1,
15466
+ TWO_IMMEDIATES = 2,
15467
+ ONE_OFFSET = 3,
15468
+ ONE_REGISTER_ONE_IMMEDIATE = 4,
15469
+ ONE_REGISTER_TWO_IMMEDIATES = 5,
15470
+ ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET = 6,
15471
+ TWO_REGISTERS = 7,
15472
+ TWO_REGISTERS_ONE_IMMEDIATE = 8,
15473
+ TWO_REGISTERS_ONE_OFFSET = 9,
15474
+ TWO_REGISTERS_TWO_IMMEDIATES = 10,
15475
+ THREE_REGISTERS = 11,
15476
+ ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE = 12,
15477
+ }
15228
15478
 
15229
- instructionArgumentTypeMap[Instruction.STORE_IMM_U8] = ArgumentType.TWO_IMMEDIATES;
15230
- instructionArgumentTypeMap[Instruction.STORE_IMM_U16] = ArgumentType.TWO_IMMEDIATES;
15231
- instructionArgumentTypeMap[Instruction.STORE_IMM_U32] = ArgumentType.TWO_IMMEDIATES;
15232
- instructionArgumentTypeMap[Instruction.STORE_IMM_U64] = ArgumentType.TWO_IMMEDIATES;
15479
+ declare class ExtendedWitdthImmediateDecoder {
15480
+ private unsignedImmediate: BigUint64Array;
15481
+ private bytes: Uint8Array;
15233
15482
 
15234
- instructionArgumentTypeMap[Instruction.JUMP] = ArgumentType.ONE_OFFSET;
15483
+ constructor() {
15484
+ const buffer = new ArrayBuffer(IMMEDIATE_SIZE);
15485
+ this.unsignedImmediate = new BigUint64Array(buffer);
15486
+ this.bytes = new Uint8Array(buffer);
15487
+ }
15235
15488
 
15236
- instructionArgumentTypeMap[Instruction.JUMP_IND] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15237
- instructionArgumentTypeMap[Instruction.LOAD_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15238
- instructionArgumentTypeMap[Instruction.LOAD_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15239
- instructionArgumentTypeMap[Instruction.LOAD_I8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15240
- instructionArgumentTypeMap[Instruction.LOAD_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15241
- instructionArgumentTypeMap[Instruction.LOAD_I16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15242
- instructionArgumentTypeMap[Instruction.LOAD_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15243
- instructionArgumentTypeMap[Instruction.LOAD_I32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15244
- instructionArgumentTypeMap[Instruction.LOAD_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15245
- instructionArgumentTypeMap[Instruction.STORE_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15246
- instructionArgumentTypeMap[Instruction.STORE_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15247
- instructionArgumentTypeMap[Instruction.STORE_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15248
- instructionArgumentTypeMap[Instruction.STORE_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15489
+ setBytes(bytes: Uint8Array) {
15490
+ let i = 0;
15491
+ for (; i < bytes.length; i++) {
15492
+ this.bytes[i] = bytes[i];
15493
+ }
15249
15494
 
15250
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U8] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15251
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U16] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15252
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U32] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15253
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U64] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15495
+ for (; i < IMMEDIATE_SIZE; i++) {
15496
+ this.bytes[i] = 0;
15497
+ }
15498
+ }
15254
15499
 
15255
- instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15256
- instructionArgumentTypeMap[Instruction.BRANCH_EQ_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15257
- instructionArgumentTypeMap[Instruction.BRANCH_NE_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15258
- instructionArgumentTypeMap[Instruction.BRANCH_LT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15259
- instructionArgumentTypeMap[Instruction.BRANCH_LE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15260
- instructionArgumentTypeMap[Instruction.BRANCH_GE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15261
- instructionArgumentTypeMap[Instruction.BRANCH_GT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15262
- instructionArgumentTypeMap[Instruction.BRANCH_LT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15263
- instructionArgumentTypeMap[Instruction.BRANCH_LE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15264
- instructionArgumentTypeMap[Instruction.BRANCH_GE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15265
- instructionArgumentTypeMap[Instruction.BRANCH_GT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15500
+ getValue() {
15501
+ return this.unsignedImmediate[0];
15502
+ }
15266
15503
 
15267
- instructionArgumentTypeMap[Instruction.MOVE_REG] = ArgumentType.TWO_REGISTERS;
15268
- instructionArgumentTypeMap[Instruction.SBRK] = ArgumentType.TWO_REGISTERS;
15269
- instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_64] = ArgumentType.TWO_REGISTERS;
15270
- instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_32] = ArgumentType.TWO_REGISTERS;
15271
- instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
15272
- instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
15273
- instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
15274
- instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
15275
- instructionArgumentTypeMap[Instruction.SIGN_EXTEND_8] = ArgumentType.TWO_REGISTERS;
15276
- instructionArgumentTypeMap[Instruction.SIGN_EXTEND_16] = ArgumentType.TWO_REGISTERS;
15277
- instructionArgumentTypeMap[Instruction.ZERO_EXTEND_16] = ArgumentType.TWO_REGISTERS;
15278
- instructionArgumentTypeMap[Instruction.REVERSE_BYTES] = ArgumentType.TWO_REGISTERS;
15504
+ getBytesAsLittleEndian() {
15505
+ return this.bytes.subarray(0, IMMEDIATE_SIZE);
15506
+ }
15507
+ }
15279
15508
 
15280
- instructionArgumentTypeMap[Instruction.STORE_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15281
- instructionArgumentTypeMap[Instruction.STORE_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15282
- instructionArgumentTypeMap[Instruction.STORE_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15283
- instructionArgumentTypeMap[Instruction.STORE_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15284
- instructionArgumentTypeMap[Instruction.LOAD_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15285
- instructionArgumentTypeMap[Instruction.LOAD_IND_I8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15286
- instructionArgumentTypeMap[Instruction.LOAD_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15287
- instructionArgumentTypeMap[Instruction.LOAD_IND_I16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15288
- instructionArgumentTypeMap[Instruction.LOAD_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15289
- instructionArgumentTypeMap[Instruction.LOAD_IND_I32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15290
- instructionArgumentTypeMap[Instruction.LOAD_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15291
- instructionArgumentTypeMap[Instruction.ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15292
- instructionArgumentTypeMap[Instruction.ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15293
- instructionArgumentTypeMap[Instruction.AND_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15294
- instructionArgumentTypeMap[Instruction.XOR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15295
- instructionArgumentTypeMap[Instruction.OR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15296
- instructionArgumentTypeMap[Instruction.MUL_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15297
- instructionArgumentTypeMap[Instruction.MUL_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15298
- instructionArgumentTypeMap[Instruction.SET_LT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15299
- instructionArgumentTypeMap[Instruction.SET_LT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15300
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15301
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15302
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15303
- instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15304
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15305
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15306
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15307
- instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15308
- instructionArgumentTypeMap[Instruction.SET_GT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15309
- instructionArgumentTypeMap[Instruction.SET_GT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15310
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15311
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15312
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15313
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15314
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15315
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15316
- instructionArgumentTypeMap[Instruction.CMOV_IZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15317
- instructionArgumentTypeMap[Instruction.CMOV_NZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15318
- instructionArgumentTypeMap[Instruction.ROT_R_64_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15319
- instructionArgumentTypeMap[Instruction.ROT_R_64_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15320
- instructionArgumentTypeMap[Instruction.ROT_R_32_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15321
- instructionArgumentTypeMap[Instruction.ROT_R_32_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15509
+ declare class ImmediateDecoder {
15510
+ private u32: Uint32Array;
15511
+ private i32: Int32Array;
15512
+ private u64: BigUint64Array;
15513
+ private i64: BigInt64Array;
15514
+ private view: DataView;
15515
+ private bytes: Uint8Array;
15322
15516
 
15323
- instructionArgumentTypeMap[Instruction.BRANCH_EQ] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15324
- instructionArgumentTypeMap[Instruction.BRANCH_NE] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15325
- instructionArgumentTypeMap[Instruction.BRANCH_LT_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15326
- instructionArgumentTypeMap[Instruction.BRANCH_LT_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15327
- instructionArgumentTypeMap[Instruction.BRANCH_GE_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15328
- instructionArgumentTypeMap[Instruction.BRANCH_GE_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15517
+ constructor() {
15518
+ const buffer = new ArrayBuffer(BUFFER_SIZE);
15519
+ this.u32 = new Uint32Array(buffer);
15520
+ this.i32 = new Int32Array(buffer);
15521
+ this.u64 = new BigUint64Array(buffer);
15522
+ this.i64 = new BigInt64Array(buffer);
15523
+ this.view = new DataView(buffer);
15524
+ this.bytes = new Uint8Array(buffer);
15525
+ }
15329
15526
 
15330
- instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP_IND] = ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
15527
+ setBytes(bytes: Uint8Array) {
15528
+ const n = bytes.length;
15529
+ const msb = n > 0 ? bytes[n - 1] & 0x80 : 0;
15530
+ const noOfBytes = Math.min(n, BUFFER_SIZE);
15531
+ const prefix = msb !== 0 ? 0xff : 0x00;
15331
15532
 
15332
- instructionArgumentTypeMap[Instruction.ADD_32] = ArgumentType.THREE_REGISTERS;
15333
- instructionArgumentTypeMap[Instruction.ADD_64] = ArgumentType.THREE_REGISTERS;
15334
- instructionArgumentTypeMap[Instruction.SUB_32] = ArgumentType.THREE_REGISTERS;
15335
- instructionArgumentTypeMap[Instruction.SUB_64] = ArgumentType.THREE_REGISTERS;
15336
- instructionArgumentTypeMap[Instruction.AND] = ArgumentType.THREE_REGISTERS;
15337
- instructionArgumentTypeMap[Instruction.XOR] = ArgumentType.THREE_REGISTERS;
15338
- instructionArgumentTypeMap[Instruction.OR] = ArgumentType.THREE_REGISTERS;
15339
- instructionArgumentTypeMap[Instruction.MUL_32] = ArgumentType.THREE_REGISTERS;
15340
- instructionArgumentTypeMap[Instruction.MUL_64] = ArgumentType.THREE_REGISTERS;
15341
- instructionArgumentTypeMap[Instruction.MUL_UPPER_S_S] = ArgumentType.THREE_REGISTERS;
15342
- instructionArgumentTypeMap[Instruction.MUL_UPPER_U_U] = ArgumentType.THREE_REGISTERS;
15343
- instructionArgumentTypeMap[Instruction.MUL_UPPER_S_U] = ArgumentType.THREE_REGISTERS;
15344
- instructionArgumentTypeMap[Instruction.DIV_U_32] = ArgumentType.THREE_REGISTERS;
15345
- instructionArgumentTypeMap[Instruction.DIV_S_32] = ArgumentType.THREE_REGISTERS;
15346
- instructionArgumentTypeMap[Instruction.REM_U_32] = ArgumentType.THREE_REGISTERS;
15347
- instructionArgumentTypeMap[Instruction.REM_S_32] = ArgumentType.THREE_REGISTERS;
15348
- instructionArgumentTypeMap[Instruction.DIV_U_64] = ArgumentType.THREE_REGISTERS;
15349
- instructionArgumentTypeMap[Instruction.DIV_S_64] = ArgumentType.THREE_REGISTERS;
15350
- instructionArgumentTypeMap[Instruction.REM_U_64] = ArgumentType.THREE_REGISTERS;
15351
- instructionArgumentTypeMap[Instruction.REM_S_64] = ArgumentType.THREE_REGISTERS;
15352
- instructionArgumentTypeMap[Instruction.SET_LT_U] = ArgumentType.THREE_REGISTERS;
15353
- instructionArgumentTypeMap[Instruction.SET_LT_S] = ArgumentType.THREE_REGISTERS;
15354
- instructionArgumentTypeMap[Instruction.SHLO_L_32] = ArgumentType.THREE_REGISTERS;
15355
- instructionArgumentTypeMap[Instruction.SHLO_R_32] = ArgumentType.THREE_REGISTERS;
15356
- instructionArgumentTypeMap[Instruction.SHAR_R_32] = ArgumentType.THREE_REGISTERS;
15357
- instructionArgumentTypeMap[Instruction.SHLO_L_64] = ArgumentType.THREE_REGISTERS;
15358
- instructionArgumentTypeMap[Instruction.SHLO_R_64] = ArgumentType.THREE_REGISTERS;
15359
- instructionArgumentTypeMap[Instruction.SHAR_R_64] = ArgumentType.THREE_REGISTERS;
15360
- instructionArgumentTypeMap[Instruction.CMOV_IZ] = ArgumentType.THREE_REGISTERS;
15361
- instructionArgumentTypeMap[Instruction.CMOV_NZ] = ArgumentType.THREE_REGISTERS;
15362
- instructionArgumentTypeMap[Instruction.ROT_L_64] = ArgumentType.THREE_REGISTERS;
15363
- instructionArgumentTypeMap[Instruction.ROT_L_32] = ArgumentType.THREE_REGISTERS;
15364
- instructionArgumentTypeMap[Instruction.ROT_R_64] = ArgumentType.THREE_REGISTERS;
15365
- instructionArgumentTypeMap[Instruction.ROT_R_32] = ArgumentType.THREE_REGISTERS;
15366
- instructionArgumentTypeMap[Instruction.AND_INV] = ArgumentType.THREE_REGISTERS;
15367
- instructionArgumentTypeMap[Instruction.OR_INV] = ArgumentType.THREE_REGISTERS;
15368
- instructionArgumentTypeMap[Instruction.XNOR] = ArgumentType.THREE_REGISTERS;
15369
- instructionArgumentTypeMap[Instruction.MAX] = ArgumentType.THREE_REGISTERS;
15370
- instructionArgumentTypeMap[Instruction.MAX_U] = ArgumentType.THREE_REGISTERS;
15371
- instructionArgumentTypeMap[Instruction.MIN] = ArgumentType.THREE_REGISTERS;
15372
- instructionArgumentTypeMap[Instruction.MIN_U] = ArgumentType.THREE_REGISTERS;
15533
+ for (let i = 0; i < noOfBytes; i++) {
15534
+ this.view.setUint8(i, bytes[i]);
15535
+ }
15373
15536
 
15374
- return instructionArgumentTypeMap;
15375
- })();
15537
+ for (let i = n; i < BUFFER_SIZE; i++) {
15538
+ this.view.setUint8(i, prefix);
15539
+ }
15540
+ }
15376
15541
 
15377
- declare class BasicBlocks {
15378
- private basicBlocks: Set<number> = new Set();
15542
+ /**
15543
+ * @deprecated Use getU32 instead
15544
+ */
15545
+ getUnsigned() {
15546
+ return this.u32[U32_INDEX];
15547
+ }
15379
15548
 
15380
- reset(code: Uint8Array, mask: Mask) {
15381
- this.basicBlocks.clear();
15382
- this.basicBlocks.add(0);
15383
- const codeLength = code.length;
15549
+ /**
15550
+ * @deprecated Use getI32 instead
15551
+ */
15552
+ getSigned() {
15553
+ return this.i32[U32_INDEX];
15554
+ }
15384
15555
 
15385
- const isBasicBlockTermination = (index: number) =>
15386
- mask.isInstruction(index) && terminationInstructions[code[index]];
15556
+ getU32(): number {
15557
+ return this.u32[U32_INDEX];
15558
+ }
15387
15559
 
15388
- for (let i = 0; i < codeLength; i++) {
15389
- if (mask.isInstruction(i) && isBasicBlockTermination(i)) {
15390
- this.basicBlocks.add(i + 1 + mask.getNoOfBytesToNextInstruction(i + 1));
15391
- }
15392
- }
15560
+ getI32(): number {
15561
+ return this.i32[U32_INDEX];
15393
15562
  }
15394
15563
 
15395
- isBeginningOfBasicBlock(index: number) {
15396
- return this.basicBlocks.has(index);
15564
+ getU64(): bigint {
15565
+ return this.u64[U64_INDEX];
15397
15566
  }
15398
- }
15399
15567
 
15400
- declare enum Result {
15401
- HALT = 0,
15402
- PANIC = 1,
15403
- FAULT_ACCESS = 2,
15404
- FAULT = 3,
15405
- HOST = 4,
15406
- }
15568
+ getI64(): bigint {
15569
+ return this.i64[U64_INDEX];
15570
+ }
15407
15571
 
15408
- declare class InstructionResult {
15409
- public nextPc = 0;
15410
- public status: Result | null = null;
15411
- /**
15412
- * A numeric exit parameter of the PVM.
15413
- *
15414
- * In case of a `status === Result.FAULT` this will be the memory address
15415
- * that triggered the fault.
15416
- * In case of a `status === Result.HOST` this will be the host call index
15417
- * that should be invoked.
15418
- *
15419
- * In any other circumstance the value should be `null`.
15420
- */
15421
- public exitParam: number | null = null;
15572
+ getBytesAsLittleEndian() {
15573
+ return this.bytes.subarray(0, IMMEDIATE_SIZE);
15574
+ }
15422
15575
 
15423
- reset() {
15424
- this.nextPc = 0;
15425
- this.status = null;
15426
- this.exitParam = null;
15576
+ getExtendedBytesAsLittleEndian() {
15577
+ return this.bytes;
15427
15578
  }
15428
15579
  }
15429
15580
 
15430
- type MemoryIndex = Opaque<number, "memory index">;
15431
-
15432
- declare const tryAsMemoryIndex = (index: number): MemoryIndex => {
15433
- check`${index >= 0 && index <= MAX_MEMORY_INDEX} Incorrect memory index: ${index}!`;
15434
- return asOpaqueType(index);
15435
- };
15581
+ declare class NibblesDecoder {
15582
+ private byte = new Int8Array(1);
15436
15583
 
15437
- type SbrkIndex = Opaque<number, "sbrk index">;
15584
+ setByte(byte: number) {
15585
+ this.byte[0] = byte;
15586
+ }
15438
15587
 
15439
- declare const tryAsSbrkIndex = (index: number): SbrkIndex => {
15440
- check`${index >= 0 && index <= MAX_MEMORY_INDEX + 1} Incorrect sbrk index: ${index}!`;
15441
- return asOpaqueType(index);
15442
- };
15588
+ getHighNibble() {
15589
+ return (this.byte[0] & 0xf0) >>> 4;
15590
+ }
15443
15591
 
15444
- type PageIndex = Opaque<number, "memory page index">;
15445
- type PageNumber = Opaque<number, "memory page number">;
15592
+ getLowNibble() {
15593
+ return this.byte[0] & 0x0f;
15594
+ }
15446
15595
 
15447
- declare class PageFault {
15448
- private constructor(
15449
- public address: MemoryIndex,
15450
- public isAccessFault = true,
15451
- ) {}
15596
+ getHighNibbleAsRegisterIndex() {
15597
+ return Math.min(this.getHighNibble(), MAX_REGISTER_INDEX);
15598
+ }
15452
15599
 
15453
- static fromPageNumber(maybePageNumber: number, isAccessFault = false) {
15454
- const pageNumber = tryAsPageNumber(maybePageNumber);
15455
- const startPageIndex = getStartPageIndexFromPageNumber(pageNumber);
15456
- return new PageFault(startPageIndex, isAccessFault);
15600
+ getLowNibbleAsRegisterIndex() {
15601
+ return Math.min(this.getLowNibble(), MAX_REGISTER_INDEX);
15457
15602
  }
15458
15603
 
15459
- static fromMemoryIndex(maybeMemoryIndex: number, isAccessFault = false) {
15460
- const memoryIndex = tryAsMemoryIndex(maybeMemoryIndex % MEMORY_SIZE);
15461
- const startPageIndex = getStartPageIndex(memoryIndex);
15462
- return new PageFault(startPageIndex, isAccessFault);
15604
+ getHighNibbleAsLength() {
15605
+ return Math.min(this.getHighNibble(), MAX_LENGTH);
15463
15606
  }
15464
- }
15465
15607
 
15466
- declare class OutOfBounds extends Error {
15467
- constructor() {
15468
- super("Out of bounds");
15608
+ getLowNibbleAsLength() {
15609
+ return Math.min(this.getLowNibble(), MAX_LENGTH);
15469
15610
  }
15470
15611
  }
15471
15612
 
15472
- /**
15473
- * A representation of open-ended range of consecutive indices in memory,
15474
- * possibly empty or wrapping around.
15475
- *
15476
- * `[start, start + length)`
15477
- */
15478
- declare class MemoryRange {
15479
- /**
15480
- * Exclusive end index of the range.
15481
- *
15482
- * NOTE: The index may be wrapped around and smaller than `start`!
15483
- */
15484
- public readonly end: MemoryIndex;
15485
- /**
15486
- * Inclusive last index of the range (present unless the range is empty).
15487
- *
15488
- * NOTE: the index may be wrapped around and smaller than `start`!
15489
- */
15490
- public readonly lastIndex: MemoryIndex | null = null;
15613
+ type EmptyArgs = {
15614
+ type: ArgumentType.NO_ARGUMENTS;
15615
+ noOfBytesToSkip: number;
15616
+ };
15491
15617
 
15492
- private constructor(
15493
- public readonly start: MemoryIndex,
15494
- public readonly length: number,
15495
- ) {
15496
- this.end = tryAsMemoryIndex((this.start + this.length) % MEMORY_SIZE);
15618
+ type OneImmediateArgs = {
15619
+ type: ArgumentType.ONE_IMMEDIATE;
15620
+ noOfBytesToSkip: number;
15621
+ /** V_X */
15622
+ immediateDecoder: ImmediateDecoder;
15623
+ };
15497
15624
 
15498
- if (length > 0) {
15499
- this.lastIndex = tryAsMemoryIndex((this.end - 1 + MEMORY_SIZE) % MEMORY_SIZE);
15500
- }
15501
- }
15625
+ type ThreeRegistersArgs = {
15626
+ type: ArgumentType.THREE_REGISTERS;
15627
+ noOfBytesToSkip: number;
15628
+ /** W_A */
15629
+ firstRegisterIndex: number;
15630
+ /** W_B */
15631
+ secondRegisterIndex: number;
15632
+ /** W_D */
15633
+ thirdRegisterIndex: number;
15634
+ };
15502
15635
 
15503
- /** Creates a memory range from given starting point and length */
15504
- static fromStartAndLength(start: MemoryIndex, length: number) {
15505
- if (!Number.isInteger(length) || length < 0 || length > MEMORY_SIZE) {
15506
- throw new TypeError(`length must be a non-negative integer and less than ${MEMORY_SIZE}, got ${length}`);
15507
- }
15636
+ type TwoRegistersArgs = {
15637
+ type: ArgumentType.TWO_REGISTERS;
15638
+ noOfBytesToSkip: number;
15639
+ /** W_A */
15640
+ firstRegisterIndex: number;
15641
+ /** W_D */
15642
+ secondRegisterIndex: number;
15643
+ };
15508
15644
 
15509
- return new MemoryRange(start, length);
15510
- }
15645
+ type TwoRegistersOneImmediateArgs = {
15646
+ type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15647
+ noOfBytesToSkip: number;
15648
+ /** W_A */
15649
+ firstRegisterIndex: number;
15650
+ /** W_B */
15651
+ secondRegisterIndex: number;
15652
+ /** V_X */
15653
+ immediateDecoder: ImmediateDecoder;
15654
+ };
15511
15655
 
15512
- /** Checks if a range is empty (`length === 0`) */
15513
- isEmpty() {
15514
- return this.length === 0;
15515
- }
15656
+ type OneRegisterOneImmediateArgs = {
15657
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15658
+ noOfBytesToSkip: number;
15659
+ /** W_A */
15660
+ registerIndex: number;
15661
+ /** V_X */
15662
+ immediateDecoder: ImmediateDecoder;
15663
+ };
15516
15664
 
15517
- /** Returns true if the range is wrapped (`start` >= `end`) and is not empty */
15518
- isWrapped() {
15519
- return this.start >= this.end && !this.isEmpty();
15520
- }
15665
+ type OneRegisterOneExtendedWidthImmediateArgs = {
15666
+ type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
15667
+ noOfBytesToSkip: number;
15668
+ /** W_A */
15669
+ registerIndex: number;
15670
+ /** V_X */
15671
+ immediateDecoder: ExtendedWitdthImmediateDecoder;
15672
+ };
15521
15673
 
15522
- /** Checks if given memory address is within the range */
15523
- isInRange(address: MemoryIndex) {
15524
- if (this.isWrapped()) {
15525
- return address >= this.start || address < this.end;
15526
- }
15674
+ type TwoRegistersTwoImmediatesArgs = {
15675
+ type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
15676
+ noOfBytesToSkip: number;
15677
+ /** W_A */
15678
+ firstRegisterIndex: number;
15679
+ /** W_B */
15680
+ secondRegisterIndex: number;
15681
+ /** V_X */
15682
+ firstImmediateDecoder: ImmediateDecoder;
15683
+ /** V_Y */
15684
+ secondImmediateDecoder: ImmediateDecoder;
15685
+ };
15527
15686
 
15528
- return address >= this.start && address < this.end;
15529
- }
15687
+ type TwoImmediatesArgs = {
15688
+ type: ArgumentType.TWO_IMMEDIATES;
15689
+ noOfBytesToSkip: number;
15690
+ /** V_X */
15691
+ firstImmediateDecoder: ImmediateDecoder;
15692
+ /** V_Y */
15693
+ secondImmediateDecoder: ImmediateDecoder;
15694
+ };
15530
15695
 
15531
- /** Checks if this range overlaps with another range */
15532
- overlapsWith(other: MemoryRange) {
15533
- if (this.lastIndex === null || other.lastIndex === null) {
15534
- return false;
15535
- }
15696
+ type TwoRegistersOneOffsetArgs = {
15697
+ type: ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15698
+ noOfBytesToSkip: number;
15699
+ /** W_A */
15700
+ firstRegisterIndex: number;
15701
+ /** W_B */
15702
+ secondRegisterIndex: number;
15703
+ nextPc: number;
15704
+ };
15536
15705
 
15537
- return (
15538
- this.isInRange(other.start) ||
15539
- this.isInRange(other.lastIndex) ||
15540
- other.isInRange(this.start) ||
15541
- other.isInRange(this.lastIndex)
15542
- );
15543
- }
15544
- }
15706
+ type OneRegisterOneImmediateOneOffsetArgs = {
15707
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15708
+ noOfBytesToSkip: number;
15709
+ /** W_A */
15710
+ registerIndex: number;
15711
+ /** V_X */
15712
+ immediateDecoder: ImmediateDecoder;
15713
+ /** V_Y */
15714
+ nextPc: number;
15715
+ };
15716
+
15717
+ type OneRegisterTwoImmediatesArgs = {
15718
+ type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15719
+ noOfBytesToSkip: number;
15720
+ /** W_A */
15721
+ registerIndex: number;
15722
+ /** V_X */
15723
+ firstImmediateDecoder: ImmediateDecoder;
15724
+ /** V_Y */
15725
+ secondImmediateDecoder: ImmediateDecoder;
15726
+ };
15727
+
15728
+ type OneOffsetArgs = {
15729
+ type: ArgumentType.ONE_OFFSET;
15730
+ noOfBytesToSkip: number;
15731
+ /** V_X */
15732
+ nextPc: number;
15733
+ };
15734
+
15735
+ type Args =
15736
+ | EmptyArgs
15737
+ | OneImmediateArgs
15738
+ | TwoRegistersArgs
15739
+ | ThreeRegistersArgs
15740
+ | TwoRegistersOneImmediateArgs
15741
+ | TwoRegistersTwoImmediatesArgs
15742
+ | OneRegisterOneImmediateOneOffsetArgs
15743
+ | TwoRegistersOneOffsetArgs
15744
+ | OneRegisterOneImmediateArgs
15745
+ | OneOffsetArgs
15746
+ | TwoImmediatesArgs
15747
+ | OneRegisterTwoImmediatesArgs
15748
+ | OneRegisterOneExtendedWidthImmediateArgs;
15545
15749
 
15546
- declare abstract class MemoryPage {
15547
- public start: MemoryIndex;
15750
+ declare class ArgsDecoder {
15751
+ private nibblesDecoder = new NibblesDecoder();
15752
+ private offsetDecoder = new ImmediateDecoder();
15753
+ private code: Uint8Array = new Uint8Array();
15754
+ private mask: Mask = Mask.empty();
15548
15755
 
15549
- constructor(pageNumber: PageNumber) {
15550
- this.start = getStartPageIndexFromPageNumber(pageNumber);
15756
+ reset(code: Uint8Array, mask: Mask) {
15757
+ this.code = code;
15758
+ this.mask = mask;
15551
15759
  }
15552
15760
 
15553
- /** Returns `true` if the page is writeable. */
15554
- abstract isWriteable(): boolean;
15761
+ fillArgs<T extends Args>(pc: number, result: T): void {
15762
+ const nextInstructionDistance = 1 + this.mask.getNoOfBytesToNextInstruction(pc + 1);
15763
+ result.noOfBytesToSkip = nextInstructionDistance;
15555
15764
 
15556
- /**
15557
- * Load exactly `length` bytes from memory page, starting at index `address`
15558
- * into the `res` array.
15559
- *
15560
- * Note that the `res` might be bigger than the number of bytes length, but cannot be smaller.
15561
- *
15562
- * Returns `null` if copying was successful and [`PageFault`] otherwise.
15563
- * NOTE That the `result` might be partially modified in case `PageFault` occurs!
15564
- */
15565
- abstract loadInto(res: Uint8Array, address: PageIndex, length: number): Result$2<OK, PageFault>;
15765
+ switch (result.type) {
15766
+ case ArgumentType.NO_ARGUMENTS:
15767
+ break;
15566
15768
 
15567
- /**
15568
- * Copy all bytes from the `data` into the page at index `address`.
15569
- *
15570
- * Returns `null` if copying was successful and [`PageFault`] otherwise.
15571
- */
15572
- abstract storeFrom(address: PageIndex, data: Uint8Array): Result$2<OK, PageFault>;
15573
- /**
15574
- * Get dump of the entire page. Should only be used for the debugger-adapter because it
15575
- * might be inefficient.
15576
- */
15577
- abstract getPageDump(): Uint8Array;
15769
+ case ArgumentType.ONE_IMMEDIATE: {
15770
+ const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
15771
+ const argsStartIndex = pc + 1;
15772
+ result.immediateDecoder.setBytes(this.code.subarray(argsStartIndex, argsStartIndex + immediateLength));
15773
+ break;
15774
+ }
15578
15775
 
15579
- abstract setData(pageIndex: PageIndex, data: Uint8Array): void;
15580
- }
15776
+ case ArgumentType.THREE_REGISTERS: {
15777
+ const firstByte = this.code[pc + 1];
15778
+ const secondByte = this.code[pc + 2];
15779
+ this.nibblesDecoder.setByte(firstByte);
15780
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15781
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15782
+ this.nibblesDecoder.setByte(secondByte);
15783
+ result.thirdRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15784
+ break;
15785
+ }
15581
15786
 
15582
- /**
15583
- * I had to extend ArrayBuffer type to use resizable ArrayBuffer.
15584
- * We will be able to remove it when this is merged: https://github.com/microsoft/TypeScript/pull/58573
15585
- * And then a new version of TypeScript is released.
15586
- */
15587
- declare global {
15588
- interface ArrayBufferConstructor {
15589
- new (length: number, options?: {
15590
- maxByteLength: number;
15591
- }): ArrayBuffer;
15592
- }
15593
- interface ArrayBuffer {
15594
- resize(length: number): void;
15595
- }
15596
- }
15787
+ case ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE: {
15788
+ const firstByte = this.code[pc + 1];
15789
+ this.nibblesDecoder.setByte(firstByte);
15790
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15791
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15597
15792
 
15598
- type InitialMemoryState = {
15599
- memory: Map<PageNumber, MemoryPage>;
15600
- sbrkIndex: SbrkIndex;
15601
- endHeapIndex: SbrkIndex;
15602
- };
15793
+ const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
15794
+ const immediateStartIndex = pc + 2;
15795
+ const immediateEndIndex = immediateStartIndex + immediateLength;
15796
+ result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
15797
+ break;
15798
+ }
15603
15799
 
15604
- declare enum AccessType {
15605
- READ = 0,
15606
- WRITE = 1,
15607
- }
15800
+ case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET: {
15801
+ const firstByte = this.code[pc + 1];
15802
+ this.nibblesDecoder.setByte(firstByte);
15803
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15608
15804
 
15609
- declare class Memory {
15610
- static fromInitialMemory(initialMemoryState: InitialMemoryState) {
15611
- return new Memory(
15612
- initialMemoryState?.sbrkIndex,
15613
- initialMemoryState?.sbrkIndex,
15614
- initialMemoryState?.endHeapIndex,
15615
- initialMemoryState?.memory,
15616
- );
15617
- }
15805
+ const immediateLength = this.nibblesDecoder.getHighNibbleAsLength();
15806
+ const immediateStartIndex = pc + 2;
15807
+ const immediateEndIndex = immediateStartIndex + immediateLength;
15808
+ result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
15618
15809
 
15619
- constructor(
15620
- private sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
15621
- private virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
15622
- private endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX),
15623
- private memory = new Map<PageNumber, MemoryPage>(),
15624
- ) {}
15810
+ const offsetLength = Math.min(
15811
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15812
+ Math.max(0, nextInstructionDistance - 2 - immediateLength),
15813
+ );
15814
+ const offsetStartIndex = pc + 2 + immediateLength;
15815
+ const offsetEndIndex = offsetStartIndex + offsetLength;
15816
+ this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
15625
15817
 
15626
- reset() {
15627
- this.sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
15628
- this.virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
15629
- this.endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX);
15630
- this.memory = new Map<PageNumber, MemoryPage>(); // TODO [MaSi]: We should keep allocated pages somewhere and reuse it when it is possible
15631
- }
15818
+ result.nextPc = pc + this.offsetDecoder.getSigned();
15819
+ break;
15820
+ }
15632
15821
 
15633
- copyFrom(memory: Memory) {
15634
- this.sbrkIndex = memory.sbrkIndex;
15635
- this.virtualSbrkIndex = memory.virtualSbrkIndex;
15636
- this.endHeapIndex = memory.endHeapIndex;
15637
- this.memory = memory.memory;
15638
- }
15822
+ case ArgumentType.TWO_REGISTERS_ONE_OFFSET: {
15823
+ const firstByte = this.code[pc + 1];
15824
+ this.nibblesDecoder.setByte(firstByte);
15825
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15826
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15639
15827
 
15640
- storeFrom(address: MemoryIndex, bytes: Uint8Array): Result$2<OK, PageFault> {
15641
- if (bytes.length === 0) {
15642
- return Result.ok(OK);
15643
- }
15828
+ const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
15829
+ const offsetStartIndex = pc + 2;
15830
+ const offsetEndIndex = offsetStartIndex + offsetLength;
15831
+ this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
15644
15832
 
15645
- logger.insane`MEM[${address}] <- ${BytesBlob.blobFrom(bytes)}`;
15646
- const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
15833
+ result.nextPc = pc + this.offsetDecoder.getSigned();
15834
+ break;
15835
+ }
15647
15836
 
15648
- if (pagesResult.isError) {
15649
- return Result.error(pagesResult.error, pagesResult.details);
15650
- }
15837
+ case ArgumentType.TWO_REGISTERS: {
15838
+ const firstByte = this.code[pc + 1];
15839
+ this.nibblesDecoder.setByte(firstByte);
15840
+ result.firstRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15841
+ result.secondRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15842
+ break;
15843
+ }
15651
15844
 
15652
- const pages = pagesResult.ok;
15653
- let currentPosition: number = address;
15654
- let bytesLeft = bytes.length;
15845
+ case ArgumentType.ONE_OFFSET: {
15846
+ const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
15847
+ const offsetStartIndex = pc + 1;
15848
+ const offsetEndIndex = offsetStartIndex + offsetLength;
15849
+ const offsetBytes = this.code.subarray(offsetStartIndex, offsetEndIndex);
15850
+ this.offsetDecoder.setBytes(offsetBytes);
15851
+ const offsetValue = this.offsetDecoder.getSigned();
15852
+ result.nextPc = pc + offsetValue;
15853
+ break;
15854
+ }
15655
15855
 
15656
- for (const page of pages) {
15657
- const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
15658
- const bytesToWrite = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
15659
- const sourceStartIndex = currentPosition - address;
15660
- const source = bytes.subarray(sourceStartIndex, sourceStartIndex + bytesToWrite);
15856
+ case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE: {
15857
+ const firstByte = this.code[pc + 1];
15858
+ this.nibblesDecoder.setByte(firstByte);
15859
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15661
15860
 
15662
- page.storeFrom(pageStartIndex, source);
15861
+ const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
15862
+ const immediateStartIndex = pc + 2;
15863
+ const immediateEndIndex = immediateStartIndex + immediateLength;
15864
+ const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
15865
+ result.immediateDecoder.setBytes(immediateBytes);
15866
+ break;
15867
+ }
15663
15868
 
15664
- currentPosition += bytesToWrite;
15665
- bytesLeft -= bytesToWrite;
15666
- }
15667
- return Result.ok(OK);
15668
- }
15869
+ case ArgumentType.TWO_IMMEDIATES: {
15870
+ const firstByte = this.code[pc + 1];
15871
+ this.nibblesDecoder.setByte(firstByte);
15872
+ const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
15873
+ const firstImmediateStartIndex = pc + 2;
15874
+ const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
15875
+ const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
15876
+ result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15669
15877
 
15670
- private getPages(startAddress: MemoryIndex, length: number, accessType: AccessType): Result$2<MemoryPage[], PageFault> {
15671
- if (length === 0) {
15672
- return Result.ok([]);
15673
- }
15878
+ const secondImmediateLength = Math.min(
15879
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15880
+ Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
15881
+ );
15882
+ const secondImmediateStartIndex = firstImmediateEndIndex;
15883
+ const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
15884
+ const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
15885
+ result.secondImmediateDecoder.setBytes(secondImmediateBytes);
15886
+ break;
15887
+ }
15674
15888
 
15675
- const memoryRange = MemoryRange.fromStartAndLength(startAddress, length);
15676
- const pageRange = PageRange.fromMemoryRange(memoryRange);
15889
+ case ArgumentType.ONE_REGISTER_TWO_IMMEDIATES: {
15890
+ const firstByte = this.code[pc + 1];
15891
+ this.nibblesDecoder.setByte(firstByte);
15892
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15677
15893
 
15678
- const pages: MemoryPage[] = [];
15894
+ const firstImmediateLength = this.nibblesDecoder.getHighNibbleAsLength();
15895
+ const firstImmediateStartIndex = pc + 2;
15896
+ const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
15897
+ const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
15898
+ result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15679
15899
 
15680
- for (const pageNumber of pageRange) {
15681
- if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
15682
- return Result.error(
15683
- PageFault.fromPageNumber(pageNumber, true),
15684
- () => `Page fault: attempted to access reserved page ${pageNumber}`,
15900
+ const secondImmediateLength = Math.min(
15901
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15902
+ Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
15685
15903
  );
15904
+ const secondImmediateStartIndex = firstImmediateEndIndex;
15905
+ const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
15906
+ const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
15907
+ result.secondImmediateDecoder.setBytes(secondImmediateBytes);
15908
+ break;
15686
15909
  }
15687
15910
 
15688
- const page = this.memory.get(pageNumber);
15911
+ case ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES: {
15912
+ const firstByte = this.code[pc + 1];
15913
+ this.nibblesDecoder.setByte(firstByte);
15914
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15915
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15689
15916
 
15690
- if (page === undefined) {
15691
- return Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
15692
- }
15917
+ const secondByte = this.code[pc + 2];
15918
+ this.nibblesDecoder.setByte(secondByte);
15919
+ const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
15920
+ const firstImmediateStartIndex = pc + 3;
15921
+ const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
15922
+ const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
15923
+ result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15693
15924
 
15694
- if (accessType === AccessType.WRITE && !page.isWriteable()) {
15695
- return Result.error(
15696
- PageFault.fromPageNumber(pageNumber, true),
15697
- () => `Page fault: attempted to write to read-only page ${pageNumber}`,
15925
+ const secondImmediateLength = Math.min(
15926
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15927
+ Math.max(0, nextInstructionDistance - 3 - firstImmediateLength),
15698
15928
  );
15929
+ const secondImmediateStartIndex = firstImmediateEndIndex;
15930
+ const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
15931
+ const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
15932
+ result.secondImmediateDecoder.setBytes(secondImmediateBytes);
15933
+ break;
15699
15934
  }
15700
15935
 
15701
- pages.push(page);
15702
- }
15936
+ case ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE: {
15937
+ const firstByte = this.code[pc + 1];
15938
+ this.nibblesDecoder.setByte(firstByte);
15939
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15703
15940
 
15704
- return Result.ok(pages);
15705
- }
15706
- /**
15707
- * Read content of the memory at `[address, address + result.length)` and
15708
- * write the result into the `result` buffer.
15709
- *
15710
- * Returns `null` if the data was read successfully or `PageFault` otherwise.
15711
- */
15712
- loadInto(result: Uint8Array, startAddress: MemoryIndex): Result$2<OK, PageFault> {
15713
- if (result.length === 0) {
15714
- return Result.ok(OK);
15941
+ const immediateStartIndex = pc + 2;
15942
+ const immediateEndIndex = immediateStartIndex + 8;
15943
+ const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
15944
+ result.immediateDecoder.setBytes(immediateBytes);
15945
+ break;
15946
+ }
15715
15947
  }
15948
+ }
15949
+ }
15716
15950
 
15717
- const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
15718
-
15719
- if (pagesResult.isError) {
15720
- return Result.error(pagesResult.error, pagesResult.details);
15721
- }
15951
+ declare const createResults = () => {
15952
+ const results = new Array(ARGUMENT_TYPE_LENGTH) as Results;
15722
15953
 
15723
- const pages = pagesResult.ok;
15954
+ results[ArgumentType.NO_ARGUMENTS] = {
15955
+ type: ArgumentType.NO_ARGUMENTS,
15956
+ noOfBytesToSkip: 1,
15957
+ };
15724
15958
 
15725
- let currentPosition: number = startAddress;
15726
- let bytesLeft = result.length;
15959
+ results[ArgumentType.ONE_IMMEDIATE] = {
15960
+ type: ArgumentType.ONE_IMMEDIATE,
15961
+ noOfBytesToSkip: 1,
15962
+ immediateDecoder: new ImmediateDecoder(),
15963
+ };
15727
15964
 
15728
- for (const page of pages) {
15729
- const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
15730
- const bytesToRead = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
15731
- const destinationStartIndex = currentPosition - startAddress;
15732
- const destination = result.subarray(destinationStartIndex);
15965
+ results[ArgumentType.TWO_REGISTERS] = {
15966
+ type: ArgumentType.TWO_REGISTERS,
15967
+ noOfBytesToSkip: 1,
15968
+ firstRegisterIndex: 0,
15969
+ secondRegisterIndex: 0,
15970
+ };
15733
15971
 
15734
- page.loadInto(destination, pageStartIndex, bytesToRead);
15972
+ results[ArgumentType.THREE_REGISTERS] = {
15973
+ type: ArgumentType.THREE_REGISTERS,
15974
+ noOfBytesToSkip: 1,
15975
+ firstRegisterIndex: 0,
15976
+ secondRegisterIndex: 0,
15977
+ thirdRegisterIndex: 0,
15978
+ };
15735
15979
 
15736
- currentPosition += bytesToRead;
15737
- bytesLeft -= bytesToRead;
15738
- }
15980
+ results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET] = {
15981
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET,
15982
+ noOfBytesToSkip: 1,
15983
+ registerIndex: 0,
15984
+ immediateDecoder: new ImmediateDecoder(),
15985
+ nextPc: 0,
15986
+ };
15739
15987
 
15740
- logger.insane`MEM[${startAddress}] => ${BytesBlob.blobFrom(result)}`;
15741
- return Result.ok(OK);
15742
- }
15988
+ results[ArgumentType.TWO_REGISTERS_ONE_OFFSET] = {
15989
+ type: ArgumentType.TWO_REGISTERS_ONE_OFFSET,
15990
+ noOfBytesToSkip: 1,
15991
+ firstRegisterIndex: 0,
15992
+ secondRegisterIndex: 0,
15993
+ nextPc: 0,
15994
+ };
15743
15995
 
15744
- sbrk(length: number): SbrkIndex {
15745
- const currentSbrkIndex = this.sbrkIndex;
15746
- const currentVirtualSbrkIndex = this.virtualSbrkIndex;
15996
+ results[ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE] = {
15997
+ type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE,
15998
+ noOfBytesToSkip: 1,
15999
+ firstRegisterIndex: 0,
16000
+ secondRegisterIndex: 0,
16001
+ immediateDecoder: new ImmediateDecoder(),
16002
+ };
15747
16003
 
15748
- // new sbrk index is bigger than 2 ** 32 or endHeapIndex
15749
- if (MAX_MEMORY_INDEX < currentVirtualSbrkIndex + length || currentVirtualSbrkIndex + length > this.endHeapIndex) {
15750
- throw new OutOfMemory();
15751
- }
16004
+ results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE] = {
16005
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE,
16006
+ noOfBytesToSkip: 1,
16007
+ registerIndex: 0,
16008
+ immediateDecoder: new ImmediateDecoder(),
16009
+ };
15752
16010
 
15753
- const newVirtualSbrkIndex = tryAsSbrkIndex(this.virtualSbrkIndex + length);
16011
+ results[ArgumentType.ONE_REGISTER_TWO_IMMEDIATES] = {
16012
+ type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES,
16013
+ noOfBytesToSkip: 1,
16014
+ registerIndex: 0,
16015
+ firstImmediateDecoder: new ImmediateDecoder(),
16016
+ secondImmediateDecoder: new ImmediateDecoder(),
16017
+ };
15754
16018
 
15755
- // no alllocation needed
15756
- if (newVirtualSbrkIndex <= currentSbrkIndex) {
15757
- this.virtualSbrkIndex = newVirtualSbrkIndex;
15758
- return currentVirtualSbrkIndex;
15759
- }
16019
+ results[ArgumentType.ONE_OFFSET] = {
16020
+ type: ArgumentType.ONE_OFFSET,
16021
+ noOfBytesToSkip: 1,
16022
+ nextPc: 0,
16023
+ };
15760
16024
 
15761
- // standard allocation using "Writeable" pages
15762
- const newSbrkIndex = tryAsSbrkIndex(alignToPageSize(newVirtualSbrkIndex));
15763
- // TODO [MaSi]: `getPageNumber` works incorrectly for SbrkIndex. Sbrk index should be changed to MemoryIndex
15764
- const firstPageNumber = getPageNumber(currentSbrkIndex);
15765
- const pagesToAllocate = (newSbrkIndex - currentSbrkIndex) / PAGE_SIZE;
15766
- const rangeToAllocate = PageRange.fromStartAndLength(firstPageNumber, pagesToAllocate);
16025
+ results[ArgumentType.TWO_IMMEDIATES] = {
16026
+ type: ArgumentType.TWO_IMMEDIATES,
16027
+ noOfBytesToSkip: 1,
16028
+ firstImmediateDecoder: new ImmediateDecoder(),
16029
+ secondImmediateDecoder: new ImmediateDecoder(),
16030
+ };
15767
16031
 
15768
- for (const pageNumber of rangeToAllocate) {
15769
- const page = new WriteablePage(pageNumber);
15770
- this.memory.set(pageNumber, page);
15771
- }
16032
+ results[ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES] = {
16033
+ type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES,
16034
+ noOfBytesToSkip: 1,
16035
+ firstImmediateDecoder: new ImmediateDecoder(),
16036
+ secondImmediateDecoder: new ImmediateDecoder(),
16037
+ firstRegisterIndex: 0,
16038
+ secondRegisterIndex: 0,
16039
+ };
15772
16040
 
15773
- this.virtualSbrkIndex = newVirtualSbrkIndex;
15774
- this.sbrkIndex = newSbrkIndex;
15775
- return currentVirtualSbrkIndex;
15776
- }
16041
+ results[ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE] = {
16042
+ type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE,
16043
+ noOfBytesToSkip: 9,
16044
+ registerIndex: 0,
16045
+ immediateDecoder: new ExtendedWitdthImmediateDecoder(),
16046
+ };
15777
16047
 
15778
- getPageDump(pageNumber: PageNumber) {
15779
- const page = this.memory.get(pageNumber);
15780
- return page?.getPageDump() ?? null;
15781
- }
16048
+ return results;
16049
+ };
15782
16050
 
15783
- getDirtyPages() {
15784
- return this.memory.keys();
15785
- }
16051
+ declare enum Instruction {
16052
+ TRAP = 0,
16053
+ FALLTHROUGH = 1,
16054
+ ECALLI = 10,
16055
+ LOAD_IMM_64 = 20,
16056
+ STORE_IMM_U8 = 30,
16057
+ STORE_IMM_U16 = 31,
16058
+ STORE_IMM_U32 = 32,
16059
+ STORE_IMM_U64 = 33,
16060
+ JUMP = 40,
16061
+ JUMP_IND = 50,
16062
+ LOAD_IMM = 51,
16063
+ LOAD_U8 = 52,
16064
+ LOAD_I8 = 53,
16065
+ LOAD_U16 = 54,
16066
+ LOAD_I16 = 55,
16067
+ LOAD_U32 = 56,
16068
+ LOAD_I32 = 57,
16069
+ LOAD_U64 = 58,
16070
+ STORE_U8 = 59,
16071
+ STORE_U16 = 60,
16072
+ STORE_U32 = 61,
16073
+ STORE_U64 = 62,
16074
+ STORE_IMM_IND_U8 = 70,
16075
+ STORE_IMM_IND_U16 = 71,
16076
+ STORE_IMM_IND_U32 = 72,
16077
+ STORE_IMM_IND_U64 = 73,
16078
+ LOAD_IMM_JUMP = 80,
16079
+ BRANCH_EQ_IMM = 81,
16080
+ BRANCH_NE_IMM = 82,
16081
+ BRANCH_LT_U_IMM = 83,
16082
+ BRANCH_LE_U_IMM = 84,
16083
+ BRANCH_GE_U_IMM = 85,
16084
+ BRANCH_GT_U_IMM = 86,
16085
+ BRANCH_LT_S_IMM = 87,
16086
+ BRANCH_LE_S_IMM = 88,
16087
+ BRANCH_GE_S_IMM = 89,
16088
+ BRANCH_GT_S_IMM = 90,
16089
+ MOVE_REG = 100,
16090
+ SBRK = 101,
16091
+ COUNT_SET_BITS_64 = 102,
16092
+ COUNT_SET_BITS_32 = 103,
16093
+ LEADING_ZERO_BITS_64 = 104,
16094
+ LEADING_ZERO_BITS_32 = 105,
16095
+ TRAILING_ZERO_BITS_64 = 106,
16096
+ TRAILING_ZERO_BITS_32 = 107,
16097
+ SIGN_EXTEND_8 = 108,
16098
+ SIGN_EXTEND_16 = 109,
16099
+ ZERO_EXTEND_16 = 110,
16100
+ REVERSE_BYTES = 111,
16101
+ STORE_IND_U8 = 120,
16102
+ STORE_IND_U16 = 121,
16103
+ STORE_IND_U32 = 122,
16104
+ STORE_IND_U64 = 123,
16105
+ LOAD_IND_U8 = 124,
16106
+ LOAD_IND_I8 = 125,
16107
+ LOAD_IND_U16 = 126,
16108
+ LOAD_IND_I16 = 127,
16109
+ LOAD_IND_U32 = 128,
16110
+ LOAD_IND_I32 = 129,
16111
+ LOAD_IND_U64 = 130,
16112
+ ADD_IMM_32 = 131,
16113
+ AND_IMM = 132,
16114
+ XOR_IMM = 133,
16115
+ OR_IMM = 134,
16116
+ MUL_IMM_32 = 135,
16117
+ SET_LT_U_IMM = 136,
16118
+ SET_LT_S_IMM = 137,
16119
+ SHLO_L_IMM_32 = 138,
16120
+ SHLO_R_IMM_32 = 139,
16121
+ SHAR_R_IMM_32 = 140,
16122
+ NEG_ADD_IMM_32 = 141,
16123
+ SET_GT_U_IMM = 142,
16124
+ SET_GT_S_IMM = 143,
16125
+ SHLO_L_IMM_ALT_32 = 144,
16126
+ SHLO_R_IMM_ALT_32 = 145,
16127
+ SHAR_R_IMM_ALT_32 = 146,
16128
+ CMOV_IZ_IMM = 147,
16129
+ CMOV_NZ_IMM = 148,
16130
+ ADD_IMM_64 = 149,
16131
+ MUL_IMM_64 = 150,
16132
+ SHLO_L_IMM_64 = 151,
16133
+ SHLO_R_IMM_64 = 152,
16134
+ SHAR_R_IMM_64 = 153,
16135
+ NEG_ADD_IMM_64 = 154,
16136
+ SHLO_L_IMM_ALT_64 = 155,
16137
+ SHLO_R_IMM_ALT_64 = 156,
16138
+ SHAR_R_IMM_ALT_64 = 157,
16139
+ ROT_R_64_IMM = 158,
16140
+ ROT_R_64_IMM_ALT = 159,
16141
+ ROT_R_32_IMM = 160,
16142
+ ROT_R_32_IMM_ALT = 161,
16143
+ BRANCH_EQ = 170,
16144
+ BRANCH_NE = 171,
16145
+ BRANCH_LT_U = 172,
16146
+ BRANCH_LT_S = 173,
16147
+ BRANCH_GE_U = 174,
16148
+ BRANCH_GE_S = 175,
16149
+ LOAD_IMM_JUMP_IND = 180,
16150
+ ADD_32 = 190,
16151
+ SUB_32 = 191,
16152
+ MUL_32 = 192,
16153
+ DIV_U_32 = 193,
16154
+ DIV_S_32 = 194,
16155
+ REM_U_32 = 195,
16156
+ REM_S_32 = 196,
16157
+ SHLO_L_32 = 197,
16158
+ SHLO_R_32 = 198,
16159
+ SHAR_R_32 = 199,
16160
+ ADD_64 = 200,
16161
+ SUB_64 = 201,
16162
+ MUL_64 = 202,
16163
+ DIV_U_64 = 203,
16164
+ DIV_S_64 = 204,
16165
+ REM_U_64 = 205,
16166
+ REM_S_64 = 206,
16167
+ SHLO_L_64 = 207,
16168
+ SHLO_R_64 = 208,
16169
+ SHAR_R_64 = 209,
16170
+ AND = 210,
16171
+ XOR = 211,
16172
+ OR = 212,
16173
+ MUL_UPPER_S_S = 213,
16174
+ MUL_UPPER_U_U = 214,
16175
+ MUL_UPPER_S_U = 215,
16176
+ SET_LT_U = 216,
16177
+ SET_LT_S = 217,
16178
+ CMOV_IZ = 218,
16179
+ CMOV_NZ = 219,
16180
+ ROT_L_64 = 220,
16181
+ ROT_L_32 = 221,
16182
+ ROT_R_64 = 222,
16183
+ ROT_R_32 = 223,
16184
+ AND_INV = 224,
16185
+ OR_INV = 225,
16186
+ XNOR = 226,
16187
+ MAX = 227,
16188
+ MAX_U = 228,
16189
+ MIN = 229,
16190
+ MIN_U = 230,
15786
16191
  }
15787
16192
 
15788
- declare class MemoryBuilder {
15789
- private readonly initialMemory: Map<PageNumber, MemoryPage> = new Map();
15790
- private isFinalized = false;
15791
-
15792
- private ensureNotFinalized() {
15793
- if (this.isFinalized) {
15794
- throw new FinalizedBuilderModification();
15795
- }
15796
- }
15797
-
15798
- private ensureNoReservedMemoryUsage(range: MemoryRange) {
15799
- if (range.overlapsWith(RESERVED_MEMORY_RANGE)) {
15800
- throw new ReservedMemoryFault();
15801
- }
15802
- }
15803
-
15804
- /**
15805
- * Create entire readable pages to handle the `[start, end)` range.
15806
- *
15807
- * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15808
- * they need to be the start indices of the pages.
15809
- *
15810
- * The data passed will be placed at `start`, but might be shorter than the requested range,
15811
- * prepend it with zeros if you don't wish to have it at the beginning of the page.
15812
- */
15813
- setReadablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15814
- this.ensureNotFinalized();
15815
- check`${start < end} end has to be bigger than start`;
15816
- check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15817
- check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15818
- check`${data.length <= end - start} the initial data is longer than address range`;
15819
-
15820
- const length = end - start;
15821
- const range = MemoryRange.fromStartAndLength(start, length);
15822
-
15823
- this.ensureNoReservedMemoryUsage(range);
15824
-
15825
- const pages = Array.from(PageRange.fromMemoryRange(range));
15826
- const noOfPages = pages.length;
16193
+ declare const instructionArgumentTypeMap = (() => {
16194
+ const instructionArgumentTypeMap = new Array<ArgumentType>(HIGHEST_INSTRUCTION_NUMBER + 1);
15827
16195
 
15828
- for (let i = 0; i < noOfPages; i++) {
15829
- const pageNumber = pages[i];
15830
- const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15831
- const page = new ReadablePage(pageNumber, dataChunk);
15832
- this.initialMemory.set(pageNumber, page);
15833
- }
16196
+ instructionArgumentTypeMap[Instruction.TRAP] = ArgumentType.NO_ARGUMENTS;
16197
+ instructionArgumentTypeMap[Instruction.FALLTHROUGH] = ArgumentType.NO_ARGUMENTS;
15834
16198
 
15835
- return this;
15836
- }
16199
+ instructionArgumentTypeMap[Instruction.ECALLI] = ArgumentType.ONE_IMMEDIATE;
15837
16200
 
15838
- /**
15839
- * Create entire writeable pages to handle the `[start, end)` range.
15840
- *
15841
- * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15842
- * they need to be the start indices of the pages.
15843
- *
15844
- * The data passed will be placed at `start`, but might be shorter than the requested range,
15845
- * prepend it with zeros if you don't wish to have it at the beginning of the page.
15846
- */
15847
- setWriteablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15848
- this.ensureNotFinalized();
15849
- check`${start < end} end has to be bigger than start`;
15850
- check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15851
- check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15852
- check`${data.length <= end - start} the initial data is longer than address range`;
16201
+ instructionArgumentTypeMap[Instruction.LOAD_IMM_64] = ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
15853
16202
 
15854
- const length = end - start;
15855
- const range = MemoryRange.fromStartAndLength(start, length);
16203
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U8] = ArgumentType.TWO_IMMEDIATES;
16204
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U16] = ArgumentType.TWO_IMMEDIATES;
16205
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U32] = ArgumentType.TWO_IMMEDIATES;
16206
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U64] = ArgumentType.TWO_IMMEDIATES;
15856
16207
 
15857
- this.ensureNoReservedMemoryUsage(range);
16208
+ instructionArgumentTypeMap[Instruction.JUMP] = ArgumentType.ONE_OFFSET;
15858
16209
 
15859
- const pages = Array.from(PageRange.fromMemoryRange(range));
15860
- const noOfPages = pages.length;
16210
+ instructionArgumentTypeMap[Instruction.JUMP_IND] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16211
+ instructionArgumentTypeMap[Instruction.LOAD_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16212
+ instructionArgumentTypeMap[Instruction.LOAD_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16213
+ instructionArgumentTypeMap[Instruction.LOAD_I8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16214
+ instructionArgumentTypeMap[Instruction.LOAD_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16215
+ instructionArgumentTypeMap[Instruction.LOAD_I16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16216
+ instructionArgumentTypeMap[Instruction.LOAD_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16217
+ instructionArgumentTypeMap[Instruction.LOAD_I32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16218
+ instructionArgumentTypeMap[Instruction.LOAD_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16219
+ instructionArgumentTypeMap[Instruction.STORE_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16220
+ instructionArgumentTypeMap[Instruction.STORE_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16221
+ instructionArgumentTypeMap[Instruction.STORE_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16222
+ instructionArgumentTypeMap[Instruction.STORE_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15861
16223
 
15862
- for (let i = 0; i < noOfPages; i++) {
15863
- const pageNumber = pages[i];
15864
- const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15865
- const page = new WriteablePage(pageNumber, dataChunk);
15866
- this.initialMemory.set(pageNumber, page);
15867
- }
16224
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U8] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
16225
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U16] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
16226
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U32] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
16227
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U64] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15868
16228
 
15869
- return this;
15870
- }
16229
+ instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16230
+ instructionArgumentTypeMap[Instruction.BRANCH_EQ_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16231
+ instructionArgumentTypeMap[Instruction.BRANCH_NE_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16232
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16233
+ instructionArgumentTypeMap[Instruction.BRANCH_LE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16234
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16235
+ instructionArgumentTypeMap[Instruction.BRANCH_GT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16236
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16237
+ instructionArgumentTypeMap[Instruction.BRANCH_LE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16238
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16239
+ instructionArgumentTypeMap[Instruction.BRANCH_GT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15871
16240
 
15872
- /**
15873
- * This function can be useful when page map and initial memory data are provided separatelly.
15874
- * You can use setWriteablePages/setReadablePages to create empty pages and then setData to fill them
15875
- */
15876
- setData(start: MemoryIndex, data: Uint8Array) {
15877
- this.ensureNotFinalized();
15878
- const pageOffset = start % PAGE_SIZE;
15879
- const remainingSpaceOnPage = PAGE_SIZE - pageOffset;
15880
- check`${data.length <= remainingSpaceOnPage} The data has to fit into a single page.`;
16241
+ instructionArgumentTypeMap[Instruction.MOVE_REG] = ArgumentType.TWO_REGISTERS;
16242
+ instructionArgumentTypeMap[Instruction.SBRK] = ArgumentType.TWO_REGISTERS;
16243
+ instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_64] = ArgumentType.TWO_REGISTERS;
16244
+ instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_32] = ArgumentType.TWO_REGISTERS;
16245
+ instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
16246
+ instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
16247
+ instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
16248
+ instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
16249
+ instructionArgumentTypeMap[Instruction.SIGN_EXTEND_8] = ArgumentType.TWO_REGISTERS;
16250
+ instructionArgumentTypeMap[Instruction.SIGN_EXTEND_16] = ArgumentType.TWO_REGISTERS;
16251
+ instructionArgumentTypeMap[Instruction.ZERO_EXTEND_16] = ArgumentType.TWO_REGISTERS;
16252
+ instructionArgumentTypeMap[Instruction.REVERSE_BYTES] = ArgumentType.TWO_REGISTERS;
15881
16253
 
15882
- const length = data.length;
15883
- const range = MemoryRange.fromStartAndLength(start, length);
16254
+ instructionArgumentTypeMap[Instruction.STORE_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16255
+ instructionArgumentTypeMap[Instruction.STORE_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16256
+ instructionArgumentTypeMap[Instruction.STORE_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16257
+ instructionArgumentTypeMap[Instruction.STORE_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16258
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16259
+ instructionArgumentTypeMap[Instruction.LOAD_IND_I8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16260
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16261
+ instructionArgumentTypeMap[Instruction.LOAD_IND_I16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16262
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16263
+ instructionArgumentTypeMap[Instruction.LOAD_IND_I32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16264
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16265
+ instructionArgumentTypeMap[Instruction.ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16266
+ instructionArgumentTypeMap[Instruction.ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16267
+ instructionArgumentTypeMap[Instruction.AND_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16268
+ instructionArgumentTypeMap[Instruction.XOR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16269
+ instructionArgumentTypeMap[Instruction.OR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16270
+ instructionArgumentTypeMap[Instruction.MUL_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16271
+ instructionArgumentTypeMap[Instruction.MUL_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16272
+ instructionArgumentTypeMap[Instruction.SET_LT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16273
+ instructionArgumentTypeMap[Instruction.SET_LT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16274
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16275
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16276
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16277
+ instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16278
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16279
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16280
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16281
+ instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16282
+ instructionArgumentTypeMap[Instruction.SET_GT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16283
+ instructionArgumentTypeMap[Instruction.SET_GT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16284
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16285
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16286
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16287
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16288
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16289
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16290
+ instructionArgumentTypeMap[Instruction.CMOV_IZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16291
+ instructionArgumentTypeMap[Instruction.CMOV_NZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16292
+ instructionArgumentTypeMap[Instruction.ROT_R_64_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16293
+ instructionArgumentTypeMap[Instruction.ROT_R_64_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16294
+ instructionArgumentTypeMap[Instruction.ROT_R_32_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16295
+ instructionArgumentTypeMap[Instruction.ROT_R_32_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15884
16296
 
15885
- this.ensureNoReservedMemoryUsage(range);
16297
+ instructionArgumentTypeMap[Instruction.BRANCH_EQ] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16298
+ instructionArgumentTypeMap[Instruction.BRANCH_NE] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16299
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16300
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16301
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16302
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15886
16303
 
15887
- const pageNumber = getPageNumber(start);
15888
- const page = this.initialMemory.get(pageNumber);
16304
+ instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP_IND] = ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
15889
16305
 
15890
- if (page === undefined) {
15891
- throw new PageNotExist();
15892
- }
16306
+ instructionArgumentTypeMap[Instruction.ADD_32] = ArgumentType.THREE_REGISTERS;
16307
+ instructionArgumentTypeMap[Instruction.ADD_64] = ArgumentType.THREE_REGISTERS;
16308
+ instructionArgumentTypeMap[Instruction.SUB_32] = ArgumentType.THREE_REGISTERS;
16309
+ instructionArgumentTypeMap[Instruction.SUB_64] = ArgumentType.THREE_REGISTERS;
16310
+ instructionArgumentTypeMap[Instruction.AND] = ArgumentType.THREE_REGISTERS;
16311
+ instructionArgumentTypeMap[Instruction.XOR] = ArgumentType.THREE_REGISTERS;
16312
+ instructionArgumentTypeMap[Instruction.OR] = ArgumentType.THREE_REGISTERS;
16313
+ instructionArgumentTypeMap[Instruction.MUL_32] = ArgumentType.THREE_REGISTERS;
16314
+ instructionArgumentTypeMap[Instruction.MUL_64] = ArgumentType.THREE_REGISTERS;
16315
+ instructionArgumentTypeMap[Instruction.MUL_UPPER_S_S] = ArgumentType.THREE_REGISTERS;
16316
+ instructionArgumentTypeMap[Instruction.MUL_UPPER_U_U] = ArgumentType.THREE_REGISTERS;
16317
+ instructionArgumentTypeMap[Instruction.MUL_UPPER_S_U] = ArgumentType.THREE_REGISTERS;
16318
+ instructionArgumentTypeMap[Instruction.DIV_U_32] = ArgumentType.THREE_REGISTERS;
16319
+ instructionArgumentTypeMap[Instruction.DIV_S_32] = ArgumentType.THREE_REGISTERS;
16320
+ instructionArgumentTypeMap[Instruction.REM_U_32] = ArgumentType.THREE_REGISTERS;
16321
+ instructionArgumentTypeMap[Instruction.REM_S_32] = ArgumentType.THREE_REGISTERS;
16322
+ instructionArgumentTypeMap[Instruction.DIV_U_64] = ArgumentType.THREE_REGISTERS;
16323
+ instructionArgumentTypeMap[Instruction.DIV_S_64] = ArgumentType.THREE_REGISTERS;
16324
+ instructionArgumentTypeMap[Instruction.REM_U_64] = ArgumentType.THREE_REGISTERS;
16325
+ instructionArgumentTypeMap[Instruction.REM_S_64] = ArgumentType.THREE_REGISTERS;
16326
+ instructionArgumentTypeMap[Instruction.SET_LT_U] = ArgumentType.THREE_REGISTERS;
16327
+ instructionArgumentTypeMap[Instruction.SET_LT_S] = ArgumentType.THREE_REGISTERS;
16328
+ instructionArgumentTypeMap[Instruction.SHLO_L_32] = ArgumentType.THREE_REGISTERS;
16329
+ instructionArgumentTypeMap[Instruction.SHLO_R_32] = ArgumentType.THREE_REGISTERS;
16330
+ instructionArgumentTypeMap[Instruction.SHAR_R_32] = ArgumentType.THREE_REGISTERS;
16331
+ instructionArgumentTypeMap[Instruction.SHLO_L_64] = ArgumentType.THREE_REGISTERS;
16332
+ instructionArgumentTypeMap[Instruction.SHLO_R_64] = ArgumentType.THREE_REGISTERS;
16333
+ instructionArgumentTypeMap[Instruction.SHAR_R_64] = ArgumentType.THREE_REGISTERS;
16334
+ instructionArgumentTypeMap[Instruction.CMOV_IZ] = ArgumentType.THREE_REGISTERS;
16335
+ instructionArgumentTypeMap[Instruction.CMOV_NZ] = ArgumentType.THREE_REGISTERS;
16336
+ instructionArgumentTypeMap[Instruction.ROT_L_64] = ArgumentType.THREE_REGISTERS;
16337
+ instructionArgumentTypeMap[Instruction.ROT_L_32] = ArgumentType.THREE_REGISTERS;
16338
+ instructionArgumentTypeMap[Instruction.ROT_R_64] = ArgumentType.THREE_REGISTERS;
16339
+ instructionArgumentTypeMap[Instruction.ROT_R_32] = ArgumentType.THREE_REGISTERS;
16340
+ instructionArgumentTypeMap[Instruction.AND_INV] = ArgumentType.THREE_REGISTERS;
16341
+ instructionArgumentTypeMap[Instruction.OR_INV] = ArgumentType.THREE_REGISTERS;
16342
+ instructionArgumentTypeMap[Instruction.XNOR] = ArgumentType.THREE_REGISTERS;
16343
+ instructionArgumentTypeMap[Instruction.MAX] = ArgumentType.THREE_REGISTERS;
16344
+ instructionArgumentTypeMap[Instruction.MAX_U] = ArgumentType.THREE_REGISTERS;
16345
+ instructionArgumentTypeMap[Instruction.MIN] = ArgumentType.THREE_REGISTERS;
16346
+ instructionArgumentTypeMap[Instruction.MIN_U] = ArgumentType.THREE_REGISTERS;
15893
16347
 
15894
- const startPageIndex = tryAsPageIndex(start - page.start);
15895
- page.setData(startPageIndex, data);
16348
+ return instructionArgumentTypeMap;
16349
+ })();
15896
16350
 
15897
- return this;
15898
- }
16351
+ declare class BasicBlocks {
16352
+ private basicBlocks: Set<number> = new Set();
15899
16353
 
15900
- finalize(startHeapIndex: MemoryIndex, endHeapIndex: SbrkIndex): Memory {
15901
- check`
15902
- ${startHeapIndex <= endHeapIndex}
15903
- startHeapIndex (${startHeapIndex}) has to be less than or equal to endHeapIndex (${endHeapIndex})
15904
- `;
15905
- this.ensureNotFinalized();
16354
+ reset(code: Uint8Array, mask: Mask) {
16355
+ this.basicBlocks.clear();
16356
+ this.basicBlocks.add(0);
16357
+ const codeLength = code.length;
15906
16358
 
15907
- const heapRange = MemoryRange.fromStartAndLength(startHeapIndex, endHeapIndex - startHeapIndex);
15908
- const heapPagesRange = PageRange.fromMemoryRange(heapRange);
15909
- const initializedPageNumbers = Array.from(this.initialMemory.keys());
16359
+ const isBasicBlockTermination = (index: number) =>
16360
+ mask.isInstruction(index) && terminationInstructions[code[index]];
15910
16361
 
15911
- for (const pageNumber of initializedPageNumbers) {
15912
- if (heapPagesRange.isInRange(pageNumber)) {
15913
- throw new IncorrectSbrkIndex();
16362
+ for (let i = 0; i < codeLength; i++) {
16363
+ if (mask.isInstruction(i) && isBasicBlockTermination(i)) {
16364
+ this.basicBlocks.add(i + 1 + mask.getNoOfBytesToNextInstruction(i + 1));
15914
16365
  }
15915
16366
  }
16367
+ }
15916
16368
 
15917
- const memory = Memory.fromInitialMemory({
15918
- memory: this.initialMemory,
15919
- sbrkIndex: tryAsSbrkIndex(startHeapIndex),
15920
- endHeapIndex,
15921
- });
16369
+ isBeginningOfBasicBlock(index: number) {
16370
+ return this.basicBlocks.has(index);
16371
+ }
16372
+ }
15922
16373
 
15923
- this.isFinalized = true;
15924
- return memory;
16374
+ declare enum Result {
16375
+ HALT = 0,
16376
+ PANIC = 1,
16377
+ FAULT_ACCESS = 2,
16378
+ FAULT = 3,
16379
+ HOST = 4,
16380
+ }
16381
+
16382
+ declare class InstructionResult {
16383
+ public nextPc = 0;
16384
+ public status: Result | null = null;
16385
+ /**
16386
+ * A numeric exit parameter of the PVM.
16387
+ *
16388
+ * In case of a `status === Result.FAULT` this will be the memory address
16389
+ * that triggered the fault.
16390
+ * In case of a `status === Result.HOST` this will be the host call index
16391
+ * that should be invoked.
16392
+ *
16393
+ * In any other circumstance the value should be `null`.
16394
+ */
16395
+ public exitParam: number | null = null;
16396
+
16397
+ reset() {
16398
+ this.nextPc = 0;
16399
+ this.status = null;
16400
+ this.exitParam = null;
15925
16401
  }
15926
16402
  }
15927
16403
 
@@ -16906,7 +17382,7 @@ declare class StoreOps {
16906
17382
  this.instructionResult.status = Result.FAULT_ACCESS;
16907
17383
  } else {
16908
17384
  this.instructionResult.status = Result.FAULT;
16909
- this.instructionResult.exitParam = getStartPageIndex(storeResult.error.address);
17385
+ this.instructionResult.exitParam = getStartPageIndex(tryAsMemoryIndex(storeResult.error.address));
16910
17386
  }
16911
17387
  }
16912
17388
  }
@@ -17707,34 +18183,20 @@ declare class ProgramDecoder {
17707
18183
  }
17708
18184
  }
17709
18185
 
17710
- /**
17711
- * Inner status codes for the PVM
17712
- *
17713
- * https://graypaper.fluffylabs.dev/#/85129da/2cae022cae02?v=0.6.3
17714
- */
17715
- declare enum Status {
17716
- OK = 255,
17717
- HALT = 0,
17718
- PANIC = 1,
17719
- FAULT = 2,
17720
- HOST = 3,
17721
- OOG = 4,
17722
- }
17723
-
17724
18186
  type InterpreterOptions = {
17725
18187
  useSbrkGas?: boolean;
17726
18188
  };
17727
18189
 
17728
18190
  declare const logger = Logger.new(import.meta.filename, "pvm");
17729
18191
 
17730
- declare class Interpreter {
18192
+ declare class Interpreter implements IPvmInterpreter {
17731
18193
  private readonly useSbrkGas: boolean;
17732
- private registers = new Registers();
18194
+ readonly registers = new Registers();
18195
+ readonly memory = new Memory();
18196
+ gas = gasCounter(tryAsGas(0));
17733
18197
  private code: Uint8Array = new Uint8Array();
17734
18198
  private mask = Mask.empty();
17735
18199
  private pc = 0;
17736
- private gas = gasCounter(tryAsGas(0));
17737
- private initialGas = gasCounter(tryAsGas(0));
17738
18200
  private argsDecoder: ArgsDecoder;
17739
18201
  private threeRegsDispatcher: ThreeRegsDispatcher;
17740
18202
  private twoRegsOneImmDispatcher: TwoRegsOneImmDispatcher;
@@ -17744,7 +18206,6 @@ declare class Interpreter {
17744
18206
  private oneOffsetDispatcher: OneOffsetDispatcher;
17745
18207
  private oneRegOneImmDispatcher: OneRegOneImmDispatcher;
17746
18208
  private instructionResult = new InstructionResult();
17747
- private memory = new Memory();
17748
18209
  private twoImmsDispatcher: TwoImmsDispatcher;
17749
18210
  private oneRegTwoImmsDispatcher: OneRegTwoImmsDispatcher;
17750
18211
  private noArgsDispatcher: NoArgsDispatcher;
@@ -17798,7 +18259,12 @@ declare class Interpreter {
17798
18259
  this.oneRegOneExtImmDispatcher = new OneRegOneExtImmDispatcher(loadOps);
17799
18260
  }
17800
18261
 
17801
- reset(rawProgram: Uint8Array, pc: number, gas: Gas, maybeRegisters?: Registers, maybeMemory?: Memory) {
18262
+ resetJam(program: Uint8Array, args: Uint8Array, pc: number, gas: Gas) {
18263
+ const p = Program.fromSpi(program, args, true);
18264
+ this.resetGeneric(p.code, pc, gas, p.registers, p.memory);
18265
+ }
18266
+
18267
+ resetGeneric(rawProgram: Uint8Array, pc: number, gas: Gas, maybeRegisters?: Registers, maybeMemory?: Memory) {
17802
18268
  const programDecoder = new ProgramDecoder(rawProgram);
17803
18269
  this.code = programDecoder.getCode();
17804
18270
  this.mask = programDecoder.getMask();
@@ -17806,7 +18272,6 @@ declare class Interpreter {
17806
18272
 
17807
18273
  this.pc = pc;
17808
18274
  this.gas = gasCounter(gas);
17809
- this.initialGas = gasCounter(gas);
17810
18275
  this.status = Status.OK;
17811
18276
  this.argsDecoder.reset(this.code, this.mask);
17812
18277
  this.basicBlocks.reset(this.code, this.mask);
@@ -17948,10 +18413,6 @@ declare class Interpreter {
17948
18413
  return this.status;
17949
18414
  }
17950
18415
 
17951
- getRegisters() {
17952
- return this.registers;
17953
- }
17954
-
17955
18416
  getPC() {
17956
18417
  return this.pc;
17957
18418
  }
@@ -17960,258 +18421,91 @@ declare class Interpreter {
17960
18421
  this.pc = nextPc;
17961
18422
  }
17962
18423
 
17963
- getGas(): Gas {
17964
- return this.gas.get();
17965
- }
17966
-
17967
- getGasConsumed(): Gas {
17968
- const gasConsumed = tryAsBigGas(this.initialGas.get()) - tryAsBigGas(this.gas.get());
17969
-
17970
- if (gasConsumed < 0) {
17971
- return this.initialGas.get();
17972
- }
17973
-
17974
- return tryAsBigGas(gasConsumed);
17975
- }
17976
-
17977
- getGasCounter(): GasCounter {
17978
- return this.gas;
17979
- }
17980
-
17981
18424
  getStatus() {
17982
18425
  return this.status;
17983
18426
  }
17984
18427
 
17985
18428
  getExitParam(): null | U32 {
17986
18429
  const p = this.instructionResult.exitParam;
17987
- return p !== null ? tryAsU32(p) : p;
17988
- }
17989
-
17990
- getMemory() {
17991
- return this.memory;
17992
- }
17993
-
17994
- getMemoryPage(pageNumber: number): null | Uint8Array {
17995
- return this.memory.getPageDump(tryAsPageNumber(pageNumber));
17996
- }
17997
-
17998
- calculateBlockGasCost(): Map<string, number> {
17999
- const codeLength = this.code.length;
18000
- const blocks: Map<string, number> = new Map();
18001
- let currentBlock = "0";
18002
- let gasCost = 0;
18003
- const getNextIstructionIndex = (index: number) => index + 1 + this.mask.getNoOfBytesToNextInstruction(index + 1);
18004
-
18005
- for (let index = 0; index < codeLength; index = getNextIstructionIndex(index)) {
18006
- const instruction = this.code[index];
18007
- if (this.basicBlocks.isBeginningOfBasicBlock(index)) {
18008
- blocks.set(currentBlock, gasCost);
18009
- currentBlock = index.toString();
18010
- gasCost = 0;
18011
- }
18012
-
18013
- gasCost += instructionGasMap[instruction];
18014
- }
18015
-
18016
- blocks.set(currentBlock, gasCost);
18017
-
18018
- return blocks;
18019
- }
18020
- }
18021
-
18022
- type index$8_BigGas = BigGas;
18023
- type index$8_Gas = Gas;
18024
- type index$8_GasCounter = GasCounter;
18025
- type index$8_Interpreter = Interpreter;
18026
- declare const index$8_Interpreter: typeof Interpreter;
18027
- type index$8_InterpreterOptions = InterpreterOptions;
18028
- type index$8_Memory = Memory;
18029
- declare const index$8_Memory: typeof Memory;
18030
- type index$8_MemoryBuilder = MemoryBuilder;
18031
- declare const index$8_MemoryBuilder: typeof MemoryBuilder;
18032
- type index$8_MemoryIndex = MemoryIndex;
18033
- type index$8_Registers = Registers;
18034
- declare const index$8_Registers: typeof Registers;
18035
- type index$8_SbrkIndex = SbrkIndex;
18036
- type index$8_SmallGas = SmallGas;
18037
- declare const index$8_gasCounter: typeof gasCounter;
18038
- declare const index$8_logger: typeof logger;
18039
- declare const index$8_tryAsBigGas: typeof tryAsBigGas;
18040
- declare const index$8_tryAsGas: typeof tryAsGas;
18041
- declare const index$8_tryAsMemoryIndex: typeof tryAsMemoryIndex;
18042
- declare const index$8_tryAsSbrkIndex: typeof tryAsSbrkIndex;
18043
- declare const index$8_tryAsSmallGas: typeof tryAsSmallGas;
18044
- declare namespace index$8 {
18045
- export { index$8_Interpreter as Interpreter, index$8_Memory as Memory, index$8_MemoryBuilder as MemoryBuilder, index$8_Registers as Registers, index$8_gasCounter as gasCounter, index$8_logger as logger, index$8_tryAsBigGas as tryAsBigGas, index$8_tryAsGas as tryAsGas, index$8_tryAsMemoryIndex as tryAsMemoryIndex, index$8_tryAsSbrkIndex as tryAsSbrkIndex, index$8_tryAsSmallGas as tryAsSmallGas };
18046
- export type { index$8_BigGas as BigGas, index$8_Gas as Gas, index$8_GasCounter as GasCounter, index$8_InterpreterOptions as InterpreterOptions, index$8_MemoryIndex as MemoryIndex, index$8_SbrkIndex as SbrkIndex, index$8_SmallGas as SmallGas };
18047
- }
18048
-
18049
- interface IHostCallMemory {
18050
- storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds>;
18051
- loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds>;
18052
- }
18053
-
18054
- declare class HostCallMemory implements IHostCallMemory {
18055
- constructor(private readonly memory: Memory) {}
18056
-
18057
- storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds> {
18058
- if (bytes.length === 0) {
18059
- return Result.ok(OK);
18060
- }
18061
-
18062
- if (address + tryAsU64(bytes.length) > MEMORY_SIZE) {
18063
- return Result.error(
18064
- new OutOfBounds(),
18065
- () => `Memory access out of bounds: address ${address} + length ${bytes.length} exceeds memory size`,
18066
- );
18067
- }
18068
-
18069
- return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
18070
- }
18071
-
18072
- loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds> {
18073
- if (result.length === 0) {
18074
- return Result.ok(OK);
18075
- }
18076
-
18077
- if (startAddress + tryAsU64(result.length) > MEMORY_SIZE) {
18078
- return Result.error(
18079
- new OutOfBounds(),
18080
- () => `Memory access out of bounds: address ${startAddress} + length ${result.length} exceeds memory size`,
18081
- );
18082
- }
18083
-
18084
- return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
18085
- }
18086
- }
18087
-
18088
- interface IHostCallRegisters {
18089
- get(registerIndex: number): U64;
18090
- set(registerIndex: number, value: U64): void;
18091
- }
18092
-
18093
- declare class HostCallRegisters implements IHostCallRegisters {
18094
- constructor(private readonly registers: Registers) {}
18095
-
18096
- get(registerIndex: number): U64 {
18097
- return tryAsU64(this.registers.getU64(registerIndex));
18098
- }
18099
-
18100
- set(registerIndex: number, value: U64) {
18101
- this.registers.setU64(registerIndex, value);
18102
- }
18103
- }
18104
-
18105
- /** Strictly-typed host call index. */
18106
- type HostCallIndex = Opaque<U32, "HostCallIndex[U32]">;
18107
- /** Attempt to convert a number into `HostCallIndex`. */
18108
- declare const tryAsHostCallIndex = (v: number): HostCallIndex => asOpaqueType(tryAsU32(v));
18109
-
18110
- /**
18111
- * Host-call exit reason.
18112
- *
18113
- * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
18114
- */
18115
- declare enum PvmExecution {
18116
- Halt = 0,
18117
- Panic = 1,
18118
- OOG = 2, // out-of-gas
18119
- }
18120
-
18121
- /** A utility function to easily trace a bunch of registers. */
18122
- declare function traceRegisters(...regs: number[]) {
18123
- return regs.map(tryAsRegisterIndex);
18124
- }
18125
-
18126
- /** An interface for a host call implementation */
18127
- interface HostCallHandler {
18128
- /** Index of that host call (i.e. what PVM invokes via `ecalli`) */
18129
- readonly index: HostCallIndex;
18130
-
18131
- /**
18132
- * The gas cost of invocation of that host call.
18133
- *
18134
- * NOTE: `((reg: IHostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
18135
- */
18136
- readonly basicGasCost: SmallGas | ((reg: IHostCallRegisters) => Gas);
18137
-
18138
- /** Currently executing service id. */
18139
- readonly currentServiceId: U32;
18140
-
18141
- /** Input&Output registers that we should add to tracing log. */
18142
- readonly tracedRegisters: RegisterIndex[];
18430
+ return p !== null ? tryAsU32(p) : p;
18431
+ }
18143
18432
 
18144
- /**
18145
- * Actually execute the host call.
18146
- *
18147
- * NOTE the call is ALLOWED and expected to modify registers and memory.
18148
- */
18149
- execute(gas: GasCounter, regs: IHostCallRegisters, memory: IHostCallMemory): Promise<undefined | PvmExecution>;
18150
- }
18433
+ getMemoryPage(pageNumber: number): null | Uint8Array {
18434
+ return this.memory.getPageDump(tryAsPageNumber(pageNumber));
18435
+ }
18151
18436
 
18152
- /** Container for all available host calls. */
18153
- declare class HostCallsManager {
18154
- private readonly hostCalls = new Map<HostCallIndex, HostCallHandler>();
18155
- private readonly missing;
18437
+ calculateBlockGasCost(): Map<string, number> {
18438
+ const codeLength = this.code.length;
18439
+ const blocks: Map<string, number> = new Map();
18440
+ let currentBlock = "0";
18441
+ let gasCost = 0;
18442
+ const getNextIstructionIndex = (index: number) => index + 1 + this.mask.getNoOfBytesToNextInstruction(index + 1);
18156
18443
 
18157
- constructor({
18158
- missing,
18159
- handlers = [],
18160
- }: {
18161
- missing: HostCallHandler;
18162
- handlers?: HostCallHandler[];
18163
- }) {
18164
- this.missing = missing;
18444
+ for (let index = 0; index < codeLength; index = getNextIstructionIndex(index)) {
18445
+ const instruction = this.code[index];
18446
+ if (this.basicBlocks.isBeginningOfBasicBlock(index)) {
18447
+ blocks.set(currentBlock, gasCost);
18448
+ currentBlock = index.toString();
18449
+ gasCost = 0;
18450
+ }
18165
18451
 
18166
- for (const handler of handlers) {
18167
- check`${this.hostCalls.get(handler.index) === undefined} Overwriting host call handler at index ${handler.index}`;
18168
- this.hostCalls.set(handler.index, handler);
18452
+ gasCost += instructionGasMap[instruction];
18169
18453
  }
18170
- }
18171
18454
 
18172
- /** Get a host call by index. */
18173
- get(hostCallIndex: HostCallIndex): HostCallHandler {
18174
- return this.hostCalls.get(hostCallIndex) ?? this.missing;
18175
- }
18455
+ blocks.set(currentBlock, gasCost);
18176
18456
 
18177
- traceHostCall(
18178
- context: string,
18179
- hostCallIndex: HostCallIndex,
18180
- hostCallHandler: HostCallHandler,
18181
- registers: IHostCallRegisters,
18182
- gas: Gas,
18183
- ) {
18184
- const { currentServiceId } = hostCallHandler;
18185
- const requested = hostCallIndex !== hostCallHandler.index ? ` (${hostCallIndex})` : "";
18186
- const name = `${hostCallHandler.constructor.name}:${hostCallHandler.index}`;
18187
- const registerValues = hostCallHandler.tracedRegisters
18188
- .map((idx) => [idx.toString().padStart(2, "0"), registers.get(idx)] as const)
18189
- .filter((v) => v[1] !== 0n)
18190
- .map(([idx, value]) => {
18191
- return `r${idx}=${value} (0x${value.toString(16)})`;
18192
- })
18193
- .join(", ");
18194
- logger.insane`[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
18457
+ return blocks;
18195
18458
  }
18196
18459
  }
18197
18460
 
18198
- type ResolveFn = (pvm: Interpreter) => void;
18461
+ type index$6_Interpreter = Interpreter;
18462
+ declare const index$6_Interpreter: typeof Interpreter;
18463
+ type index$6_InterpreterOptions = InterpreterOptions;
18464
+ type index$6_Memory = Memory;
18465
+ declare const index$6_Memory: typeof Memory;
18466
+ type index$6_MemoryBuilder = MemoryBuilder;
18467
+ declare const index$6_MemoryBuilder: typeof MemoryBuilder;
18468
+ type index$6_MemoryIndex = MemoryIndex;
18469
+ type index$6_Registers = Registers;
18470
+ declare const index$6_Registers: typeof Registers;
18471
+ type index$6_SbrkIndex = SbrkIndex;
18472
+ declare const index$6_gasCounter: typeof gasCounter;
18473
+ declare const index$6_logger: typeof logger;
18474
+ declare const index$6_tryAsMemoryIndex: typeof tryAsMemoryIndex;
18475
+ declare const index$6_tryAsSbrkIndex: typeof tryAsSbrkIndex;
18476
+ declare namespace index$6 {
18477
+ export { index$6_Interpreter as Interpreter, index$6_Memory as Memory, index$6_MemoryBuilder as MemoryBuilder, index$6_Registers as Registers, index$6_gasCounter as gasCounter, index$6_logger as logger, index$6_tryAsMemoryIndex as tryAsMemoryIndex, index$6_tryAsSbrkIndex as tryAsSbrkIndex };
18478
+ export type { index$6_InterpreterOptions as InterpreterOptions, index$6_MemoryIndex as MemoryIndex, index$6_SbrkIndex as SbrkIndex };
18479
+ }
18199
18480
 
18481
+ type ResolveFn = (pvm: IPvmInterpreter) => void;
18482
+
18483
+ // TODO [MaSo] Delete this & also make host calls independent from intepreters.
18200
18484
  declare class InterpreterInstanceManager {
18201
- private instances: Interpreter[] = [];
18202
18485
  private waitingQueue: ResolveFn[] = [];
18203
18486
 
18204
- constructor(noOfPvmInstances: number) {
18205
- for (let i = 0; i < noOfPvmInstances; i++) {
18206
- this.instances.push(
18207
- new Interpreter({
18208
- useSbrkGas: false,
18209
- }),
18210
- );
18487
+ private constructor(private readonly instances: IPvmInterpreter[]) {}
18488
+
18489
+ static async new(interpreter: PvmBackend): Promise<InterpreterInstanceManager> {
18490
+ const instances: IPvmInterpreter[] = [];
18491
+ switch (interpreter) {
18492
+ case PvmBackend.BuiltIn:
18493
+ instances.push(
18494
+ new Interpreter({
18495
+ useSbrkGas: false,
18496
+ }),
18497
+ );
18498
+ break;
18499
+ case PvmBackend.Ananas:
18500
+ instances.push(await AnanasInterpreter.new());
18501
+ break;
18502
+ default:
18503
+ assertNever(interpreter);
18211
18504
  }
18505
+ return new InterpreterInstanceManager(instances);
18212
18506
  }
18213
18507
 
18214
- async getInstance(): Promise<Interpreter> {
18508
+ async getInstance(): Promise<IPvmInterpreter> {
18215
18509
  const instance = this.instances.pop();
18216
18510
  if (instance !== undefined) {
18217
18511
  return Promise.resolve(instance);
@@ -18221,7 +18515,7 @@ declare class InterpreterInstanceManager {
18221
18515
  });
18222
18516
  }
18223
18517
 
18224
- releaseInstance(pvm: Interpreter) {
18518
+ releaseInstance(pvm: IPvmInterpreter) {
18225
18519
  const waiting = this.waitingQueue.shift();
18226
18520
  if (waiting !== undefined) {
18227
18521
  return waiting(pvm);
@@ -18264,21 +18558,22 @@ declare class HostCalls {
18264
18558
  private hostCalls: HostCallsManager,
18265
18559
  ) {}
18266
18560
 
18267
- private getReturnValue(status: Status, pvmInstance: Interpreter): ReturnValue {
18268
- const gasConsumed = pvmInstance.getGasConsumed();
18561
+ private getReturnValue(status: Status, pvmInstance: IPvmInterpreter): ReturnValue {
18562
+ const gasConsumed = pvmInstance.gas.used();
18269
18563
  if (status === Status.OOG) {
18270
18564
  return ReturnValue.fromStatus(gasConsumed, status);
18271
18565
  }
18272
18566
 
18273
18567
  if (status === Status.HALT) {
18274
- const memory = pvmInstance.getMemory();
18275
- const regs = pvmInstance.getRegisters();
18276
- const maybeAddress = regs.getLowerU32(7);
18277
- const maybeLength = regs.getLowerU32(8);
18568
+ const regs = new HostCallRegisters(pvmInstance.registers.getAllEncoded());
18569
+ const memory = new HostCallMemory(pvmInstance.memory);
18570
+ const address = regs.get(7);
18571
+ // NOTE we are taking the the lower U32 part of the register, hence it's safe.
18572
+ const length = Number(regs.get(8) & 0xffff_ffffn);
18573
+
18574
+ const result = safeAllocUint8Array(length);
18278
18575
 
18279
- const result = safeAllocUint8Array(maybeLength);
18280
- const startAddress = tryAsMemoryIndex(maybeAddress);
18281
- const loadResult = memory.loadInto(result, startAddress);
18576
+ const loadResult = memory.loadInto(result, address);
18282
18577
 
18283
18578
  if (loadResult.isError) {
18284
18579
  return ReturnValue.fromMemorySlice(gasConsumed, new Uint8Array());
@@ -18290,7 +18585,7 @@ declare class HostCalls {
18290
18585
  return ReturnValue.fromStatus(gasConsumed, Status.PANIC);
18291
18586
  }
18292
18587
 
18293
- private async execute(pvmInstance: Interpreter) {
18588
+ private async execute(pvmInstance: IPvmInterpreter) {
18294
18589
  pvmInstance.runProgram();
18295
18590
  for (;;) {
18296
18591
  let status = pvmInstance.getStatus();
@@ -18302,9 +18597,9 @@ declare class HostCalls {
18302
18597
  "We know that the exit param is not null, because the status is 'Status.HOST'
18303
18598
  `;
18304
18599
  const hostCallIndex = pvmInstance.getExitParam() ?? -1;
18305
- const gas = pvmInstance.getGasCounter();
18306
- const regs = new HostCallRegisters(pvmInstance.getRegisters());
18307
- const memory = new HostCallMemory(pvmInstance.getMemory());
18600
+ const gas = pvmInstance.gas;
18601
+ const regs = new HostCallRegisters(pvmInstance.registers.getAllEncoded());
18602
+ const memory = new HostCallMemory(pvmInstance.memory);
18308
18603
  const index = tryAsHostCallIndex(hostCallIndex);
18309
18604
 
18310
18605
  const hostCall = this.hostCalls.get(index);
@@ -18317,7 +18612,7 @@ declare class HostCalls {
18317
18612
  const pcLog = `[PC: ${pvmInstance.getPC()}]`;
18318
18613
  if (underflow) {
18319
18614
  this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
18320
- return ReturnValue.fromStatus(pvmInstance.getGasConsumed(), Status.OOG);
18615
+ return ReturnValue.fromStatus(gas.used(), Status.OOG);
18321
18616
  }
18322
18617
  this.hostCalls.traceHostCall(`${pcLog} Invoking`, index, hostCall, regs, gasBefore);
18323
18618
  const result = await hostCall.execute(gas, regs, memory);
@@ -18328,6 +18623,7 @@ declare class HostCalls {
18328
18623
  regs,
18329
18624
  gas.get(),
18330
18625
  );
18626
+ pvmInstance.registers.setAllEncoded(regs.getEncoded());
18331
18627
 
18332
18628
  if (result === PvmExecution.Halt) {
18333
18629
  status = Status.HALT;
@@ -18354,15 +18650,9 @@ declare class HostCalls {
18354
18650
  }
18355
18651
  }
18356
18652
 
18357
- async runProgram(
18358
- rawProgram: Uint8Array,
18359
- initialPc: number,
18360
- initialGas: Gas,
18361
- maybeRegisters?: Registers,
18362
- maybeMemory?: Memory,
18363
- ): Promise<ReturnValue> {
18653
+ async runProgram(program: Uint8Array, args: Uint8Array, initialPc: number, initialGas: Gas): Promise<ReturnValue> {
18364
18654
  const pvmInstance = await this.pvmInstanceManager.getInstance();
18365
- pvmInstance.reset(rawProgram, initialPc, initialGas, maybeRegisters, maybeMemory);
18655
+ pvmInstance.resetJam(program, args, initialPc, initialGas);
18366
18656
  try {
18367
18657
  return await this.execute(pvmInstance);
18368
18658
  } finally {
@@ -18371,20 +18661,18 @@ declare class HostCalls {
18371
18661
  }
18372
18662
  }
18373
18663
 
18374
- type index$7_HostCallHandler = HostCallHandler;
18375
- type index$7_HostCallMemory = HostCallMemory;
18376
- declare const index$7_HostCallMemory: typeof HostCallMemory;
18377
- type index$7_HostCallRegisters = HostCallRegisters;
18378
- declare const index$7_HostCallRegisters: typeof HostCallRegisters;
18379
- type index$7_IHostCallMemory = IHostCallMemory;
18380
- type index$7_IHostCallRegisters = IHostCallRegisters;
18381
- type index$7_PvmExecution = PvmExecution;
18382
- declare const index$7_PvmExecution: typeof PvmExecution;
18383
- declare const index$7_traceRegisters: typeof traceRegisters;
18384
- declare const index$7_tryAsHostCallIndex: typeof tryAsHostCallIndex;
18385
- declare namespace index$7 {
18386
- export { index$7_HostCallMemory as HostCallMemory, index$7_HostCallRegisters as HostCallRegisters, HostCallsManager as HostCalls, index$7_PvmExecution as PvmExecution, HostCalls as PvmHostCallExtension, InterpreterInstanceManager as PvmInstanceManager, index$7_traceRegisters as traceRegisters, index$7_tryAsHostCallIndex as tryAsHostCallIndex };
18387
- export type { index$7_HostCallHandler as HostCallHandler, index$7_IHostCallMemory as IHostCallMemory, index$7_IHostCallRegisters as IHostCallRegisters };
18664
+ type index$5_HostCallHandler = HostCallHandler;
18665
+ type index$5_HostCallMemory = HostCallMemory;
18666
+ declare const index$5_HostCallMemory: typeof HostCallMemory;
18667
+ type index$5_HostCallRegisters = HostCallRegisters;
18668
+ declare const index$5_HostCallRegisters: typeof HostCallRegisters;
18669
+ type index$5_PvmExecution = PvmExecution;
18670
+ declare const index$5_PvmExecution: typeof PvmExecution;
18671
+ declare const index$5_traceRegisters: typeof traceRegisters;
18672
+ declare const index$5_tryAsHostCallIndex: typeof tryAsHostCallIndex;
18673
+ declare namespace index$5 {
18674
+ export { index$5_HostCallMemory as HostCallMemory, index$5_HostCallRegisters as HostCallRegisters, HostCallsManager as HostCalls, index$5_PvmExecution as PvmExecution, HostCalls as PvmHostCallExtension, InterpreterInstanceManager as PvmInstanceManager, index$5_traceRegisters as traceRegisters, index$5_tryAsHostCallIndex as tryAsHostCallIndex };
18675
+ export type { index$5_HostCallHandler as HostCallHandler };
18388
18676
  }
18389
18677
 
18390
18678
  /**
@@ -18402,7 +18690,7 @@ type MachineId = Opaque<U64, "MachineId[u64]">;
18402
18690
  declare const tryAsMachineId = (v: number | bigint): MachineId => asOpaqueType(tryAsU64(v));
18403
18691
 
18404
18692
  declare class MachineInstance {
18405
- async run(gas: BigGas, registers: Registers): Promise<MachineResult> {
18693
+ async run(gas: BigGas, registers: HostCallRegisters): Promise<MachineResult> {
18406
18694
  return {
18407
18695
  result: {
18408
18696
  status: Status.OK,
@@ -18430,7 +18718,7 @@ type MachineStatus =
18430
18718
  type MachineResult = {
18431
18719
  result: MachineStatus;
18432
18720
  gas: BigGas;
18433
- registers: Registers;
18721
+ registers: HostCallRegisters;
18434
18722
  };
18435
18723
 
18436
18724
  /** Types of possbile operations to request by Pages host call. */
@@ -18502,7 +18790,7 @@ interface RefineExternalities {
18502
18790
  destinationStart: U64,
18503
18791
  sourceStart: U64,
18504
18792
  length: U64,
18505
- destination: IHostCallMemory,
18793
+ destination: HostCallMemory,
18506
18794
  ): Promise<Result$2<OK, PeekPokeError>>;
18507
18795
 
18508
18796
  /** Write a fragment of memory into `machineIndex` from given source memory. */
@@ -18511,7 +18799,7 @@ interface RefineExternalities {
18511
18799
  sourceStart: U64,
18512
18800
  destinationStart: U64,
18513
18801
  length: U64,
18514
- source: IHostCallMemory,
18802
+ source: HostCallMemory,
18515
18803
  ): Promise<Result$2<OK, PeekPokeError>>;
18516
18804
 
18517
18805
  /** Start an inner PVM instance with given entry point and starting code. */
@@ -18521,7 +18809,7 @@ interface RefineExternalities {
18521
18809
  machineInvoke(
18522
18810
  machineIndex: MachineId,
18523
18811
  gas: BigGas,
18524
- registers: Registers,
18812
+ registers: HostCallRegisters,
18525
18813
  ): Promise<Result$2<MachineResult, NoMachineError>>;
18526
18814
 
18527
18815
  /**
@@ -18943,7 +19231,7 @@ declare const CURRENT_SERVICE_ID = tryAsServiceId(2 ** 32 - 1);
18943
19231
 
18944
19232
  declare function getServiceIdOrCurrent(
18945
19233
  regNumber: number,
18946
- regs: IHostCallRegisters,
19234
+ regs: HostCallRegisters,
18947
19235
  currentServiceId: ServiceId,
18948
19236
  ): ServiceId | null {
18949
19237
  const regValue = regs.get(regNumber);
@@ -18974,270 +19262,75 @@ declare function clampU64ToU32(value: U64): U32 {
18974
19262
  return value > MAX_U32_BIG_INT ? MAX_U32 : tryAsU32(Number(value));
18975
19263
  }
18976
19264
 
18977
- type index$6_AccumulationStateUpdate = AccumulationStateUpdate;
18978
- declare const index$6_AccumulationStateUpdate: typeof AccumulationStateUpdate;
18979
- declare const index$6_CURRENT_SERVICE_ID: typeof CURRENT_SERVICE_ID;
18980
- type index$6_EjectError = EjectError;
18981
- declare const index$6_EjectError: typeof EjectError;
18982
- type index$6_ForgetPreimageError = ForgetPreimageError;
18983
- declare const index$6_ForgetPreimageError: typeof ForgetPreimageError;
18984
- declare const index$6_HostCallResult: typeof HostCallResult;
18985
- type index$6_InsufficientFundsError = InsufficientFundsError;
18986
- declare const index$6_MAX_U32: typeof MAX_U32;
18987
- declare const index$6_MAX_U32_BIG_INT: typeof MAX_U32_BIG_INT;
18988
- type index$6_MachineId = MachineId;
18989
- type index$6_MachineInstance = MachineInstance;
18990
- declare const index$6_MachineInstance: typeof MachineInstance;
18991
- type index$6_MachineResult = MachineResult;
18992
- type index$6_MachineStatus = MachineStatus;
18993
- type index$6_MemoryOperation = MemoryOperation;
18994
- declare const index$6_MemoryOperation: typeof MemoryOperation;
18995
- type index$6_NewServiceError = NewServiceError;
18996
- declare const index$6_NewServiceError: typeof NewServiceError;
18997
- type index$6_NoMachineError = NoMachineError;
18998
- type index$6_PagesError = PagesError;
18999
- declare const index$6_PagesError: typeof PagesError;
19000
- type index$6_PartialState = PartialState;
19001
- type index$6_PartiallyUpdatedState<T extends StateSlice = StateSlice> = PartiallyUpdatedState<T>;
19002
- declare const index$6_PartiallyUpdatedState: typeof PartiallyUpdatedState;
19003
- type index$6_PeekPokeError = PeekPokeError;
19004
- declare const index$6_PeekPokeError: typeof PeekPokeError;
19005
- type index$6_PendingTransfer = PendingTransfer;
19006
- declare const index$6_PendingTransfer: typeof PendingTransfer;
19007
- type index$6_PreimageStatus = PreimageStatus;
19008
- type index$6_PreimageStatusKind = PreimageStatusKind;
19009
- declare const index$6_PreimageStatusKind: typeof PreimageStatusKind;
19010
- type index$6_ProgramCounter = ProgramCounter;
19011
- type index$6_ProvidePreimageError = ProvidePreimageError;
19012
- declare const index$6_ProvidePreimageError: typeof ProvidePreimageError;
19013
- type index$6_RefineExternalities = RefineExternalities;
19014
- type index$6_RequestPreimageError = RequestPreimageError;
19015
- declare const index$6_RequestPreimageError: typeof RequestPreimageError;
19016
- declare const index$6_SERVICE_ID_BYTES: typeof SERVICE_ID_BYTES;
19017
- type index$6_SegmentExportError = SegmentExportError;
19018
- type index$6_ServiceStateUpdate = ServiceStateUpdate;
19019
- type index$6_StateSlice = StateSlice;
19020
- type index$6_TRANSFER_MEMO_BYTES = TRANSFER_MEMO_BYTES;
19021
- type index$6_TransferError = TransferError;
19022
- declare const index$6_TransferError: typeof TransferError;
19023
- type index$6_UnprivilegedError = UnprivilegedError;
19024
- type index$6_UpdatePrivilegesError = UpdatePrivilegesError;
19025
- declare const index$6_UpdatePrivilegesError: typeof UpdatePrivilegesError;
19026
- type index$6_ZeroVoidError = ZeroVoidError;
19027
- declare const index$6_ZeroVoidError: typeof ZeroVoidError;
19028
- declare const index$6_clampU64ToU32: typeof clampU64ToU32;
19029
- declare const index$6_deepCloneMapWithArray: typeof deepCloneMapWithArray;
19030
- declare const index$6_getServiceId: typeof getServiceId;
19031
- declare const index$6_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
19032
- declare const index$6_preimageLenAsU32: typeof preimageLenAsU32;
19033
- declare const index$6_slotsToPreimageStatus: typeof slotsToPreimageStatus;
19034
- declare const index$6_toMemoryOperation: typeof toMemoryOperation;
19035
- declare const index$6_tryAsMachineId: typeof tryAsMachineId;
19036
- declare const index$6_tryAsProgramCounter: typeof tryAsProgramCounter;
19037
- declare const index$6_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
19038
- declare namespace index$6 {
19039
- export { index$6_AccumulationStateUpdate as AccumulationStateUpdate, index$6_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$6_EjectError as EjectError, index$6_ForgetPreimageError as ForgetPreimageError, index$6_HostCallResult as HostCallResult, index$6_MAX_U32 as MAX_U32, index$6_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$6_MachineInstance as MachineInstance, index$6_MemoryOperation as MemoryOperation, index$6_NewServiceError as NewServiceError, index$6_PagesError as PagesError, index$6_PartiallyUpdatedState as PartiallyUpdatedState, index$6_PeekPokeError as PeekPokeError, index$6_PendingTransfer as PendingTransfer, index$6_PreimageStatusKind as PreimageStatusKind, index$6_ProvidePreimageError as ProvidePreimageError, index$6_RequestPreimageError as RequestPreimageError, index$6_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$6_TransferError as TransferError, index$6_UpdatePrivilegesError as UpdatePrivilegesError, index$6_ZeroVoidError as ZeroVoidError, index$6_clampU64ToU32 as clampU64ToU32, index$6_deepCloneMapWithArray as deepCloneMapWithArray, index$6_getServiceId as getServiceId, index$6_getServiceIdOrCurrent as getServiceIdOrCurrent, index$6_preimageLenAsU32 as preimageLenAsU32, index$6_slotsToPreimageStatus as slotsToPreimageStatus, index$6_toMemoryOperation as toMemoryOperation, index$6_tryAsMachineId as tryAsMachineId, index$6_tryAsProgramCounter as tryAsProgramCounter, index$6_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
19040
- export type { index$6_InsufficientFundsError as InsufficientFundsError, index$6_MachineId as MachineId, index$6_MachineResult as MachineResult, index$6_MachineStatus as MachineStatus, index$6_NoMachineError as NoMachineError, index$6_PartialState as PartialState, index$6_PreimageStatus as PreimageStatus, index$6_ProgramCounter as ProgramCounter, index$6_RefineExternalities as RefineExternalities, index$6_SegmentExportError as SegmentExportError, index$6_ServiceStateUpdate as ServiceStateUpdate, index$6_StateSlice as StateSlice, index$6_TRANSFER_MEMO_BYTES as TRANSFER_MEMO_BYTES, index$6_UnprivilegedError as UnprivilegedError };
19041
- }
19042
-
19043
- declare const NO_OF_REGISTERS = 13;
19044
-
19045
- declare class MemorySegment extends WithDebug {
19046
- static from({ start, end, data }: Omit<MemorySegment, never>) {
19047
- return new MemorySegment(start, end, data);
19048
- }
19049
-
19050
- constructor(
19051
- public readonly start: number,
19052
- public readonly end: number,
19053
- public readonly data: Uint8Array | null,
19054
- ) {
19055
- super();
19056
- }
19057
- }
19058
- declare class SpiMemory extends WithDebug {
19059
- constructor(
19060
- public readonly readable: MemorySegment[],
19061
- public readonly writeable: MemorySegment[],
19062
- public readonly sbrkIndex: number,
19063
- public readonly heapEnd: number,
19064
- ) {
19065
- super();
19066
- }
19067
- }
19068
-
19069
- declare class SpiProgram extends WithDebug {
19070
- constructor(
19071
- public readonly code: Uint8Array,
19072
- public readonly memory: SpiMemory,
19073
- public readonly registers: BigUint64Array,
19074
- ) {
19075
- super();
19076
- }
19077
- }
19078
-
19079
- /**
19080
- * program = E_3(|o|) ++ E_3(|w|) ++ E_2(z) ++ E_3(s) ++ o ++ w ++ E_4(|c|) ++ c
19081
- *
19082
- * E_n - little endian encoding, n - length
19083
- * o - initial read only data
19084
- * w - initial heap
19085
- * z - heap pages filled with zeros
19086
- * s - stack size
19087
- * c - program code
19088
- *
19089
- * https://graypaper.fluffylabs.dev/#/579bd12/2b92022b9202
19090
- */
19091
- declare function decodeStandardProgram(program: Uint8Array, args: Uint8Array) {
19092
- const decoder = Decoder.fromBlob(program);
19093
- const oLength = decoder.u24();
19094
- const wLength = decoder.u24();
19095
- check`${args.length <= DATA_LENGTH} Incorrect arguments length`;
19096
- check`${oLength <= DATA_LENGTH} Incorrect readonly segment length`;
19097
- const readOnlyLength = oLength;
19098
- check`${wLength <= DATA_LENGTH} Incorrect heap segment length`;
19099
- const heapLength = wLength;
19100
- const noOfHeapZerosPages = decoder.u16();
19101
- const stackSize = decoder.u24();
19102
- const readOnlyMemory = decoder.bytes(readOnlyLength).raw;
19103
- const initialHeap = decoder.bytes(heapLength).raw;
19104
- const codeLength = decoder.u32();
19105
- const code = decoder.bytes(codeLength).raw;
19106
- decoder.finish();
19107
-
19108
- const readonlyDataStart = SEGMENT_SIZE;
19109
- const readonlyDataEnd = SEGMENT_SIZE + alignToPageSize(readOnlyLength);
19110
- const heapDataStart = 2 * SEGMENT_SIZE + alignToSegmentSize(readOnlyLength);
19111
- const heapDataEnd = heapDataStart + alignToPageSize(heapLength);
19112
- const heapZerosEnd = heapDataStart + alignToPageSize(heapLength) + noOfHeapZerosPages * PAGE_SIZE;
19113
- const stackStart = STACK_SEGMENT - alignToPageSize(stackSize);
19114
- const stackEnd = STACK_SEGMENT;
19115
- const argsStart = ARGS_SEGMENT;
19116
- const argsEnd = argsStart + alignToPageSize(args.length);
19117
- const argsZerosEnd = argsEnd + alignToPageSize(args.length);
19118
-
19119
- function nonEmpty(s: MemorySegment | false): s is MemorySegment {
19120
- return s !== false;
19121
- }
19122
-
19123
- const readableMemory = [
19124
- readOnlyLength > 0 && getMemorySegment(readonlyDataStart, readonlyDataEnd, readOnlyMemory),
19125
- args.length > 0 && getMemorySegment(argsStart, argsEnd, args),
19126
- argsEnd < argsZerosEnd && getMemorySegment(argsEnd, argsZerosEnd),
19127
- ].filter(nonEmpty);
19128
- const writeableMemory = [
19129
- heapLength > 0 && getMemorySegment(heapDataStart, heapDataEnd, initialHeap),
19130
- heapDataEnd < heapZerosEnd && getMemorySegment(heapDataEnd, heapZerosEnd),
19131
- stackStart < stackEnd && getMemorySegment(stackStart, stackEnd),
19132
- ].filter(nonEmpty);
19133
-
19134
- return new SpiProgram(
19135
- code,
19136
- new SpiMemory(readableMemory, writeableMemory, heapZerosEnd, stackStart),
19137
- getRegisters(args.length),
19138
- );
19139
- }
19140
-
19141
- declare function getMemorySegment(start: number, end: number, data: Uint8Array | null = null) {
19142
- return new MemorySegment(start, end, data);
19143
- }
19144
-
19145
- declare function getRegisters(argsLength: number) {
19146
- const regs = new BigUint64Array(NO_OF_REGISTERS);
19147
-
19148
- // GP reference: https://graypaper.fluffylabs.dev/#/579bd12/2c7c012cb101
19149
- regs[0] = BigInt(LAST_PAGE);
19150
- regs[1] = BigInt(STACK_SEGMENT);
19151
- regs[7] = BigInt(ARGS_SEGMENT);
19152
- regs[8] = BigInt(argsLength);
19153
-
19154
- return regs;
19155
- }
19156
-
19157
- type index$5_MemorySegment = MemorySegment;
19158
- declare const index$5_MemorySegment: typeof MemorySegment;
19159
- declare const index$5_NO_OF_REGISTERS: typeof NO_OF_REGISTERS;
19160
- type index$5_SpiMemory = SpiMemory;
19161
- declare const index$5_SpiMemory: typeof SpiMemory;
19162
- type index$5_SpiProgram = SpiProgram;
19163
- declare const index$5_SpiProgram: typeof SpiProgram;
19164
- declare const index$5_decodeStandardProgram: typeof decodeStandardProgram;
19165
- declare const index$5_getMemorySegment: typeof getMemorySegment;
19166
- declare const index$5_getRegisters: typeof getRegisters;
19167
- declare namespace index$5 {
19168
- export {
19169
- index$5_MemorySegment as MemorySegment,
19170
- index$5_NO_OF_REGISTERS as NO_OF_REGISTERS,
19171
- index$5_SpiMemory as SpiMemory,
19172
- index$5_SpiProgram as SpiProgram,
19173
- index$5_decodeStandardProgram as decodeStandardProgram,
19174
- index$5_getMemorySegment as getMemorySegment,
19175
- index$5_getRegisters as getRegisters,
19176
- };
19177
- }
19178
-
19179
- declare class Program {
19180
- static fromSpi(blob: Uint8Array, args: Uint8Array, hasMetadata: boolean) {
19181
- const { code: spiCode, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
19182
- const { code, memory: rawMemory, registers } = decodeStandardProgram(spiCode, args);
19183
- const regs = new Registers();
19184
- regs.copyFrom(registers);
19185
- const memoryBuilder = new MemoryBuilder();
19186
-
19187
- for (const { start, end, data } of rawMemory.readable) {
19188
- const startIndex = tryAsMemoryIndex(start);
19189
- const endIndex = tryAsMemoryIndex(end);
19190
- memoryBuilder.setReadablePages(startIndex, endIndex, data ?? new Uint8Array());
19191
- }
19192
-
19193
- for (const { start, end, data } of rawMemory.writeable) {
19194
- const startIndex = tryAsMemoryIndex(start);
19195
- const endIndex = tryAsMemoryIndex(end);
19196
- memoryBuilder.setWriteablePages(startIndex, endIndex, data ?? new Uint8Array());
19197
- }
19198
-
19199
- const heapStart = tryAsMemoryIndex(rawMemory.sbrkIndex);
19200
- const heapEnd = tryAsSbrkIndex(rawMemory.heapEnd);
19201
- const memory = memoryBuilder.finalize(heapStart, heapEnd);
19202
-
19203
- return new Program(code, regs, memory, metadata);
19204
- }
19205
-
19206
- static fromGeneric(blob: Uint8Array, hasMetadata: boolean) {
19207
- const { code, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
19208
- const regs = new Registers();
19209
- const memory = new Memory();
19210
- return new Program(code, regs, memory, metadata);
19211
- }
19212
-
19213
- private constructor(
19214
- public readonly code: Uint8Array,
19215
- public readonly registers: Registers,
19216
- public readonly memory: Memory,
19217
- public metadata: Uint8Array = new Uint8Array(),
19218
- ) {}
19219
- }
19220
-
19221
- /**
19222
- * A function that splits preimage into metadata and code.
19223
- *
19224
- * https://graypaper.fluffylabs.dev/#/cc517d7/109a01109a01?v=0.6.5
19225
- */
19226
- declare function extractCodeAndMetadata(blobWithMetadata: Uint8Array) {
19227
- const decoder = Decoder.fromBlob(blobWithMetadata);
19228
- const metadata = decoder.bytesBlob().raw;
19229
- const code = decoder.remainingBytes().raw;
19230
- return { metadata, code };
19231
- }
19232
-
19233
- type index$4_Program = Program;
19234
- declare const index$4_Program: typeof Program;
19235
- declare const index$4_extractCodeAndMetadata: typeof extractCodeAndMetadata;
19265
+ declare function emptyRegistersBuffer(): Uint8Array {
19266
+ return safeAllocUint8Array(NO_OF_REGISTERS * REGISTER_BYTE_SIZE);
19267
+ }
19268
+
19269
+ type index$4_AccumulationStateUpdate = AccumulationStateUpdate;
19270
+ declare const index$4_AccumulationStateUpdate: typeof AccumulationStateUpdate;
19271
+ declare const index$4_CURRENT_SERVICE_ID: typeof CURRENT_SERVICE_ID;
19272
+ type index$4_EjectError = EjectError;
19273
+ declare const index$4_EjectError: typeof EjectError;
19274
+ type index$4_ForgetPreimageError = ForgetPreimageError;
19275
+ declare const index$4_ForgetPreimageError: typeof ForgetPreimageError;
19276
+ declare const index$4_HostCallResult: typeof HostCallResult;
19277
+ type index$4_InsufficientFundsError = InsufficientFundsError;
19278
+ declare const index$4_MAX_U32: typeof MAX_U32;
19279
+ declare const index$4_MAX_U32_BIG_INT: typeof MAX_U32_BIG_INT;
19280
+ type index$4_MachineId = MachineId;
19281
+ type index$4_MachineInstance = MachineInstance;
19282
+ declare const index$4_MachineInstance: typeof MachineInstance;
19283
+ type index$4_MachineResult = MachineResult;
19284
+ type index$4_MachineStatus = MachineStatus;
19285
+ type index$4_MemoryOperation = MemoryOperation;
19286
+ declare const index$4_MemoryOperation: typeof MemoryOperation;
19287
+ type index$4_NewServiceError = NewServiceError;
19288
+ declare const index$4_NewServiceError: typeof NewServiceError;
19289
+ type index$4_NoMachineError = NoMachineError;
19290
+ type index$4_PagesError = PagesError;
19291
+ declare const index$4_PagesError: typeof PagesError;
19292
+ type index$4_PartialState = PartialState;
19293
+ type index$4_PartiallyUpdatedState<T extends StateSlice = StateSlice> = PartiallyUpdatedState<T>;
19294
+ declare const index$4_PartiallyUpdatedState: typeof PartiallyUpdatedState;
19295
+ type index$4_PeekPokeError = PeekPokeError;
19296
+ declare const index$4_PeekPokeError: typeof PeekPokeError;
19297
+ type index$4_PendingTransfer = PendingTransfer;
19298
+ declare const index$4_PendingTransfer: typeof PendingTransfer;
19299
+ type index$4_PreimageStatus = PreimageStatus;
19300
+ type index$4_PreimageStatusKind = PreimageStatusKind;
19301
+ declare const index$4_PreimageStatusKind: typeof PreimageStatusKind;
19302
+ type index$4_ProgramCounter = ProgramCounter;
19303
+ type index$4_ProvidePreimageError = ProvidePreimageError;
19304
+ declare const index$4_ProvidePreimageError: typeof ProvidePreimageError;
19305
+ type index$4_RefineExternalities = RefineExternalities;
19306
+ type index$4_RequestPreimageError = RequestPreimageError;
19307
+ declare const index$4_RequestPreimageError: typeof RequestPreimageError;
19308
+ declare const index$4_SERVICE_ID_BYTES: typeof SERVICE_ID_BYTES;
19309
+ type index$4_SegmentExportError = SegmentExportError;
19310
+ type index$4_ServiceStateUpdate = ServiceStateUpdate;
19311
+ type index$4_StateSlice = StateSlice;
19312
+ type index$4_TRANSFER_MEMO_BYTES = TRANSFER_MEMO_BYTES;
19313
+ type index$4_TransferError = TransferError;
19314
+ declare const index$4_TransferError: typeof TransferError;
19315
+ type index$4_UnprivilegedError = UnprivilegedError;
19316
+ type index$4_UpdatePrivilegesError = UpdatePrivilegesError;
19317
+ declare const index$4_UpdatePrivilegesError: typeof UpdatePrivilegesError;
19318
+ type index$4_ZeroVoidError = ZeroVoidError;
19319
+ declare const index$4_ZeroVoidError: typeof ZeroVoidError;
19320
+ declare const index$4_clampU64ToU32: typeof clampU64ToU32;
19321
+ declare const index$4_deepCloneMapWithArray: typeof deepCloneMapWithArray;
19322
+ declare const index$4_emptyRegistersBuffer: typeof emptyRegistersBuffer;
19323
+ declare const index$4_getServiceId: typeof getServiceId;
19324
+ declare const index$4_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
19325
+ declare const index$4_preimageLenAsU32: typeof preimageLenAsU32;
19326
+ declare const index$4_slotsToPreimageStatus: typeof slotsToPreimageStatus;
19327
+ declare const index$4_toMemoryOperation: typeof toMemoryOperation;
19328
+ declare const index$4_tryAsMachineId: typeof tryAsMachineId;
19329
+ declare const index$4_tryAsProgramCounter: typeof tryAsProgramCounter;
19330
+ declare const index$4_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
19236
19331
  declare namespace index$4 {
19237
- export {
19238
- index$4_Program as Program,
19239
- index$4_extractCodeAndMetadata as extractCodeAndMetadata,
19240
- };
19332
+ export { index$4_AccumulationStateUpdate as AccumulationStateUpdate, index$4_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$4_EjectError as EjectError, index$4_ForgetPreimageError as ForgetPreimageError, index$4_HostCallResult as HostCallResult, index$4_MAX_U32 as MAX_U32, index$4_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$4_MachineInstance as MachineInstance, index$4_MemoryOperation as MemoryOperation, index$4_NewServiceError as NewServiceError, index$4_PagesError as PagesError, index$4_PartiallyUpdatedState as PartiallyUpdatedState, index$4_PeekPokeError as PeekPokeError, index$4_PendingTransfer as PendingTransfer, index$4_PreimageStatusKind as PreimageStatusKind, index$4_ProvidePreimageError as ProvidePreimageError, index$4_RequestPreimageError as RequestPreimageError, index$4_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$4_TransferError as TransferError, index$4_UpdatePrivilegesError as UpdatePrivilegesError, index$4_ZeroVoidError as ZeroVoidError, index$4_clampU64ToU32 as clampU64ToU32, index$4_deepCloneMapWithArray as deepCloneMapWithArray, index$4_emptyRegistersBuffer as emptyRegistersBuffer, index$4_getServiceId as getServiceId, index$4_getServiceIdOrCurrent as getServiceIdOrCurrent, index$4_preimageLenAsU32 as preimageLenAsU32, index$4_slotsToPreimageStatus as slotsToPreimageStatus, index$4_toMemoryOperation as toMemoryOperation, index$4_tryAsMachineId as tryAsMachineId, index$4_tryAsProgramCounter as tryAsProgramCounter, index$4_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
19333
+ export type { index$4_InsufficientFundsError as InsufficientFundsError, index$4_MachineId as MachineId, index$4_MachineResult as MachineResult, index$4_MachineStatus as MachineStatus, index$4_NoMachineError as NoMachineError, index$4_PartialState as PartialState, index$4_PreimageStatus as PreimageStatus, index$4_ProgramCounter as ProgramCounter, index$4_RefineExternalities as RefineExternalities, index$4_SegmentExportError as SegmentExportError, index$4_ServiceStateUpdate as ServiceStateUpdate, index$4_StateSlice as StateSlice, index$4_TRANSFER_MEMO_BYTES as TRANSFER_MEMO_BYTES, index$4_UnprivilegedError as UnprivilegedError };
19241
19334
  }
19242
19335
 
19243
19336
  declare class DebuggerAdapter {
@@ -19253,11 +19346,11 @@ declare class DebuggerAdapter {
19253
19346
  }
19254
19347
 
19255
19348
  resetGeneric(rawProgram: Uint8Array, flatRegisters: Uint8Array, initialGas: bigint) {
19256
- this.pvm.reset(rawProgram, 0, tryAsGas(initialGas), new Registers(flatRegisters));
19349
+ this.pvm.resetGeneric(rawProgram, 0, tryAsGas(initialGas), new Registers(flatRegisters));
19257
19350
  }
19258
19351
 
19259
19352
  reset(rawProgram: Uint8Array, pc: number, gas: bigint, maybeRegisters?: Registers, maybeMemory?: Memory) {
19260
- this.pvm.reset(rawProgram, pc, tryAsGas(gas), maybeRegisters, maybeMemory);
19353
+ this.pvm.resetGeneric(rawProgram, pc, tryAsGas(gas), maybeRegisters, maybeMemory);
19261
19354
  }
19262
19355
 
19263
19356
  getPageDump(pageNumber: number): null | Uint8Array {
@@ -19280,7 +19373,7 @@ declare class DebuggerAdapter {
19280
19373
  }
19281
19374
 
19282
19375
  setMemory(address: number, value: Uint8Array) {
19283
- this.pvm.getMemory().storeFrom(tryAsMemoryIndex(address), value);
19376
+ this.pvm.memory.storeFrom(tryAsMemoryIndex(address), value);
19284
19377
  }
19285
19378
 
19286
19379
  getExitArg(): number {
@@ -19307,11 +19400,11 @@ declare class DebuggerAdapter {
19307
19400
  }
19308
19401
 
19309
19402
  getRegisters(): BigUint64Array {
19310
- return this.pvm.getRegisters().getAllU64();
19403
+ return this.pvm.registers.getAllU64();
19311
19404
  }
19312
19405
 
19313
19406
  setRegisters(registers: Uint8Array) {
19314
- this.pvm.getRegisters().copyFrom(new Registers(registers));
19407
+ this.pvm.registers.copyFrom(new Registers(registers));
19315
19408
  }
19316
19409
 
19317
19410
  getProgramCounter(): number {
@@ -19323,11 +19416,11 @@ declare class DebuggerAdapter {
19323
19416
  }
19324
19417
 
19325
19418
  getGasLeft(): bigint {
19326
- return BigInt(this.pvm.getGas());
19419
+ return BigInt(this.pvm.gas.get());
19327
19420
  }
19328
19421
 
19329
19422
  setGasLeft(gas: bigint) {
19330
- this.pvm.getGasCounter().set(tryAsGas(gas));
19423
+ this.pvm.gas.set(tryAsGas(gas));
19331
19424
  }
19332
19425
  }
19333
19426
 
@@ -19354,8 +19447,6 @@ declare const index$3_HostCallMemory: typeof HostCallMemory;
19354
19447
  type index$3_HostCallRegisters = HostCallRegisters;
19355
19448
  declare const index$3_HostCallRegisters: typeof HostCallRegisters;
19356
19449
  declare const index$3_HostCallResult: typeof HostCallResult;
19357
- type index$3_IHostCallMemory = IHostCallMemory;
19358
- type index$3_IHostCallRegisters = IHostCallRegisters;
19359
19450
  type index$3_ImmediateDecoder = ImmediateDecoder;
19360
19451
  declare const index$3_ImmediateDecoder: typeof ImmediateDecoder;
19361
19452
  type index$3_InsufficientFundsError = InsufficientFundsError;
@@ -19438,6 +19529,7 @@ declare const index$3_clampU64ToU32: typeof clampU64ToU32;
19438
19529
  declare const index$3_createResults: typeof createResults;
19439
19530
  declare const index$3_decodeStandardProgram: typeof decodeStandardProgram;
19440
19531
  declare const index$3_deepCloneMapWithArray: typeof deepCloneMapWithArray;
19532
+ declare const index$3_emptyRegistersBuffer: typeof emptyRegistersBuffer;
19441
19533
  declare const index$3_extractCodeAndMetadata: typeof extractCodeAndMetadata;
19442
19534
  declare const index$3_getServiceId: typeof getServiceId;
19443
19535
  declare const index$3_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
@@ -19456,8 +19548,8 @@ declare const index$3_tryAsMachineId: typeof tryAsMachineId;
19456
19548
  declare const index$3_tryAsProgramCounter: typeof tryAsProgramCounter;
19457
19549
  declare const index$3_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
19458
19550
  declare namespace index$3 {
19459
- export { index$3_AccumulationStateUpdate as AccumulationStateUpdate, index$3_ArgsDecoder as ArgsDecoder, index$3_ArgumentType as ArgumentType, index$3_BasicBlocks as BasicBlocks, index$3_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$3_EjectError as EjectError, index$3_ExtendedWitdthImmediateDecoder as ExtendedWitdthImmediateDecoder, index$3_ForgetPreimageError as ForgetPreimageError, index$3_HostCallMemory as HostCallMemory, index$3_HostCallRegisters as HostCallRegisters, index$3_HostCallResult as HostCallResult, index$3_ImmediateDecoder as ImmediateDecoder, index$3_MAX_U32 as MAX_U32, index$3_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$3_MachineInstance as MachineInstance, index$3_Mask as Mask, index$3_MemoryOperation as MemoryOperation, index$3_MemorySegment as MemorySegment, NO_OF_REGISTERS$1 as NO_OF_REGISTERS, index$3_NewServiceError as NewServiceError, index$3_NibblesDecoder as NibblesDecoder, index$3_PagesError as PagesError, index$3_PartiallyUpdatedState as PartiallyUpdatedState, index$3_PeekPokeError as PeekPokeError, index$3_PendingTransfer as PendingTransfer, index$3_PreimageStatusKind as PreimageStatusKind, index$3_Program as Program, index$3_ProgramDecoder as ProgramDecoder, index$3_ProvidePreimageError as ProvidePreimageError, DebuggerAdapter as Pvm, index$3_Registers as Registers, index$3_RequestPreimageError as RequestPreimageError, Result$2 as Result, index$3_RichTaggedError as RichTaggedError, index$3_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$3_SpiMemory as SpiMemory, index$3_SpiProgram as SpiProgram, index$3_TransferError as TransferError, index$3_UpdatePrivilegesError as UpdatePrivilegesError, index$3_WithDebug as WithDebug, index$3_ZeroVoidError as ZeroVoidError, index$3___OPAQUE_TYPE__ as __OPAQUE_TYPE__, index$3_asOpaqueType as asOpaqueType, index$3_assertEmpty as assertEmpty, index$3_assertNever as assertNever, index$l as block, index$s as bytes, index$3_check as check, index$3_clampU64ToU32 as clampU64ToU32, index$3_createResults as createResults, index$3_decodeStandardProgram as decodeStandardProgram, index$3_deepCloneMapWithArray as deepCloneMapWithArray, index$3_extractCodeAndMetadata as extractCodeAndMetadata, index$3_getServiceId as getServiceId, index$3_getServiceIdOrCurrent as getServiceIdOrCurrent, index$p as hash, index$3_inspect as inspect, index$3_instructionArgumentTypeMap as instructionArgumentTypeMap, index$8 as interpreter, index$3_isBrowser as isBrowser, index$3_isTaggedError as isTaggedError, index$3_maybeTaggedErrorToString as maybeTaggedErrorToString, index$3_measure as measure, index$r as numbers, index$3_preimageLenAsU32 as preimageLenAsU32, index$3_resultToString as resultToString, index$3_seeThrough as seeThrough, index$3_slotsToPreimageStatus as slotsToPreimageStatus, index$3_toMemoryOperation as toMemoryOperation, index$3_tryAsMachineId as tryAsMachineId, index$3_tryAsProgramCounter as tryAsProgramCounter, index$3_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
19460
- export type { index$3_Args as Args, index$3_EnumMapping as EnumMapping, index$3_ErrorResult as ErrorResult, index$3_IHostCallMemory as IHostCallMemory, index$3_IHostCallRegisters as IHostCallRegisters, index$3_InsufficientFundsError as InsufficientFundsError, index$3_MachineId as MachineId, index$3_MachineResult as MachineResult, index$3_MachineStatus as MachineStatus, index$3_NoMachineError as NoMachineError, index$3_OK as OK, index$3_OkResult as OkResult, index$3_Opaque as Opaque, index$3_PartialState as PartialState, index$3_PreimageStatus as PreimageStatus, index$3_ProgramCounter as ProgramCounter, index$3_RefineExternalities as RefineExternalities, index$3_SegmentExportError as SegmentExportError, index$3_ServiceStateUpdate as ServiceStateUpdate, index$3_StateSlice as StateSlice, index$3_StringLiteral as StringLiteral, index$3_TRANSFER_MEMO_BYTES as TRANSFER_MEMO_BYTES, index$3_TaggedError as TaggedError, index$3_TokenOf as TokenOf, index$3_Uninstantiable as Uninstantiable, index$3_UnprivilegedError as UnprivilegedError, index$3_WithOpaque as WithOpaque };
19551
+ export { index$3_AccumulationStateUpdate as AccumulationStateUpdate, index$3_ArgsDecoder as ArgsDecoder, index$3_ArgumentType as ArgumentType, index$3_BasicBlocks as BasicBlocks, index$3_CURRENT_SERVICE_ID as CURRENT_SERVICE_ID, index$3_EjectError as EjectError, index$3_ExtendedWitdthImmediateDecoder as ExtendedWitdthImmediateDecoder, index$3_ForgetPreimageError as ForgetPreimageError, index$3_HostCallMemory as HostCallMemory, index$3_HostCallRegisters as HostCallRegisters, index$3_HostCallResult as HostCallResult, index$3_ImmediateDecoder as ImmediateDecoder, index$3_MAX_U32 as MAX_U32, index$3_MAX_U32_BIG_INT as MAX_U32_BIG_INT, index$3_MachineInstance as MachineInstance, index$3_Mask as Mask, index$3_MemoryOperation as MemoryOperation, index$3_MemorySegment as MemorySegment, NO_OF_REGISTERS$1 as NO_OF_REGISTERS, index$3_NewServiceError as NewServiceError, index$3_NibblesDecoder as NibblesDecoder, index$3_PagesError as PagesError, index$3_PartiallyUpdatedState as PartiallyUpdatedState, index$3_PeekPokeError as PeekPokeError, index$3_PendingTransfer as PendingTransfer, index$3_PreimageStatusKind as PreimageStatusKind, index$3_Program as Program, index$3_ProgramDecoder as ProgramDecoder, index$3_ProvidePreimageError as ProvidePreimageError, DebuggerAdapter as Pvm, index$3_Registers as Registers, index$3_RequestPreimageError as RequestPreimageError, Result$2 as Result, index$3_RichTaggedError as RichTaggedError, index$3_SERVICE_ID_BYTES as SERVICE_ID_BYTES, index$3_SpiMemory as SpiMemory, index$3_SpiProgram as SpiProgram, index$3_TransferError as TransferError, index$3_UpdatePrivilegesError as UpdatePrivilegesError, index$3_WithDebug as WithDebug, index$3_ZeroVoidError as ZeroVoidError, index$3___OPAQUE_TYPE__ as __OPAQUE_TYPE__, index$3_asOpaqueType as asOpaqueType, index$3_assertEmpty as assertEmpty, index$3_assertNever as assertNever, index$l as block, index$s as bytes, index$3_check as check, index$3_clampU64ToU32 as clampU64ToU32, index$3_createResults as createResults, index$3_decodeStandardProgram as decodeStandardProgram, index$3_deepCloneMapWithArray as deepCloneMapWithArray, index$3_emptyRegistersBuffer as emptyRegistersBuffer, index$3_extractCodeAndMetadata as extractCodeAndMetadata, index$3_getServiceId as getServiceId, index$3_getServiceIdOrCurrent as getServiceIdOrCurrent, index$p as hash, index$3_inspect as inspect, index$3_instructionArgumentTypeMap as instructionArgumentTypeMap, index$6 as interpreter, index$3_isBrowser as isBrowser, index$3_isTaggedError as isTaggedError, index$3_maybeTaggedErrorToString as maybeTaggedErrorToString, index$3_measure as measure, index$r as numbers, index$3_preimageLenAsU32 as preimageLenAsU32, index$3_resultToString as resultToString, index$3_seeThrough as seeThrough, index$3_slotsToPreimageStatus as slotsToPreimageStatus, index$3_toMemoryOperation as toMemoryOperation, index$3_tryAsMachineId as tryAsMachineId, index$3_tryAsProgramCounter as tryAsProgramCounter, index$3_writeServiceIdAsLeBytes as writeServiceIdAsLeBytes };
19552
+ export type { index$3_Args as Args, index$3_EnumMapping as EnumMapping, index$3_ErrorResult as ErrorResult, index$3_InsufficientFundsError as InsufficientFundsError, index$3_MachineId as MachineId, index$3_MachineResult as MachineResult, index$3_MachineStatus as MachineStatus, index$3_NoMachineError as NoMachineError, index$3_OK as OK, index$3_OkResult as OkResult, index$3_Opaque as Opaque, index$3_PartialState as PartialState, index$3_PreimageStatus as PreimageStatus, index$3_ProgramCounter as ProgramCounter, index$3_RefineExternalities as RefineExternalities, index$3_SegmentExportError as SegmentExportError, index$3_ServiceStateUpdate as ServiceStateUpdate, index$3_StateSlice as StateSlice, index$3_StringLiteral as StringLiteral, index$3_TRANSFER_MEMO_BYTES as TRANSFER_MEMO_BYTES, index$3_TaggedError as TaggedError, index$3_TokenOf as TokenOf, index$3_Uninstantiable as Uninstantiable, index$3_UnprivilegedError as UnprivilegedError, index$3_WithOpaque as WithOpaque };
19461
19553
  }
19462
19554
 
19463
19555
  declare const ENTROPY_BYTES = 32;
@@ -20349,4 +20441,4 @@ declare namespace index {
20349
20441
  export type { index_PreimagesInput as PreimagesInput, index_PreimagesState as PreimagesState, index_PreimagesStateUpdate as PreimagesStateUpdate };
20350
20442
  }
20351
20443
 
20352
- export { index$l as block, index$j as block_json, index$s as bytes, index$q as codec, index$o as collections, index$m as config, index$h as config_node, index$n as crypto, index$c as database, index$b as erasure_coding, index$9 as fuzz_proto, index$p as hash, index$6 as jam_host_calls, index$k as json_parser, index$i as logger, index$f as mmr, index$r as numbers, index$t as ordering, index$3 as pvm, index$7 as pvm_host_calls, index$8 as pvm_interpreter, index$4 as pvm_program, index$5 as pvm_spi_decoder, index$2 as shuffling, index$e as state, index$1 as state_json, index$d as state_merkleization, index as transition, index$g as trie, index$u as utils };
20444
+ export { index$l as block, index$j as block_json, index$s as bytes, index$q as codec, index$o as collections, index$m as config, index$h as config_node, index$n as crypto, index$c as database, index$b as erasure_coding, index$9 as fuzz_proto, index$p as hash, index$4 as jam_host_calls, index$k as json_parser, index$i as logger, index$f as mmr, index$r as numbers, index$t as ordering, index$3 as pvm, index$5 as pvm_host_calls, index$6 as pvm_interpreter, index$7 as pvm_program, index$8 as pvm_spi_decoder, index$2 as shuffling, index$e as state, index$1 as state_json, index$d as state_merkleization, index as transition, index$g as trie, index$u as utils };