@typeberry/lib 0.2.0-0a3dfd4 → 0.2.0-5746fdc

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 +2662 -2134
  2. package/index.d.ts +2124 -1884
  3. package/index.js +2660 -2132
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -1467,8 +1467,8 @@ declare class Decoder {
1467
1467
  /**
1468
1468
  * Create a new [`Decoder`] instance given a raw array of bytes as a source.
1469
1469
  */
1470
- static fromBlob(source: Uint8Array) {
1471
- return new Decoder(source);
1470
+ static fromBlob(source: Uint8Array, context?: unknown) {
1471
+ return new Decoder(source, undefined, context);
1472
1472
  }
1473
1473
 
1474
1474
  /**
@@ -1818,7 +1818,7 @@ declare class Decoder {
1818
1818
  private ensureHasBytes(bytes: number) {
1819
1819
  check`${bytes >= 0} Negative number of bytes given.`;
1820
1820
  if (this.offset + bytes > this.source.length) {
1821
- throw new Error(
1821
+ throw new EndOfDataError(
1822
1822
  `Attempting to decode more data than there is left. Need ${bytes}, left: ${this.source.length - this.offset}.`,
1823
1823
  );
1824
1824
  }
@@ -1837,6 +1837,8 @@ declare function decodeVariableLengthExtraBytes(firstByte: number) {
1837
1837
  return 0;
1838
1838
  }
1839
1839
 
1840
+ declare class EndOfDataError extends Error {}
1841
+
1840
1842
  /** Hint for how big the encoded object will be. */
1841
1843
  type SizeHint = {
1842
1844
  /** Number of bytes in the encoding. */
@@ -2879,6 +2881,15 @@ declare namespace codec$1 {
2879
2881
  };
2880
2882
  })();
2881
2883
 
2884
+ /** Zero-size `void` value. */
2885
+ export const nothing = Descriptor.new<void>(
2886
+ "void",
2887
+ { bytes: 0, isExact: true },
2888
+ (_e, _v) => {},
2889
+ (_d) => {},
2890
+ (_s) => {},
2891
+ );
2892
+
2882
2893
  /** Variable-length U32. */
2883
2894
  export const varU32 = Descriptor.new<U32>(
2884
2895
  "var_u32",
@@ -3346,6 +3357,9 @@ declare function forEachDescriptor<T>(
3346
3357
  try {
3347
3358
  f(k, descriptors[k]);
3348
3359
  } catch (e) {
3360
+ if (e instanceof EndOfDataError) {
3361
+ throw new EndOfDataError(`${key}: ${e}`);
3362
+ }
3349
3363
  throw new Error(`${key}: ${e}`);
3350
3364
  }
3351
3365
  }
@@ -3469,6 +3483,8 @@ type index$q_DescriptorRecord<T> = DescriptorRecord<T>;
3469
3483
  type index$q_Encode<T> = Encode<T>;
3470
3484
  type index$q_Encoder = Encoder;
3471
3485
  declare const index$q_Encoder: typeof Encoder;
3486
+ type index$q_EndOfDataError = EndOfDataError;
3487
+ declare const index$q_EndOfDataError: typeof EndOfDataError;
3472
3488
  type index$q_LengthRange = LengthRange;
3473
3489
  declare const index$q_MASKS: typeof MASKS;
3474
3490
  declare const index$q_MAX_LENGTH: typeof MAX_LENGTH;
@@ -3497,7 +3513,7 @@ declare const index$q_sequenceViewVarLen: typeof sequenceViewVarLen;
3497
3513
  declare const index$q_tryAsExactBytes: typeof tryAsExactBytes;
3498
3514
  declare const index$q_validateLength: typeof validateLength;
3499
3515
  declare namespace index$q {
3500
- export { index$q_DEFAULT_START_LENGTH as DEFAULT_START_LENGTH, index$q_Decoder as Decoder, index$q_Descriptor as Descriptor, index$q_Encoder as Encoder, index$q_MASKS as MASKS, index$q_MAX_LENGTH as MAX_LENGTH, index$q_ObjectView as ObjectView, index$q_SequenceView as SequenceView, index$q_TYPICAL_DICTIONARY_LENGTH as TYPICAL_DICTIONARY_LENGTH, index$q_TYPICAL_SEQUENCE_LENGTH as TYPICAL_SEQUENCE_LENGTH, index$q_ViewField as ViewField, index$q_addSizeHints as addSizeHints, codec$1 as codec, index$q_decodeVariableLengthExtraBytes as decodeVariableLengthExtraBytes, index$q_exactHint as exactHint, index$q_forEachDescriptor as forEachDescriptor, index$q_hasUniqueView as hasUniqueView, index$q_objectView as objectView, index$q_readonlyArray as readonlyArray, index$q_sequenceViewFixLen as sequenceViewFixLen, index$q_sequenceViewVarLen as sequenceViewVarLen, index$q_tryAsExactBytes as tryAsExactBytes, index$q_validateLength as validateLength };
3516
+ export { index$q_DEFAULT_START_LENGTH as DEFAULT_START_LENGTH, index$q_Decoder as Decoder, index$q_Descriptor as Descriptor, index$q_Encoder as Encoder, index$q_EndOfDataError as EndOfDataError, index$q_MASKS as MASKS, index$q_MAX_LENGTH as MAX_LENGTH, index$q_ObjectView as ObjectView, index$q_SequenceView as SequenceView, index$q_TYPICAL_DICTIONARY_LENGTH as TYPICAL_DICTIONARY_LENGTH, index$q_TYPICAL_SEQUENCE_LENGTH as TYPICAL_SEQUENCE_LENGTH, index$q_ViewField as ViewField, index$q_addSizeHints as addSizeHints, codec$1 as codec, index$q_decodeVariableLengthExtraBytes as decodeVariableLengthExtraBytes, index$q_exactHint as exactHint, index$q_forEachDescriptor as forEachDescriptor, index$q_hasUniqueView as hasUniqueView, index$q_objectView as objectView, index$q_readonlyArray as readonlyArray, index$q_sequenceViewFixLen as sequenceViewFixLen, index$q_sequenceViewVarLen as sequenceViewVarLen, index$q_tryAsExactBytes as tryAsExactBytes, index$q_validateLength as validateLength };
3501
3517
  export type { index$q_ClassConstructor as ClassConstructor, index$q_Codec as Codec, index$q_CodecRecord as CodecRecord, index$q_CodecWithView as CodecWithView, index$q_Decode as Decode, index$q_DescribedBy as DescribedBy, index$q_DescriptorRecord as DescriptorRecord, index$q_Encode as Encode, index$q_LengthRange as LengthRange, index$q_OptionalRecord as OptionalRecord, Options$1 as Options, index$q_PropertyKeys as PropertyKeys, index$q_SimpleDescriptorRecord as SimpleDescriptorRecord, index$q_SizeHint as SizeHint, index$q_ViewOf as ViewOf };
3502
3518
  }
3503
3519
 
@@ -4263,7 +4279,7 @@ declare class SortedArray<V> implements ImmutableSortedArray<V> {
4263
4279
  };
4264
4280
  }
4265
4281
 
4266
- /** Create a new SortedSet from two sorted collections. */
4282
+ /** Create a new SortedArray from two sorted collections. */
4267
4283
  static fromTwoSortedCollections<V>(first: ImmutableSortedArray<V>, second: ImmutableSortedArray<V>) {
4268
4284
  check`${first.comparator === second.comparator} Cannot merge arrays if they do not use the same comparator`;
4269
4285
  const comparator = first.comparator;
@@ -5070,29 +5086,6 @@ declare const fullChainSpec = new ChainSpec({
5070
5086
  maxLookupAnchorAge: tryAsU32(14_400),
5071
5087
  });
5072
5088
 
5073
- /**
5074
- * Configuration object for typeberry workers.
5075
- */
5076
- declare class WorkerConfig {
5077
- /**
5078
- * Since we loose prototypes when transferring the context,
5079
- * this function is re-initializing proper types.
5080
- *
5081
- * TODO [ToDr] instead of doing this hack, we might prefer to pass data
5082
- * between workers using JAM codec maybe?
5083
- */
5084
- static reInit(config: unknown) {
5085
- const { chainSpec, dbPath, omitSealVerification } = config as WorkerConfig;
5086
- return new WorkerConfig(new ChainSpec(chainSpec), dbPath, omitSealVerification);
5087
- }
5088
-
5089
- constructor(
5090
- public readonly chainSpec: ChainSpec,
5091
- public readonly dbPath: string,
5092
- public readonly omitSealVerification: boolean = false,
5093
- ) {}
5094
- }
5095
-
5096
5089
  /** Peer id. */
5097
5090
  type PeerId = Opaque<string, "peerId">;
5098
5091
 
@@ -5124,6 +5117,17 @@ declare class Bootnode implements PeerAddress {
5124
5117
  }
5125
5118
  }
5126
5119
 
5120
+ /** Implemented PVM Backends names in THE SAME ORDER as enum. */
5121
+ declare const PvmBackendNames = ["built-in", "ananas"];
5122
+
5123
+ /** Implemented PVM Backends to choose from. */
5124
+ declare enum PvmBackend {
5125
+ /** Built-in aka. Typeberry 🫐 interpreter. */
5126
+ BuiltIn = 0,
5127
+ /** Ananas 🍍 interpreter. */
5128
+ Ananas = 1,
5129
+ }
5130
+
5127
5131
  type index$m_Bootnode = Bootnode;
5128
5132
  declare const index$m_Bootnode: typeof Bootnode;
5129
5133
  type index$m_ChainSpec = ChainSpec;
@@ -5135,12 +5139,13 @@ declare const index$m_EST_VALIDATORS: typeof EST_VALIDATORS;
5135
5139
  declare const index$m_EST_VALIDATORS_SUPER_MAJORITY: typeof EST_VALIDATORS_SUPER_MAJORITY;
5136
5140
  type index$m_PeerAddress = PeerAddress;
5137
5141
  type index$m_PeerId = PeerId;
5138
- type index$m_WorkerConfig = WorkerConfig;
5139
- declare const index$m_WorkerConfig: typeof WorkerConfig;
5142
+ type index$m_PvmBackend = PvmBackend;
5143
+ declare const index$m_PvmBackend: typeof PvmBackend;
5144
+ declare const index$m_PvmBackendNames: typeof PvmBackendNames;
5140
5145
  declare const index$m_fullChainSpec: typeof fullChainSpec;
5141
5146
  declare const index$m_tinyChainSpec: typeof tinyChainSpec;
5142
5147
  declare namespace index$m {
5143
- 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_WorkerConfig as WorkerConfig, index$m_fullChainSpec as fullChainSpec, index$m_tinyChainSpec as tinyChainSpec };
5148
+ 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 };
5144
5149
  export type { index$m_PeerAddress as PeerAddress, index$m_PeerId as PeerId };
5145
5150
  }
5146
5151
 
@@ -8164,6 +8169,7 @@ declare const DEFAULT_CONFIG = "default";
8164
8169
  declare const NODE_DEFAULTS = {
8165
8170
  name: isBrowser() ? "browser" : os.hostname(),
8166
8171
  config: DEFAULT_CONFIG,
8172
+ pvm: PvmBackend.BuiltIn,
8167
8173
  };
8168
8174
 
8169
8175
  /** Chain spec chooser. */
@@ -8192,7 +8198,7 @@ declare class NodeConfiguration {
8192
8198
  version: "number",
8193
8199
  flavor: knownChainSpecFromJson,
8194
8200
  chain_spec: JipChainSpec.fromJson,
8195
- database_base_path: "string",
8201
+ database_base_path: json.optional("string"),
8196
8202
  authorship: AuthorshipOptions.fromJson,
8197
8203
  },
8198
8204
  NodeConfiguration.new,
@@ -8202,7 +8208,7 @@ declare class NodeConfiguration {
8202
8208
  if (version !== 1) {
8203
8209
  throw new Error("Only version=1 config is supported.");
8204
8210
  }
8205
- return new NodeConfiguration($schema, version, flavor, chain_spec, database_base_path, authorship);
8211
+ return new NodeConfiguration($schema, version, flavor, chain_spec, database_base_path ?? undefined, authorship);
8206
8212
  }
8207
8213
 
8208
8214
  private constructor(
@@ -8210,7 +8216,8 @@ declare class NodeConfiguration {
8210
8216
  public readonly version: number,
8211
8217
  public readonly flavor: KnownChainSpec,
8212
8218
  public readonly chainSpec: JipChainSpec,
8213
- public readonly databaseBasePath: string,
8219
+ /** If database path is not provided, we load an in-memory db. */
8220
+ public readonly databaseBasePath: string | undefined,
8214
8221
  public readonly authorship: AuthorshipOptions,
8215
8222
  ) {}
8216
8223
  }
@@ -8285,6 +8292,8 @@ interface BlocksDb {
8285
8292
  * NOTE: this is not extrinsic hash!
8286
8293
  */
8287
8294
  getExtrinsic(hash: HeaderHash): ExtrinsicView | null;
8295
+ /** Close the database and free resources. */
8296
+ close(): Promise<void>;
8288
8297
  }
8289
8298
 
8290
8299
  /** In-memory (non-persistent) blocks database. */
@@ -8343,6 +8352,8 @@ declare class InMemoryBlocks implements BlocksDb {
8343
8352
  getExtrinsic(hash: HeaderHash): ExtrinsicView | null {
8344
8353
  return this.extrinsicsByHeaderHash.get(hash) ?? null;
8345
8354
  }
8355
+
8356
+ async close() {}
8346
8357
  }
8347
8358
 
8348
8359
  type StateKey$1 = Opaque<OpaqueHash, "trieStateKey">;
@@ -12251,6 +12262,18 @@ declare class StateEntries {
12251
12262
  return Object.fromEntries(this.entries);
12252
12263
  }
12253
12264
 
12265
+ /** Dump state entries to JSON string (format compatible with stf vectors). */
12266
+ toString() {
12267
+ return JSON.stringify(
12268
+ Array.from(this.entries.entries()).map(([key, value]) => ({
12269
+ key,
12270
+ value,
12271
+ })),
12272
+ null,
12273
+ 2,
12274
+ );
12275
+ }
12276
+
12254
12277
  [Symbol.iterator]() {
12255
12278
  return this.entries[Symbol.iterator]();
12256
12279
  }
@@ -12665,7 +12688,7 @@ interface ValuesDb {
12665
12688
  * Missing value is considered an irrecoverable error, so the implementations
12666
12689
  * are free to throw if that happens.
12667
12690
  */
12668
- get(key: Uint8Array): Uint8Array;
12691
+ get(key: ValueHash): Uint8Array;
12669
12692
  }
12670
12693
 
12671
12694
  /**
@@ -12698,15 +12721,20 @@ declare class LeafDb implements SerializedStateBackend {
12698
12721
  return Result.ok(new LeafDb(leaves, db));
12699
12722
  }
12700
12723
 
12724
+ /** Create leaf db from sorted set of leaves. */
12725
+ static fromLeaves(leaves: SortedSet<LeafNode>, db: ValuesDb): LeafDb {
12726
+ return new LeafDb(leaves, db);
12727
+ }
12728
+
12701
12729
  /** A mapping between an embedded value or db lookup key. */
12702
12730
  private readonly lookup: TruncatedHashDictionary<StateKey, Lookup>;
12703
12731
 
12704
12732
  private constructor(
12705
- public readonly leaves: SortedSet<LeafNode>,
12733
+ public readonly leafs: SortedSet<LeafNode>,
12706
12734
  public readonly db: ValuesDb,
12707
12735
  ) {
12708
12736
  this.lookup = TruncatedHashDictionary.fromEntries(
12709
- leaves.array.map((leaf) => {
12737
+ leafs.array.map((leaf) => {
12710
12738
  const key: StateKey = leaf.getKey().asOpaque();
12711
12739
  const value: Lookup = leaf.hasEmbeddedValue()
12712
12740
  ? {
@@ -12715,7 +12743,7 @@ declare class LeafDb implements SerializedStateBackend {
12715
12743
  }
12716
12744
  : {
12717
12745
  kind: LookupKind.DbKey,
12718
- key: leaf.getValueHash().raw,
12746
+ key: leaf.getValueHash(),
12719
12747
  };
12720
12748
  return [key, value];
12721
12749
  }),
@@ -12741,7 +12769,7 @@ declare class LeafDb implements SerializedStateBackend {
12741
12769
 
12742
12770
  getStateRoot(blake2b: Blake2b): StateRootHash {
12743
12771
  const blake2bTrieHasher = getBlake2bTrieHasher(blake2b);
12744
- return InMemoryTrie.computeStateRoot(blake2bTrieHasher, this.leaves).asOpaque();
12772
+ return InMemoryTrie.computeStateRoot(blake2bTrieHasher, this.leafs).asOpaque();
12745
12773
  }
12746
12774
 
12747
12775
  intoStateEntries(): StateEntries {
@@ -12775,9 +12803,42 @@ type Lookup =
12775
12803
  }
12776
12804
  | {
12777
12805
  kind: LookupKind.DbKey;
12778
- key: Uint8Array;
12806
+ key: ValueHash;
12779
12807
  };
12780
12808
 
12809
+ declare function updateLeafs(
12810
+ leafs: SortedSet<LeafNode>,
12811
+ blake2b: Blake2b,
12812
+ data: Iterable<[StateEntryUpdateAction, StateKey | TruncatedHash, BytesBlob]>,
12813
+ ): {
12814
+ values: [ValueHash, BytesBlob][];
12815
+ leafs: SortedSet<LeafNode>;
12816
+ } {
12817
+ const blake2bTrieHasher = getBlake2bTrieHasher(blake2b);
12818
+ // We will collect all values that don't fit directly into leaf nodes.
12819
+ const values: [ValueHash, BytesBlob][] = [];
12820
+ for (const [action, key, value] of data) {
12821
+ if (action === StateEntryUpdateAction.Insert) {
12822
+ const leafNode = InMemoryTrie.constructLeaf(blake2bTrieHasher, key.asOpaque(), value);
12823
+ leafs.replace(leafNode);
12824
+ if (!leafNode.hasEmbeddedValue()) {
12825
+ values.push([leafNode.getValueHash(), value]);
12826
+ }
12827
+ } else if (action === StateEntryUpdateAction.Remove) {
12828
+ const leafNode = InMemoryTrie.constructLeaf(blake2bTrieHasher, key.asOpaque(), BytesBlob.empty());
12829
+ leafs.removeOne(leafNode);
12830
+ // TODO [ToDr] Handle ref-counting values or updating some header-hash-based references.
12831
+ } else {
12832
+ assertNever(action);
12833
+ }
12834
+ }
12835
+
12836
+ return {
12837
+ values,
12838
+ leafs,
12839
+ };
12840
+ }
12841
+
12781
12842
  /** A potential error that occured during state update. */
12782
12843
  declare enum StateUpdateError {
12783
12844
  /** A conflicting state update has been provided. */
@@ -12785,6 +12846,13 @@ declare enum StateUpdateError {
12785
12846
  /** There was an error committing the changes. */
12786
12847
  Commit = 1,
12787
12848
  }
12849
+
12850
+ /** Interface to initialize states db. Typically used in conjunction with `StatesDb`. */
12851
+ interface InitStatesDb<T = State> {
12852
+ /** Insert a pre-defined initial state directly into the database. */
12853
+ insertInitialState(headerHash: HeaderHash, initialState: T): Promise<Result$2<OK, StateUpdateError>>;
12854
+ }
12855
+
12788
12856
  /**
12789
12857
  * Interface for accessing states stored in the database.
12790
12858
  *
@@ -12810,12 +12878,18 @@ interface StatesDb<T extends State = State> {
12810
12878
 
12811
12879
  /** Retrieve posterior state of given header. */
12812
12880
  getState(header: HeaderHash): T | null;
12881
+
12882
+ /** Close the database and free resources. */
12883
+ close(): Promise<void>;
12813
12884
  }
12814
12885
 
12815
12886
  declare class InMemoryStates implements StatesDb<InMemoryState> {
12816
- private readonly db: HashDictionary<HeaderHash, BytesBlob> = HashDictionary.new();
12887
+ private readonly db: HashDictionary<HeaderHash, InMemoryState> = HashDictionary.new();
12888
+ private readonly blake2b: Promise<Blake2b>;
12817
12889
 
12818
- constructor(private readonly spec: ChainSpec) {}
12890
+ constructor(private readonly spec: ChainSpec) {
12891
+ this.blake2b = Blake2b.createHasher();
12892
+ }
12819
12893
 
12820
12894
  async updateAndSetState(
12821
12895
  headerHash: HeaderHash,
@@ -12824,7 +12898,7 @@ declare class InMemoryStates implements StatesDb<InMemoryState> {
12824
12898
  ): Promise<Result$2<OK, StateUpdateError>> {
12825
12899
  const res = state.applyUpdate(update);
12826
12900
  if (res.isOk) {
12827
- return await this.insertState(headerHash, state);
12901
+ return await this.insertInitialState(headerHash, state);
12828
12902
  }
12829
12903
 
12830
12904
  switch (res.error) {
@@ -12838,32 +12912,126 @@ declare class InMemoryStates implements StatesDb<InMemoryState> {
12838
12912
  }
12839
12913
 
12840
12914
  async getStateRoot(state: InMemoryState): Promise<StateRootHash> {
12841
- const blake2b = await Blake2b.createHasher();
12915
+ const blake2b = await this.blake2b;
12842
12916
  return StateEntries.serializeInMemory(this.spec, blake2b, state).getRootHash(blake2b);
12843
12917
  }
12844
12918
 
12845
12919
  /** Insert a full state into the database. */
12846
- async insertState(headerHash: HeaderHash, state: InMemoryState): Promise<Result$2<OK, StateUpdateError>> {
12847
- const encoded = Encoder.encodeObject(inMemoryStateCodec(this.spec), state, this.spec);
12848
- this.db.set(headerHash, encoded);
12920
+ async insertInitialState(headerHash: HeaderHash, state: InMemoryState): Promise<Result$2<OK, StateUpdateError>> {
12921
+ const copy = InMemoryState.copyFrom(this.spec, state, state.intoServicesData());
12922
+ this.db.set(headerHash, copy);
12849
12923
  return Result.ok(OK);
12850
12924
  }
12851
12925
 
12852
12926
  getState(headerHash: HeaderHash): InMemoryState | null {
12853
- const encodedState = this.db.get(headerHash);
12854
- if (encodedState === undefined) {
12927
+ const state = this.db.get(headerHash);
12928
+ if (state === undefined) {
12855
12929
  return null;
12856
12930
  }
12857
12931
 
12858
- return Decoder.decodeObject(inMemoryStateCodec(this.spec), encodedState, this.spec);
12932
+ return InMemoryState.copyFrom(this.spec, state, state.intoServicesData());
12933
+ }
12934
+
12935
+ async close() {}
12936
+ }
12937
+
12938
+ /** Root database. */
12939
+ interface RootDb<TBlocks = BlocksDb, TStates = StatesDb> {
12940
+ /** Blocks DB. */
12941
+ getBlocksDb(): TBlocks;
12942
+
12943
+ /** States DB. */
12944
+ getStatesDb(): TStates;
12945
+
12946
+ /** Close access to the DB. */
12947
+ close(): Promise<void>;
12948
+ }
12949
+
12950
+ /** Abstract serialized-states db. */
12951
+ type SerializedStatesDb = StatesDb<SerializedState<LeafDb>> & InitStatesDb<StateEntries>;
12952
+
12953
+ /** In-memory serialized-states db. */
12954
+ declare class InMemorySerializedStates implements StatesDb<SerializedState<LeafDb>>, InitStatesDb<StateEntries> {
12955
+ private readonly db: HashDictionary<HeaderHash, SortedSet<LeafNode>> = HashDictionary.new();
12956
+ private readonly valuesDb: HashDictionary<ValueHash, BytesBlob> = HashDictionary.new();
12957
+
12958
+ constructor(
12959
+ private readonly spec: ChainSpec,
12960
+ private readonly blake2b: Blake2b,
12961
+ ) {}
12962
+
12963
+ async insertInitialState(headerHash: HeaderHash, entries: StateEntries): Promise<Result$2<OK, StateUpdateError>> {
12964
+ // convert state entries into leafdb
12965
+ const { values, leafs } = updateLeafs(
12966
+ SortedSet.fromArray(leafComparator, []),
12967
+ this.blake2b,
12968
+ Array.from(entries, (x) => [StateEntryUpdateAction.Insert, x[0], x[1]]),
12969
+ );
12970
+
12971
+ // insert values to the db.
12972
+ for (const val of values) {
12973
+ this.valuesDb.set(val[0], val[1]);
12974
+ }
12975
+
12976
+ this.db.set(headerHash, leafs);
12977
+ return Result.ok(OK);
12978
+ }
12979
+
12980
+ async getStateRoot(state: SerializedState<LeafDb>): Promise<StateRootHash> {
12981
+ return state.backend.getStateRoot(this.blake2b);
12982
+ }
12983
+
12984
+ async updateAndSetState(
12985
+ header: HeaderHash,
12986
+ state: SerializedState<LeafDb>,
12987
+ update: Partial<State & ServicesUpdate>,
12988
+ ): Promise<Result$2<OK, StateUpdateError>> {
12989
+ const blake2b = this.blake2b;
12990
+ const updatedValues = serializeStateUpdate(this.spec, blake2b, update);
12991
+ const { values, leafs } = updateLeafs(state.backend.leafs, blake2b, updatedValues);
12992
+
12993
+ // insert values to the db
12994
+ // valuesdb can be shared between all states because it's just
12995
+ // <valuehash> -> <value> mapping and existence is managed by trie leafs.
12996
+ for (const val of values) {
12997
+ this.valuesDb.set(val[0], val[1]);
12998
+ }
12999
+
13000
+ // make sure to clone the leafs before writing, since the collection is re-used.
13001
+ this.db.set(header, SortedSet.fromSortedArray(leafComparator, leafs.slice()));
13002
+
13003
+ return Result.ok(OK);
13004
+ }
13005
+
13006
+ getState(header: HeaderHash): SerializedState<LeafDb> | null {
13007
+ const leafs = this.db.get(header);
13008
+ if (leafs === undefined) {
13009
+ return null;
13010
+ }
13011
+ // now create a leafdb with shared values db.
13012
+ const leafDb = LeafDb.fromLeaves(leafs, {
13013
+ get: (key: ValueHash) => {
13014
+ const val = this.valuesDb.get(key);
13015
+ if (val === undefined) {
13016
+ throw new Error(`Missing value at key: ${key}`);
13017
+ }
13018
+ return val.raw;
13019
+ },
13020
+ });
13021
+ return SerializedState.new(this.spec, this.blake2b, leafDb);
12859
13022
  }
13023
+
13024
+ async close() {}
12860
13025
  }
12861
13026
 
12862
13027
  type index$c_BlocksDb = BlocksDb;
12863
13028
  type index$c_InMemoryBlocks = InMemoryBlocks;
12864
13029
  declare const index$c_InMemoryBlocks: typeof InMemoryBlocks;
13030
+ type index$c_InMemorySerializedStates = InMemorySerializedStates;
13031
+ declare const index$c_InMemorySerializedStates: typeof InMemorySerializedStates;
12865
13032
  type index$c_InMemoryStates = InMemoryStates;
12866
13033
  declare const index$c_InMemoryStates: typeof InMemoryStates;
13034
+ type index$c_InitStatesDb<T = State> = InitStatesDb<T>;
12867
13035
  type index$c_LeafDb = LeafDb;
12868
13036
  declare const index$c_LeafDb: typeof LeafDb;
12869
13037
  type index$c_LeafDbError = LeafDbError;
@@ -12871,13 +13039,16 @@ declare const index$c_LeafDbError: typeof LeafDbError;
12871
13039
  type index$c_Lookup = Lookup;
12872
13040
  type index$c_LookupKind = LookupKind;
12873
13041
  declare const index$c_LookupKind: typeof LookupKind;
13042
+ type index$c_RootDb<TBlocks = BlocksDb, TStates = StatesDb> = RootDb<TBlocks, TStates>;
13043
+ type index$c_SerializedStatesDb = SerializedStatesDb;
12874
13044
  type index$c_StateUpdateError = StateUpdateError;
12875
13045
  declare const index$c_StateUpdateError: typeof StateUpdateError;
12876
13046
  type index$c_StatesDb<T extends State = State> = StatesDb<T>;
12877
13047
  type index$c_ValuesDb = ValuesDb;
13048
+ declare const index$c_updateLeafs: typeof updateLeafs;
12878
13049
  declare namespace index$c {
12879
- export { index$c_InMemoryBlocks as InMemoryBlocks, index$c_InMemoryStates as InMemoryStates, index$c_LeafDb as LeafDb, index$c_LeafDbError as LeafDbError, index$c_LookupKind as LookupKind, index$c_StateUpdateError as StateUpdateError };
12880
- export type { index$c_BlocksDb as BlocksDb, index$c_Lookup as Lookup, index$c_StatesDb as StatesDb, index$c_ValuesDb as ValuesDb };
13050
+ export { index$c_InMemoryBlocks as InMemoryBlocks, index$c_InMemorySerializedStates as InMemorySerializedStates, index$c_InMemoryStates as InMemoryStates, index$c_LeafDb as LeafDb, index$c_LeafDbError as LeafDbError, index$c_LookupKind as LookupKind, index$c_StateUpdateError as StateUpdateError, index$c_updateLeafs as updateLeafs };
13051
+ export type { index$c_BlocksDb as BlocksDb, index$c_InitStatesDb as InitStatesDb, index$c_Lookup as Lookup, index$c_RootDb as RootDb, index$c_SerializedStatesDb as SerializedStatesDb, index$c_StatesDb as StatesDb, index$c_ValuesDb as ValuesDb };
12881
13052
  }
12882
13053
 
12883
13054
  /**
@@ -14178,48 +14349,133 @@ declare class PendingTransfer {
14178
14349
  }
14179
14350
  }
14180
14351
 
14181
- /** Gas measuring type. Can be either U64 or U32 for performance reasons. */
14182
- type Gas = BigGas | SmallGas;
14183
14352
  /** A U64 version of `Gas`. */
14184
14353
  type BigGas = Opaque<U64, "BigGas[U64]">;
14185
14354
  /** A U32 version of `Gas`. */
14186
14355
  type SmallGas = Opaque<U32, "SmallGas[U32]">;
14187
-
14188
- /** Attempt to convert given number into U32 gas representation. */
14189
- declare const tryAsSmallGas = (v: number): SmallGas => asOpaqueType(tryAsU32(v));
14190
-
14191
- /** Attempt to convert given number into U64 gas representation. */
14192
- declare const tryAsBigGas = (v: number | bigint): BigGas => asOpaqueType(tryAsU64(v));
14193
-
14194
- /** Attempt to convert given number into gas. */
14195
- declare const tryAsGas = (v: number | bigint): Gas =>
14196
- typeof v === "number" && v < 2 ** 32 ? tryAsSmallGas(v) : tryAsBigGas(v);
14197
-
14198
- /** Create a new gas counter instance depending on the gas value. */
14199
- declare function gasCounter(gas: Gas): GasCounter {
14200
- return new GasCounterU64(tryAsU64(gas));
14201
- }
14356
+ /** Gas measuring type. Can be either U64 or U32 for performance reasons. */
14357
+ type Gas = BigGas | SmallGas;
14202
14358
 
14203
14359
  /** An abstraction over gas counter.
14204
14360
  *
14205
14361
  * It can be optimized to use numbers instead of bigint in case of small gas.
14206
14362
  */
14207
- interface GasCounter {
14363
+ interface IGasCounter {
14364
+ /**
14365
+ * Set during initialization of GasCounter.
14366
+ *
14367
+ * NOTE: Needed to calculate `used()` gas.
14368
+ */
14369
+ initialGas: Gas;
14370
+
14208
14371
  /** Return remaining gas. */
14209
14372
  get(): Gas;
14210
14373
 
14211
- /** Overwrite remaining gas. Prefer sub method instead. */
14374
+ /**
14375
+ * Overwrite remaining gas.
14376
+ *
14377
+ * NOTE: Could cause `used()` gas calculation to be incorrect.
14378
+ *
14379
+ * @see
14380
+ * Prefer sub method instead.
14381
+ */
14212
14382
  set(g: Gas): void;
14213
14383
 
14214
14384
  /** Returns true if there was an underflow. */
14215
14385
  sub(g: Gas): boolean;
14386
+
14387
+ /**
14388
+ * Calculates used gas since creation of GasCounter.
14389
+ *
14390
+ * The interface does not handle negative or more than `initialGas` values.
14391
+ *
14392
+ * NOTE: We can use at most `initialGas` and as little as `0`.
14393
+ */
14394
+ used(): Gas;
14395
+ }
14396
+
14397
+ type PageFault$1 = {
14398
+ address: U32;
14399
+ };
14400
+
14401
+ /** Allows store and read segments of memory. */
14402
+ interface IMemory {
14403
+ /** Store bytes into memory at given address. */
14404
+ store(address: U32, bytes: Uint8Array): Result$2<OK, PageFault$1>;
14405
+
14406
+ /** Load bytes from memory from given address into given buffer. */
14407
+ read(address: U32, result: Uint8Array): Result$2<OK, PageFault$1>;
14216
14408
  }
14217
14409
 
14218
14410
  declare const NO_OF_REGISTERS$1 = 13;
14219
14411
 
14412
+ /** Allow to set and get all registers encoded into little-endian bytes. */
14413
+ interface IRegisters {
14414
+ /**
14415
+ * Get all registers encoded into little-endian bytes.
14416
+ *
14417
+ * NOTE: Total length of bytes must be NO_OF_REGISTERS * REGISTER_BYTE_SIZE.
14418
+ */
14419
+ getAllEncoded(): Uint8Array;
14420
+ /**
14421
+ * Set all registers from little-endian encoded bytes.
14422
+ *
14423
+ * NOTE: Total length of bytes must be NO_OF_REGISTERS * REGISTER_BYTE_SIZE.
14424
+ */
14425
+ setAllEncoded(bytes: Uint8Array): void;
14426
+ }
14427
+
14428
+ /**
14429
+ * Result codes for the PVM execution.
14430
+ *
14431
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/2e43002e4300?v=0.7.2
14432
+ */
14433
+ declare enum Status {
14434
+ /** Continue */
14435
+ OK = 255,
14436
+ /** Finished */
14437
+ HALT = 0,
14438
+ /** Panic */
14439
+ PANIC = 1,
14440
+ /** Page-fault */
14441
+ FAULT = 2,
14442
+ /** Host-call */
14443
+ HOST = 3,
14444
+ /** Out of gas */
14445
+ OOG = 4,
14446
+ }
14447
+
14448
+ interface IPvmInterpreter {
14449
+ /** Manipulate gas. */
14450
+ readonly gas: IGasCounter;
14451
+
14452
+ /** Manipulate registers. */
14453
+ readonly registers: IRegisters;
14454
+
14455
+ /** Manipulate memory. */
14456
+ readonly memory: IMemory;
14457
+
14458
+ /** Prepare SPI program to be executed. */
14459
+ resetJam(program: Uint8Array, args: Uint8Array, pc: number, gas: Gas): void;
14460
+
14461
+ /** Execute loaded program. */
14462
+ runProgram(): void;
14463
+
14464
+ /** Get current Status. */
14465
+ getStatus(): Status;
14466
+
14467
+ /** Get current Program Counter. */
14468
+ getPC(): number;
14469
+
14470
+ /** Get exit args. Needed in case of HOST or FAULT. */
14471
+ getExitParam(): U32 | null;
14472
+ }
14473
+
14474
+ // x << 3 === x * 8
14475
+
14220
14476
  type RegisterIndex = Opaque<number, "register index">;
14221
14477
 
14222
- declare class Registers {
14478
+ declare class Registers implements IRegisters {
14223
14479
  private asSigned: BigInt64Array;
14224
14480
  private asUnsigned: BigUint64Array;
14225
14481
 
@@ -14229,6 +14485,15 @@ declare class Registers {
14229
14485
  this.asUnsigned = new BigUint64Array(bytes.buffer, bytes.byteOffset);
14230
14486
  }
14231
14487
 
14488
+ getAllEncoded(): Uint8Array {
14489
+ return this.bytes;
14490
+ }
14491
+
14492
+ setAllEncoded(bytes: Uint8Array): void {
14493
+ check`${bytes.length === this.bytes.length} Incorrect size of input registers. Got: ${bytes.length}, need: ${this.bytes.length}`;
14494
+ this.bytes.set(bytes, 0);
14495
+ }
14496
+
14232
14497
  static fromBytes(bytes: Uint8Array) {
14233
14498
  check`${bytes.length === NO_OF_REGISTERS << REGISTER_SIZE_SHIFT} Invalid size of registers array.`;
14234
14499
  return new Registers(bytes);
@@ -14239,10 +14504,6 @@ declare class Registers {
14239
14504
  return this.bytes.subarray(offset, offset + len);
14240
14505
  }
14241
14506
 
14242
- getAllBytesAsLittleEndian() {
14243
- return this.bytes;
14244
- }
14245
-
14246
14507
  copyFrom(regs: Registers | BigUint64Array) {
14247
14508
  const array = regs instanceof BigUint64Array ? regs : regs.asUnsigned;
14248
14509
  this.asUnsigned.set(array);
@@ -14291,1493 +14552,1856 @@ declare class Registers {
14291
14552
  }
14292
14553
  }
14293
14554
 
14294
- /**
14295
- * Mask class is an implementation of skip function defined in GP.
14296
- *
14297
- * https://graypaper.fluffylabs.dev/#/5f542d7/237201239801
14298
- */
14299
- declare class Mask {
14555
+ declare class HostCallMemory {
14556
+ constructor(private readonly memory: IMemory) {}
14557
+
14300
14558
  /**
14301
- * The lookup table will have `0` at the index which corresponds to an instruction on the same index in the bytecode.
14302
- * In case the value is non-zero it signifies the offset to the index with next instruction.
14559
+ * Save some bytes into memory under given address.
14303
14560
  *
14304
- * Example:
14305
- * ```
14306
- * 0..1..2..3..4..5..6..7..8..9 # Indices
14307
- * 0..2..1..0..1..0..3..2..1..0 # lookupTable forward values
14308
- * ```
14309
- * There are instructions at indices `0, 3, 5, 9`.
14561
+ * NOTE: Given address is U64 (pure register value),
14562
+ * but we use only lower 32-bits.
14310
14563
  */
14311
- private lookupTableForward: Uint8Array;
14312
-
14313
- constructor(mask: BitVec) {
14314
- this.lookupTableForward = this.buildLookupTableForward(mask);
14315
- }
14316
-
14317
- isInstruction(index: number) {
14318
- return this.lookupTableForward[index] === 0;
14319
- }
14564
+ storeFrom(regAddress: U64, bytes: Uint8Array): Result$2<OK, PageFault$1> {
14565
+ if (bytes.length === 0) {
14566
+ return Result.ok(OK);
14567
+ }
14320
14568
 
14321
- getNoOfBytesToNextInstruction(index: number) {
14322
- check`${index >= 0} index (${index}) cannot be a negative number`;
14323
- return Math.min(this.lookupTableForward[index] ?? 0, MAX_INSTRUCTION_DISTANCE);
14569
+ // NOTE: We always take lower 32 bits from register value.
14570
+ //
14571
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/25ed0025ed00?v=0.7.2
14572
+ const address = tryAsU32(Number(regAddress & 0xffff_ffffn));
14573
+ return this.memory.store(address, bytes);
14324
14574
  }
14325
14575
 
14326
- private buildLookupTableForward(mask: BitVec) {
14327
- const table = safeAllocUint8Array(mask.bitLength);
14328
- let lastInstructionOffset = 0;
14329
- for (let i = mask.bitLength - 1; i >= 0; i--) {
14330
- if (mask.isSet(i)) {
14331
- lastInstructionOffset = 0;
14332
- } else {
14333
- lastInstructionOffset++;
14334
- }
14335
- table[i] = lastInstructionOffset;
14576
+ /**
14577
+ * Read some bytes from memory under given address.
14578
+ *
14579
+ * NOTE: Given address is U64 (pure register value),
14580
+ * but we use only lower 32-bits.
14581
+ */
14582
+ loadInto(output: Uint8Array, regAddress: U64): Result$2<OK, PageFault$1> {
14583
+ if (output.length === 0) {
14584
+ return Result.ok(OK);
14336
14585
  }
14337
- return table;
14338
- }
14339
14586
 
14340
- static empty() {
14341
- return new Mask(BitVec.empty(0));
14587
+ // https://graypaper.fluffylabs.dev/#/ab2cdbd/25ed0025ed00?v=0.7.2
14588
+ //
14589
+ // NOTE we are taking the the lower U32 part of the register, hence it's safe.
14590
+ const address = tryAsU32(Number(regAddress & 0xffff_ffffn));
14591
+ return this.memory.read(address, output);
14342
14592
  }
14343
14593
  }
14344
14594
 
14345
- declare enum ArgumentType {
14346
- NO_ARGUMENTS = 0,
14347
- ONE_IMMEDIATE = 1,
14348
- TWO_IMMEDIATES = 2,
14349
- ONE_OFFSET = 3,
14350
- ONE_REGISTER_ONE_IMMEDIATE = 4,
14351
- ONE_REGISTER_TWO_IMMEDIATES = 5,
14352
- ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET = 6,
14353
- TWO_REGISTERS = 7,
14354
- TWO_REGISTERS_ONE_IMMEDIATE = 8,
14355
- TWO_REGISTERS_ONE_OFFSET = 9,
14356
- TWO_REGISTERS_TWO_IMMEDIATES = 10,
14357
- THREE_REGISTERS = 11,
14358
- ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE = 12,
14359
- }
14360
-
14361
- declare class ExtendedWitdthImmediateDecoder {
14362
- private unsignedImmediate: BigUint64Array;
14363
- private bytes: Uint8Array;
14595
+ declare class HostCallRegisters {
14596
+ private readonly registers: DataView;
14364
14597
 
14365
- constructor() {
14366
- const buffer = new ArrayBuffer(IMMEDIATE_SIZE);
14367
- this.unsignedImmediate = new BigUint64Array(buffer);
14368
- this.bytes = new Uint8Array(buffer);
14598
+ constructor(private readonly bytes: Uint8Array) {
14599
+ this.registers = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
14369
14600
  }
14370
14601
 
14371
- setBytes(bytes: Uint8Array) {
14372
- let i = 0;
14373
- for (; i < bytes.length; i++) {
14374
- this.bytes[i] = bytes[i];
14375
- }
14376
-
14377
- for (; i < IMMEDIATE_SIZE; i++) {
14378
- this.bytes[i] = 0;
14379
- }
14602
+ /** Get U64 register value. */
14603
+ get(registerIndex: number): U64 {
14604
+ return tryAsU64(this.registers.getBigUint64(registerIndex * REGISTER_BYTE_SIZE, true));
14380
14605
  }
14381
14606
 
14382
- getValue() {
14383
- return this.unsignedImmediate[0];
14607
+ /** Set U64 register value. */
14608
+ set(registerIndex: number, value: U64) {
14609
+ this.registers.setBigUint64(registerIndex * REGISTER_BYTE_SIZE, value, true);
14384
14610
  }
14385
14611
 
14386
- getBytesAsLittleEndian() {
14387
- return this.bytes.subarray(0, IMMEDIATE_SIZE);
14612
+ /** Get all registers encoded into little-endian bytes. */
14613
+ getEncoded(): Uint8Array {
14614
+ return this.bytes;
14388
14615
  }
14389
14616
  }
14390
14617
 
14391
- declare class ImmediateDecoder {
14392
- private u32: Uint32Array;
14393
- private i32: Int32Array;
14394
- private u64: BigUint64Array;
14395
- private i64: BigInt64Array;
14396
- private view: DataView;
14397
- private bytes: Uint8Array;
14618
+ /** Strictly-typed host call index. */
14619
+ type HostCallIndex = Opaque<U32, "HostCallIndex[U32]">;
14620
+ /** Attempt to convert a number into `HostCallIndex`. */
14621
+ declare const tryAsHostCallIndex = (v: number): HostCallIndex => asOpaqueType(tryAsU32(v));
14398
14622
 
14399
- constructor() {
14400
- const buffer = new ArrayBuffer(BUFFER_SIZE);
14401
- this.u32 = new Uint32Array(buffer);
14402
- this.i32 = new Int32Array(buffer);
14403
- this.u64 = new BigUint64Array(buffer);
14404
- this.i64 = new BigInt64Array(buffer);
14405
- this.view = new DataView(buffer);
14406
- this.bytes = new Uint8Array(buffer);
14407
- }
14408
-
14409
- setBytes(bytes: Uint8Array) {
14410
- const n = bytes.length;
14411
- const msb = n > 0 ? bytes[n - 1] & 0x80 : 0;
14412
- const noOfBytes = Math.min(n, BUFFER_SIZE);
14413
- const prefix = msb !== 0 ? 0xff : 0x00;
14623
+ /**
14624
+ * Host-call exit reason.
14625
+ *
14626
+ * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
14627
+ */
14628
+ declare enum PvmExecution {
14629
+ Halt = 0,
14630
+ Panic = 1,
14631
+ OOG = 2, // out-of-gas
14632
+ }
14414
14633
 
14415
- for (let i = 0; i < noOfBytes; i++) {
14416
- this.view.setUint8(i, bytes[i]);
14417
- }
14634
+ /** A utility function to easily trace a bunch of registers. */
14635
+ declare function traceRegisters(...regs: number[]) {
14636
+ return regs.map(tryAsRegisterIndex);
14637
+ }
14418
14638
 
14419
- for (let i = n; i < BUFFER_SIZE; i++) {
14420
- this.view.setUint8(i, prefix);
14421
- }
14422
- }
14639
+ /** An interface for a host call implementation */
14640
+ interface HostCallHandler {
14641
+ /** Index of that host call (i.e. what PVM invokes via `ecalli`) */
14642
+ readonly index: HostCallIndex;
14423
14643
 
14424
14644
  /**
14425
- * @deprecated Use getU32 instead
14645
+ * The gas cost of invocation of that host call.
14646
+ *
14647
+ * NOTE: `((reg: HostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
14426
14648
  */
14427
- getUnsigned() {
14428
- return this.u32[U32_INDEX];
14429
- }
14649
+ readonly basicGasCost: SmallGas | ((reg: HostCallRegisters) => Gas);
14650
+
14651
+ /** Currently executing service id. */
14652
+ readonly currentServiceId: U32;
14653
+
14654
+ /** Input&Output registers that we should add to tracing log. */
14655
+ readonly tracedRegisters: RegisterIndex[];
14430
14656
 
14431
14657
  /**
14432
- * @deprecated Use getI32 instead
14658
+ * Actually execute the host call.
14659
+ *
14660
+ * NOTE the call is ALLOWED and expected to modify registers and memory.
14433
14661
  */
14434
- getSigned() {
14435
- return this.i32[U32_INDEX];
14436
- }
14662
+ execute(gas: IGasCounter, regs: HostCallRegisters, memory: HostCallMemory): Promise<undefined | PvmExecution>;
14663
+ }
14437
14664
 
14438
- getU32(): number {
14439
- return this.u32[U32_INDEX];
14440
- }
14665
+ /** Container for all available host calls. */
14666
+ declare class HostCallsManager {
14667
+ private readonly hostCalls = new Map<HostCallIndex, HostCallHandler>();
14668
+ private readonly missing;
14441
14669
 
14442
- getI32(): number {
14443
- return this.i32[U32_INDEX];
14670
+ constructor({
14671
+ missing,
14672
+ handlers = [],
14673
+ }: {
14674
+ missing: HostCallHandler;
14675
+ handlers?: HostCallHandler[];
14676
+ }) {
14677
+ this.missing = missing;
14678
+
14679
+ for (const handler of handlers) {
14680
+ check`${this.hostCalls.get(handler.index) === undefined} Overwriting host call handler at index ${handler.index}`;
14681
+ this.hostCalls.set(handler.index, handler);
14682
+ }
14444
14683
  }
14445
14684
 
14446
- getU64(): bigint {
14447
- return this.u64[U64_INDEX];
14685
+ /** Get a host call by index. */
14686
+ get(hostCallIndex: HostCallIndex): HostCallHandler {
14687
+ return this.hostCalls.get(hostCallIndex) ?? this.missing;
14448
14688
  }
14449
14689
 
14450
- getI64(): bigint {
14451
- return this.i64[U64_INDEX];
14690
+ traceHostCall(
14691
+ context: string,
14692
+ hostCallIndex: HostCallIndex,
14693
+ hostCallHandler: HostCallHandler,
14694
+ registers: HostCallRegisters,
14695
+ gas: Gas,
14696
+ ) {
14697
+ const { currentServiceId } = hostCallHandler;
14698
+ const requested = hostCallIndex !== hostCallHandler.index ? ` (${hostCallIndex})` : "";
14699
+ const name = `${hostCallHandler.constructor.name}:${hostCallHandler.index}`;
14700
+ const registerValues = hostCallHandler.tracedRegisters
14701
+ .map((idx) => [idx.toString().padStart(2, "0"), registers.get(idx)] as const)
14702
+ .filter((v) => v[1] !== 0n)
14703
+ .map(([idx, value]) => {
14704
+ return `r${idx}=${value} (0x${value.toString(16)})`;
14705
+ })
14706
+ .join(", ");
14707
+ logger.insane`[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
14452
14708
  }
14709
+ }
14453
14710
 
14454
- getBytesAsLittleEndian() {
14455
- return this.bytes.subarray(0, IMMEDIATE_SIZE);
14711
+ /** Create a new gas counter instance depending on the gas value. */
14712
+ declare function gasCounter(gas: Gas): IGasCounter {
14713
+ return new GasCounterU64(tryAsU64(gas));
14714
+ }
14715
+
14716
+ type MemoryIndex = Opaque<number, "memory index">;
14717
+
14718
+ declare const tryAsMemoryIndex = (index: number): MemoryIndex => {
14719
+ check`${index >= 0 && index <= MAX_MEMORY_INDEX} Incorrect memory index: ${index}!`;
14720
+ return asOpaqueType(index);
14721
+ };
14722
+
14723
+ type SbrkIndex = Opaque<number, "sbrk index">;
14724
+
14725
+ declare const tryAsSbrkIndex = (index: number): SbrkIndex => {
14726
+ check`${index >= 0 && index <= MAX_MEMORY_INDEX + 1} Incorrect sbrk index: ${index}!`;
14727
+ return asOpaqueType(index);
14728
+ };
14729
+
14730
+ type PageIndex = Opaque<number, "memory page index">;
14731
+ type PageNumber = Opaque<number, "memory page number">;
14732
+
14733
+ declare class PageFault implements PageFault$1 {
14734
+ private constructor(
14735
+ public address: U32,
14736
+ public isAccessFault = true,
14737
+ ) {}
14738
+
14739
+ static fromPageNumber(maybePageNumber: number, isAccessFault = false) {
14740
+ const pageNumber = tryAsPageNumber(maybePageNumber);
14741
+ const startPageIndex = getStartPageIndexFromPageNumber(pageNumber);
14742
+ return new PageFault(tryAsU32(startPageIndex), isAccessFault);
14456
14743
  }
14457
14744
 
14458
- getExtendedBytesAsLittleEndian() {
14459
- return this.bytes;
14745
+ static fromMemoryIndex(maybeMemoryIndex: number, isAccessFault = false) {
14746
+ const memoryIndex = tryAsMemoryIndex(maybeMemoryIndex % MEMORY_SIZE);
14747
+ const startPageIndex = getStartPageIndex(memoryIndex);
14748
+ return new PageFault(tryAsU32(startPageIndex), isAccessFault);
14460
14749
  }
14461
14750
  }
14462
14751
 
14463
- declare class NibblesDecoder {
14464
- private byte = new Int8Array(1);
14752
+ /**
14753
+ * A representation of open-ended range of consecutive indices in memory,
14754
+ * possibly empty or wrapping around.
14755
+ *
14756
+ * `[start, start + length)`
14757
+ */
14758
+ declare class MemoryRange {
14759
+ /**
14760
+ * Exclusive end index of the range.
14761
+ *
14762
+ * NOTE: The index may be wrapped around and smaller than `start`!
14763
+ */
14764
+ public readonly end: MemoryIndex;
14765
+ /**
14766
+ * Inclusive last index of the range (present unless the range is empty).
14767
+ *
14768
+ * NOTE: the index may be wrapped around and smaller than `start`!
14769
+ */
14770
+ public readonly lastIndex: MemoryIndex | null = null;
14465
14771
 
14466
- setByte(byte: number) {
14467
- this.byte[0] = byte;
14468
- }
14772
+ private constructor(
14773
+ public readonly start: MemoryIndex,
14774
+ public readonly length: number,
14775
+ ) {
14776
+ this.end = tryAsMemoryIndex((this.start + this.length) % MEMORY_SIZE);
14469
14777
 
14470
- getHighNibble() {
14471
- return (this.byte[0] & 0xf0) >>> 4;
14778
+ if (length > 0) {
14779
+ this.lastIndex = tryAsMemoryIndex((this.end - 1 + MEMORY_SIZE) % MEMORY_SIZE);
14780
+ }
14472
14781
  }
14473
14782
 
14474
- getLowNibble() {
14475
- return this.byte[0] & 0x0f;
14783
+ /** Creates a memory range from given starting point and length */
14784
+ static fromStartAndLength(start: MemoryIndex, length: number) {
14785
+ if (!Number.isInteger(length) || length < 0 || length > MEMORY_SIZE) {
14786
+ throw new TypeError(`length must be a non-negative integer and less than ${MEMORY_SIZE}, got ${length}`);
14787
+ }
14788
+
14789
+ return new MemoryRange(start, length);
14476
14790
  }
14477
14791
 
14478
- getHighNibbleAsRegisterIndex() {
14479
- return Math.min(this.getHighNibble(), MAX_REGISTER_INDEX);
14792
+ /** Checks if a range is empty (`length === 0`) */
14793
+ isEmpty() {
14794
+ return this.length === 0;
14480
14795
  }
14481
14796
 
14482
- getLowNibbleAsRegisterIndex() {
14483
- return Math.min(this.getLowNibble(), MAX_REGISTER_INDEX);
14797
+ /** Returns true if the range is wrapped (`start` >= `end`) and is not empty */
14798
+ isWrapped() {
14799
+ return this.start >= this.end && !this.isEmpty();
14484
14800
  }
14485
14801
 
14486
- getHighNibbleAsLength() {
14487
- return Math.min(this.getHighNibble(), MAX_LENGTH);
14802
+ /** Checks if given memory address is within the range */
14803
+ isInRange(address: MemoryIndex) {
14804
+ if (this.isWrapped()) {
14805
+ return address >= this.start || address < this.end;
14806
+ }
14807
+
14808
+ return address >= this.start && address < this.end;
14488
14809
  }
14489
14810
 
14490
- getLowNibbleAsLength() {
14491
- return Math.min(this.getLowNibble(), MAX_LENGTH);
14811
+ /** Checks if this range overlaps with another range */
14812
+ overlapsWith(other: MemoryRange) {
14813
+ if (this.lastIndex === null || other.lastIndex === null) {
14814
+ return false;
14815
+ }
14816
+
14817
+ return (
14818
+ this.isInRange(other.start) ||
14819
+ this.isInRange(other.lastIndex) ||
14820
+ other.isInRange(this.start) ||
14821
+ other.isInRange(this.lastIndex)
14822
+ );
14492
14823
  }
14493
14824
  }
14494
14825
 
14495
- type EmptyArgs = {
14496
- type: ArgumentType.NO_ARGUMENTS;
14497
- noOfBytesToSkip: number;
14498
- };
14499
-
14500
- type OneImmediateArgs = {
14501
- type: ArgumentType.ONE_IMMEDIATE;
14502
- noOfBytesToSkip: number;
14503
- /** V_X */
14504
- immediateDecoder: ImmediateDecoder;
14505
- };
14826
+ declare abstract class MemoryPage {
14827
+ public start: MemoryIndex;
14506
14828
 
14507
- type ThreeRegistersArgs = {
14508
- type: ArgumentType.THREE_REGISTERS;
14509
- noOfBytesToSkip: number;
14510
- /** W_A */
14511
- firstRegisterIndex: number;
14512
- /** W_B */
14513
- secondRegisterIndex: number;
14514
- /** W_D */
14515
- thirdRegisterIndex: number;
14516
- };
14829
+ constructor(pageNumber: PageNumber) {
14830
+ this.start = getStartPageIndexFromPageNumber(pageNumber);
14831
+ }
14517
14832
 
14518
- type TwoRegistersArgs = {
14519
- type: ArgumentType.TWO_REGISTERS;
14520
- noOfBytesToSkip: number;
14521
- /** W_A */
14522
- firstRegisterIndex: number;
14523
- /** W_D */
14524
- secondRegisterIndex: number;
14525
- };
14833
+ /** Returns `true` if the page is writeable. */
14834
+ abstract isWriteable(): boolean;
14526
14835
 
14527
- type TwoRegistersOneImmediateArgs = {
14528
- type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
14529
- noOfBytesToSkip: number;
14530
- /** W_A */
14531
- firstRegisterIndex: number;
14532
- /** W_B */
14533
- secondRegisterIndex: number;
14534
- /** V_X */
14535
- immediateDecoder: ImmediateDecoder;
14536
- };
14836
+ /**
14837
+ * Load exactly `length` bytes from memory page, starting at index `address`
14838
+ * into the `res` array.
14839
+ *
14840
+ * Note that the `res` might be bigger than the number of bytes length, but cannot be smaller.
14841
+ *
14842
+ * Returns `null` if copying was successful and [`PageFault`] otherwise.
14843
+ * NOTE That the `result` might be partially modified in case `PageFault` occurs!
14844
+ */
14845
+ abstract loadInto(res: Uint8Array, address: PageIndex, length: number): Result$2<OK, PageFault>;
14537
14846
 
14538
- type OneRegisterOneImmediateArgs = {
14539
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
14540
- noOfBytesToSkip: number;
14541
- /** W_A */
14542
- registerIndex: number;
14543
- /** V_X */
14544
- immediateDecoder: ImmediateDecoder;
14545
- };
14847
+ /**
14848
+ * Copy all bytes from the `data` into the page at index `address`.
14849
+ *
14850
+ * Returns `null` if copying was successful and [`PageFault`] otherwise.
14851
+ */
14852
+ abstract storeFrom(address: PageIndex, data: Uint8Array): Result$2<OK, PageFault>;
14853
+ /**
14854
+ * Get dump of the entire page. Should only be used for the debugger-adapter because it
14855
+ * might be inefficient.
14856
+ */
14857
+ abstract getPageDump(): Uint8Array;
14546
14858
 
14547
- type OneRegisterOneExtendedWidthImmediateArgs = {
14548
- type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
14549
- noOfBytesToSkip: number;
14550
- /** W_A */
14551
- registerIndex: number;
14552
- /** V_X */
14553
- immediateDecoder: ExtendedWitdthImmediateDecoder;
14554
- };
14859
+ abstract setData(pageIndex: PageIndex, data: Uint8Array): void;
14860
+ }
14555
14861
 
14556
- type TwoRegistersTwoImmediatesArgs = {
14557
- type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
14558
- noOfBytesToSkip: number;
14559
- /** W_A */
14560
- firstRegisterIndex: number;
14561
- /** W_B */
14562
- secondRegisterIndex: number;
14563
- /** V_X */
14564
- firstImmediateDecoder: ImmediateDecoder;
14565
- /** V_Y */
14566
- secondImmediateDecoder: ImmediateDecoder;
14567
- };
14862
+ /**
14863
+ * I had to extend ArrayBuffer type to use resizable ArrayBuffer.
14864
+ * We will be able to remove it when this is merged: https://github.com/microsoft/TypeScript/pull/58573
14865
+ * And then a new version of TypeScript is released.
14866
+ */
14867
+ declare global {
14868
+ interface ArrayBufferConstructor {
14869
+ new (length: number, options?: {
14870
+ maxByteLength: number;
14871
+ }): ArrayBuffer;
14872
+ }
14873
+ interface ArrayBuffer {
14874
+ resize(length: number): void;
14875
+ }
14876
+ }
14568
14877
 
14569
- type TwoImmediatesArgs = {
14570
- type: ArgumentType.TWO_IMMEDIATES;
14571
- noOfBytesToSkip: number;
14572
- /** V_X */
14573
- firstImmediateDecoder: ImmediateDecoder;
14574
- /** V_Y */
14575
- secondImmediateDecoder: ImmediateDecoder;
14878
+ type InitialMemoryState = {
14879
+ memory: Map<PageNumber, MemoryPage>;
14880
+ sbrkIndex: SbrkIndex;
14881
+ endHeapIndex: SbrkIndex;
14576
14882
  };
14577
14883
 
14578
- type TwoRegistersOneOffsetArgs = {
14579
- type: ArgumentType.TWO_REGISTERS_ONE_OFFSET;
14580
- noOfBytesToSkip: number;
14581
- /** W_A */
14582
- firstRegisterIndex: number;
14583
- /** W_B */
14584
- secondRegisterIndex: number;
14585
- nextPc: number;
14586
- };
14884
+ declare enum AccessType {
14885
+ READ = 0,
14886
+ WRITE = 1,
14887
+ }
14587
14888
 
14588
- type OneRegisterOneImmediateOneOffsetArgs = {
14589
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
14590
- noOfBytesToSkip: number;
14591
- /** W_A */
14592
- registerIndex: number;
14593
- /** V_X */
14594
- immediateDecoder: ImmediateDecoder;
14595
- /** V_Y */
14596
- nextPc: number;
14597
- };
14889
+ declare class Memory implements IMemory {
14890
+ static fromInitialMemory(initialMemoryState: InitialMemoryState) {
14891
+ return new Memory(
14892
+ initialMemoryState?.sbrkIndex,
14893
+ initialMemoryState?.sbrkIndex,
14894
+ initialMemoryState?.endHeapIndex,
14895
+ initialMemoryState?.memory,
14896
+ );
14897
+ }
14598
14898
 
14599
- type OneRegisterTwoImmediatesArgs = {
14600
- type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
14601
- noOfBytesToSkip: number;
14602
- /** W_A */
14603
- registerIndex: number;
14604
- /** V_X */
14605
- firstImmediateDecoder: ImmediateDecoder;
14606
- /** V_Y */
14607
- secondImmediateDecoder: ImmediateDecoder;
14608
- };
14899
+ constructor(
14900
+ private sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
14901
+ private virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
14902
+ private endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX),
14903
+ private memory = new Map<PageNumber, MemoryPage>(),
14904
+ ) {}
14609
14905
 
14610
- type OneOffsetArgs = {
14611
- type: ArgumentType.ONE_OFFSET;
14612
- noOfBytesToSkip: number;
14613
- /** V_X */
14614
- nextPc: number;
14615
- };
14906
+ store(address: U32, bytes: Uint8Array): Result$2<OK, PageFault$1> {
14907
+ return this.storeFrom(tryAsMemoryIndex(address), bytes);
14908
+ }
14616
14909
 
14617
- type Args =
14618
- | EmptyArgs
14619
- | OneImmediateArgs
14620
- | TwoRegistersArgs
14621
- | ThreeRegistersArgs
14622
- | TwoRegistersOneImmediateArgs
14623
- | TwoRegistersTwoImmediatesArgs
14624
- | OneRegisterOneImmediateOneOffsetArgs
14625
- | TwoRegistersOneOffsetArgs
14626
- | OneRegisterOneImmediateArgs
14627
- | OneOffsetArgs
14628
- | TwoImmediatesArgs
14629
- | OneRegisterTwoImmediatesArgs
14630
- | OneRegisterOneExtendedWidthImmediateArgs;
14910
+ read(address: U32, output: Uint8Array): Result$2<OK, PageFault$1> {
14911
+ return this.loadInto(output, tryAsMemoryIndex(address));
14912
+ }
14631
14913
 
14632
- declare class ArgsDecoder {
14633
- private nibblesDecoder = new NibblesDecoder();
14634
- private offsetDecoder = new ImmediateDecoder();
14635
- private code: Uint8Array = new Uint8Array();
14636
- private mask: Mask = Mask.empty();
14914
+ reset() {
14915
+ this.sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
14916
+ this.virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
14917
+ this.endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX);
14918
+ this.memory = new Map<PageNumber, MemoryPage>(); // TODO [MaSi]: We should keep allocated pages somewhere and reuse it when it is possible
14919
+ }
14637
14920
 
14638
- reset(code: Uint8Array, mask: Mask) {
14639
- this.code = code;
14640
- this.mask = mask;
14921
+ copyFrom(memory: Memory) {
14922
+ this.sbrkIndex = memory.sbrkIndex;
14923
+ this.virtualSbrkIndex = memory.virtualSbrkIndex;
14924
+ this.endHeapIndex = memory.endHeapIndex;
14925
+ this.memory = memory.memory;
14641
14926
  }
14642
14927
 
14643
- fillArgs<T extends Args>(pc: number, result: T): void {
14644
- const nextInstructionDistance = 1 + this.mask.getNoOfBytesToNextInstruction(pc + 1);
14645
- result.noOfBytesToSkip = nextInstructionDistance;
14928
+ storeFrom(address: MemoryIndex, bytes: Uint8Array): Result$2<OK, PageFault> {
14929
+ if (bytes.length === 0) {
14930
+ return Result.ok(OK);
14931
+ }
14646
14932
 
14647
- switch (result.type) {
14648
- case ArgumentType.NO_ARGUMENTS:
14649
- break;
14933
+ logger.insane`MEM[${address}] <- ${BytesBlob.blobFrom(bytes)}`;
14934
+ const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
14650
14935
 
14651
- case ArgumentType.ONE_IMMEDIATE: {
14652
- const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
14653
- const argsStartIndex = pc + 1;
14654
- result.immediateDecoder.setBytes(this.code.subarray(argsStartIndex, argsStartIndex + immediateLength));
14655
- break;
14656
- }
14936
+ if (pagesResult.isError) {
14937
+ return Result.error(pagesResult.error, pagesResult.details);
14938
+ }
14657
14939
 
14658
- case ArgumentType.THREE_REGISTERS: {
14659
- const firstByte = this.code[pc + 1];
14660
- const secondByte = this.code[pc + 2];
14661
- this.nibblesDecoder.setByte(firstByte);
14662
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14663
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14664
- this.nibblesDecoder.setByte(secondByte);
14665
- result.thirdRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14666
- break;
14667
- }
14940
+ const pages = pagesResult.ok;
14941
+ let currentPosition: number = address;
14942
+ let bytesLeft = bytes.length;
14668
14943
 
14669
- case ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE: {
14670
- const firstByte = this.code[pc + 1];
14671
- this.nibblesDecoder.setByte(firstByte);
14672
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14673
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14944
+ for (const page of pages) {
14945
+ const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
14946
+ const bytesToWrite = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
14947
+ const sourceStartIndex = currentPosition - address;
14948
+ const source = bytes.subarray(sourceStartIndex, sourceStartIndex + bytesToWrite);
14674
14949
 
14675
- const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
14676
- const immediateStartIndex = pc + 2;
14677
- const immediateEndIndex = immediateStartIndex + immediateLength;
14678
- result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
14679
- break;
14680
- }
14950
+ page.storeFrom(pageStartIndex, source);
14681
14951
 
14682
- case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET: {
14683
- const firstByte = this.code[pc + 1];
14684
- this.nibblesDecoder.setByte(firstByte);
14685
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14952
+ currentPosition += bytesToWrite;
14953
+ bytesLeft -= bytesToWrite;
14954
+ }
14955
+ return Result.ok(OK);
14956
+ }
14686
14957
 
14687
- const immediateLength = this.nibblesDecoder.getHighNibbleAsLength();
14688
- const immediateStartIndex = pc + 2;
14689
- const immediateEndIndex = immediateStartIndex + immediateLength;
14690
- result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
14958
+ private getPages(startAddress: MemoryIndex, length: number, accessType: AccessType): Result$2<MemoryPage[], PageFault> {
14959
+ if (length === 0) {
14960
+ return Result.ok([]);
14961
+ }
14691
14962
 
14692
- const offsetLength = Math.min(
14693
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14694
- Math.max(0, nextInstructionDistance - 2 - immediateLength),
14695
- );
14696
- const offsetStartIndex = pc + 2 + immediateLength;
14697
- const offsetEndIndex = offsetStartIndex + offsetLength;
14698
- this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
14963
+ const memoryRange = MemoryRange.fromStartAndLength(startAddress, length);
14964
+ const pageRange = PageRange.fromMemoryRange(memoryRange);
14699
14965
 
14700
- result.nextPc = pc + this.offsetDecoder.getSigned();
14701
- break;
14966
+ const pages: MemoryPage[] = [];
14967
+
14968
+ for (const pageNumber of pageRange) {
14969
+ if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
14970
+ return Result.error(
14971
+ PageFault.fromPageNumber(pageNumber, true),
14972
+ () => `Page fault: attempted to access reserved page ${pageNumber}`,
14973
+ );
14702
14974
  }
14703
14975
 
14704
- case ArgumentType.TWO_REGISTERS_ONE_OFFSET: {
14705
- const firstByte = this.code[pc + 1];
14706
- this.nibblesDecoder.setByte(firstByte);
14707
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14708
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14709
-
14710
- const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
14711
- const offsetStartIndex = pc + 2;
14712
- const offsetEndIndex = offsetStartIndex + offsetLength;
14713
- this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
14714
-
14715
- result.nextPc = pc + this.offsetDecoder.getSigned();
14716
- break;
14717
- }
14976
+ const page = this.memory.get(pageNumber);
14718
14977
 
14719
- case ArgumentType.TWO_REGISTERS: {
14720
- const firstByte = this.code[pc + 1];
14721
- this.nibblesDecoder.setByte(firstByte);
14722
- result.firstRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
14723
- result.secondRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14724
- break;
14978
+ if (page === undefined) {
14979
+ return Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
14725
14980
  }
14726
14981
 
14727
- case ArgumentType.ONE_OFFSET: {
14728
- const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
14729
- const offsetStartIndex = pc + 1;
14730
- const offsetEndIndex = offsetStartIndex + offsetLength;
14731
- const offsetBytes = this.code.subarray(offsetStartIndex, offsetEndIndex);
14732
- this.offsetDecoder.setBytes(offsetBytes);
14733
- const offsetValue = this.offsetDecoder.getSigned();
14734
- result.nextPc = pc + offsetValue;
14735
- break;
14982
+ if (accessType === AccessType.WRITE && !page.isWriteable()) {
14983
+ return Result.error(
14984
+ PageFault.fromPageNumber(pageNumber, true),
14985
+ () => `Page fault: attempted to write to read-only page ${pageNumber}`,
14986
+ );
14736
14987
  }
14737
14988
 
14738
- case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE: {
14739
- const firstByte = this.code[pc + 1];
14740
- this.nibblesDecoder.setByte(firstByte);
14741
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14989
+ pages.push(page);
14990
+ }
14742
14991
 
14743
- const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
14744
- const immediateStartIndex = pc + 2;
14745
- const immediateEndIndex = immediateStartIndex + immediateLength;
14746
- const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
14747
- result.immediateDecoder.setBytes(immediateBytes);
14748
- break;
14749
- }
14992
+ return Result.ok(pages);
14993
+ }
14994
+ /**
14995
+ * Read content of the memory at `[address, address + result.length)` and
14996
+ * write the result into the `result` buffer.
14997
+ *
14998
+ * Returns `null` if the data was read successfully or `PageFault` otherwise.
14999
+ */
15000
+ loadInto(result: Uint8Array, startAddress: MemoryIndex): Result$2<OK, PageFault> {
15001
+ if (result.length === 0) {
15002
+ return Result.ok(OK);
15003
+ }
14750
15004
 
14751
- case ArgumentType.TWO_IMMEDIATES: {
14752
- const firstByte = this.code[pc + 1];
14753
- this.nibblesDecoder.setByte(firstByte);
14754
- const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
14755
- const firstImmediateStartIndex = pc + 2;
14756
- const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
14757
- const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
14758
- result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15005
+ const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
14759
15006
 
14760
- const secondImmediateLength = Math.min(
14761
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14762
- Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
14763
- );
14764
- const secondImmediateStartIndex = firstImmediateEndIndex;
14765
- const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
14766
- const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
14767
- result.secondImmediateDecoder.setBytes(secondImmediateBytes);
14768
- break;
14769
- }
15007
+ if (pagesResult.isError) {
15008
+ return Result.error(pagesResult.error, pagesResult.details);
15009
+ }
14770
15010
 
14771
- case ArgumentType.ONE_REGISTER_TWO_IMMEDIATES: {
14772
- const firstByte = this.code[pc + 1];
14773
- this.nibblesDecoder.setByte(firstByte);
14774
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15011
+ const pages = pagesResult.ok;
14775
15012
 
14776
- const firstImmediateLength = this.nibblesDecoder.getHighNibbleAsLength();
14777
- const firstImmediateStartIndex = pc + 2;
14778
- const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
14779
- const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
14780
- result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15013
+ let currentPosition: number = startAddress;
15014
+ let bytesLeft = result.length;
14781
15015
 
14782
- const secondImmediateLength = Math.min(
14783
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14784
- Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
14785
- );
14786
- const secondImmediateStartIndex = firstImmediateEndIndex;
14787
- const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
14788
- const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
14789
- result.secondImmediateDecoder.setBytes(secondImmediateBytes);
14790
- break;
14791
- }
15016
+ for (const page of pages) {
15017
+ const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
15018
+ const bytesToRead = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
15019
+ const destinationStartIndex = currentPosition - startAddress;
15020
+ const destination = result.subarray(destinationStartIndex);
14792
15021
 
14793
- case ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES: {
14794
- const firstByte = this.code[pc + 1];
14795
- this.nibblesDecoder.setByte(firstByte);
14796
- result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
14797
- result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15022
+ page.loadInto(destination, pageStartIndex, bytesToRead);
14798
15023
 
14799
- const secondByte = this.code[pc + 2];
14800
- this.nibblesDecoder.setByte(secondByte);
14801
- const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
14802
- const firstImmediateStartIndex = pc + 3;
14803
- const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
14804
- const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
14805
- result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15024
+ currentPosition += bytesToRead;
15025
+ bytesLeft -= bytesToRead;
15026
+ }
14806
15027
 
14807
- const secondImmediateLength = Math.min(
14808
- IMMEDIATE_AND_OFFSET_MAX_LENGTH,
14809
- Math.max(0, nextInstructionDistance - 3 - firstImmediateLength),
14810
- );
14811
- const secondImmediateStartIndex = firstImmediateEndIndex;
14812
- const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
14813
- const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
14814
- result.secondImmediateDecoder.setBytes(secondImmediateBytes);
14815
- break;
14816
- }
15028
+ logger.insane`MEM[${startAddress}] => ${BytesBlob.blobFrom(result)}`;
15029
+ return Result.ok(OK);
15030
+ }
14817
15031
 
14818
- case ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE: {
14819
- const firstByte = this.code[pc + 1];
14820
- this.nibblesDecoder.setByte(firstByte);
14821
- result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15032
+ sbrk(length: number): SbrkIndex {
15033
+ const currentSbrkIndex = this.sbrkIndex;
15034
+ const currentVirtualSbrkIndex = this.virtualSbrkIndex;
14822
15035
 
14823
- const immediateStartIndex = pc + 2;
14824
- const immediateEndIndex = immediateStartIndex + 8;
14825
- const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
14826
- result.immediateDecoder.setBytes(immediateBytes);
14827
- break;
14828
- }
15036
+ // new sbrk index is bigger than 2 ** 32 or endHeapIndex
15037
+ if (MAX_MEMORY_INDEX < currentVirtualSbrkIndex + length || currentVirtualSbrkIndex + length > this.endHeapIndex) {
15038
+ throw new OutOfMemory();
14829
15039
  }
14830
- }
14831
- }
14832
15040
 
14833
- declare const createResults = () => {
14834
- const results = new Array(ARGUMENT_TYPE_LENGTH) as Results;
15041
+ const newVirtualSbrkIndex = tryAsSbrkIndex(this.virtualSbrkIndex + length);
14835
15042
 
14836
- results[ArgumentType.NO_ARGUMENTS] = {
14837
- type: ArgumentType.NO_ARGUMENTS,
14838
- noOfBytesToSkip: 1,
14839
- };
15043
+ // no alllocation needed
15044
+ if (newVirtualSbrkIndex <= currentSbrkIndex) {
15045
+ this.virtualSbrkIndex = newVirtualSbrkIndex;
15046
+ return currentVirtualSbrkIndex;
15047
+ }
14840
15048
 
14841
- results[ArgumentType.ONE_IMMEDIATE] = {
14842
- type: ArgumentType.ONE_IMMEDIATE,
14843
- noOfBytesToSkip: 1,
14844
- immediateDecoder: new ImmediateDecoder(),
14845
- };
15049
+ // standard allocation using "Writeable" pages
15050
+ const newSbrkIndex = tryAsSbrkIndex(alignToPageSize(newVirtualSbrkIndex));
15051
+ // TODO [MaSi]: `getPageNumber` works incorrectly for SbrkIndex. Sbrk index should be changed to MemoryIndex
15052
+ const firstPageNumber = getPageNumber(currentSbrkIndex);
15053
+ const pagesToAllocate = (newSbrkIndex - currentSbrkIndex) / PAGE_SIZE;
15054
+ const rangeToAllocate = PageRange.fromStartAndLength(firstPageNumber, pagesToAllocate);
14846
15055
 
14847
- results[ArgumentType.TWO_REGISTERS] = {
14848
- type: ArgumentType.TWO_REGISTERS,
14849
- noOfBytesToSkip: 1,
14850
- firstRegisterIndex: 0,
14851
- secondRegisterIndex: 0,
14852
- };
15056
+ for (const pageNumber of rangeToAllocate) {
15057
+ const page = new WriteablePage(pageNumber);
15058
+ this.memory.set(pageNumber, page);
15059
+ }
14853
15060
 
14854
- results[ArgumentType.THREE_REGISTERS] = {
14855
- type: ArgumentType.THREE_REGISTERS,
14856
- noOfBytesToSkip: 1,
14857
- firstRegisterIndex: 0,
14858
- secondRegisterIndex: 0,
14859
- thirdRegisterIndex: 0,
14860
- };
15061
+ this.virtualSbrkIndex = newVirtualSbrkIndex;
15062
+ this.sbrkIndex = newSbrkIndex;
15063
+ return currentVirtualSbrkIndex;
15064
+ }
14861
15065
 
14862
- results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET] = {
14863
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET,
14864
- noOfBytesToSkip: 1,
14865
- registerIndex: 0,
14866
- immediateDecoder: new ImmediateDecoder(),
14867
- nextPc: 0,
14868
- };
15066
+ getPageDump(pageNumber: PageNumber) {
15067
+ const page = this.memory.get(pageNumber);
15068
+ return page?.getPageDump() ?? null;
15069
+ }
14869
15070
 
14870
- results[ArgumentType.TWO_REGISTERS_ONE_OFFSET] = {
14871
- type: ArgumentType.TWO_REGISTERS_ONE_OFFSET,
14872
- noOfBytesToSkip: 1,
14873
- firstRegisterIndex: 0,
14874
- secondRegisterIndex: 0,
14875
- nextPc: 0,
14876
- };
15071
+ getDirtyPages() {
15072
+ return this.memory.keys();
15073
+ }
15074
+ }
14877
15075
 
14878
- results[ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE] = {
14879
- type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE,
14880
- noOfBytesToSkip: 1,
14881
- firstRegisterIndex: 0,
14882
- secondRegisterIndex: 0,
14883
- immediateDecoder: new ImmediateDecoder(),
14884
- };
15076
+ declare class MemoryBuilder {
15077
+ private readonly initialMemory: Map<PageNumber, MemoryPage> = new Map();
15078
+ private isFinalized = false;
14885
15079
 
14886
- results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE] = {
14887
- type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE,
14888
- noOfBytesToSkip: 1,
14889
- registerIndex: 0,
14890
- immediateDecoder: new ImmediateDecoder(),
14891
- };
15080
+ private ensureNotFinalized() {
15081
+ if (this.isFinalized) {
15082
+ throw new FinalizedBuilderModification();
15083
+ }
15084
+ }
14892
15085
 
14893
- results[ArgumentType.ONE_REGISTER_TWO_IMMEDIATES] = {
14894
- type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES,
14895
- noOfBytesToSkip: 1,
14896
- registerIndex: 0,
14897
- firstImmediateDecoder: new ImmediateDecoder(),
14898
- secondImmediateDecoder: new ImmediateDecoder(),
14899
- };
15086
+ private ensureNoReservedMemoryUsage(range: MemoryRange) {
15087
+ if (range.overlapsWith(RESERVED_MEMORY_RANGE)) {
15088
+ throw new ReservedMemoryFault();
15089
+ }
15090
+ }
14900
15091
 
14901
- results[ArgumentType.ONE_OFFSET] = {
14902
- type: ArgumentType.ONE_OFFSET,
14903
- noOfBytesToSkip: 1,
14904
- nextPc: 0,
14905
- };
15092
+ /**
15093
+ * Create entire readable pages to handle the `[start, end)` range.
15094
+ *
15095
+ * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15096
+ * they need to be the start indices of the pages.
15097
+ *
15098
+ * The data passed will be placed at `start`, but might be shorter than the requested range,
15099
+ * prepend it with zeros if you don't wish to have it at the beginning of the page.
15100
+ */
15101
+ setReadablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15102
+ this.ensureNotFinalized();
15103
+ check`${start < end} end has to be bigger than start`;
15104
+ check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15105
+ check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15106
+ check`${data.length <= end - start} the initial data is longer than address range`;
14906
15107
 
14907
- results[ArgumentType.TWO_IMMEDIATES] = {
14908
- type: ArgumentType.TWO_IMMEDIATES,
14909
- noOfBytesToSkip: 1,
14910
- firstImmediateDecoder: new ImmediateDecoder(),
14911
- secondImmediateDecoder: new ImmediateDecoder(),
14912
- };
15108
+ const length = end - start;
15109
+ const range = MemoryRange.fromStartAndLength(start, length);
14913
15110
 
14914
- results[ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES] = {
14915
- type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES,
14916
- noOfBytesToSkip: 1,
14917
- firstImmediateDecoder: new ImmediateDecoder(),
14918
- secondImmediateDecoder: new ImmediateDecoder(),
14919
- firstRegisterIndex: 0,
14920
- secondRegisterIndex: 0,
14921
- };
15111
+ this.ensureNoReservedMemoryUsage(range);
14922
15112
 
14923
- results[ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE] = {
14924
- type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE,
14925
- noOfBytesToSkip: 9,
14926
- registerIndex: 0,
14927
- immediateDecoder: new ExtendedWitdthImmediateDecoder(),
14928
- };
15113
+ const pages = Array.from(PageRange.fromMemoryRange(range));
15114
+ const noOfPages = pages.length;
14929
15115
 
14930
- return results;
14931
- };
15116
+ for (let i = 0; i < noOfPages; i++) {
15117
+ const pageNumber = pages[i];
15118
+ const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15119
+ const page = new ReadablePage(pageNumber, dataChunk);
15120
+ this.initialMemory.set(pageNumber, page);
15121
+ }
14932
15122
 
14933
- declare enum Instruction {
14934
- TRAP = 0,
14935
- FALLTHROUGH = 1,
14936
- ECALLI = 10,
14937
- LOAD_IMM_64 = 20,
14938
- STORE_IMM_U8 = 30,
14939
- STORE_IMM_U16 = 31,
14940
- STORE_IMM_U32 = 32,
14941
- STORE_IMM_U64 = 33,
14942
- JUMP = 40,
14943
- JUMP_IND = 50,
14944
- LOAD_IMM = 51,
14945
- LOAD_U8 = 52,
14946
- LOAD_I8 = 53,
14947
- LOAD_U16 = 54,
14948
- LOAD_I16 = 55,
14949
- LOAD_U32 = 56,
14950
- LOAD_I32 = 57,
14951
- LOAD_U64 = 58,
14952
- STORE_U8 = 59,
14953
- STORE_U16 = 60,
14954
- STORE_U32 = 61,
14955
- STORE_U64 = 62,
14956
- STORE_IMM_IND_U8 = 70,
14957
- STORE_IMM_IND_U16 = 71,
14958
- STORE_IMM_IND_U32 = 72,
14959
- STORE_IMM_IND_U64 = 73,
14960
- LOAD_IMM_JUMP = 80,
14961
- BRANCH_EQ_IMM = 81,
14962
- BRANCH_NE_IMM = 82,
14963
- BRANCH_LT_U_IMM = 83,
14964
- BRANCH_LE_U_IMM = 84,
14965
- BRANCH_GE_U_IMM = 85,
14966
- BRANCH_GT_U_IMM = 86,
14967
- BRANCH_LT_S_IMM = 87,
14968
- BRANCH_LE_S_IMM = 88,
14969
- BRANCH_GE_S_IMM = 89,
14970
- BRANCH_GT_S_IMM = 90,
14971
- MOVE_REG = 100,
14972
- SBRK = 101,
14973
- COUNT_SET_BITS_64 = 102,
14974
- COUNT_SET_BITS_32 = 103,
14975
- LEADING_ZERO_BITS_64 = 104,
14976
- LEADING_ZERO_BITS_32 = 105,
14977
- TRAILING_ZERO_BITS_64 = 106,
14978
- TRAILING_ZERO_BITS_32 = 107,
14979
- SIGN_EXTEND_8 = 108,
14980
- SIGN_EXTEND_16 = 109,
14981
- ZERO_EXTEND_16 = 110,
14982
- REVERSE_BYTES = 111,
14983
- STORE_IND_U8 = 120,
14984
- STORE_IND_U16 = 121,
14985
- STORE_IND_U32 = 122,
14986
- STORE_IND_U64 = 123,
14987
- LOAD_IND_U8 = 124,
14988
- LOAD_IND_I8 = 125,
14989
- LOAD_IND_U16 = 126,
14990
- LOAD_IND_I16 = 127,
14991
- LOAD_IND_U32 = 128,
14992
- LOAD_IND_I32 = 129,
14993
- LOAD_IND_U64 = 130,
14994
- ADD_IMM_32 = 131,
14995
- AND_IMM = 132,
14996
- XOR_IMM = 133,
14997
- OR_IMM = 134,
14998
- MUL_IMM_32 = 135,
14999
- SET_LT_U_IMM = 136,
15000
- SET_LT_S_IMM = 137,
15001
- SHLO_L_IMM_32 = 138,
15002
- SHLO_R_IMM_32 = 139,
15003
- SHAR_R_IMM_32 = 140,
15004
- NEG_ADD_IMM_32 = 141,
15005
- SET_GT_U_IMM = 142,
15006
- SET_GT_S_IMM = 143,
15007
- SHLO_L_IMM_ALT_32 = 144,
15008
- SHLO_R_IMM_ALT_32 = 145,
15009
- SHAR_R_IMM_ALT_32 = 146,
15010
- CMOV_IZ_IMM = 147,
15011
- CMOV_NZ_IMM = 148,
15012
- ADD_IMM_64 = 149,
15013
- MUL_IMM_64 = 150,
15014
- SHLO_L_IMM_64 = 151,
15015
- SHLO_R_IMM_64 = 152,
15016
- SHAR_R_IMM_64 = 153,
15017
- NEG_ADD_IMM_64 = 154,
15018
- SHLO_L_IMM_ALT_64 = 155,
15019
- SHLO_R_IMM_ALT_64 = 156,
15020
- SHAR_R_IMM_ALT_64 = 157,
15021
- ROT_R_64_IMM = 158,
15022
- ROT_R_64_IMM_ALT = 159,
15023
- ROT_R_32_IMM = 160,
15024
- ROT_R_32_IMM_ALT = 161,
15025
- BRANCH_EQ = 170,
15026
- BRANCH_NE = 171,
15027
- BRANCH_LT_U = 172,
15028
- BRANCH_LT_S = 173,
15029
- BRANCH_GE_U = 174,
15030
- BRANCH_GE_S = 175,
15031
- LOAD_IMM_JUMP_IND = 180,
15032
- ADD_32 = 190,
15033
- SUB_32 = 191,
15034
- MUL_32 = 192,
15035
- DIV_U_32 = 193,
15036
- DIV_S_32 = 194,
15037
- REM_U_32 = 195,
15038
- REM_S_32 = 196,
15039
- SHLO_L_32 = 197,
15040
- SHLO_R_32 = 198,
15041
- SHAR_R_32 = 199,
15042
- ADD_64 = 200,
15043
- SUB_64 = 201,
15044
- MUL_64 = 202,
15045
- DIV_U_64 = 203,
15046
- DIV_S_64 = 204,
15047
- REM_U_64 = 205,
15048
- REM_S_64 = 206,
15049
- SHLO_L_64 = 207,
15050
- SHLO_R_64 = 208,
15051
- SHAR_R_64 = 209,
15052
- AND = 210,
15053
- XOR = 211,
15054
- OR = 212,
15055
- MUL_UPPER_S_S = 213,
15056
- MUL_UPPER_U_U = 214,
15057
- MUL_UPPER_S_U = 215,
15058
- SET_LT_U = 216,
15059
- SET_LT_S = 217,
15060
- CMOV_IZ = 218,
15061
- CMOV_NZ = 219,
15062
- ROT_L_64 = 220,
15063
- ROT_L_32 = 221,
15064
- ROT_R_64 = 222,
15065
- ROT_R_32 = 223,
15066
- AND_INV = 224,
15067
- OR_INV = 225,
15068
- XNOR = 226,
15069
- MAX = 227,
15070
- MAX_U = 228,
15071
- MIN = 229,
15072
- MIN_U = 230,
15073
- }
15123
+ return this;
15124
+ }
15074
15125
 
15075
- declare const instructionArgumentTypeMap = (() => {
15076
- const instructionArgumentTypeMap = new Array<ArgumentType>(HIGHEST_INSTRUCTION_NUMBER + 1);
15126
+ /**
15127
+ * Create entire writeable pages to handle the `[start, end)` range.
15128
+ *
15129
+ * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15130
+ * they need to be the start indices of the pages.
15131
+ *
15132
+ * The data passed will be placed at `start`, but might be shorter than the requested range,
15133
+ * prepend it with zeros if you don't wish to have it at the beginning of the page.
15134
+ */
15135
+ setWriteablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15136
+ this.ensureNotFinalized();
15137
+ check`${start < end} end has to be bigger than start`;
15138
+ check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15139
+ check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15140
+ check`${data.length <= end - start} the initial data is longer than address range`;
15077
15141
 
15078
- instructionArgumentTypeMap[Instruction.TRAP] = ArgumentType.NO_ARGUMENTS;
15079
- instructionArgumentTypeMap[Instruction.FALLTHROUGH] = ArgumentType.NO_ARGUMENTS;
15142
+ const length = end - start;
15143
+ const range = MemoryRange.fromStartAndLength(start, length);
15080
15144
 
15081
- instructionArgumentTypeMap[Instruction.ECALLI] = ArgumentType.ONE_IMMEDIATE;
15145
+ this.ensureNoReservedMemoryUsage(range);
15082
15146
 
15083
- instructionArgumentTypeMap[Instruction.LOAD_IMM_64] = ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
15147
+ const pages = Array.from(PageRange.fromMemoryRange(range));
15148
+ const noOfPages = pages.length;
15084
15149
 
15085
- instructionArgumentTypeMap[Instruction.STORE_IMM_U8] = ArgumentType.TWO_IMMEDIATES;
15086
- instructionArgumentTypeMap[Instruction.STORE_IMM_U16] = ArgumentType.TWO_IMMEDIATES;
15087
- instructionArgumentTypeMap[Instruction.STORE_IMM_U32] = ArgumentType.TWO_IMMEDIATES;
15088
- instructionArgumentTypeMap[Instruction.STORE_IMM_U64] = ArgumentType.TWO_IMMEDIATES;
15150
+ for (let i = 0; i < noOfPages; i++) {
15151
+ const pageNumber = pages[i];
15152
+ const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15153
+ const page = new WriteablePage(pageNumber, dataChunk);
15154
+ this.initialMemory.set(pageNumber, page);
15155
+ }
15089
15156
 
15090
- instructionArgumentTypeMap[Instruction.JUMP] = ArgumentType.ONE_OFFSET;
15157
+ return this;
15158
+ }
15091
15159
 
15092
- instructionArgumentTypeMap[Instruction.JUMP_IND] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15093
- instructionArgumentTypeMap[Instruction.LOAD_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15094
- instructionArgumentTypeMap[Instruction.LOAD_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15095
- instructionArgumentTypeMap[Instruction.LOAD_I8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15096
- instructionArgumentTypeMap[Instruction.LOAD_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15097
- instructionArgumentTypeMap[Instruction.LOAD_I16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15098
- instructionArgumentTypeMap[Instruction.LOAD_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15099
- instructionArgumentTypeMap[Instruction.LOAD_I32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15100
- instructionArgumentTypeMap[Instruction.LOAD_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15101
- instructionArgumentTypeMap[Instruction.STORE_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15102
- instructionArgumentTypeMap[Instruction.STORE_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15103
- instructionArgumentTypeMap[Instruction.STORE_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15104
- instructionArgumentTypeMap[Instruction.STORE_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15160
+ /**
15161
+ * This function can be useful when page map and initial memory data are provided separatelly.
15162
+ * You can use setWriteablePages/setReadablePages to create empty pages and then setData to fill them
15163
+ */
15164
+ setData(start: MemoryIndex, data: Uint8Array) {
15165
+ this.ensureNotFinalized();
15166
+ const pageOffset = start % PAGE_SIZE;
15167
+ const remainingSpaceOnPage = PAGE_SIZE - pageOffset;
15168
+ check`${data.length <= remainingSpaceOnPage} The data has to fit into a single page.`;
15105
15169
 
15106
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U8] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15107
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U16] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15108
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U32] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15109
- instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U64] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15110
-
15111
- instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15112
- instructionArgumentTypeMap[Instruction.BRANCH_EQ_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15113
- instructionArgumentTypeMap[Instruction.BRANCH_NE_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15114
- instructionArgumentTypeMap[Instruction.BRANCH_LT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15115
- instructionArgumentTypeMap[Instruction.BRANCH_LE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15116
- instructionArgumentTypeMap[Instruction.BRANCH_GE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15117
- instructionArgumentTypeMap[Instruction.BRANCH_GT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15118
- instructionArgumentTypeMap[Instruction.BRANCH_LT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15119
- instructionArgumentTypeMap[Instruction.BRANCH_LE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15120
- instructionArgumentTypeMap[Instruction.BRANCH_GE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15121
- instructionArgumentTypeMap[Instruction.BRANCH_GT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15122
-
15123
- instructionArgumentTypeMap[Instruction.MOVE_REG] = ArgumentType.TWO_REGISTERS;
15124
- instructionArgumentTypeMap[Instruction.SBRK] = ArgumentType.TWO_REGISTERS;
15125
- instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_64] = ArgumentType.TWO_REGISTERS;
15126
- instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_32] = ArgumentType.TWO_REGISTERS;
15127
- instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
15128
- instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
15129
- instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
15130
- instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
15131
- instructionArgumentTypeMap[Instruction.SIGN_EXTEND_8] = ArgumentType.TWO_REGISTERS;
15132
- instructionArgumentTypeMap[Instruction.SIGN_EXTEND_16] = ArgumentType.TWO_REGISTERS;
15133
- instructionArgumentTypeMap[Instruction.ZERO_EXTEND_16] = ArgumentType.TWO_REGISTERS;
15134
- instructionArgumentTypeMap[Instruction.REVERSE_BYTES] = ArgumentType.TWO_REGISTERS;
15135
-
15136
- instructionArgumentTypeMap[Instruction.STORE_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15137
- instructionArgumentTypeMap[Instruction.STORE_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15138
- instructionArgumentTypeMap[Instruction.STORE_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15139
- instructionArgumentTypeMap[Instruction.STORE_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15140
- instructionArgumentTypeMap[Instruction.LOAD_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15141
- instructionArgumentTypeMap[Instruction.LOAD_IND_I8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15142
- instructionArgumentTypeMap[Instruction.LOAD_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15143
- instructionArgumentTypeMap[Instruction.LOAD_IND_I16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15144
- instructionArgumentTypeMap[Instruction.LOAD_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15145
- instructionArgumentTypeMap[Instruction.LOAD_IND_I32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15146
- instructionArgumentTypeMap[Instruction.LOAD_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15147
- instructionArgumentTypeMap[Instruction.ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15148
- instructionArgumentTypeMap[Instruction.ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15149
- instructionArgumentTypeMap[Instruction.AND_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15150
- instructionArgumentTypeMap[Instruction.XOR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15151
- instructionArgumentTypeMap[Instruction.OR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15152
- instructionArgumentTypeMap[Instruction.MUL_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15153
- instructionArgumentTypeMap[Instruction.MUL_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15154
- instructionArgumentTypeMap[Instruction.SET_LT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15155
- instructionArgumentTypeMap[Instruction.SET_LT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15156
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15157
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15158
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15159
- instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15160
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15161
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15162
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15163
- instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15164
- instructionArgumentTypeMap[Instruction.SET_GT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15165
- instructionArgumentTypeMap[Instruction.SET_GT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15166
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15167
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15168
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15169
- instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15170
- instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15171
- instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15172
- instructionArgumentTypeMap[Instruction.CMOV_IZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15173
- instructionArgumentTypeMap[Instruction.CMOV_NZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15174
- instructionArgumentTypeMap[Instruction.ROT_R_64_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15175
- instructionArgumentTypeMap[Instruction.ROT_R_64_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15176
- instructionArgumentTypeMap[Instruction.ROT_R_32_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15177
- instructionArgumentTypeMap[Instruction.ROT_R_32_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15170
+ const length = data.length;
15171
+ const range = MemoryRange.fromStartAndLength(start, length);
15178
15172
 
15179
- instructionArgumentTypeMap[Instruction.BRANCH_EQ] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15180
- instructionArgumentTypeMap[Instruction.BRANCH_NE] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15181
- instructionArgumentTypeMap[Instruction.BRANCH_LT_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15182
- instructionArgumentTypeMap[Instruction.BRANCH_LT_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15183
- instructionArgumentTypeMap[Instruction.BRANCH_GE_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15184
- instructionArgumentTypeMap[Instruction.BRANCH_GE_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15173
+ this.ensureNoReservedMemoryUsage(range);
15185
15174
 
15186
- instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP_IND] = ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
15175
+ const pageNumber = getPageNumber(start);
15176
+ const page = this.initialMemory.get(pageNumber);
15187
15177
 
15188
- instructionArgumentTypeMap[Instruction.ADD_32] = ArgumentType.THREE_REGISTERS;
15189
- instructionArgumentTypeMap[Instruction.ADD_64] = ArgumentType.THREE_REGISTERS;
15190
- instructionArgumentTypeMap[Instruction.SUB_32] = ArgumentType.THREE_REGISTERS;
15191
- instructionArgumentTypeMap[Instruction.SUB_64] = ArgumentType.THREE_REGISTERS;
15192
- instructionArgumentTypeMap[Instruction.AND] = ArgumentType.THREE_REGISTERS;
15193
- instructionArgumentTypeMap[Instruction.XOR] = ArgumentType.THREE_REGISTERS;
15194
- instructionArgumentTypeMap[Instruction.OR] = ArgumentType.THREE_REGISTERS;
15195
- instructionArgumentTypeMap[Instruction.MUL_32] = ArgumentType.THREE_REGISTERS;
15196
- instructionArgumentTypeMap[Instruction.MUL_64] = ArgumentType.THREE_REGISTERS;
15197
- instructionArgumentTypeMap[Instruction.MUL_UPPER_S_S] = ArgumentType.THREE_REGISTERS;
15198
- instructionArgumentTypeMap[Instruction.MUL_UPPER_U_U] = ArgumentType.THREE_REGISTERS;
15199
- instructionArgumentTypeMap[Instruction.MUL_UPPER_S_U] = ArgumentType.THREE_REGISTERS;
15200
- instructionArgumentTypeMap[Instruction.DIV_U_32] = ArgumentType.THREE_REGISTERS;
15201
- instructionArgumentTypeMap[Instruction.DIV_S_32] = ArgumentType.THREE_REGISTERS;
15202
- instructionArgumentTypeMap[Instruction.REM_U_32] = ArgumentType.THREE_REGISTERS;
15203
- instructionArgumentTypeMap[Instruction.REM_S_32] = ArgumentType.THREE_REGISTERS;
15204
- instructionArgumentTypeMap[Instruction.DIV_U_64] = ArgumentType.THREE_REGISTERS;
15205
- instructionArgumentTypeMap[Instruction.DIV_S_64] = ArgumentType.THREE_REGISTERS;
15206
- instructionArgumentTypeMap[Instruction.REM_U_64] = ArgumentType.THREE_REGISTERS;
15207
- instructionArgumentTypeMap[Instruction.REM_S_64] = ArgumentType.THREE_REGISTERS;
15208
- instructionArgumentTypeMap[Instruction.SET_LT_U] = ArgumentType.THREE_REGISTERS;
15209
- instructionArgumentTypeMap[Instruction.SET_LT_S] = ArgumentType.THREE_REGISTERS;
15210
- instructionArgumentTypeMap[Instruction.SHLO_L_32] = ArgumentType.THREE_REGISTERS;
15211
- instructionArgumentTypeMap[Instruction.SHLO_R_32] = ArgumentType.THREE_REGISTERS;
15212
- instructionArgumentTypeMap[Instruction.SHAR_R_32] = ArgumentType.THREE_REGISTERS;
15213
- instructionArgumentTypeMap[Instruction.SHLO_L_64] = ArgumentType.THREE_REGISTERS;
15214
- instructionArgumentTypeMap[Instruction.SHLO_R_64] = ArgumentType.THREE_REGISTERS;
15215
- instructionArgumentTypeMap[Instruction.SHAR_R_64] = ArgumentType.THREE_REGISTERS;
15216
- instructionArgumentTypeMap[Instruction.CMOV_IZ] = ArgumentType.THREE_REGISTERS;
15217
- instructionArgumentTypeMap[Instruction.CMOV_NZ] = ArgumentType.THREE_REGISTERS;
15218
- instructionArgumentTypeMap[Instruction.ROT_L_64] = ArgumentType.THREE_REGISTERS;
15219
- instructionArgumentTypeMap[Instruction.ROT_L_32] = ArgumentType.THREE_REGISTERS;
15220
- instructionArgumentTypeMap[Instruction.ROT_R_64] = ArgumentType.THREE_REGISTERS;
15221
- instructionArgumentTypeMap[Instruction.ROT_R_32] = ArgumentType.THREE_REGISTERS;
15222
- instructionArgumentTypeMap[Instruction.AND_INV] = ArgumentType.THREE_REGISTERS;
15223
- instructionArgumentTypeMap[Instruction.OR_INV] = ArgumentType.THREE_REGISTERS;
15224
- instructionArgumentTypeMap[Instruction.XNOR] = ArgumentType.THREE_REGISTERS;
15225
- instructionArgumentTypeMap[Instruction.MAX] = ArgumentType.THREE_REGISTERS;
15226
- instructionArgumentTypeMap[Instruction.MAX_U] = ArgumentType.THREE_REGISTERS;
15227
- instructionArgumentTypeMap[Instruction.MIN] = ArgumentType.THREE_REGISTERS;
15228
- instructionArgumentTypeMap[Instruction.MIN_U] = ArgumentType.THREE_REGISTERS;
15178
+ if (page === undefined) {
15179
+ throw new PageNotExist();
15180
+ }
15229
15181
 
15230
- return instructionArgumentTypeMap;
15231
- })();
15182
+ const startPageIndex = tryAsPageIndex(start - page.start);
15183
+ page.setData(startPageIndex, data);
15232
15184
 
15233
- declare class BasicBlocks {
15234
- private basicBlocks: Set<number> = new Set();
15185
+ return this;
15186
+ }
15235
15187
 
15236
- reset(code: Uint8Array, mask: Mask) {
15237
- this.basicBlocks.clear();
15238
- this.basicBlocks.add(0);
15239
- const codeLength = code.length;
15188
+ finalize(startHeapIndex: MemoryIndex, endHeapIndex: SbrkIndex): Memory {
15189
+ check`
15190
+ ${startHeapIndex <= endHeapIndex}
15191
+ startHeapIndex (${startHeapIndex}) has to be less than or equal to endHeapIndex (${endHeapIndex})
15192
+ `;
15193
+ this.ensureNotFinalized();
15240
15194
 
15241
- const isBasicBlockTermination = (index: number) =>
15242
- mask.isInstruction(index) && terminationInstructions[code[index]];
15195
+ const heapRange = MemoryRange.fromStartAndLength(startHeapIndex, endHeapIndex - startHeapIndex);
15196
+ const heapPagesRange = PageRange.fromMemoryRange(heapRange);
15197
+ const initializedPageNumbers = Array.from(this.initialMemory.keys());
15243
15198
 
15244
- for (let i = 0; i < codeLength; i++) {
15245
- if (mask.isInstruction(i) && isBasicBlockTermination(i)) {
15246
- this.basicBlocks.add(i + 1 + mask.getNoOfBytesToNextInstruction(i + 1));
15199
+ for (const pageNumber of initializedPageNumbers) {
15200
+ if (heapPagesRange.isInRange(pageNumber)) {
15201
+ throw new IncorrectSbrkIndex();
15247
15202
  }
15248
15203
  }
15249
- }
15250
-
15251
- isBeginningOfBasicBlock(index: number) {
15252
- return this.basicBlocks.has(index);
15253
- }
15254
- }
15255
-
15256
- declare enum Result {
15257
- HALT = 0,
15258
- PANIC = 1,
15259
- FAULT_ACCESS = 2,
15260
- FAULT = 3,
15261
- HOST = 4,
15262
- }
15263
15204
 
15264
- declare class InstructionResult {
15265
- public nextPc = 0;
15266
- public status: Result | null = null;
15267
- /**
15268
- * A numeric exit parameter of the PVM.
15269
- *
15270
- * In case of a `status === Result.FAULT` this will be the memory address
15271
- * that triggered the fault.
15272
- * In case of a `status === Result.HOST` this will be the host call index
15273
- * that should be invoked.
15274
- *
15275
- * In any other circumstance the value should be `null`.
15276
- */
15277
- public exitParam: number | null = null;
15205
+ const memory = Memory.fromInitialMemory({
15206
+ memory: this.initialMemory,
15207
+ sbrkIndex: tryAsSbrkIndex(startHeapIndex),
15208
+ endHeapIndex,
15209
+ });
15278
15210
 
15279
- reset() {
15280
- this.nextPc = 0;
15281
- this.status = null;
15282
- this.exitParam = null;
15211
+ this.isFinalized = true;
15212
+ return memory;
15283
15213
  }
15284
15214
  }
15285
15215
 
15286
- type MemoryIndex = Opaque<number, "memory index">;
15287
-
15288
- declare const tryAsMemoryIndex = (index: number): MemoryIndex => {
15289
- check`${index >= 0 && index <= MAX_MEMORY_INDEX} Incorrect memory index: ${index}!`;
15290
- return asOpaqueType(index);
15291
- };
15292
-
15293
- type SbrkIndex = Opaque<number, "sbrk index">;
15294
-
15295
- declare const tryAsSbrkIndex = (index: number): SbrkIndex => {
15296
- check`${index >= 0 && index <= MAX_MEMORY_INDEX + 1} Incorrect sbrk index: ${index}!`;
15297
- return asOpaqueType(index);
15298
- };
15299
-
15300
- type PageIndex = Opaque<number, "memory page index">;
15301
- type PageNumber = Opaque<number, "memory page number">;
15302
-
15303
- declare class PageFault {
15304
- private constructor(
15305
- public address: MemoryIndex,
15306
- public isAccessFault = true,
15307
- ) {}
15216
+ declare const NO_OF_REGISTERS = 13;
15308
15217
 
15309
- static fromPageNumber(maybePageNumber: number, isAccessFault = false) {
15310
- const pageNumber = tryAsPageNumber(maybePageNumber);
15311
- const startPageIndex = getStartPageIndexFromPageNumber(pageNumber);
15312
- return new PageFault(startPageIndex, isAccessFault);
15218
+ declare class MemorySegment extends WithDebug {
15219
+ static from({ start, end, data }: Omit<MemorySegment, never>) {
15220
+ return new MemorySegment(start, end, data);
15313
15221
  }
15314
15222
 
15315
- static fromMemoryIndex(maybeMemoryIndex: number, isAccessFault = false) {
15316
- const memoryIndex = tryAsMemoryIndex(maybeMemoryIndex % MEMORY_SIZE);
15317
- const startPageIndex = getStartPageIndex(memoryIndex);
15318
- return new PageFault(startPageIndex, isAccessFault);
15223
+ constructor(
15224
+ public readonly start: number,
15225
+ public readonly end: number,
15226
+ public readonly data: Uint8Array | null,
15227
+ ) {
15228
+ super();
15229
+ }
15230
+ }
15231
+ declare class SpiMemory extends WithDebug {
15232
+ constructor(
15233
+ public readonly readable: MemorySegment[],
15234
+ public readonly writeable: MemorySegment[],
15235
+ public readonly sbrkIndex: number,
15236
+ public readonly heapEnd: number,
15237
+ ) {
15238
+ super();
15319
15239
  }
15320
15240
  }
15321
15241
 
15322
- declare class OutOfBounds extends Error {
15323
- constructor() {
15324
- super("Out of bounds");
15242
+ declare class SpiProgram extends WithDebug {
15243
+ constructor(
15244
+ public readonly code: Uint8Array,
15245
+ public readonly memory: SpiMemory,
15246
+ public readonly registers: BigUint64Array,
15247
+ ) {
15248
+ super();
15325
15249
  }
15326
15250
  }
15327
15251
 
15328
15252
  /**
15329
- * A representation of open-ended range of consecutive indices in memory,
15330
- * possibly empty or wrapping around.
15253
+ * program = E_3(|o|) ++ E_3(|w|) ++ E_2(z) ++ E_3(s) ++ o ++ w ++ E_4(|c|) ++ c
15331
15254
  *
15332
- * `[start, start + length)`
15333
- */
15334
- declare class MemoryRange {
15335
- /**
15336
- * Exclusive end index of the range.
15337
- *
15338
- * NOTE: The index may be wrapped around and smaller than `start`!
15339
- */
15340
- public readonly end: MemoryIndex;
15341
- /**
15342
- * Inclusive last index of the range (present unless the range is empty).
15343
- *
15344
- * NOTE: the index may be wrapped around and smaller than `start`!
15345
- */
15346
- public readonly lastIndex: MemoryIndex | null = null;
15255
+ * E_n - little endian encoding, n - length
15256
+ * o - initial read only data
15257
+ * w - initial heap
15258
+ * z - heap pages filled with zeros
15259
+ * s - stack size
15260
+ * c - program code
15261
+ *
15262
+ * https://graypaper.fluffylabs.dev/#/579bd12/2b92022b9202
15263
+ */
15264
+ declare function decodeStandardProgram(program: Uint8Array, args: Uint8Array) {
15265
+ const decoder = Decoder.fromBlob(program);
15266
+ const oLength = decoder.u24();
15267
+ const wLength = decoder.u24();
15268
+ check`${args.length <= DATA_LENGTH} Incorrect arguments length`;
15269
+ check`${oLength <= DATA_LENGTH} Incorrect readonly segment length`;
15270
+ const readOnlyLength = oLength;
15271
+ check`${wLength <= DATA_LENGTH} Incorrect heap segment length`;
15272
+ const heapLength = wLength;
15273
+ const noOfHeapZerosPages = decoder.u16();
15274
+ const stackSize = decoder.u24();
15275
+ const readOnlyMemory = decoder.bytes(readOnlyLength).raw;
15276
+ const initialHeap = decoder.bytes(heapLength).raw;
15277
+ const codeLength = decoder.u32();
15278
+ const code = decoder.bytes(codeLength).raw;
15279
+ decoder.finish();
15347
15280
 
15348
- private constructor(
15349
- public readonly start: MemoryIndex,
15350
- public readonly length: number,
15351
- ) {
15352
- this.end = tryAsMemoryIndex((this.start + this.length) % MEMORY_SIZE);
15281
+ const readonlyDataStart = SEGMENT_SIZE;
15282
+ const readonlyDataEnd = SEGMENT_SIZE + alignToPageSize(readOnlyLength);
15283
+ const heapDataStart = 2 * SEGMENT_SIZE + alignToSegmentSize(readOnlyLength);
15284
+ const heapDataEnd = heapDataStart + alignToPageSize(heapLength);
15285
+ const heapZerosEnd = heapDataStart + alignToPageSize(heapLength) + noOfHeapZerosPages * PAGE_SIZE;
15286
+ const stackStart = STACK_SEGMENT - alignToPageSize(stackSize);
15287
+ const stackEnd = STACK_SEGMENT;
15288
+ const argsStart = ARGS_SEGMENT;
15289
+ const argsEnd = argsStart + alignToPageSize(args.length);
15290
+ const argsZerosEnd = argsEnd + alignToPageSize(args.length);
15353
15291
 
15354
- if (length > 0) {
15355
- this.lastIndex = tryAsMemoryIndex((this.end - 1 + MEMORY_SIZE) % MEMORY_SIZE);
15356
- }
15292
+ function nonEmpty(s: MemorySegment | false): s is MemorySegment {
15293
+ return s !== false;
15357
15294
  }
15358
15295
 
15359
- /** Creates a memory range from given starting point and length */
15360
- static fromStartAndLength(start: MemoryIndex, length: number) {
15361
- if (!Number.isInteger(length) || length < 0 || length > MEMORY_SIZE) {
15362
- throw new TypeError(`length must be a non-negative integer and less than ${MEMORY_SIZE}, got ${length}`);
15363
- }
15364
-
15365
- return new MemoryRange(start, length);
15366
- }
15296
+ const readableMemory = [
15297
+ readOnlyLength > 0 && getMemorySegment(readonlyDataStart, readonlyDataEnd, readOnlyMemory),
15298
+ args.length > 0 && getMemorySegment(argsStart, argsEnd, args),
15299
+ argsEnd < argsZerosEnd && getMemorySegment(argsEnd, argsZerosEnd),
15300
+ ].filter(nonEmpty);
15301
+ const writeableMemory = [
15302
+ heapLength > 0 && getMemorySegment(heapDataStart, heapDataEnd, initialHeap),
15303
+ heapDataEnd < heapZerosEnd && getMemorySegment(heapDataEnd, heapZerosEnd),
15304
+ stackStart < stackEnd && getMemorySegment(stackStart, stackEnd),
15305
+ ].filter(nonEmpty);
15367
15306
 
15368
- /** Checks if a range is empty (`length === 0`) */
15369
- isEmpty() {
15370
- return this.length === 0;
15371
- }
15307
+ return new SpiProgram(
15308
+ code,
15309
+ new SpiMemory(readableMemory, writeableMemory, heapZerosEnd, stackStart),
15310
+ getRegisters(args.length),
15311
+ );
15312
+ }
15372
15313
 
15373
- /** Returns true if the range is wrapped (`start` >= `end`) and is not empty */
15374
- isWrapped() {
15375
- return this.start >= this.end && !this.isEmpty();
15376
- }
15314
+ declare function getMemorySegment(start: number, end: number, data: Uint8Array | null = null) {
15315
+ return new MemorySegment(start, end, data);
15316
+ }
15377
15317
 
15378
- /** Checks if given memory address is within the range */
15379
- isInRange(address: MemoryIndex) {
15380
- if (this.isWrapped()) {
15381
- return address >= this.start || address < this.end;
15382
- }
15318
+ declare function getRegisters(argsLength: number) {
15319
+ const regs = new BigUint64Array(NO_OF_REGISTERS);
15383
15320
 
15384
- return address >= this.start && address < this.end;
15385
- }
15321
+ // GP reference: https://graypaper.fluffylabs.dev/#/579bd12/2c7c012cb101
15322
+ regs[0] = BigInt(LAST_PAGE);
15323
+ regs[1] = BigInt(STACK_SEGMENT);
15324
+ regs[7] = BigInt(ARGS_SEGMENT);
15325
+ regs[8] = BigInt(argsLength);
15386
15326
 
15387
- /** Checks if this range overlaps with another range */
15388
- overlapsWith(other: MemoryRange) {
15389
- if (this.lastIndex === null || other.lastIndex === null) {
15390
- return false;
15391
- }
15327
+ return regs;
15328
+ }
15392
15329
 
15393
- return (
15394
- this.isInRange(other.start) ||
15395
- this.isInRange(other.lastIndex) ||
15396
- other.isInRange(this.start) ||
15397
- other.isInRange(this.lastIndex)
15398
- );
15399
- }
15330
+ type index$8_MemorySegment = MemorySegment;
15331
+ declare const index$8_MemorySegment: typeof MemorySegment;
15332
+ declare const index$8_NO_OF_REGISTERS: typeof NO_OF_REGISTERS;
15333
+ type index$8_SpiMemory = SpiMemory;
15334
+ declare const index$8_SpiMemory: typeof SpiMemory;
15335
+ type index$8_SpiProgram = SpiProgram;
15336
+ declare const index$8_SpiProgram: typeof SpiProgram;
15337
+ declare const index$8_decodeStandardProgram: typeof decodeStandardProgram;
15338
+ declare const index$8_getMemorySegment: typeof getMemorySegment;
15339
+ declare const index$8_getRegisters: typeof getRegisters;
15340
+ declare namespace index$8 {
15341
+ export {
15342
+ index$8_MemorySegment as MemorySegment,
15343
+ index$8_NO_OF_REGISTERS as NO_OF_REGISTERS,
15344
+ index$8_SpiMemory as SpiMemory,
15345
+ index$8_SpiProgram as SpiProgram,
15346
+ index$8_decodeStandardProgram as decodeStandardProgram,
15347
+ index$8_getMemorySegment as getMemorySegment,
15348
+ index$8_getRegisters as getRegisters,
15349
+ };
15400
15350
  }
15401
15351
 
15402
- declare abstract class MemoryPage {
15403
- public start: MemoryIndex;
15352
+ declare class Program {
15353
+ static fromSpi(blob: Uint8Array, args: Uint8Array, hasMetadata: boolean) {
15354
+ const { code: spiCode, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
15355
+ const { code, memory: rawMemory, registers } = decodeStandardProgram(spiCode, args);
15356
+ const regs = new Registers();
15357
+ regs.copyFrom(registers);
15358
+ const memoryBuilder = new MemoryBuilder();
15404
15359
 
15405
- constructor(pageNumber: PageNumber) {
15406
- this.start = getStartPageIndexFromPageNumber(pageNumber);
15407
- }
15360
+ for (const { start, end, data } of rawMemory.readable) {
15361
+ const startIndex = tryAsMemoryIndex(start);
15362
+ const endIndex = tryAsMemoryIndex(end);
15363
+ memoryBuilder.setReadablePages(startIndex, endIndex, data ?? new Uint8Array());
15364
+ }
15408
15365
 
15409
- /** Returns `true` if the page is writeable. */
15410
- abstract isWriteable(): boolean;
15366
+ for (const { start, end, data } of rawMemory.writeable) {
15367
+ const startIndex = tryAsMemoryIndex(start);
15368
+ const endIndex = tryAsMemoryIndex(end);
15369
+ memoryBuilder.setWriteablePages(startIndex, endIndex, data ?? new Uint8Array());
15370
+ }
15411
15371
 
15412
- /**
15413
- * Load exactly `length` bytes from memory page, starting at index `address`
15414
- * into the `res` array.
15415
- *
15416
- * Note that the `res` might be bigger than the number of bytes length, but cannot be smaller.
15417
- *
15418
- * Returns `null` if copying was successful and [`PageFault`] otherwise.
15419
- * NOTE That the `result` might be partially modified in case `PageFault` occurs!
15420
- */
15421
- abstract loadInto(res: Uint8Array, address: PageIndex, length: number): Result$2<OK, PageFault>;
15372
+ const heapStart = tryAsMemoryIndex(rawMemory.sbrkIndex);
15373
+ const heapEnd = tryAsSbrkIndex(rawMemory.heapEnd);
15374
+ const memory = memoryBuilder.finalize(heapStart, heapEnd);
15422
15375
 
15423
- /**
15424
- * Copy all bytes from the `data` into the page at index `address`.
15425
- *
15426
- * Returns `null` if copying was successful and [`PageFault`] otherwise.
15427
- */
15428
- abstract storeFrom(address: PageIndex, data: Uint8Array): Result$2<OK, PageFault>;
15429
- /**
15430
- * Get dump of the entire page. Should only be used for the debugger-adapter because it
15431
- * might be inefficient.
15432
- */
15433
- abstract getPageDump(): Uint8Array;
15376
+ return new Program(code, regs, memory, metadata);
15377
+ }
15434
15378
 
15435
- abstract setData(pageIndex: PageIndex, data: Uint8Array): void;
15379
+ static fromGeneric(blob: Uint8Array, hasMetadata: boolean) {
15380
+ const { code, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
15381
+ const regs = new Registers();
15382
+ const memory = new Memory();
15383
+ return new Program(code, regs, memory, metadata);
15384
+ }
15385
+
15386
+ private constructor(
15387
+ public readonly code: Uint8Array,
15388
+ public readonly registers: Registers,
15389
+ public readonly memory: Memory,
15390
+ public metadata: Uint8Array = new Uint8Array(),
15391
+ ) {}
15436
15392
  }
15437
15393
 
15438
15394
  /**
15439
- * I had to extend ArrayBuffer type to use resizable ArrayBuffer.
15440
- * We will be able to remove it when this is merged: https://github.com/microsoft/TypeScript/pull/58573
15441
- * And then a new version of TypeScript is released.
15395
+ * A function that splits preimage into metadata and code.
15396
+ *
15397
+ * https://graypaper.fluffylabs.dev/#/cc517d7/109a01109a01?v=0.6.5
15442
15398
  */
15443
- declare global {
15444
- interface ArrayBufferConstructor {
15445
- new (length: number, options?: {
15446
- maxByteLength: number;
15447
- }): ArrayBuffer;
15448
- }
15449
- interface ArrayBuffer {
15450
- resize(length: number): void;
15451
- }
15399
+ declare function extractCodeAndMetadata(blobWithMetadata: Uint8Array) {
15400
+ const decoder = Decoder.fromBlob(blobWithMetadata);
15401
+ const metadata = decoder.bytesBlob().raw;
15402
+ const code = decoder.remainingBytes().raw;
15403
+ return { metadata, code };
15452
15404
  }
15453
15405
 
15454
- type InitialMemoryState = {
15455
- memory: Map<PageNumber, MemoryPage>;
15456
- sbrkIndex: SbrkIndex;
15457
- endHeapIndex: SbrkIndex;
15458
- };
15459
-
15460
- declare enum AccessType {
15461
- READ = 0,
15462
- WRITE = 1,
15406
+ type index$7_Program = Program;
15407
+ declare const index$7_Program: typeof Program;
15408
+ declare const index$7_extractCodeAndMetadata: typeof extractCodeAndMetadata;
15409
+ declare namespace index$7 {
15410
+ export {
15411
+ index$7_Program as Program,
15412
+ index$7_extractCodeAndMetadata as extractCodeAndMetadata,
15413
+ };
15463
15414
  }
15464
15415
 
15465
- declare class Memory {
15466
- static fromInitialMemory(initialMemoryState: InitialMemoryState) {
15467
- return new Memory(
15468
- initialMemoryState?.sbrkIndex,
15469
- initialMemoryState?.sbrkIndex,
15470
- initialMemoryState?.endHeapIndex,
15471
- initialMemoryState?.memory,
15472
- );
15416
+ /**
15417
+ * Mask class is an implementation of skip function defined in GP.
15418
+ *
15419
+ * https://graypaper.fluffylabs.dev/#/5f542d7/237201239801
15420
+ */
15421
+ declare class Mask {
15422
+ /**
15423
+ * The lookup table will have `0` at the index which corresponds to an instruction on the same index in the bytecode.
15424
+ * In case the value is non-zero it signifies the offset to the index with next instruction.
15425
+ *
15426
+ * Example:
15427
+ * ```
15428
+ * 0..1..2..3..4..5..6..7..8..9 # Indices
15429
+ * 0..2..1..0..1..0..3..2..1..0 # lookupTable forward values
15430
+ * ```
15431
+ * There are instructions at indices `0, 3, 5, 9`.
15432
+ */
15433
+ private lookupTableForward: Uint8Array;
15434
+
15435
+ constructor(mask: BitVec) {
15436
+ this.lookupTableForward = this.buildLookupTableForward(mask);
15473
15437
  }
15474
15438
 
15475
- constructor(
15476
- private sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
15477
- private virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end),
15478
- private endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX),
15479
- private memory = new Map<PageNumber, MemoryPage>(),
15480
- ) {}
15439
+ isInstruction(index: number) {
15440
+ return this.lookupTableForward[index] === 0;
15441
+ }
15481
15442
 
15482
- reset() {
15483
- this.sbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
15484
- this.virtualSbrkIndex = tryAsSbrkIndex(RESERVED_MEMORY_RANGE.end);
15485
- this.endHeapIndex = tryAsSbrkIndex(MAX_MEMORY_INDEX);
15486
- this.memory = new Map<PageNumber, MemoryPage>(); // TODO [MaSi]: We should keep allocated pages somewhere and reuse it when it is possible
15487
- }
15488
-
15489
- copyFrom(memory: Memory) {
15490
- this.sbrkIndex = memory.sbrkIndex;
15491
- this.virtualSbrkIndex = memory.virtualSbrkIndex;
15492
- this.endHeapIndex = memory.endHeapIndex;
15493
- this.memory = memory.memory;
15443
+ getNoOfBytesToNextInstruction(index: number) {
15444
+ check`${index >= 0} index (${index}) cannot be a negative number`;
15445
+ return Math.min(this.lookupTableForward[index] ?? 0, MAX_INSTRUCTION_DISTANCE);
15494
15446
  }
15495
15447
 
15496
- storeFrom(address: MemoryIndex, bytes: Uint8Array): Result$2<OK, PageFault> {
15497
- if (bytes.length === 0) {
15498
- return Result.ok(OK);
15499
- }
15500
-
15501
- logger.insane`MEM[${address}] <- ${BytesBlob.blobFrom(bytes)}`;
15502
- const pagesResult = this.getPages(address, bytes.length, AccessType.WRITE);
15503
-
15504
- if (pagesResult.isError) {
15505
- return Result.error(pagesResult.error, pagesResult.details);
15448
+ private buildLookupTableForward(mask: BitVec) {
15449
+ const table = safeAllocUint8Array(mask.bitLength);
15450
+ let lastInstructionOffset = 0;
15451
+ for (let i = mask.bitLength - 1; i >= 0; i--) {
15452
+ if (mask.isSet(i)) {
15453
+ lastInstructionOffset = 0;
15454
+ } else {
15455
+ lastInstructionOffset++;
15456
+ }
15457
+ table[i] = lastInstructionOffset;
15506
15458
  }
15459
+ return table;
15460
+ }
15507
15461
 
15508
- const pages = pagesResult.ok;
15509
- let currentPosition: number = address;
15510
- let bytesLeft = bytes.length;
15462
+ static empty() {
15463
+ return new Mask(BitVec.empty(0));
15464
+ }
15465
+ }
15511
15466
 
15512
- for (const page of pages) {
15513
- const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
15514
- const bytesToWrite = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
15515
- const sourceStartIndex = currentPosition - address;
15516
- const source = bytes.subarray(sourceStartIndex, sourceStartIndex + bytesToWrite);
15467
+ declare enum ArgumentType {
15468
+ NO_ARGUMENTS = 0,
15469
+ ONE_IMMEDIATE = 1,
15470
+ TWO_IMMEDIATES = 2,
15471
+ ONE_OFFSET = 3,
15472
+ ONE_REGISTER_ONE_IMMEDIATE = 4,
15473
+ ONE_REGISTER_TWO_IMMEDIATES = 5,
15474
+ ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET = 6,
15475
+ TWO_REGISTERS = 7,
15476
+ TWO_REGISTERS_ONE_IMMEDIATE = 8,
15477
+ TWO_REGISTERS_ONE_OFFSET = 9,
15478
+ TWO_REGISTERS_TWO_IMMEDIATES = 10,
15479
+ THREE_REGISTERS = 11,
15480
+ ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE = 12,
15481
+ }
15517
15482
 
15518
- page.storeFrom(pageStartIndex, source);
15483
+ declare class ExtendedWitdthImmediateDecoder {
15484
+ private unsignedImmediate: BigUint64Array;
15485
+ private bytes: Uint8Array;
15519
15486
 
15520
- currentPosition += bytesToWrite;
15521
- bytesLeft -= bytesToWrite;
15522
- }
15523
- return Result.ok(OK);
15487
+ constructor() {
15488
+ const buffer = new ArrayBuffer(IMMEDIATE_SIZE);
15489
+ this.unsignedImmediate = new BigUint64Array(buffer);
15490
+ this.bytes = new Uint8Array(buffer);
15524
15491
  }
15525
15492
 
15526
- private getPages(startAddress: MemoryIndex, length: number, accessType: AccessType): Result$2<MemoryPage[], PageFault> {
15527
- if (length === 0) {
15528
- return Result.ok([]);
15493
+ setBytes(bytes: Uint8Array) {
15494
+ let i = 0;
15495
+ for (; i < bytes.length; i++) {
15496
+ this.bytes[i] = bytes[i];
15529
15497
  }
15530
15498
 
15531
- const memoryRange = MemoryRange.fromStartAndLength(startAddress, length);
15532
- const pageRange = PageRange.fromMemoryRange(memoryRange);
15499
+ for (; i < IMMEDIATE_SIZE; i++) {
15500
+ this.bytes[i] = 0;
15501
+ }
15502
+ }
15533
15503
 
15534
- const pages: MemoryPage[] = [];
15504
+ getValue() {
15505
+ return this.unsignedImmediate[0];
15506
+ }
15535
15507
 
15536
- for (const pageNumber of pageRange) {
15537
- if (pageNumber < RESERVED_NUMBER_OF_PAGES) {
15538
- return Result.error(
15539
- PageFault.fromPageNumber(pageNumber, true),
15540
- () => `Page fault: attempted to access reserved page ${pageNumber}`,
15541
- );
15542
- }
15508
+ getBytesAsLittleEndian() {
15509
+ return this.bytes.subarray(0, IMMEDIATE_SIZE);
15510
+ }
15511
+ }
15543
15512
 
15544
- const page = this.memory.get(pageNumber);
15513
+ declare class ImmediateDecoder {
15514
+ private u32: Uint32Array;
15515
+ private i32: Int32Array;
15516
+ private u64: BigUint64Array;
15517
+ private i64: BigInt64Array;
15518
+ private view: DataView;
15519
+ private bytes: Uint8Array;
15545
15520
 
15546
- if (page === undefined) {
15547
- return Result.error(PageFault.fromPageNumber(pageNumber), () => `Page fault: page ${pageNumber} not allocated`);
15548
- }
15521
+ constructor() {
15522
+ const buffer = new ArrayBuffer(BUFFER_SIZE);
15523
+ this.u32 = new Uint32Array(buffer);
15524
+ this.i32 = new Int32Array(buffer);
15525
+ this.u64 = new BigUint64Array(buffer);
15526
+ this.i64 = new BigInt64Array(buffer);
15527
+ this.view = new DataView(buffer);
15528
+ this.bytes = new Uint8Array(buffer);
15529
+ }
15549
15530
 
15550
- if (accessType === AccessType.WRITE && !page.isWriteable()) {
15551
- return Result.error(
15552
- PageFault.fromPageNumber(pageNumber, true),
15553
- () => `Page fault: attempted to write to read-only page ${pageNumber}`,
15554
- );
15555
- }
15531
+ setBytes(bytes: Uint8Array) {
15532
+ const n = bytes.length;
15533
+ const msb = n > 0 ? bytes[n - 1] & 0x80 : 0;
15534
+ const noOfBytes = Math.min(n, BUFFER_SIZE);
15535
+ const prefix = msb !== 0 ? 0xff : 0x00;
15556
15536
 
15557
- pages.push(page);
15537
+ for (let i = 0; i < noOfBytes; i++) {
15538
+ this.view.setUint8(i, bytes[i]);
15558
15539
  }
15559
15540
 
15560
- return Result.ok(pages);
15541
+ for (let i = n; i < BUFFER_SIZE; i++) {
15542
+ this.view.setUint8(i, prefix);
15543
+ }
15561
15544
  }
15545
+
15562
15546
  /**
15563
- * Read content of the memory at `[address, address + result.length)` and
15564
- * write the result into the `result` buffer.
15565
- *
15566
- * Returns `null` if the data was read successfully or `PageFault` otherwise.
15547
+ * @deprecated Use getU32 instead
15567
15548
  */
15568
- loadInto(result: Uint8Array, startAddress: MemoryIndex): Result$2<OK, PageFault> {
15569
- if (result.length === 0) {
15570
- return Result.ok(OK);
15571
- }
15572
-
15573
- const pagesResult = this.getPages(startAddress, result.length, AccessType.READ);
15574
-
15575
- if (pagesResult.isError) {
15576
- return Result.error(pagesResult.error, pagesResult.details);
15577
- }
15549
+ getUnsigned() {
15550
+ return this.u32[U32_INDEX];
15551
+ }
15578
15552
 
15579
- const pages = pagesResult.ok;
15553
+ /**
15554
+ * @deprecated Use getI32 instead
15555
+ */
15556
+ getSigned() {
15557
+ return this.i32[U32_INDEX];
15558
+ }
15580
15559
 
15581
- let currentPosition: number = startAddress;
15582
- let bytesLeft = result.length;
15560
+ getU32(): number {
15561
+ return this.u32[U32_INDEX];
15562
+ }
15583
15563
 
15584
- for (const page of pages) {
15585
- const pageStartIndex = tryAsPageIndex(currentPosition % PAGE_SIZE);
15586
- const bytesToRead = Math.min(PAGE_SIZE - pageStartIndex, bytesLeft);
15587
- const destinationStartIndex = currentPosition - startAddress;
15588
- const destination = result.subarray(destinationStartIndex);
15564
+ getI32(): number {
15565
+ return this.i32[U32_INDEX];
15566
+ }
15589
15567
 
15590
- page.loadInto(destination, pageStartIndex, bytesToRead);
15568
+ getU64(): bigint {
15569
+ return this.u64[U64_INDEX];
15570
+ }
15591
15571
 
15592
- currentPosition += bytesToRead;
15593
- bytesLeft -= bytesToRead;
15594
- }
15572
+ getI64(): bigint {
15573
+ return this.i64[U64_INDEX];
15574
+ }
15595
15575
 
15596
- logger.insane`MEM[${startAddress}] => ${BytesBlob.blobFrom(result)}`;
15597
- return Result.ok(OK);
15576
+ getBytesAsLittleEndian() {
15577
+ return this.bytes.subarray(0, IMMEDIATE_SIZE);
15598
15578
  }
15599
15579
 
15600
- sbrk(length: number): SbrkIndex {
15601
- const currentSbrkIndex = this.sbrkIndex;
15602
- const currentVirtualSbrkIndex = this.virtualSbrkIndex;
15580
+ getExtendedBytesAsLittleEndian() {
15581
+ return this.bytes;
15582
+ }
15583
+ }
15603
15584
 
15604
- // new sbrk index is bigger than 2 ** 32 or endHeapIndex
15605
- if (MAX_MEMORY_INDEX < currentVirtualSbrkIndex + length || currentVirtualSbrkIndex + length > this.endHeapIndex) {
15606
- throw new OutOfMemory();
15607
- }
15585
+ declare class NibblesDecoder {
15586
+ private byte = new Int8Array(1);
15608
15587
 
15609
- const newVirtualSbrkIndex = tryAsSbrkIndex(this.virtualSbrkIndex + length);
15588
+ setByte(byte: number) {
15589
+ this.byte[0] = byte;
15590
+ }
15610
15591
 
15611
- // no alllocation needed
15612
- if (newVirtualSbrkIndex <= currentSbrkIndex) {
15613
- this.virtualSbrkIndex = newVirtualSbrkIndex;
15614
- return currentVirtualSbrkIndex;
15615
- }
15592
+ getHighNibble() {
15593
+ return (this.byte[0] & 0xf0) >>> 4;
15594
+ }
15616
15595
 
15617
- // standard allocation using "Writeable" pages
15618
- const newSbrkIndex = tryAsSbrkIndex(alignToPageSize(newVirtualSbrkIndex));
15619
- // TODO [MaSi]: `getPageNumber` works incorrectly for SbrkIndex. Sbrk index should be changed to MemoryIndex
15620
- const firstPageNumber = getPageNumber(currentSbrkIndex);
15621
- const pagesToAllocate = (newSbrkIndex - currentSbrkIndex) / PAGE_SIZE;
15622
- const rangeToAllocate = PageRange.fromStartAndLength(firstPageNumber, pagesToAllocate);
15596
+ getLowNibble() {
15597
+ return this.byte[0] & 0x0f;
15598
+ }
15623
15599
 
15624
- for (const pageNumber of rangeToAllocate) {
15625
- const page = new WriteablePage(pageNumber);
15626
- this.memory.set(pageNumber, page);
15627
- }
15600
+ getHighNibbleAsRegisterIndex() {
15601
+ return Math.min(this.getHighNibble(), MAX_REGISTER_INDEX);
15602
+ }
15628
15603
 
15629
- this.virtualSbrkIndex = newVirtualSbrkIndex;
15630
- this.sbrkIndex = newSbrkIndex;
15631
- return currentVirtualSbrkIndex;
15604
+ getLowNibbleAsRegisterIndex() {
15605
+ return Math.min(this.getLowNibble(), MAX_REGISTER_INDEX);
15632
15606
  }
15633
15607
 
15634
- getPageDump(pageNumber: PageNumber) {
15635
- const page = this.memory.get(pageNumber);
15636
- return page?.getPageDump() ?? null;
15608
+ getHighNibbleAsLength() {
15609
+ return Math.min(this.getHighNibble(), MAX_LENGTH);
15637
15610
  }
15638
15611
 
15639
- getDirtyPages() {
15640
- return this.memory.keys();
15612
+ getLowNibbleAsLength() {
15613
+ return Math.min(this.getLowNibble(), MAX_LENGTH);
15641
15614
  }
15642
15615
  }
15643
15616
 
15644
- declare class MemoryBuilder {
15645
- private readonly initialMemory: Map<PageNumber, MemoryPage> = new Map();
15646
- private isFinalized = false;
15647
-
15648
- private ensureNotFinalized() {
15649
- if (this.isFinalized) {
15650
- throw new FinalizedBuilderModification();
15651
- }
15652
- }
15617
+ type EmptyArgs = {
15618
+ type: ArgumentType.NO_ARGUMENTS;
15619
+ noOfBytesToSkip: number;
15620
+ };
15653
15621
 
15654
- private ensureNoReservedMemoryUsage(range: MemoryRange) {
15655
- if (range.overlapsWith(RESERVED_MEMORY_RANGE)) {
15656
- throw new ReservedMemoryFault();
15657
- }
15658
- }
15622
+ type OneImmediateArgs = {
15623
+ type: ArgumentType.ONE_IMMEDIATE;
15624
+ noOfBytesToSkip: number;
15625
+ /** V_X */
15626
+ immediateDecoder: ImmediateDecoder;
15627
+ };
15659
15628
 
15660
- /**
15661
- * Create entire readable pages to handle the `[start, end)` range.
15662
- *
15663
- * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15664
- * they need to be the start indices of the pages.
15665
- *
15666
- * The data passed will be placed at `start`, but might be shorter than the requested range,
15667
- * prepend it with zeros if you don't wish to have it at the beginning of the page.
15668
- */
15669
- setReadablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15670
- this.ensureNotFinalized();
15671
- check`${start < end} end has to be bigger than start`;
15672
- check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15673
- check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15674
- check`${data.length <= end - start} the initial data is longer than address range`;
15629
+ type ThreeRegistersArgs = {
15630
+ type: ArgumentType.THREE_REGISTERS;
15631
+ noOfBytesToSkip: number;
15632
+ /** W_A */
15633
+ firstRegisterIndex: number;
15634
+ /** W_B */
15635
+ secondRegisterIndex: number;
15636
+ /** W_D */
15637
+ thirdRegisterIndex: number;
15638
+ };
15675
15639
 
15676
- const length = end - start;
15677
- const range = MemoryRange.fromStartAndLength(start, length);
15640
+ type TwoRegistersArgs = {
15641
+ type: ArgumentType.TWO_REGISTERS;
15642
+ noOfBytesToSkip: number;
15643
+ /** W_A */
15644
+ firstRegisterIndex: number;
15645
+ /** W_D */
15646
+ secondRegisterIndex: number;
15647
+ };
15678
15648
 
15679
- this.ensureNoReservedMemoryUsage(range);
15649
+ type TwoRegistersOneImmediateArgs = {
15650
+ type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15651
+ noOfBytesToSkip: number;
15652
+ /** W_A */
15653
+ firstRegisterIndex: number;
15654
+ /** W_B */
15655
+ secondRegisterIndex: number;
15656
+ /** V_X */
15657
+ immediateDecoder: ImmediateDecoder;
15658
+ };
15680
15659
 
15681
- const pages = Array.from(PageRange.fromMemoryRange(range));
15682
- const noOfPages = pages.length;
15660
+ type OneRegisterOneImmediateArgs = {
15661
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
15662
+ noOfBytesToSkip: number;
15663
+ /** W_A */
15664
+ registerIndex: number;
15665
+ /** V_X */
15666
+ immediateDecoder: ImmediateDecoder;
15667
+ };
15683
15668
 
15684
- for (let i = 0; i < noOfPages; i++) {
15685
- const pageNumber = pages[i];
15686
- const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15687
- const page = new ReadablePage(pageNumber, dataChunk);
15688
- this.initialMemory.set(pageNumber, page);
15689
- }
15669
+ type OneRegisterOneExtendedWidthImmediateArgs = {
15670
+ type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
15671
+ noOfBytesToSkip: number;
15672
+ /** W_A */
15673
+ registerIndex: number;
15674
+ /** V_X */
15675
+ immediateDecoder: ExtendedWitdthImmediateDecoder;
15676
+ };
15690
15677
 
15691
- return this;
15692
- }
15678
+ type TwoRegistersTwoImmediatesArgs = {
15679
+ type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
15680
+ noOfBytesToSkip: number;
15681
+ /** W_A */
15682
+ firstRegisterIndex: number;
15683
+ /** W_B */
15684
+ secondRegisterIndex: number;
15685
+ /** V_X */
15686
+ firstImmediateDecoder: ImmediateDecoder;
15687
+ /** V_Y */
15688
+ secondImmediateDecoder: ImmediateDecoder;
15689
+ };
15693
15690
 
15694
- /**
15695
- * Create entire writeable pages to handle the `[start, end)` range.
15696
- *
15697
- * Note that both `start` and `end` must be multiple of the `PAGE_SIZE`, i.e.
15698
- * they need to be the start indices of the pages.
15699
- *
15700
- * The data passed will be placed at `start`, but might be shorter than the requested range,
15701
- * prepend it with zeros if you don't wish to have it at the beginning of the page.
15702
- */
15703
- setWriteablePages(start: MemoryIndex, end: MemoryIndex, data: Uint8Array = new Uint8Array()) {
15704
- this.ensureNotFinalized();
15705
- check`${start < end} end has to be bigger than start`;
15706
- check`${start % PAGE_SIZE === 0} start needs to be a multiple of page size (${PAGE_SIZE})`;
15707
- check`${end % PAGE_SIZE === 0} end needs to be a multiple of page size (${PAGE_SIZE})`;
15708
- check`${data.length <= end - start} the initial data is longer than address range`;
15691
+ type TwoImmediatesArgs = {
15692
+ type: ArgumentType.TWO_IMMEDIATES;
15693
+ noOfBytesToSkip: number;
15694
+ /** V_X */
15695
+ firstImmediateDecoder: ImmediateDecoder;
15696
+ /** V_Y */
15697
+ secondImmediateDecoder: ImmediateDecoder;
15698
+ };
15709
15699
 
15710
- const length = end - start;
15711
- const range = MemoryRange.fromStartAndLength(start, length);
15700
+ type TwoRegistersOneOffsetArgs = {
15701
+ type: ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15702
+ noOfBytesToSkip: number;
15703
+ /** W_A */
15704
+ firstRegisterIndex: number;
15705
+ /** W_B */
15706
+ secondRegisterIndex: number;
15707
+ nextPc: number;
15708
+ };
15712
15709
 
15713
- this.ensureNoReservedMemoryUsage(range);
15710
+ type OneRegisterOneImmediateOneOffsetArgs = {
15711
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
15712
+ noOfBytesToSkip: number;
15713
+ /** W_A */
15714
+ registerIndex: number;
15715
+ /** V_X */
15716
+ immediateDecoder: ImmediateDecoder;
15717
+ /** V_Y */
15718
+ nextPc: number;
15719
+ };
15714
15720
 
15715
- const pages = Array.from(PageRange.fromMemoryRange(range));
15716
- const noOfPages = pages.length;
15721
+ type OneRegisterTwoImmediatesArgs = {
15722
+ type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
15723
+ noOfBytesToSkip: number;
15724
+ /** W_A */
15725
+ registerIndex: number;
15726
+ /** V_X */
15727
+ firstImmediateDecoder: ImmediateDecoder;
15728
+ /** V_Y */
15729
+ secondImmediateDecoder: ImmediateDecoder;
15730
+ };
15717
15731
 
15718
- for (let i = 0; i < noOfPages; i++) {
15719
- const pageNumber = pages[i];
15720
- const dataChunk = data.subarray(i * PAGE_SIZE, (i + 1) * PAGE_SIZE);
15721
- const page = new WriteablePage(pageNumber, dataChunk);
15722
- this.initialMemory.set(pageNumber, page);
15723
- }
15732
+ type OneOffsetArgs = {
15733
+ type: ArgumentType.ONE_OFFSET;
15734
+ noOfBytesToSkip: number;
15735
+ /** V_X */
15736
+ nextPc: number;
15737
+ };
15724
15738
 
15725
- return this;
15739
+ type Args =
15740
+ | EmptyArgs
15741
+ | OneImmediateArgs
15742
+ | TwoRegistersArgs
15743
+ | ThreeRegistersArgs
15744
+ | TwoRegistersOneImmediateArgs
15745
+ | TwoRegistersTwoImmediatesArgs
15746
+ | OneRegisterOneImmediateOneOffsetArgs
15747
+ | TwoRegistersOneOffsetArgs
15748
+ | OneRegisterOneImmediateArgs
15749
+ | OneOffsetArgs
15750
+ | TwoImmediatesArgs
15751
+ | OneRegisterTwoImmediatesArgs
15752
+ | OneRegisterOneExtendedWidthImmediateArgs;
15753
+
15754
+ declare class ArgsDecoder {
15755
+ private nibblesDecoder = new NibblesDecoder();
15756
+ private offsetDecoder = new ImmediateDecoder();
15757
+ private code: Uint8Array = new Uint8Array();
15758
+ private mask: Mask = Mask.empty();
15759
+
15760
+ reset(code: Uint8Array, mask: Mask) {
15761
+ this.code = code;
15762
+ this.mask = mask;
15726
15763
  }
15727
15764
 
15728
- /**
15729
- * This function can be useful when page map and initial memory data are provided separatelly.
15730
- * You can use setWriteablePages/setReadablePages to create empty pages and then setData to fill them
15731
- */
15732
- setData(start: MemoryIndex, data: Uint8Array) {
15733
- this.ensureNotFinalized();
15734
- const pageOffset = start % PAGE_SIZE;
15735
- const remainingSpaceOnPage = PAGE_SIZE - pageOffset;
15736
- check`${data.length <= remainingSpaceOnPage} The data has to fit into a single page.`;
15765
+ fillArgs<T extends Args>(pc: number, result: T): void {
15766
+ const nextInstructionDistance = 1 + this.mask.getNoOfBytesToNextInstruction(pc + 1);
15767
+ result.noOfBytesToSkip = nextInstructionDistance;
15737
15768
 
15738
- const length = data.length;
15739
- const range = MemoryRange.fromStartAndLength(start, length);
15769
+ switch (result.type) {
15770
+ case ArgumentType.NO_ARGUMENTS:
15771
+ break;
15772
+
15773
+ case ArgumentType.ONE_IMMEDIATE: {
15774
+ const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
15775
+ const argsStartIndex = pc + 1;
15776
+ result.immediateDecoder.setBytes(this.code.subarray(argsStartIndex, argsStartIndex + immediateLength));
15777
+ break;
15778
+ }
15779
+
15780
+ case ArgumentType.THREE_REGISTERS: {
15781
+ const firstByte = this.code[pc + 1];
15782
+ const secondByte = this.code[pc + 2];
15783
+ this.nibblesDecoder.setByte(firstByte);
15784
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15785
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15786
+ this.nibblesDecoder.setByte(secondByte);
15787
+ result.thirdRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15788
+ break;
15789
+ }
15790
+
15791
+ case ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE: {
15792
+ const firstByte = this.code[pc + 1];
15793
+ this.nibblesDecoder.setByte(firstByte);
15794
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15795
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15796
+
15797
+ const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
15798
+ const immediateStartIndex = pc + 2;
15799
+ const immediateEndIndex = immediateStartIndex + immediateLength;
15800
+ result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
15801
+ break;
15802
+ }
15803
+
15804
+ case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET: {
15805
+ const firstByte = this.code[pc + 1];
15806
+ this.nibblesDecoder.setByte(firstByte);
15807
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15808
+
15809
+ const immediateLength = this.nibblesDecoder.getHighNibbleAsLength();
15810
+ const immediateStartIndex = pc + 2;
15811
+ const immediateEndIndex = immediateStartIndex + immediateLength;
15812
+ result.immediateDecoder.setBytes(this.code.subarray(immediateStartIndex, immediateEndIndex));
15813
+
15814
+ const offsetLength = Math.min(
15815
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15816
+ Math.max(0, nextInstructionDistance - 2 - immediateLength),
15817
+ );
15818
+ const offsetStartIndex = pc + 2 + immediateLength;
15819
+ const offsetEndIndex = offsetStartIndex + offsetLength;
15820
+ this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
15821
+
15822
+ result.nextPc = pc + this.offsetDecoder.getSigned();
15823
+ break;
15824
+ }
15825
+
15826
+ case ArgumentType.TWO_REGISTERS_ONE_OFFSET: {
15827
+ const firstByte = this.code[pc + 1];
15828
+ this.nibblesDecoder.setByte(firstByte);
15829
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15830
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15831
+
15832
+ const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
15833
+ const offsetStartIndex = pc + 2;
15834
+ const offsetEndIndex = offsetStartIndex + offsetLength;
15835
+ this.offsetDecoder.setBytes(this.code.subarray(offsetStartIndex, offsetEndIndex));
15836
+
15837
+ result.nextPc = pc + this.offsetDecoder.getSigned();
15838
+ break;
15839
+ }
15840
+
15841
+ case ArgumentType.TWO_REGISTERS: {
15842
+ const firstByte = this.code[pc + 1];
15843
+ this.nibblesDecoder.setByte(firstByte);
15844
+ result.firstRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15845
+ result.secondRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15846
+ break;
15847
+ }
15848
+
15849
+ case ArgumentType.ONE_OFFSET: {
15850
+ const offsetLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, nextInstructionDistance - 1);
15851
+ const offsetStartIndex = pc + 1;
15852
+ const offsetEndIndex = offsetStartIndex + offsetLength;
15853
+ const offsetBytes = this.code.subarray(offsetStartIndex, offsetEndIndex);
15854
+ this.offsetDecoder.setBytes(offsetBytes);
15855
+ const offsetValue = this.offsetDecoder.getSigned();
15856
+ result.nextPc = pc + offsetValue;
15857
+ break;
15858
+ }
15859
+
15860
+ case ArgumentType.ONE_REGISTER_ONE_IMMEDIATE: {
15861
+ const firstByte = this.code[pc + 1];
15862
+ this.nibblesDecoder.setByte(firstByte);
15863
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15864
+
15865
+ const immediateLength = Math.min(IMMEDIATE_AND_OFFSET_MAX_LENGTH, Math.max(0, nextInstructionDistance - 2));
15866
+ const immediateStartIndex = pc + 2;
15867
+ const immediateEndIndex = immediateStartIndex + immediateLength;
15868
+ const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
15869
+ result.immediateDecoder.setBytes(immediateBytes);
15870
+ break;
15871
+ }
15872
+
15873
+ case ArgumentType.TWO_IMMEDIATES: {
15874
+ const firstByte = this.code[pc + 1];
15875
+ this.nibblesDecoder.setByte(firstByte);
15876
+ const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
15877
+ const firstImmediateStartIndex = pc + 2;
15878
+ const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
15879
+ const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
15880
+ result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15881
+
15882
+ const secondImmediateLength = Math.min(
15883
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15884
+ Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
15885
+ );
15886
+ const secondImmediateStartIndex = firstImmediateEndIndex;
15887
+ const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
15888
+ const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
15889
+ result.secondImmediateDecoder.setBytes(secondImmediateBytes);
15890
+ break;
15891
+ }
15892
+
15893
+ case ArgumentType.ONE_REGISTER_TWO_IMMEDIATES: {
15894
+ const firstByte = this.code[pc + 1];
15895
+ this.nibblesDecoder.setByte(firstByte);
15896
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15897
+
15898
+ const firstImmediateLength = this.nibblesDecoder.getHighNibbleAsLength();
15899
+ const firstImmediateStartIndex = pc + 2;
15900
+ const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
15901
+ const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
15902
+ result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15903
+
15904
+ const secondImmediateLength = Math.min(
15905
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15906
+ Math.max(0, nextInstructionDistance - 2 - firstImmediateLength),
15907
+ );
15908
+ const secondImmediateStartIndex = firstImmediateEndIndex;
15909
+ const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
15910
+ const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
15911
+ result.secondImmediateDecoder.setBytes(secondImmediateBytes);
15912
+ break;
15913
+ }
15914
+
15915
+ case ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES: {
15916
+ const firstByte = this.code[pc + 1];
15917
+ this.nibblesDecoder.setByte(firstByte);
15918
+ result.firstRegisterIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15919
+ result.secondRegisterIndex = this.nibblesDecoder.getHighNibbleAsRegisterIndex();
15920
+
15921
+ const secondByte = this.code[pc + 2];
15922
+ this.nibblesDecoder.setByte(secondByte);
15923
+ const firstImmediateLength = this.nibblesDecoder.getLowNibbleAsLength();
15924
+ const firstImmediateStartIndex = pc + 3;
15925
+ const firstImmediateEndIndex = firstImmediateStartIndex + firstImmediateLength;
15926
+ const firstImmediateBytes = this.code.subarray(firstImmediateStartIndex, firstImmediateEndIndex);
15927
+ result.firstImmediateDecoder.setBytes(firstImmediateBytes);
15928
+
15929
+ const secondImmediateLength = Math.min(
15930
+ IMMEDIATE_AND_OFFSET_MAX_LENGTH,
15931
+ Math.max(0, nextInstructionDistance - 3 - firstImmediateLength),
15932
+ );
15933
+ const secondImmediateStartIndex = firstImmediateEndIndex;
15934
+ const secondImmediateEndIndex = secondImmediateStartIndex + secondImmediateLength;
15935
+ const secondImmediateBytes = this.code.subarray(secondImmediateStartIndex, secondImmediateEndIndex);
15936
+ result.secondImmediateDecoder.setBytes(secondImmediateBytes);
15937
+ break;
15938
+ }
15939
+
15940
+ case ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE: {
15941
+ const firstByte = this.code[pc + 1];
15942
+ this.nibblesDecoder.setByte(firstByte);
15943
+ result.registerIndex = this.nibblesDecoder.getLowNibbleAsRegisterIndex();
15944
+
15945
+ const immediateStartIndex = pc + 2;
15946
+ const immediateEndIndex = immediateStartIndex + 8;
15947
+ const immediateBytes = this.code.subarray(immediateStartIndex, immediateEndIndex);
15948
+ result.immediateDecoder.setBytes(immediateBytes);
15949
+ break;
15950
+ }
15951
+ }
15952
+ }
15953
+ }
15954
+
15955
+ declare const createResults = () => {
15956
+ const results = new Array(ARGUMENT_TYPE_LENGTH) as Results;
15957
+
15958
+ results[ArgumentType.NO_ARGUMENTS] = {
15959
+ type: ArgumentType.NO_ARGUMENTS,
15960
+ noOfBytesToSkip: 1,
15961
+ };
15962
+
15963
+ results[ArgumentType.ONE_IMMEDIATE] = {
15964
+ type: ArgumentType.ONE_IMMEDIATE,
15965
+ noOfBytesToSkip: 1,
15966
+ immediateDecoder: new ImmediateDecoder(),
15967
+ };
15968
+
15969
+ results[ArgumentType.TWO_REGISTERS] = {
15970
+ type: ArgumentType.TWO_REGISTERS,
15971
+ noOfBytesToSkip: 1,
15972
+ firstRegisterIndex: 0,
15973
+ secondRegisterIndex: 0,
15974
+ };
15975
+
15976
+ results[ArgumentType.THREE_REGISTERS] = {
15977
+ type: ArgumentType.THREE_REGISTERS,
15978
+ noOfBytesToSkip: 1,
15979
+ firstRegisterIndex: 0,
15980
+ secondRegisterIndex: 0,
15981
+ thirdRegisterIndex: 0,
15982
+ };
15983
+
15984
+ results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET] = {
15985
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET,
15986
+ noOfBytesToSkip: 1,
15987
+ registerIndex: 0,
15988
+ immediateDecoder: new ImmediateDecoder(),
15989
+ nextPc: 0,
15990
+ };
15991
+
15992
+ results[ArgumentType.TWO_REGISTERS_ONE_OFFSET] = {
15993
+ type: ArgumentType.TWO_REGISTERS_ONE_OFFSET,
15994
+ noOfBytesToSkip: 1,
15995
+ firstRegisterIndex: 0,
15996
+ secondRegisterIndex: 0,
15997
+ nextPc: 0,
15998
+ };
15999
+
16000
+ results[ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE] = {
16001
+ type: ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE,
16002
+ noOfBytesToSkip: 1,
16003
+ firstRegisterIndex: 0,
16004
+ secondRegisterIndex: 0,
16005
+ immediateDecoder: new ImmediateDecoder(),
16006
+ };
16007
+
16008
+ results[ArgumentType.ONE_REGISTER_ONE_IMMEDIATE] = {
16009
+ type: ArgumentType.ONE_REGISTER_ONE_IMMEDIATE,
16010
+ noOfBytesToSkip: 1,
16011
+ registerIndex: 0,
16012
+ immediateDecoder: new ImmediateDecoder(),
16013
+ };
16014
+
16015
+ results[ArgumentType.ONE_REGISTER_TWO_IMMEDIATES] = {
16016
+ type: ArgumentType.ONE_REGISTER_TWO_IMMEDIATES,
16017
+ noOfBytesToSkip: 1,
16018
+ registerIndex: 0,
16019
+ firstImmediateDecoder: new ImmediateDecoder(),
16020
+ secondImmediateDecoder: new ImmediateDecoder(),
16021
+ };
16022
+
16023
+ results[ArgumentType.ONE_OFFSET] = {
16024
+ type: ArgumentType.ONE_OFFSET,
16025
+ noOfBytesToSkip: 1,
16026
+ nextPc: 0,
16027
+ };
16028
+
16029
+ results[ArgumentType.TWO_IMMEDIATES] = {
16030
+ type: ArgumentType.TWO_IMMEDIATES,
16031
+ noOfBytesToSkip: 1,
16032
+ firstImmediateDecoder: new ImmediateDecoder(),
16033
+ secondImmediateDecoder: new ImmediateDecoder(),
16034
+ };
16035
+
16036
+ results[ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES] = {
16037
+ type: ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES,
16038
+ noOfBytesToSkip: 1,
16039
+ firstImmediateDecoder: new ImmediateDecoder(),
16040
+ secondImmediateDecoder: new ImmediateDecoder(),
16041
+ firstRegisterIndex: 0,
16042
+ secondRegisterIndex: 0,
16043
+ };
16044
+
16045
+ results[ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE] = {
16046
+ type: ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE,
16047
+ noOfBytesToSkip: 9,
16048
+ registerIndex: 0,
16049
+ immediateDecoder: new ExtendedWitdthImmediateDecoder(),
16050
+ };
16051
+
16052
+ return results;
16053
+ };
16054
+
16055
+ declare enum Instruction {
16056
+ TRAP = 0,
16057
+ FALLTHROUGH = 1,
16058
+ ECALLI = 10,
16059
+ LOAD_IMM_64 = 20,
16060
+ STORE_IMM_U8 = 30,
16061
+ STORE_IMM_U16 = 31,
16062
+ STORE_IMM_U32 = 32,
16063
+ STORE_IMM_U64 = 33,
16064
+ JUMP = 40,
16065
+ JUMP_IND = 50,
16066
+ LOAD_IMM = 51,
16067
+ LOAD_U8 = 52,
16068
+ LOAD_I8 = 53,
16069
+ LOAD_U16 = 54,
16070
+ LOAD_I16 = 55,
16071
+ LOAD_U32 = 56,
16072
+ LOAD_I32 = 57,
16073
+ LOAD_U64 = 58,
16074
+ STORE_U8 = 59,
16075
+ STORE_U16 = 60,
16076
+ STORE_U32 = 61,
16077
+ STORE_U64 = 62,
16078
+ STORE_IMM_IND_U8 = 70,
16079
+ STORE_IMM_IND_U16 = 71,
16080
+ STORE_IMM_IND_U32 = 72,
16081
+ STORE_IMM_IND_U64 = 73,
16082
+ LOAD_IMM_JUMP = 80,
16083
+ BRANCH_EQ_IMM = 81,
16084
+ BRANCH_NE_IMM = 82,
16085
+ BRANCH_LT_U_IMM = 83,
16086
+ BRANCH_LE_U_IMM = 84,
16087
+ BRANCH_GE_U_IMM = 85,
16088
+ BRANCH_GT_U_IMM = 86,
16089
+ BRANCH_LT_S_IMM = 87,
16090
+ BRANCH_LE_S_IMM = 88,
16091
+ BRANCH_GE_S_IMM = 89,
16092
+ BRANCH_GT_S_IMM = 90,
16093
+ MOVE_REG = 100,
16094
+ SBRK = 101,
16095
+ COUNT_SET_BITS_64 = 102,
16096
+ COUNT_SET_BITS_32 = 103,
16097
+ LEADING_ZERO_BITS_64 = 104,
16098
+ LEADING_ZERO_BITS_32 = 105,
16099
+ TRAILING_ZERO_BITS_64 = 106,
16100
+ TRAILING_ZERO_BITS_32 = 107,
16101
+ SIGN_EXTEND_8 = 108,
16102
+ SIGN_EXTEND_16 = 109,
16103
+ ZERO_EXTEND_16 = 110,
16104
+ REVERSE_BYTES = 111,
16105
+ STORE_IND_U8 = 120,
16106
+ STORE_IND_U16 = 121,
16107
+ STORE_IND_U32 = 122,
16108
+ STORE_IND_U64 = 123,
16109
+ LOAD_IND_U8 = 124,
16110
+ LOAD_IND_I8 = 125,
16111
+ LOAD_IND_U16 = 126,
16112
+ LOAD_IND_I16 = 127,
16113
+ LOAD_IND_U32 = 128,
16114
+ LOAD_IND_I32 = 129,
16115
+ LOAD_IND_U64 = 130,
16116
+ ADD_IMM_32 = 131,
16117
+ AND_IMM = 132,
16118
+ XOR_IMM = 133,
16119
+ OR_IMM = 134,
16120
+ MUL_IMM_32 = 135,
16121
+ SET_LT_U_IMM = 136,
16122
+ SET_LT_S_IMM = 137,
16123
+ SHLO_L_IMM_32 = 138,
16124
+ SHLO_R_IMM_32 = 139,
16125
+ SHAR_R_IMM_32 = 140,
16126
+ NEG_ADD_IMM_32 = 141,
16127
+ SET_GT_U_IMM = 142,
16128
+ SET_GT_S_IMM = 143,
16129
+ SHLO_L_IMM_ALT_32 = 144,
16130
+ SHLO_R_IMM_ALT_32 = 145,
16131
+ SHAR_R_IMM_ALT_32 = 146,
16132
+ CMOV_IZ_IMM = 147,
16133
+ CMOV_NZ_IMM = 148,
16134
+ ADD_IMM_64 = 149,
16135
+ MUL_IMM_64 = 150,
16136
+ SHLO_L_IMM_64 = 151,
16137
+ SHLO_R_IMM_64 = 152,
16138
+ SHAR_R_IMM_64 = 153,
16139
+ NEG_ADD_IMM_64 = 154,
16140
+ SHLO_L_IMM_ALT_64 = 155,
16141
+ SHLO_R_IMM_ALT_64 = 156,
16142
+ SHAR_R_IMM_ALT_64 = 157,
16143
+ ROT_R_64_IMM = 158,
16144
+ ROT_R_64_IMM_ALT = 159,
16145
+ ROT_R_32_IMM = 160,
16146
+ ROT_R_32_IMM_ALT = 161,
16147
+ BRANCH_EQ = 170,
16148
+ BRANCH_NE = 171,
16149
+ BRANCH_LT_U = 172,
16150
+ BRANCH_LT_S = 173,
16151
+ BRANCH_GE_U = 174,
16152
+ BRANCH_GE_S = 175,
16153
+ LOAD_IMM_JUMP_IND = 180,
16154
+ ADD_32 = 190,
16155
+ SUB_32 = 191,
16156
+ MUL_32 = 192,
16157
+ DIV_U_32 = 193,
16158
+ DIV_S_32 = 194,
16159
+ REM_U_32 = 195,
16160
+ REM_S_32 = 196,
16161
+ SHLO_L_32 = 197,
16162
+ SHLO_R_32 = 198,
16163
+ SHAR_R_32 = 199,
16164
+ ADD_64 = 200,
16165
+ SUB_64 = 201,
16166
+ MUL_64 = 202,
16167
+ DIV_U_64 = 203,
16168
+ DIV_S_64 = 204,
16169
+ REM_U_64 = 205,
16170
+ REM_S_64 = 206,
16171
+ SHLO_L_64 = 207,
16172
+ SHLO_R_64 = 208,
16173
+ SHAR_R_64 = 209,
16174
+ AND = 210,
16175
+ XOR = 211,
16176
+ OR = 212,
16177
+ MUL_UPPER_S_S = 213,
16178
+ MUL_UPPER_U_U = 214,
16179
+ MUL_UPPER_S_U = 215,
16180
+ SET_LT_U = 216,
16181
+ SET_LT_S = 217,
16182
+ CMOV_IZ = 218,
16183
+ CMOV_NZ = 219,
16184
+ ROT_L_64 = 220,
16185
+ ROT_L_32 = 221,
16186
+ ROT_R_64 = 222,
16187
+ ROT_R_32 = 223,
16188
+ AND_INV = 224,
16189
+ OR_INV = 225,
16190
+ XNOR = 226,
16191
+ MAX = 227,
16192
+ MAX_U = 228,
16193
+ MIN = 229,
16194
+ MIN_U = 230,
16195
+ }
16196
+
16197
+ declare const instructionArgumentTypeMap = (() => {
16198
+ const instructionArgumentTypeMap = new Array<ArgumentType>(HIGHEST_INSTRUCTION_NUMBER + 1);
16199
+
16200
+ instructionArgumentTypeMap[Instruction.TRAP] = ArgumentType.NO_ARGUMENTS;
16201
+ instructionArgumentTypeMap[Instruction.FALLTHROUGH] = ArgumentType.NO_ARGUMENTS;
16202
+
16203
+ instructionArgumentTypeMap[Instruction.ECALLI] = ArgumentType.ONE_IMMEDIATE;
16204
+
16205
+ instructionArgumentTypeMap[Instruction.LOAD_IMM_64] = ArgumentType.ONE_REGISTER_ONE_EXTENDED_WIDTH_IMMEDIATE;
16206
+
16207
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U8] = ArgumentType.TWO_IMMEDIATES;
16208
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U16] = ArgumentType.TWO_IMMEDIATES;
16209
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U32] = ArgumentType.TWO_IMMEDIATES;
16210
+ instructionArgumentTypeMap[Instruction.STORE_IMM_U64] = ArgumentType.TWO_IMMEDIATES;
16211
+
16212
+ instructionArgumentTypeMap[Instruction.JUMP] = ArgumentType.ONE_OFFSET;
16213
+
16214
+ instructionArgumentTypeMap[Instruction.JUMP_IND] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16215
+ instructionArgumentTypeMap[Instruction.LOAD_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16216
+ instructionArgumentTypeMap[Instruction.LOAD_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16217
+ instructionArgumentTypeMap[Instruction.LOAD_I8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16218
+ instructionArgumentTypeMap[Instruction.LOAD_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16219
+ instructionArgumentTypeMap[Instruction.LOAD_I16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16220
+ instructionArgumentTypeMap[Instruction.LOAD_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16221
+ instructionArgumentTypeMap[Instruction.LOAD_I32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16222
+ instructionArgumentTypeMap[Instruction.LOAD_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16223
+ instructionArgumentTypeMap[Instruction.STORE_U8] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16224
+ instructionArgumentTypeMap[Instruction.STORE_U16] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16225
+ instructionArgumentTypeMap[Instruction.STORE_U32] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16226
+ instructionArgumentTypeMap[Instruction.STORE_U64] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE;
16227
+
16228
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U8] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
16229
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U16] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
16230
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U32] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
16231
+ instructionArgumentTypeMap[Instruction.STORE_IMM_IND_U64] = ArgumentType.ONE_REGISTER_TWO_IMMEDIATES;
16232
+
16233
+ instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16234
+ instructionArgumentTypeMap[Instruction.BRANCH_EQ_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16235
+ instructionArgumentTypeMap[Instruction.BRANCH_NE_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16236
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16237
+ instructionArgumentTypeMap[Instruction.BRANCH_LE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16238
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16239
+ instructionArgumentTypeMap[Instruction.BRANCH_GT_U_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16240
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16241
+ instructionArgumentTypeMap[Instruction.BRANCH_LE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16242
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16243
+ instructionArgumentTypeMap[Instruction.BRANCH_GT_S_IMM] = ArgumentType.ONE_REGISTER_ONE_IMMEDIATE_ONE_OFFSET;
16244
+
16245
+ instructionArgumentTypeMap[Instruction.MOVE_REG] = ArgumentType.TWO_REGISTERS;
16246
+ instructionArgumentTypeMap[Instruction.SBRK] = ArgumentType.TWO_REGISTERS;
16247
+ instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_64] = ArgumentType.TWO_REGISTERS;
16248
+ instructionArgumentTypeMap[Instruction.COUNT_SET_BITS_32] = ArgumentType.TWO_REGISTERS;
16249
+ instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
16250
+ instructionArgumentTypeMap[Instruction.LEADING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
16251
+ instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_64] = ArgumentType.TWO_REGISTERS;
16252
+ instructionArgumentTypeMap[Instruction.TRAILING_ZERO_BITS_32] = ArgumentType.TWO_REGISTERS;
16253
+ instructionArgumentTypeMap[Instruction.SIGN_EXTEND_8] = ArgumentType.TWO_REGISTERS;
16254
+ instructionArgumentTypeMap[Instruction.SIGN_EXTEND_16] = ArgumentType.TWO_REGISTERS;
16255
+ instructionArgumentTypeMap[Instruction.ZERO_EXTEND_16] = ArgumentType.TWO_REGISTERS;
16256
+ instructionArgumentTypeMap[Instruction.REVERSE_BYTES] = ArgumentType.TWO_REGISTERS;
16257
+
16258
+ instructionArgumentTypeMap[Instruction.STORE_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16259
+ instructionArgumentTypeMap[Instruction.STORE_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16260
+ instructionArgumentTypeMap[Instruction.STORE_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16261
+ instructionArgumentTypeMap[Instruction.STORE_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16262
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16263
+ instructionArgumentTypeMap[Instruction.LOAD_IND_I8] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16264
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16265
+ instructionArgumentTypeMap[Instruction.LOAD_IND_I16] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16266
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16267
+ instructionArgumentTypeMap[Instruction.LOAD_IND_I32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16268
+ instructionArgumentTypeMap[Instruction.LOAD_IND_U64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16269
+ instructionArgumentTypeMap[Instruction.ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16270
+ instructionArgumentTypeMap[Instruction.ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16271
+ instructionArgumentTypeMap[Instruction.AND_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16272
+ instructionArgumentTypeMap[Instruction.XOR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16273
+ instructionArgumentTypeMap[Instruction.OR_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16274
+ instructionArgumentTypeMap[Instruction.MUL_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16275
+ instructionArgumentTypeMap[Instruction.MUL_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16276
+ instructionArgumentTypeMap[Instruction.SET_LT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16277
+ instructionArgumentTypeMap[Instruction.SET_LT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16278
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16279
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16280
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16281
+ instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16282
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16283
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16284
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16285
+ instructionArgumentTypeMap[Instruction.NEG_ADD_IMM_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16286
+ instructionArgumentTypeMap[Instruction.SET_GT_U_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16287
+ instructionArgumentTypeMap[Instruction.SET_GT_S_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16288
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16289
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16290
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_32] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16291
+ instructionArgumentTypeMap[Instruction.SHLO_L_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16292
+ instructionArgumentTypeMap[Instruction.SHLO_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16293
+ instructionArgumentTypeMap[Instruction.SHAR_R_IMM_ALT_64] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16294
+ instructionArgumentTypeMap[Instruction.CMOV_IZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16295
+ instructionArgumentTypeMap[Instruction.CMOV_NZ_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16296
+ instructionArgumentTypeMap[Instruction.ROT_R_64_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16297
+ instructionArgumentTypeMap[Instruction.ROT_R_64_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16298
+ instructionArgumentTypeMap[Instruction.ROT_R_32_IMM] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
16299
+ instructionArgumentTypeMap[Instruction.ROT_R_32_IMM_ALT] = ArgumentType.TWO_REGISTERS_ONE_IMMEDIATE;
15740
16300
 
15741
- this.ensureNoReservedMemoryUsage(range);
16301
+ instructionArgumentTypeMap[Instruction.BRANCH_EQ] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16302
+ instructionArgumentTypeMap[Instruction.BRANCH_NE] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16303
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16304
+ instructionArgumentTypeMap[Instruction.BRANCH_LT_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16305
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_U] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
16306
+ instructionArgumentTypeMap[Instruction.BRANCH_GE_S] = ArgumentType.TWO_REGISTERS_ONE_OFFSET;
15742
16307
 
15743
- const pageNumber = getPageNumber(start);
15744
- const page = this.initialMemory.get(pageNumber);
16308
+ instructionArgumentTypeMap[Instruction.LOAD_IMM_JUMP_IND] = ArgumentType.TWO_REGISTERS_TWO_IMMEDIATES;
15745
16309
 
15746
- if (page === undefined) {
15747
- throw new PageNotExist();
15748
- }
16310
+ instructionArgumentTypeMap[Instruction.ADD_32] = ArgumentType.THREE_REGISTERS;
16311
+ instructionArgumentTypeMap[Instruction.ADD_64] = ArgumentType.THREE_REGISTERS;
16312
+ instructionArgumentTypeMap[Instruction.SUB_32] = ArgumentType.THREE_REGISTERS;
16313
+ instructionArgumentTypeMap[Instruction.SUB_64] = ArgumentType.THREE_REGISTERS;
16314
+ instructionArgumentTypeMap[Instruction.AND] = ArgumentType.THREE_REGISTERS;
16315
+ instructionArgumentTypeMap[Instruction.XOR] = ArgumentType.THREE_REGISTERS;
16316
+ instructionArgumentTypeMap[Instruction.OR] = ArgumentType.THREE_REGISTERS;
16317
+ instructionArgumentTypeMap[Instruction.MUL_32] = ArgumentType.THREE_REGISTERS;
16318
+ instructionArgumentTypeMap[Instruction.MUL_64] = ArgumentType.THREE_REGISTERS;
16319
+ instructionArgumentTypeMap[Instruction.MUL_UPPER_S_S] = ArgumentType.THREE_REGISTERS;
16320
+ instructionArgumentTypeMap[Instruction.MUL_UPPER_U_U] = ArgumentType.THREE_REGISTERS;
16321
+ instructionArgumentTypeMap[Instruction.MUL_UPPER_S_U] = ArgumentType.THREE_REGISTERS;
16322
+ instructionArgumentTypeMap[Instruction.DIV_U_32] = ArgumentType.THREE_REGISTERS;
16323
+ instructionArgumentTypeMap[Instruction.DIV_S_32] = ArgumentType.THREE_REGISTERS;
16324
+ instructionArgumentTypeMap[Instruction.REM_U_32] = ArgumentType.THREE_REGISTERS;
16325
+ instructionArgumentTypeMap[Instruction.REM_S_32] = ArgumentType.THREE_REGISTERS;
16326
+ instructionArgumentTypeMap[Instruction.DIV_U_64] = ArgumentType.THREE_REGISTERS;
16327
+ instructionArgumentTypeMap[Instruction.DIV_S_64] = ArgumentType.THREE_REGISTERS;
16328
+ instructionArgumentTypeMap[Instruction.REM_U_64] = ArgumentType.THREE_REGISTERS;
16329
+ instructionArgumentTypeMap[Instruction.REM_S_64] = ArgumentType.THREE_REGISTERS;
16330
+ instructionArgumentTypeMap[Instruction.SET_LT_U] = ArgumentType.THREE_REGISTERS;
16331
+ instructionArgumentTypeMap[Instruction.SET_LT_S] = ArgumentType.THREE_REGISTERS;
16332
+ instructionArgumentTypeMap[Instruction.SHLO_L_32] = ArgumentType.THREE_REGISTERS;
16333
+ instructionArgumentTypeMap[Instruction.SHLO_R_32] = ArgumentType.THREE_REGISTERS;
16334
+ instructionArgumentTypeMap[Instruction.SHAR_R_32] = ArgumentType.THREE_REGISTERS;
16335
+ instructionArgumentTypeMap[Instruction.SHLO_L_64] = ArgumentType.THREE_REGISTERS;
16336
+ instructionArgumentTypeMap[Instruction.SHLO_R_64] = ArgumentType.THREE_REGISTERS;
16337
+ instructionArgumentTypeMap[Instruction.SHAR_R_64] = ArgumentType.THREE_REGISTERS;
16338
+ instructionArgumentTypeMap[Instruction.CMOV_IZ] = ArgumentType.THREE_REGISTERS;
16339
+ instructionArgumentTypeMap[Instruction.CMOV_NZ] = ArgumentType.THREE_REGISTERS;
16340
+ instructionArgumentTypeMap[Instruction.ROT_L_64] = ArgumentType.THREE_REGISTERS;
16341
+ instructionArgumentTypeMap[Instruction.ROT_L_32] = ArgumentType.THREE_REGISTERS;
16342
+ instructionArgumentTypeMap[Instruction.ROT_R_64] = ArgumentType.THREE_REGISTERS;
16343
+ instructionArgumentTypeMap[Instruction.ROT_R_32] = ArgumentType.THREE_REGISTERS;
16344
+ instructionArgumentTypeMap[Instruction.AND_INV] = ArgumentType.THREE_REGISTERS;
16345
+ instructionArgumentTypeMap[Instruction.OR_INV] = ArgumentType.THREE_REGISTERS;
16346
+ instructionArgumentTypeMap[Instruction.XNOR] = ArgumentType.THREE_REGISTERS;
16347
+ instructionArgumentTypeMap[Instruction.MAX] = ArgumentType.THREE_REGISTERS;
16348
+ instructionArgumentTypeMap[Instruction.MAX_U] = ArgumentType.THREE_REGISTERS;
16349
+ instructionArgumentTypeMap[Instruction.MIN] = ArgumentType.THREE_REGISTERS;
16350
+ instructionArgumentTypeMap[Instruction.MIN_U] = ArgumentType.THREE_REGISTERS;
15749
16351
 
15750
- const startPageIndex = tryAsPageIndex(start - page.start);
15751
- page.setData(startPageIndex, data);
16352
+ return instructionArgumentTypeMap;
16353
+ })();
15752
16354
 
15753
- return this;
15754
- }
16355
+ declare class BasicBlocks {
16356
+ private basicBlocks: Set<number> = new Set();
15755
16357
 
15756
- finalize(startHeapIndex: MemoryIndex, endHeapIndex: SbrkIndex): Memory {
15757
- check`
15758
- ${startHeapIndex <= endHeapIndex}
15759
- startHeapIndex (${startHeapIndex}) has to be less than or equal to endHeapIndex (${endHeapIndex})
15760
- `;
15761
- this.ensureNotFinalized();
16358
+ reset(code: Uint8Array, mask: Mask) {
16359
+ this.basicBlocks.clear();
16360
+ this.basicBlocks.add(0);
16361
+ const codeLength = code.length;
15762
16362
 
15763
- const heapRange = MemoryRange.fromStartAndLength(startHeapIndex, endHeapIndex - startHeapIndex);
15764
- const heapPagesRange = PageRange.fromMemoryRange(heapRange);
15765
- const initializedPageNumbers = Array.from(this.initialMemory.keys());
16363
+ const isBasicBlockTermination = (index: number) =>
16364
+ mask.isInstruction(index) && terminationInstructions[code[index]];
15766
16365
 
15767
- for (const pageNumber of initializedPageNumbers) {
15768
- if (heapPagesRange.isInRange(pageNumber)) {
15769
- throw new IncorrectSbrkIndex();
16366
+ for (let i = 0; i < codeLength; i++) {
16367
+ if (mask.isInstruction(i) && isBasicBlockTermination(i)) {
16368
+ this.basicBlocks.add(i + 1 + mask.getNoOfBytesToNextInstruction(i + 1));
15770
16369
  }
15771
16370
  }
16371
+ }
15772
16372
 
15773
- const memory = Memory.fromInitialMemory({
15774
- memory: this.initialMemory,
15775
- sbrkIndex: tryAsSbrkIndex(startHeapIndex),
15776
- endHeapIndex,
15777
- });
16373
+ isBeginningOfBasicBlock(index: number) {
16374
+ return this.basicBlocks.has(index);
16375
+ }
16376
+ }
15778
16377
 
15779
- this.isFinalized = true;
15780
- return memory;
16378
+ declare enum Result {
16379
+ HALT = 0,
16380
+ PANIC = 1,
16381
+ FAULT_ACCESS = 2,
16382
+ FAULT = 3,
16383
+ HOST = 4,
16384
+ }
16385
+
16386
+ declare class InstructionResult {
16387
+ public nextPc = 0;
16388
+ public status: Result | null = null;
16389
+ /**
16390
+ * A numeric exit parameter of the PVM.
16391
+ *
16392
+ * In case of a `status === Result.FAULT` this will be the memory address
16393
+ * that triggered the fault.
16394
+ * In case of a `status === Result.HOST` this will be the host call index
16395
+ * that should be invoked.
16396
+ *
16397
+ * In any other circumstance the value should be `null`.
16398
+ */
16399
+ public exitParam: number | null = null;
16400
+
16401
+ reset() {
16402
+ this.nextPc = 0;
16403
+ this.status = null;
16404
+ this.exitParam = null;
15781
16405
  }
15782
16406
  }
15783
16407
 
@@ -16762,7 +17386,7 @@ declare class StoreOps {
16762
17386
  this.instructionResult.status = Result.FAULT_ACCESS;
16763
17387
  } else {
16764
17388
  this.instructionResult.status = Result.FAULT;
16765
- this.instructionResult.exitParam = getStartPageIndex(storeResult.error.address);
17389
+ this.instructionResult.exitParam = getStartPageIndex(tryAsMemoryIndex(storeResult.error.address));
16766
17390
  }
16767
17391
  }
16768
17392
  }
@@ -17563,34 +18187,20 @@ declare class ProgramDecoder {
17563
18187
  }
17564
18188
  }
17565
18189
 
17566
- /**
17567
- * Inner status codes for the PVM
17568
- *
17569
- * https://graypaper.fluffylabs.dev/#/85129da/2cae022cae02?v=0.6.3
17570
- */
17571
- declare enum Status {
17572
- OK = 255,
17573
- HALT = 0,
17574
- PANIC = 1,
17575
- FAULT = 2,
17576
- HOST = 3,
17577
- OOG = 4,
17578
- }
17579
-
17580
18190
  type InterpreterOptions = {
17581
18191
  useSbrkGas?: boolean;
17582
18192
  };
17583
18193
 
17584
18194
  declare const logger = Logger.new(import.meta.filename, "pvm");
17585
18195
 
17586
- declare class Interpreter {
18196
+ declare class Interpreter implements IPvmInterpreter {
17587
18197
  private readonly useSbrkGas: boolean;
17588
- private registers = new Registers();
18198
+ readonly registers = new Registers();
18199
+ readonly memory = new Memory();
18200
+ gas = gasCounter(tryAsGas(0));
17589
18201
  private code: Uint8Array = new Uint8Array();
17590
18202
  private mask = Mask.empty();
17591
18203
  private pc = 0;
17592
- private gas = gasCounter(tryAsGas(0));
17593
- private initialGas = gasCounter(tryAsGas(0));
17594
18204
  private argsDecoder: ArgsDecoder;
17595
18205
  private threeRegsDispatcher: ThreeRegsDispatcher;
17596
18206
  private twoRegsOneImmDispatcher: TwoRegsOneImmDispatcher;
@@ -17600,7 +18210,6 @@ declare class Interpreter {
17600
18210
  private oneOffsetDispatcher: OneOffsetDispatcher;
17601
18211
  private oneRegOneImmDispatcher: OneRegOneImmDispatcher;
17602
18212
  private instructionResult = new InstructionResult();
17603
- private memory = new Memory();
17604
18213
  private twoImmsDispatcher: TwoImmsDispatcher;
17605
18214
  private oneRegTwoImmsDispatcher: OneRegTwoImmsDispatcher;
17606
18215
  private noArgsDispatcher: NoArgsDispatcher;
@@ -17654,7 +18263,12 @@ declare class Interpreter {
17654
18263
  this.oneRegOneExtImmDispatcher = new OneRegOneExtImmDispatcher(loadOps);
17655
18264
  }
17656
18265
 
17657
- reset(rawProgram: Uint8Array, pc: number, gas: Gas, maybeRegisters?: Registers, maybeMemory?: Memory) {
18266
+ resetJam(program: Uint8Array, args: Uint8Array, pc: number, gas: Gas) {
18267
+ const p = Program.fromSpi(program, args, true);
18268
+ this.resetGeneric(p.code, pc, gas, p.registers, p.memory);
18269
+ }
18270
+
18271
+ resetGeneric(rawProgram: Uint8Array, pc: number, gas: Gas, maybeRegisters?: Registers, maybeMemory?: Memory) {
17658
18272
  const programDecoder = new ProgramDecoder(rawProgram);
17659
18273
  this.code = programDecoder.getCode();
17660
18274
  this.mask = programDecoder.getMask();
@@ -17662,7 +18276,6 @@ declare class Interpreter {
17662
18276
 
17663
18277
  this.pc = pc;
17664
18278
  this.gas = gasCounter(gas);
17665
- this.initialGas = gasCounter(gas);
17666
18279
  this.status = Status.OK;
17667
18280
  this.argsDecoder.reset(this.code, this.mask);
17668
18281
  this.basicBlocks.reset(this.code, this.mask);
@@ -17804,10 +18417,6 @@ declare class Interpreter {
17804
18417
  return this.status;
17805
18418
  }
17806
18419
 
17807
- getRegisters() {
17808
- return this.registers;
17809
- }
17810
-
17811
18420
  getPC() {
17812
18421
  return this.pc;
17813
18422
  }
@@ -17816,258 +18425,91 @@ declare class Interpreter {
17816
18425
  this.pc = nextPc;
17817
18426
  }
17818
18427
 
17819
- getGas(): Gas {
17820
- return this.gas.get();
17821
- }
17822
-
17823
- getGasConsumed(): Gas {
17824
- const gasConsumed = tryAsBigGas(this.initialGas.get()) - tryAsBigGas(this.gas.get());
17825
-
17826
- if (gasConsumed < 0) {
17827
- return this.initialGas.get();
17828
- }
17829
-
17830
- return tryAsBigGas(gasConsumed);
17831
- }
17832
-
17833
- getGasCounter(): GasCounter {
17834
- return this.gas;
17835
- }
17836
-
17837
18428
  getStatus() {
17838
18429
  return this.status;
17839
18430
  }
17840
18431
 
17841
18432
  getExitParam(): null | U32 {
17842
18433
  const p = this.instructionResult.exitParam;
17843
- return p !== null ? tryAsU32(p) : p;
17844
- }
17845
-
17846
- getMemory() {
17847
- return this.memory;
17848
- }
17849
-
17850
- getMemoryPage(pageNumber: number): null | Uint8Array {
17851
- return this.memory.getPageDump(tryAsPageNumber(pageNumber));
17852
- }
17853
-
17854
- calculateBlockGasCost(): Map<string, number> {
17855
- const codeLength = this.code.length;
17856
- const blocks: Map<string, number> = new Map();
17857
- let currentBlock = "0";
17858
- let gasCost = 0;
17859
- const getNextIstructionIndex = (index: number) => index + 1 + this.mask.getNoOfBytesToNextInstruction(index + 1);
17860
-
17861
- for (let index = 0; index < codeLength; index = getNextIstructionIndex(index)) {
17862
- const instruction = this.code[index];
17863
- if (this.basicBlocks.isBeginningOfBasicBlock(index)) {
17864
- blocks.set(currentBlock, gasCost);
17865
- currentBlock = index.toString();
17866
- gasCost = 0;
17867
- }
17868
-
17869
- gasCost += instructionGasMap[instruction];
17870
- }
17871
-
17872
- blocks.set(currentBlock, gasCost);
17873
-
17874
- return blocks;
17875
- }
17876
- }
17877
-
17878
- type index$8_BigGas = BigGas;
17879
- type index$8_Gas = Gas;
17880
- type index$8_GasCounter = GasCounter;
17881
- type index$8_Interpreter = Interpreter;
17882
- declare const index$8_Interpreter: typeof Interpreter;
17883
- type index$8_InterpreterOptions = InterpreterOptions;
17884
- type index$8_Memory = Memory;
17885
- declare const index$8_Memory: typeof Memory;
17886
- type index$8_MemoryBuilder = MemoryBuilder;
17887
- declare const index$8_MemoryBuilder: typeof MemoryBuilder;
17888
- type index$8_MemoryIndex = MemoryIndex;
17889
- type index$8_Registers = Registers;
17890
- declare const index$8_Registers: typeof Registers;
17891
- type index$8_SbrkIndex = SbrkIndex;
17892
- type index$8_SmallGas = SmallGas;
17893
- declare const index$8_gasCounter: typeof gasCounter;
17894
- declare const index$8_logger: typeof logger;
17895
- declare const index$8_tryAsBigGas: typeof tryAsBigGas;
17896
- declare const index$8_tryAsGas: typeof tryAsGas;
17897
- declare const index$8_tryAsMemoryIndex: typeof tryAsMemoryIndex;
17898
- declare const index$8_tryAsSbrkIndex: typeof tryAsSbrkIndex;
17899
- declare const index$8_tryAsSmallGas: typeof tryAsSmallGas;
17900
- declare namespace index$8 {
17901
- 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 };
17902
- 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 };
17903
- }
17904
-
17905
- interface IHostCallMemory {
17906
- storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds>;
17907
- loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds>;
17908
- }
17909
-
17910
- declare class HostCallMemory implements IHostCallMemory {
17911
- constructor(private readonly memory: Memory) {}
17912
-
17913
- storeFrom(address: U64, bytes: Uint8Array): Result$2<OK, PageFault | OutOfBounds> {
17914
- if (bytes.length === 0) {
17915
- return Result.ok(OK);
17916
- }
17917
-
17918
- if (address + tryAsU64(bytes.length) > MEMORY_SIZE) {
17919
- return Result.error(
17920
- new OutOfBounds(),
17921
- () => `Memory access out of bounds: address ${address} + length ${bytes.length} exceeds memory size`,
17922
- );
17923
- }
17924
-
17925
- return this.memory.storeFrom(tryAsMemoryIndex(Number(address)), bytes);
17926
- }
17927
-
17928
- loadInto(result: Uint8Array, startAddress: U64): Result$2<OK, PageFault | OutOfBounds> {
17929
- if (result.length === 0) {
17930
- return Result.ok(OK);
17931
- }
17932
-
17933
- if (startAddress + tryAsU64(result.length) > MEMORY_SIZE) {
17934
- return Result.error(
17935
- new OutOfBounds(),
17936
- () => `Memory access out of bounds: address ${startAddress} + length ${result.length} exceeds memory size`,
17937
- );
17938
- }
17939
-
17940
- return this.memory.loadInto(result, tryAsMemoryIndex(Number(startAddress)));
17941
- }
17942
- }
17943
-
17944
- interface IHostCallRegisters {
17945
- get(registerIndex: number): U64;
17946
- set(registerIndex: number, value: U64): void;
17947
- }
17948
-
17949
- declare class HostCallRegisters implements IHostCallRegisters {
17950
- constructor(private readonly registers: Registers) {}
17951
-
17952
- get(registerIndex: number): U64 {
17953
- return tryAsU64(this.registers.getU64(registerIndex));
17954
- }
17955
-
17956
- set(registerIndex: number, value: U64) {
17957
- this.registers.setU64(registerIndex, value);
17958
- }
17959
- }
17960
-
17961
- /** Strictly-typed host call index. */
17962
- type HostCallIndex = Opaque<U32, "HostCallIndex[U32]">;
17963
- /** Attempt to convert a number into `HostCallIndex`. */
17964
- declare const tryAsHostCallIndex = (v: number): HostCallIndex => asOpaqueType(tryAsU32(v));
17965
-
17966
- /**
17967
- * Host-call exit reason.
17968
- *
17969
- * https://graypaper.fluffylabs.dev/#/ab2cdbd/24a30124a501?v=0.7.2
17970
- */
17971
- declare enum PvmExecution {
17972
- Halt = 0,
17973
- Panic = 1,
17974
- OOG = 2, // out-of-gas
17975
- }
17976
-
17977
- /** A utility function to easily trace a bunch of registers. */
17978
- declare function traceRegisters(...regs: number[]) {
17979
- return regs.map(tryAsRegisterIndex);
17980
- }
17981
-
17982
- /** An interface for a host call implementation */
17983
- interface HostCallHandler {
17984
- /** Index of that host call (i.e. what PVM invokes via `ecalli`) */
17985
- readonly index: HostCallIndex;
17986
-
17987
- /**
17988
- * The gas cost of invocation of that host call.
17989
- *
17990
- * NOTE: `((reg: IHostCallRegisters) => Gas)` function is for compatibility reasons: pre GP 0.7.2
17991
- */
17992
- readonly basicGasCost: SmallGas | ((reg: IHostCallRegisters) => Gas);
17993
-
17994
- /** Currently executing service id. */
17995
- readonly currentServiceId: U32;
17996
-
17997
- /** Input&Output registers that we should add to tracing log. */
17998
- readonly tracedRegisters: RegisterIndex[];
18434
+ return p !== null ? tryAsU32(p) : p;
18435
+ }
17999
18436
 
18000
- /**
18001
- * Actually execute the host call.
18002
- *
18003
- * NOTE the call is ALLOWED and expected to modify registers and memory.
18004
- */
18005
- execute(gas: GasCounter, regs: IHostCallRegisters, memory: IHostCallMemory): Promise<undefined | PvmExecution>;
18006
- }
18437
+ getMemoryPage(pageNumber: number): null | Uint8Array {
18438
+ return this.memory.getPageDump(tryAsPageNumber(pageNumber));
18439
+ }
18007
18440
 
18008
- /** Container for all available host calls. */
18009
- declare class HostCallsManager {
18010
- private readonly hostCalls = new Map<HostCallIndex, HostCallHandler>();
18011
- private readonly missing;
18441
+ calculateBlockGasCost(): Map<string, number> {
18442
+ const codeLength = this.code.length;
18443
+ const blocks: Map<string, number> = new Map();
18444
+ let currentBlock = "0";
18445
+ let gasCost = 0;
18446
+ const getNextIstructionIndex = (index: number) => index + 1 + this.mask.getNoOfBytesToNextInstruction(index + 1);
18012
18447
 
18013
- constructor({
18014
- missing,
18015
- handlers = [],
18016
- }: {
18017
- missing: HostCallHandler;
18018
- handlers?: HostCallHandler[];
18019
- }) {
18020
- this.missing = missing;
18448
+ for (let index = 0; index < codeLength; index = getNextIstructionIndex(index)) {
18449
+ const instruction = this.code[index];
18450
+ if (this.basicBlocks.isBeginningOfBasicBlock(index)) {
18451
+ blocks.set(currentBlock, gasCost);
18452
+ currentBlock = index.toString();
18453
+ gasCost = 0;
18454
+ }
18021
18455
 
18022
- for (const handler of handlers) {
18023
- check`${this.hostCalls.get(handler.index) === undefined} Overwriting host call handler at index ${handler.index}`;
18024
- this.hostCalls.set(handler.index, handler);
18456
+ gasCost += instructionGasMap[instruction];
18025
18457
  }
18026
- }
18027
18458
 
18028
- /** Get a host call by index. */
18029
- get(hostCallIndex: HostCallIndex): HostCallHandler {
18030
- return this.hostCalls.get(hostCallIndex) ?? this.missing;
18031
- }
18459
+ blocks.set(currentBlock, gasCost);
18032
18460
 
18033
- traceHostCall(
18034
- context: string,
18035
- hostCallIndex: HostCallIndex,
18036
- hostCallHandler: HostCallHandler,
18037
- registers: IHostCallRegisters,
18038
- gas: Gas,
18039
- ) {
18040
- const { currentServiceId } = hostCallHandler;
18041
- const requested = hostCallIndex !== hostCallHandler.index ? ` (${hostCallIndex})` : "";
18042
- const name = `${hostCallHandler.constructor.name}:${hostCallHandler.index}`;
18043
- const registerValues = hostCallHandler.tracedRegisters
18044
- .map((idx) => [idx.toString().padStart(2, "0"), registers.get(idx)] as const)
18045
- .filter((v) => v[1] !== 0n)
18046
- .map(([idx, value]) => {
18047
- return `r${idx}=${value} (0x${value.toString(16)})`;
18048
- })
18049
- .join(", ");
18050
- logger.insane`[${currentServiceId}] ${context} ${name}${requested}. Gas: ${gas}. Regs: ${registerValues}.`;
18461
+ return blocks;
18051
18462
  }
18052
18463
  }
18053
18464
 
18054
- type ResolveFn = (pvm: Interpreter) => void;
18465
+ type index$6_Interpreter = Interpreter;
18466
+ declare const index$6_Interpreter: typeof Interpreter;
18467
+ type index$6_InterpreterOptions = InterpreterOptions;
18468
+ type index$6_Memory = Memory;
18469
+ declare const index$6_Memory: typeof Memory;
18470
+ type index$6_MemoryBuilder = MemoryBuilder;
18471
+ declare const index$6_MemoryBuilder: typeof MemoryBuilder;
18472
+ type index$6_MemoryIndex = MemoryIndex;
18473
+ type index$6_Registers = Registers;
18474
+ declare const index$6_Registers: typeof Registers;
18475
+ type index$6_SbrkIndex = SbrkIndex;
18476
+ declare const index$6_gasCounter: typeof gasCounter;
18477
+ declare const index$6_logger: typeof logger;
18478
+ declare const index$6_tryAsMemoryIndex: typeof tryAsMemoryIndex;
18479
+ declare const index$6_tryAsSbrkIndex: typeof tryAsSbrkIndex;
18480
+ declare namespace index$6 {
18481
+ 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 };
18482
+ export type { index$6_InterpreterOptions as InterpreterOptions, index$6_MemoryIndex as MemoryIndex, index$6_SbrkIndex as SbrkIndex };
18483
+ }
18055
18484
 
18485
+ type ResolveFn = (pvm: IPvmInterpreter) => void;
18486
+
18487
+ // TODO [MaSo] Delete this & also make host calls independent from intepreters.
18056
18488
  declare class InterpreterInstanceManager {
18057
- private instances: Interpreter[] = [];
18058
18489
  private waitingQueue: ResolveFn[] = [];
18059
18490
 
18060
- constructor(noOfPvmInstances: number) {
18061
- for (let i = 0; i < noOfPvmInstances; i++) {
18062
- this.instances.push(
18063
- new Interpreter({
18064
- useSbrkGas: false,
18065
- }),
18066
- );
18491
+ private constructor(private readonly instances: IPvmInterpreter[]) {}
18492
+
18493
+ static async new(interpreter: PvmBackend): Promise<InterpreterInstanceManager> {
18494
+ const instances: IPvmInterpreter[] = [];
18495
+ switch (interpreter) {
18496
+ case PvmBackend.BuiltIn:
18497
+ instances.push(
18498
+ new Interpreter({
18499
+ useSbrkGas: false,
18500
+ }),
18501
+ );
18502
+ break;
18503
+ case PvmBackend.Ananas:
18504
+ instances.push(await AnanasInterpreter.new());
18505
+ break;
18506
+ default:
18507
+ assertNever(interpreter);
18067
18508
  }
18509
+ return new InterpreterInstanceManager(instances);
18068
18510
  }
18069
18511
 
18070
- async getInstance(): Promise<Interpreter> {
18512
+ async getInstance(): Promise<IPvmInterpreter> {
18071
18513
  const instance = this.instances.pop();
18072
18514
  if (instance !== undefined) {
18073
18515
  return Promise.resolve(instance);
@@ -18077,7 +18519,7 @@ declare class InterpreterInstanceManager {
18077
18519
  });
18078
18520
  }
18079
18521
 
18080
- releaseInstance(pvm: Interpreter) {
18522
+ releaseInstance(pvm: IPvmInterpreter) {
18081
18523
  const waiting = this.waitingQueue.shift();
18082
18524
  if (waiting !== undefined) {
18083
18525
  return waiting(pvm);
@@ -18120,21 +18562,22 @@ declare class HostCalls {
18120
18562
  private hostCalls: HostCallsManager,
18121
18563
  ) {}
18122
18564
 
18123
- private getReturnValue(status: Status, pvmInstance: Interpreter): ReturnValue {
18124
- const gasConsumed = pvmInstance.getGasConsumed();
18565
+ private getReturnValue(status: Status, pvmInstance: IPvmInterpreter): ReturnValue {
18566
+ const gasConsumed = pvmInstance.gas.used();
18125
18567
  if (status === Status.OOG) {
18126
18568
  return ReturnValue.fromStatus(gasConsumed, status);
18127
18569
  }
18128
18570
 
18129
18571
  if (status === Status.HALT) {
18130
- const memory = pvmInstance.getMemory();
18131
- const regs = pvmInstance.getRegisters();
18132
- const maybeAddress = regs.getLowerU32(7);
18133
- const maybeLength = regs.getLowerU32(8);
18572
+ const regs = new HostCallRegisters(pvmInstance.registers.getAllEncoded());
18573
+ const memory = new HostCallMemory(pvmInstance.memory);
18574
+ const address = regs.get(7);
18575
+ // NOTE we are taking the the lower U32 part of the register, hence it's safe.
18576
+ const length = Number(regs.get(8) & 0xffff_ffffn);
18577
+
18578
+ const result = safeAllocUint8Array(length);
18134
18579
 
18135
- const result = safeAllocUint8Array(maybeLength);
18136
- const startAddress = tryAsMemoryIndex(maybeAddress);
18137
- const loadResult = memory.loadInto(result, startAddress);
18580
+ const loadResult = memory.loadInto(result, address);
18138
18581
 
18139
18582
  if (loadResult.isError) {
18140
18583
  return ReturnValue.fromMemorySlice(gasConsumed, new Uint8Array());
@@ -18146,7 +18589,7 @@ declare class HostCalls {
18146
18589
  return ReturnValue.fromStatus(gasConsumed, Status.PANIC);
18147
18590
  }
18148
18591
 
18149
- private async execute(pvmInstance: Interpreter) {
18592
+ private async execute(pvmInstance: IPvmInterpreter) {
18150
18593
  pvmInstance.runProgram();
18151
18594
  for (;;) {
18152
18595
  let status = pvmInstance.getStatus();
@@ -18158,9 +18601,9 @@ declare class HostCalls {
18158
18601
  "We know that the exit param is not null, because the status is 'Status.HOST'
18159
18602
  `;
18160
18603
  const hostCallIndex = pvmInstance.getExitParam() ?? -1;
18161
- const gas = pvmInstance.getGasCounter();
18162
- const regs = new HostCallRegisters(pvmInstance.getRegisters());
18163
- const memory = new HostCallMemory(pvmInstance.getMemory());
18604
+ const gas = pvmInstance.gas;
18605
+ const regs = new HostCallRegisters(pvmInstance.registers.getAllEncoded());
18606
+ const memory = new HostCallMemory(pvmInstance.memory);
18164
18607
  const index = tryAsHostCallIndex(hostCallIndex);
18165
18608
 
18166
18609
  const hostCall = this.hostCalls.get(index);
@@ -18173,7 +18616,7 @@ declare class HostCalls {
18173
18616
  const pcLog = `[PC: ${pvmInstance.getPC()}]`;
18174
18617
  if (underflow) {
18175
18618
  this.hostCalls.traceHostCall(`${pcLog} OOG`, index, hostCall, regs, gas.get());
18176
- return ReturnValue.fromStatus(pvmInstance.getGasConsumed(), Status.OOG);
18619
+ return ReturnValue.fromStatus(gas.used(), Status.OOG);
18177
18620
  }
18178
18621
  this.hostCalls.traceHostCall(`${pcLog} Invoking`, index, hostCall, regs, gasBefore);
18179
18622
  const result = await hostCall.execute(gas, regs, memory);
@@ -18184,6 +18627,7 @@ declare class HostCalls {
18184
18627
  regs,
18185
18628
  gas.get(),
18186
18629
  );
18630
+ pvmInstance.registers.setAllEncoded(regs.getEncoded());
18187
18631
 
18188
18632
  if (result === PvmExecution.Halt) {
18189
18633
  status = Status.HALT;
@@ -18210,15 +18654,9 @@ declare class HostCalls {
18210
18654
  }
18211
18655
  }
18212
18656
 
18213
- async runProgram(
18214
- rawProgram: Uint8Array,
18215
- initialPc: number,
18216
- initialGas: Gas,
18217
- maybeRegisters?: Registers,
18218
- maybeMemory?: Memory,
18219
- ): Promise<ReturnValue> {
18657
+ async runProgram(program: Uint8Array, args: Uint8Array, initialPc: number, initialGas: Gas): Promise<ReturnValue> {
18220
18658
  const pvmInstance = await this.pvmInstanceManager.getInstance();
18221
- pvmInstance.reset(rawProgram, initialPc, initialGas, maybeRegisters, maybeMemory);
18659
+ pvmInstance.resetJam(program, args, initialPc, initialGas);
18222
18660
  try {
18223
18661
  return await this.execute(pvmInstance);
18224
18662
  } finally {
@@ -18227,20 +18665,18 @@ declare class HostCalls {
18227
18665
  }
18228
18666
  }
18229
18667
 
18230
- type index$7_HostCallHandler = HostCallHandler;
18231
- type index$7_HostCallMemory = HostCallMemory;
18232
- declare const index$7_HostCallMemory: typeof HostCallMemory;
18233
- type index$7_HostCallRegisters = HostCallRegisters;
18234
- declare const index$7_HostCallRegisters: typeof HostCallRegisters;
18235
- type index$7_IHostCallMemory = IHostCallMemory;
18236
- type index$7_IHostCallRegisters = IHostCallRegisters;
18237
- type index$7_PvmExecution = PvmExecution;
18238
- declare const index$7_PvmExecution: typeof PvmExecution;
18239
- declare const index$7_traceRegisters: typeof traceRegisters;
18240
- declare const index$7_tryAsHostCallIndex: typeof tryAsHostCallIndex;
18241
- declare namespace index$7 {
18242
- 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 };
18243
- export type { index$7_HostCallHandler as HostCallHandler, index$7_IHostCallMemory as IHostCallMemory, index$7_IHostCallRegisters as IHostCallRegisters };
18668
+ type index$5_HostCallHandler = HostCallHandler;
18669
+ type index$5_HostCallMemory = HostCallMemory;
18670
+ declare const index$5_HostCallMemory: typeof HostCallMemory;
18671
+ type index$5_HostCallRegisters = HostCallRegisters;
18672
+ declare const index$5_HostCallRegisters: typeof HostCallRegisters;
18673
+ type index$5_PvmExecution = PvmExecution;
18674
+ declare const index$5_PvmExecution: typeof PvmExecution;
18675
+ declare const index$5_traceRegisters: typeof traceRegisters;
18676
+ declare const index$5_tryAsHostCallIndex: typeof tryAsHostCallIndex;
18677
+ declare namespace index$5 {
18678
+ 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 };
18679
+ export type { index$5_HostCallHandler as HostCallHandler };
18244
18680
  }
18245
18681
 
18246
18682
  /**
@@ -18258,7 +18694,7 @@ type MachineId = Opaque<U64, "MachineId[u64]">;
18258
18694
  declare const tryAsMachineId = (v: number | bigint): MachineId => asOpaqueType(tryAsU64(v));
18259
18695
 
18260
18696
  declare class MachineInstance {
18261
- async run(gas: BigGas, registers: Registers): Promise<MachineResult> {
18697
+ async run(gas: BigGas, registers: HostCallRegisters): Promise<MachineResult> {
18262
18698
  return {
18263
18699
  result: {
18264
18700
  status: Status.OK,
@@ -18286,7 +18722,7 @@ type MachineStatus =
18286
18722
  type MachineResult = {
18287
18723
  result: MachineStatus;
18288
18724
  gas: BigGas;
18289
- registers: Registers;
18725
+ registers: HostCallRegisters;
18290
18726
  };
18291
18727
 
18292
18728
  /** Types of possbile operations to request by Pages host call. */
@@ -18358,7 +18794,7 @@ interface RefineExternalities {
18358
18794
  destinationStart: U64,
18359
18795
  sourceStart: U64,
18360
18796
  length: U64,
18361
- destination: IHostCallMemory,
18797
+ destination: HostCallMemory,
18362
18798
  ): Promise<Result$2<OK, PeekPokeError>>;
18363
18799
 
18364
18800
  /** Write a fragment of memory into `machineIndex` from given source memory. */
@@ -18367,7 +18803,7 @@ interface RefineExternalities {
18367
18803
  sourceStart: U64,
18368
18804
  destinationStart: U64,
18369
18805
  length: U64,
18370
- source: IHostCallMemory,
18806
+ source: HostCallMemory,
18371
18807
  ): Promise<Result$2<OK, PeekPokeError>>;
18372
18808
 
18373
18809
  /** Start an inner PVM instance with given entry point and starting code. */
@@ -18377,7 +18813,7 @@ interface RefineExternalities {
18377
18813
  machineInvoke(
18378
18814
  machineIndex: MachineId,
18379
18815
  gas: BigGas,
18380
- registers: Registers,
18816
+ registers: HostCallRegisters,
18381
18817
  ): Promise<Result$2<MachineResult, NoMachineError>>;
18382
18818
 
18383
18819
  /**
@@ -18799,7 +19235,7 @@ declare const CURRENT_SERVICE_ID = tryAsServiceId(2 ** 32 - 1);
18799
19235
 
18800
19236
  declare function getServiceIdOrCurrent(
18801
19237
  regNumber: number,
18802
- regs: IHostCallRegisters,
19238
+ regs: HostCallRegisters,
18803
19239
  currentServiceId: ServiceId,
18804
19240
  ): ServiceId | null {
18805
19241
  const regValue = regs.get(regNumber);
@@ -18830,270 +19266,75 @@ declare function clampU64ToU32(value: U64): U32 {
18830
19266
  return value > MAX_U32_BIG_INT ? MAX_U32 : tryAsU32(Number(value));
18831
19267
  }
18832
19268
 
18833
- type index$6_AccumulationStateUpdate = AccumulationStateUpdate;
18834
- declare const index$6_AccumulationStateUpdate: typeof AccumulationStateUpdate;
18835
- declare const index$6_CURRENT_SERVICE_ID: typeof CURRENT_SERVICE_ID;
18836
- type index$6_EjectError = EjectError;
18837
- declare const index$6_EjectError: typeof EjectError;
18838
- type index$6_ForgetPreimageError = ForgetPreimageError;
18839
- declare const index$6_ForgetPreimageError: typeof ForgetPreimageError;
18840
- declare const index$6_HostCallResult: typeof HostCallResult;
18841
- type index$6_InsufficientFundsError = InsufficientFundsError;
18842
- declare const index$6_MAX_U32: typeof MAX_U32;
18843
- declare const index$6_MAX_U32_BIG_INT: typeof MAX_U32_BIG_INT;
18844
- type index$6_MachineId = MachineId;
18845
- type index$6_MachineInstance = MachineInstance;
18846
- declare const index$6_MachineInstance: typeof MachineInstance;
18847
- type index$6_MachineResult = MachineResult;
18848
- type index$6_MachineStatus = MachineStatus;
18849
- type index$6_MemoryOperation = MemoryOperation;
18850
- declare const index$6_MemoryOperation: typeof MemoryOperation;
18851
- type index$6_NewServiceError = NewServiceError;
18852
- declare const index$6_NewServiceError: typeof NewServiceError;
18853
- type index$6_NoMachineError = NoMachineError;
18854
- type index$6_PagesError = PagesError;
18855
- declare const index$6_PagesError: typeof PagesError;
18856
- type index$6_PartialState = PartialState;
18857
- type index$6_PartiallyUpdatedState<T extends StateSlice = StateSlice> = PartiallyUpdatedState<T>;
18858
- declare const index$6_PartiallyUpdatedState: typeof PartiallyUpdatedState;
18859
- type index$6_PeekPokeError = PeekPokeError;
18860
- declare const index$6_PeekPokeError: typeof PeekPokeError;
18861
- type index$6_PendingTransfer = PendingTransfer;
18862
- declare const index$6_PendingTransfer: typeof PendingTransfer;
18863
- type index$6_PreimageStatus = PreimageStatus;
18864
- type index$6_PreimageStatusKind = PreimageStatusKind;
18865
- declare const index$6_PreimageStatusKind: typeof PreimageStatusKind;
18866
- type index$6_ProgramCounter = ProgramCounter;
18867
- type index$6_ProvidePreimageError = ProvidePreimageError;
18868
- declare const index$6_ProvidePreimageError: typeof ProvidePreimageError;
18869
- type index$6_RefineExternalities = RefineExternalities;
18870
- type index$6_RequestPreimageError = RequestPreimageError;
18871
- declare const index$6_RequestPreimageError: typeof RequestPreimageError;
18872
- declare const index$6_SERVICE_ID_BYTES: typeof SERVICE_ID_BYTES;
18873
- type index$6_SegmentExportError = SegmentExportError;
18874
- type index$6_ServiceStateUpdate = ServiceStateUpdate;
18875
- type index$6_StateSlice = StateSlice;
18876
- type index$6_TRANSFER_MEMO_BYTES = TRANSFER_MEMO_BYTES;
18877
- type index$6_TransferError = TransferError;
18878
- declare const index$6_TransferError: typeof TransferError;
18879
- type index$6_UnprivilegedError = UnprivilegedError;
18880
- type index$6_UpdatePrivilegesError = UpdatePrivilegesError;
18881
- declare const index$6_UpdatePrivilegesError: typeof UpdatePrivilegesError;
18882
- type index$6_ZeroVoidError = ZeroVoidError;
18883
- declare const index$6_ZeroVoidError: typeof ZeroVoidError;
18884
- declare const index$6_clampU64ToU32: typeof clampU64ToU32;
18885
- declare const index$6_deepCloneMapWithArray: typeof deepCloneMapWithArray;
18886
- declare const index$6_getServiceId: typeof getServiceId;
18887
- declare const index$6_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
18888
- declare const index$6_preimageLenAsU32: typeof preimageLenAsU32;
18889
- declare const index$6_slotsToPreimageStatus: typeof slotsToPreimageStatus;
18890
- declare const index$6_toMemoryOperation: typeof toMemoryOperation;
18891
- declare const index$6_tryAsMachineId: typeof tryAsMachineId;
18892
- declare const index$6_tryAsProgramCounter: typeof tryAsProgramCounter;
18893
- declare const index$6_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
18894
- declare namespace index$6 {
18895
- 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 };
18896
- 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 };
18897
- }
18898
-
18899
- declare const NO_OF_REGISTERS = 13;
18900
-
18901
- declare class MemorySegment extends WithDebug {
18902
- static from({ start, end, data }: Omit<MemorySegment, never>) {
18903
- return new MemorySegment(start, end, data);
18904
- }
18905
-
18906
- constructor(
18907
- public readonly start: number,
18908
- public readonly end: number,
18909
- public readonly data: Uint8Array | null,
18910
- ) {
18911
- super();
18912
- }
18913
- }
18914
- declare class SpiMemory extends WithDebug {
18915
- constructor(
18916
- public readonly readable: MemorySegment[],
18917
- public readonly writeable: MemorySegment[],
18918
- public readonly sbrkIndex: number,
18919
- public readonly heapEnd: number,
18920
- ) {
18921
- super();
18922
- }
18923
- }
18924
-
18925
- declare class SpiProgram extends WithDebug {
18926
- constructor(
18927
- public readonly code: Uint8Array,
18928
- public readonly memory: SpiMemory,
18929
- public readonly registers: BigUint64Array,
18930
- ) {
18931
- super();
18932
- }
18933
- }
18934
-
18935
- /**
18936
- * program = E_3(|o|) ++ E_3(|w|) ++ E_2(z) ++ E_3(s) ++ o ++ w ++ E_4(|c|) ++ c
18937
- *
18938
- * E_n - little endian encoding, n - length
18939
- * o - initial read only data
18940
- * w - initial heap
18941
- * z - heap pages filled with zeros
18942
- * s - stack size
18943
- * c - program code
18944
- *
18945
- * https://graypaper.fluffylabs.dev/#/579bd12/2b92022b9202
18946
- */
18947
- declare function decodeStandardProgram(program: Uint8Array, args: Uint8Array) {
18948
- const decoder = Decoder.fromBlob(program);
18949
- const oLength = decoder.u24();
18950
- const wLength = decoder.u24();
18951
- check`${args.length <= DATA_LENGTH} Incorrect arguments length`;
18952
- check`${oLength <= DATA_LENGTH} Incorrect readonly segment length`;
18953
- const readOnlyLength = oLength;
18954
- check`${wLength <= DATA_LENGTH} Incorrect heap segment length`;
18955
- const heapLength = wLength;
18956
- const noOfHeapZerosPages = decoder.u16();
18957
- const stackSize = decoder.u24();
18958
- const readOnlyMemory = decoder.bytes(readOnlyLength).raw;
18959
- const initialHeap = decoder.bytes(heapLength).raw;
18960
- const codeLength = decoder.u32();
18961
- const code = decoder.bytes(codeLength).raw;
18962
- decoder.finish();
18963
-
18964
- const readonlyDataStart = SEGMENT_SIZE;
18965
- const readonlyDataEnd = SEGMENT_SIZE + alignToPageSize(readOnlyLength);
18966
- const heapDataStart = 2 * SEGMENT_SIZE + alignToSegmentSize(readOnlyLength);
18967
- const heapDataEnd = heapDataStart + alignToPageSize(heapLength);
18968
- const heapZerosEnd = heapDataStart + alignToPageSize(heapLength) + noOfHeapZerosPages * PAGE_SIZE;
18969
- const stackStart = STACK_SEGMENT - alignToPageSize(stackSize);
18970
- const stackEnd = STACK_SEGMENT;
18971
- const argsStart = ARGS_SEGMENT;
18972
- const argsEnd = argsStart + alignToPageSize(args.length);
18973
- const argsZerosEnd = argsEnd + alignToPageSize(args.length);
18974
-
18975
- function nonEmpty(s: MemorySegment | false): s is MemorySegment {
18976
- return s !== false;
18977
- }
18978
-
18979
- const readableMemory = [
18980
- readOnlyLength > 0 && getMemorySegment(readonlyDataStart, readonlyDataEnd, readOnlyMemory),
18981
- args.length > 0 && getMemorySegment(argsStart, argsEnd, args),
18982
- argsEnd < argsZerosEnd && getMemorySegment(argsEnd, argsZerosEnd),
18983
- ].filter(nonEmpty);
18984
- const writeableMemory = [
18985
- heapLength > 0 && getMemorySegment(heapDataStart, heapDataEnd, initialHeap),
18986
- heapDataEnd < heapZerosEnd && getMemorySegment(heapDataEnd, heapZerosEnd),
18987
- stackStart < stackEnd && getMemorySegment(stackStart, stackEnd),
18988
- ].filter(nonEmpty);
18989
-
18990
- return new SpiProgram(
18991
- code,
18992
- new SpiMemory(readableMemory, writeableMemory, heapZerosEnd, stackStart),
18993
- getRegisters(args.length),
18994
- );
18995
- }
18996
-
18997
- declare function getMemorySegment(start: number, end: number, data: Uint8Array | null = null) {
18998
- return new MemorySegment(start, end, data);
18999
- }
19000
-
19001
- declare function getRegisters(argsLength: number) {
19002
- const regs = new BigUint64Array(NO_OF_REGISTERS);
19003
-
19004
- // GP reference: https://graypaper.fluffylabs.dev/#/579bd12/2c7c012cb101
19005
- regs[0] = BigInt(LAST_PAGE);
19006
- regs[1] = BigInt(STACK_SEGMENT);
19007
- regs[7] = BigInt(ARGS_SEGMENT);
19008
- regs[8] = BigInt(argsLength);
19009
-
19010
- return regs;
19011
- }
19012
-
19013
- type index$5_MemorySegment = MemorySegment;
19014
- declare const index$5_MemorySegment: typeof MemorySegment;
19015
- declare const index$5_NO_OF_REGISTERS: typeof NO_OF_REGISTERS;
19016
- type index$5_SpiMemory = SpiMemory;
19017
- declare const index$5_SpiMemory: typeof SpiMemory;
19018
- type index$5_SpiProgram = SpiProgram;
19019
- declare const index$5_SpiProgram: typeof SpiProgram;
19020
- declare const index$5_decodeStandardProgram: typeof decodeStandardProgram;
19021
- declare const index$5_getMemorySegment: typeof getMemorySegment;
19022
- declare const index$5_getRegisters: typeof getRegisters;
19023
- declare namespace index$5 {
19024
- export {
19025
- index$5_MemorySegment as MemorySegment,
19026
- index$5_NO_OF_REGISTERS as NO_OF_REGISTERS,
19027
- index$5_SpiMemory as SpiMemory,
19028
- index$5_SpiProgram as SpiProgram,
19029
- index$5_decodeStandardProgram as decodeStandardProgram,
19030
- index$5_getMemorySegment as getMemorySegment,
19031
- index$5_getRegisters as getRegisters,
19032
- };
19033
- }
19034
-
19035
- declare class Program {
19036
- static fromSpi(blob: Uint8Array, args: Uint8Array, hasMetadata: boolean) {
19037
- const { code: spiCode, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
19038
- const { code, memory: rawMemory, registers } = decodeStandardProgram(spiCode, args);
19039
- const regs = new Registers();
19040
- regs.copyFrom(registers);
19041
- const memoryBuilder = new MemoryBuilder();
19042
-
19043
- for (const { start, end, data } of rawMemory.readable) {
19044
- const startIndex = tryAsMemoryIndex(start);
19045
- const endIndex = tryAsMemoryIndex(end);
19046
- memoryBuilder.setReadablePages(startIndex, endIndex, data ?? new Uint8Array());
19047
- }
19048
-
19049
- for (const { start, end, data } of rawMemory.writeable) {
19050
- const startIndex = tryAsMemoryIndex(start);
19051
- const endIndex = tryAsMemoryIndex(end);
19052
- memoryBuilder.setWriteablePages(startIndex, endIndex, data ?? new Uint8Array());
19053
- }
19054
-
19055
- const heapStart = tryAsMemoryIndex(rawMemory.sbrkIndex);
19056
- const heapEnd = tryAsSbrkIndex(rawMemory.heapEnd);
19057
- const memory = memoryBuilder.finalize(heapStart, heapEnd);
19058
-
19059
- return new Program(code, regs, memory, metadata);
19060
- }
19061
-
19062
- static fromGeneric(blob: Uint8Array, hasMetadata: boolean) {
19063
- const { code, metadata } = hasMetadata ? extractCodeAndMetadata(blob) : { code: blob };
19064
- const regs = new Registers();
19065
- const memory = new Memory();
19066
- return new Program(code, regs, memory, metadata);
19067
- }
19068
-
19069
- private constructor(
19070
- public readonly code: Uint8Array,
19071
- public readonly registers: Registers,
19072
- public readonly memory: Memory,
19073
- public metadata: Uint8Array = new Uint8Array(),
19074
- ) {}
19075
- }
19076
-
19077
- /**
19078
- * A function that splits preimage into metadata and code.
19079
- *
19080
- * https://graypaper.fluffylabs.dev/#/cc517d7/109a01109a01?v=0.6.5
19081
- */
19082
- declare function extractCodeAndMetadata(blobWithMetadata: Uint8Array) {
19083
- const decoder = Decoder.fromBlob(blobWithMetadata);
19084
- const metadata = decoder.bytesBlob().raw;
19085
- const code = decoder.remainingBytes().raw;
19086
- return { metadata, code };
19087
- }
19088
-
19089
- type index$4_Program = Program;
19090
- declare const index$4_Program: typeof Program;
19091
- declare const index$4_extractCodeAndMetadata: typeof extractCodeAndMetadata;
19269
+ declare function emptyRegistersBuffer(): Uint8Array {
19270
+ return safeAllocUint8Array(NO_OF_REGISTERS * REGISTER_BYTE_SIZE);
19271
+ }
19272
+
19273
+ type index$4_AccumulationStateUpdate = AccumulationStateUpdate;
19274
+ declare const index$4_AccumulationStateUpdate: typeof AccumulationStateUpdate;
19275
+ declare const index$4_CURRENT_SERVICE_ID: typeof CURRENT_SERVICE_ID;
19276
+ type index$4_EjectError = EjectError;
19277
+ declare const index$4_EjectError: typeof EjectError;
19278
+ type index$4_ForgetPreimageError = ForgetPreimageError;
19279
+ declare const index$4_ForgetPreimageError: typeof ForgetPreimageError;
19280
+ declare const index$4_HostCallResult: typeof HostCallResult;
19281
+ type index$4_InsufficientFundsError = InsufficientFundsError;
19282
+ declare const index$4_MAX_U32: typeof MAX_U32;
19283
+ declare const index$4_MAX_U32_BIG_INT: typeof MAX_U32_BIG_INT;
19284
+ type index$4_MachineId = MachineId;
19285
+ type index$4_MachineInstance = MachineInstance;
19286
+ declare const index$4_MachineInstance: typeof MachineInstance;
19287
+ type index$4_MachineResult = MachineResult;
19288
+ type index$4_MachineStatus = MachineStatus;
19289
+ type index$4_MemoryOperation = MemoryOperation;
19290
+ declare const index$4_MemoryOperation: typeof MemoryOperation;
19291
+ type index$4_NewServiceError = NewServiceError;
19292
+ declare const index$4_NewServiceError: typeof NewServiceError;
19293
+ type index$4_NoMachineError = NoMachineError;
19294
+ type index$4_PagesError = PagesError;
19295
+ declare const index$4_PagesError: typeof PagesError;
19296
+ type index$4_PartialState = PartialState;
19297
+ type index$4_PartiallyUpdatedState<T extends StateSlice = StateSlice> = PartiallyUpdatedState<T>;
19298
+ declare const index$4_PartiallyUpdatedState: typeof PartiallyUpdatedState;
19299
+ type index$4_PeekPokeError = PeekPokeError;
19300
+ declare const index$4_PeekPokeError: typeof PeekPokeError;
19301
+ type index$4_PendingTransfer = PendingTransfer;
19302
+ declare const index$4_PendingTransfer: typeof PendingTransfer;
19303
+ type index$4_PreimageStatus = PreimageStatus;
19304
+ type index$4_PreimageStatusKind = PreimageStatusKind;
19305
+ declare const index$4_PreimageStatusKind: typeof PreimageStatusKind;
19306
+ type index$4_ProgramCounter = ProgramCounter;
19307
+ type index$4_ProvidePreimageError = ProvidePreimageError;
19308
+ declare const index$4_ProvidePreimageError: typeof ProvidePreimageError;
19309
+ type index$4_RefineExternalities = RefineExternalities;
19310
+ type index$4_RequestPreimageError = RequestPreimageError;
19311
+ declare const index$4_RequestPreimageError: typeof RequestPreimageError;
19312
+ declare const index$4_SERVICE_ID_BYTES: typeof SERVICE_ID_BYTES;
19313
+ type index$4_SegmentExportError = SegmentExportError;
19314
+ type index$4_ServiceStateUpdate = ServiceStateUpdate;
19315
+ type index$4_StateSlice = StateSlice;
19316
+ type index$4_TRANSFER_MEMO_BYTES = TRANSFER_MEMO_BYTES;
19317
+ type index$4_TransferError = TransferError;
19318
+ declare const index$4_TransferError: typeof TransferError;
19319
+ type index$4_UnprivilegedError = UnprivilegedError;
19320
+ type index$4_UpdatePrivilegesError = UpdatePrivilegesError;
19321
+ declare const index$4_UpdatePrivilegesError: typeof UpdatePrivilegesError;
19322
+ type index$4_ZeroVoidError = ZeroVoidError;
19323
+ declare const index$4_ZeroVoidError: typeof ZeroVoidError;
19324
+ declare const index$4_clampU64ToU32: typeof clampU64ToU32;
19325
+ declare const index$4_deepCloneMapWithArray: typeof deepCloneMapWithArray;
19326
+ declare const index$4_emptyRegistersBuffer: typeof emptyRegistersBuffer;
19327
+ declare const index$4_getServiceId: typeof getServiceId;
19328
+ declare const index$4_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
19329
+ declare const index$4_preimageLenAsU32: typeof preimageLenAsU32;
19330
+ declare const index$4_slotsToPreimageStatus: typeof slotsToPreimageStatus;
19331
+ declare const index$4_toMemoryOperation: typeof toMemoryOperation;
19332
+ declare const index$4_tryAsMachineId: typeof tryAsMachineId;
19333
+ declare const index$4_tryAsProgramCounter: typeof tryAsProgramCounter;
19334
+ declare const index$4_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
19092
19335
  declare namespace index$4 {
19093
- export {
19094
- index$4_Program as Program,
19095
- index$4_extractCodeAndMetadata as extractCodeAndMetadata,
19096
- };
19336
+ 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 };
19337
+ 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 };
19097
19338
  }
19098
19339
 
19099
19340
  declare class DebuggerAdapter {
@@ -19109,11 +19350,11 @@ declare class DebuggerAdapter {
19109
19350
  }
19110
19351
 
19111
19352
  resetGeneric(rawProgram: Uint8Array, flatRegisters: Uint8Array, initialGas: bigint) {
19112
- this.pvm.reset(rawProgram, 0, tryAsGas(initialGas), new Registers(flatRegisters));
19353
+ this.pvm.resetGeneric(rawProgram, 0, tryAsGas(initialGas), new Registers(flatRegisters));
19113
19354
  }
19114
19355
 
19115
19356
  reset(rawProgram: Uint8Array, pc: number, gas: bigint, maybeRegisters?: Registers, maybeMemory?: Memory) {
19116
- this.pvm.reset(rawProgram, pc, tryAsGas(gas), maybeRegisters, maybeMemory);
19357
+ this.pvm.resetGeneric(rawProgram, pc, tryAsGas(gas), maybeRegisters, maybeMemory);
19117
19358
  }
19118
19359
 
19119
19360
  getPageDump(pageNumber: number): null | Uint8Array {
@@ -19136,7 +19377,7 @@ declare class DebuggerAdapter {
19136
19377
  }
19137
19378
 
19138
19379
  setMemory(address: number, value: Uint8Array) {
19139
- this.pvm.getMemory().storeFrom(tryAsMemoryIndex(address), value);
19380
+ this.pvm.memory.storeFrom(tryAsMemoryIndex(address), value);
19140
19381
  }
19141
19382
 
19142
19383
  getExitArg(): number {
@@ -19163,11 +19404,11 @@ declare class DebuggerAdapter {
19163
19404
  }
19164
19405
 
19165
19406
  getRegisters(): BigUint64Array {
19166
- return this.pvm.getRegisters().getAllU64();
19407
+ return this.pvm.registers.getAllU64();
19167
19408
  }
19168
19409
 
19169
19410
  setRegisters(registers: Uint8Array) {
19170
- this.pvm.getRegisters().copyFrom(new Registers(registers));
19411
+ this.pvm.registers.copyFrom(new Registers(registers));
19171
19412
  }
19172
19413
 
19173
19414
  getProgramCounter(): number {
@@ -19179,11 +19420,11 @@ declare class DebuggerAdapter {
19179
19420
  }
19180
19421
 
19181
19422
  getGasLeft(): bigint {
19182
- return BigInt(this.pvm.getGas());
19423
+ return BigInt(this.pvm.gas.get());
19183
19424
  }
19184
19425
 
19185
19426
  setGasLeft(gas: bigint) {
19186
- this.pvm.getGasCounter().set(tryAsGas(gas));
19427
+ this.pvm.gas.set(tryAsGas(gas));
19187
19428
  }
19188
19429
  }
19189
19430
 
@@ -19210,8 +19451,6 @@ declare const index$3_HostCallMemory: typeof HostCallMemory;
19210
19451
  type index$3_HostCallRegisters = HostCallRegisters;
19211
19452
  declare const index$3_HostCallRegisters: typeof HostCallRegisters;
19212
19453
  declare const index$3_HostCallResult: typeof HostCallResult;
19213
- type index$3_IHostCallMemory = IHostCallMemory;
19214
- type index$3_IHostCallRegisters = IHostCallRegisters;
19215
19454
  type index$3_ImmediateDecoder = ImmediateDecoder;
19216
19455
  declare const index$3_ImmediateDecoder: typeof ImmediateDecoder;
19217
19456
  type index$3_InsufficientFundsError = InsufficientFundsError;
@@ -19294,6 +19533,7 @@ declare const index$3_clampU64ToU32: typeof clampU64ToU32;
19294
19533
  declare const index$3_createResults: typeof createResults;
19295
19534
  declare const index$3_decodeStandardProgram: typeof decodeStandardProgram;
19296
19535
  declare const index$3_deepCloneMapWithArray: typeof deepCloneMapWithArray;
19536
+ declare const index$3_emptyRegistersBuffer: typeof emptyRegistersBuffer;
19297
19537
  declare const index$3_extractCodeAndMetadata: typeof extractCodeAndMetadata;
19298
19538
  declare const index$3_getServiceId: typeof getServiceId;
19299
19539
  declare const index$3_getServiceIdOrCurrent: typeof getServiceIdOrCurrent;
@@ -19312,8 +19552,8 @@ declare const index$3_tryAsMachineId: typeof tryAsMachineId;
19312
19552
  declare const index$3_tryAsProgramCounter: typeof tryAsProgramCounter;
19313
19553
  declare const index$3_writeServiceIdAsLeBytes: typeof writeServiceIdAsLeBytes;
19314
19554
  declare namespace index$3 {
19315
- 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 };
19316
- 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 };
19555
+ 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 };
19556
+ 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 };
19317
19557
  }
19318
19558
 
19319
19559
  declare const ENTROPY_BYTES = 32;
@@ -20205,4 +20445,4 @@ declare namespace index {
20205
20445
  export type { index_PreimagesInput as PreimagesInput, index_PreimagesState as PreimagesState, index_PreimagesStateUpdate as PreimagesStateUpdate };
20206
20446
  }
20207
20447
 
20208
- 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 };
20448
+ 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 };