Skip to content

Commit

Permalink
feat: add footprint in spread layout
Browse files Browse the repository at this point in the history
  • Loading branch information
ashutoshvarma committed Feb 19, 2023
1 parent e0e2260 commit 8671900
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 1 deletion.
10 changes: 10 additions & 0 deletions as-packages/lang/assembly/collections/lazy/lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ export class Lazy<T> implements SpreadLayout {
return this._cache as StorageEntry<T>;
}

@inline
FOOTPRINT(): u64 {
return 1;
}

@inline
REQUIRES_DEEP_CLEAN_UP(): bool {
return true;
}

pullSpread<K extends IKey>(key: K): void {
// @ts-ignore
++key;
Expand Down
11 changes: 11 additions & 0 deletions as-packages/lang/assembly/collections/lazy/storageEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ export class StorageEntry<T> implements SpreadLayout, PackedLayout {
return this._state == EntryState.Cleared;
}

@inline
FOOTPRINT(): u64 {
// @ts-ignore
return 1 + this._value.FOOTPRINT();
}

@inline
REQUIRES_DEEP_CLEAN_UP(): bool {
return true;
}

/**
* Pulls the entity from the underlying associated storage as a `SpreadLayout` storage layout representation.
* @param key
Expand Down
10 changes: 10 additions & 0 deletions as-packages/lang/assembly/collections/lazyIndexMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,16 @@ export class LazyIndexMap<V> implements SpreadLayout {
}
}

@inline
FOOTPRINT(): u64 {
return 1;
}

@inline
REQUIRES_DEEP_CLEAN_UP(): bool {
return true;
}

@inline
protected keyAt(key: u32): Key {
// make indexKey unique by adding a big offset key.
Expand Down
10 changes: 10 additions & 0 deletions as-packages/lang/assembly/collections/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ export class Mapping<K1, V, H extends IHash256> implements SpreadLayout {
env().clearContractStroage<Key>(k);
}

@inline
FOOTPRINT(): u64 {
return 1;
}

@inline
REQUIRES_DEEP_CLEAN_UP(): bool {
return true;
}

pullSpread<T extends IKey>(key: T): void {
// @ts-ignore
++key;
Expand Down
10 changes: 10 additions & 0 deletions as-packages/lang/assembly/collections/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ export class Pack<T> implements PackedLayout, SpreadLayout, ISerialize, IDeseria
return this.inner;
}

@inline
FOOTPRINT(): u64 {
return 1;
}

@inline
REQUIRES_DEEP_CLEAN_UP(): bool {
return true;
}

@inline
pullSpread<K extends IKey>(key: K): void {
// @ts-ignore
Expand Down
11 changes: 11 additions & 0 deletions as-packages/lang/assembly/collections/vector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,17 @@ export class Vector<T> implements SpreadLayout {
this._elems.pushSpread<K>(key);
}

@inline
FOOTPRINT(): u64 {
// 1 + len + map
return 3;
}

@inline
REQUIRES_DEEP_CLEAN_UP(): bool {
return true;
}

protected clearAll(): void {
if (this._elems.key() === null) {
// We won't clear any storage if we are in lazy state since there
Expand Down
29 changes: 29 additions & 0 deletions as-packages/lang/assembly/interfaces/spreadlayout.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
import { IKey } from "./key";

export interface SpreadLayout {
/// The footprint of the type.
///
/// This is the number of adjunctive cells the type requires in order to
/// be stored in the contract storage with spread layout.
///
/// # Examples
///
/// An instance of type `i32` requires one storage cell, so its footprint is 1.
/// An instance of type `(i32, i32)` requires 2 storage cells since a
/// tuple or any other combined data structure always associates disjunctive
/// cells for its sub types. The same applies to arrays, e.g. `[i32; 5]`
/// has a footprint of 5.
FOOTPRINT(): u64;

/// Indicates whether a type requires deep clean-up of its state meaning that
/// a clean-up routine has to decode an entity into an instance in order to
/// eventually recurse upon its tear-down.
/// This is not required for the majority of primitive data types such as `i32`,
/// however types such as `storage::Box` that might want to forward the clean-up
/// procedure to their inner `T` require a deep clean-up.
///
/// # Note
///
/// The default is set to `true` in order to have correctness by default since
/// no type invariants break if a deep clean-up is performed on a type that does
/// not need it but performing a shallow clean-up for a type that requires a
/// deep clean-up would break invariants.
/// This is solely a setting to improve performance upon clean-up for some types.
REQUIRES_DEEP_CLEAN_UP(): bool;
/**
* Pulls an instance of `this` from the contract storage.
* The pointer denotes the position where the instance is being pulled
Expand Down
53 changes: 53 additions & 0 deletions as-packages/lang/assembly/storage/spread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,56 @@ export function clearSpread<T extends SpreadLayout, K extends IKey>(value: T, ke
value.clearSpread<K>(key);
}
}

export function defaultFoorprint<T extends SpreadLayout>(): u64 {
return 1;
}

export function spreadFootprint<T extends SpreadLayout>(): u64 {
let dummy: T;
if (!isReference<T>() || false) {
return defaultFoorprint<T>();
} else if (
isString<T>() ||
idof<T>() == idof<i128>() ||
idof<T>() == idof<u128>() ||
idof<T>() == idof<Error>() ||
idof<T>() == idof<SyntaxError>() ||
idof<T>() == idof<RangeError>() ||
idof<T>() == idof<TypeError>() ||
idof<T>() == idof<URIError>() ||
idof<T>() == idof<TypeError>() ||
idof<T>() == idof<ArrayBuffer>() ||
idof<T>() == idof<Int8Array>() ||
idof<T>() == idof<Int16Array>() ||
idof<T>() == idof<Int32Array>() ||
idof<T>() == idof<Int64Array>() ||
idof<T>() == idof<Uint8Array>() ||
idof<T>() == idof<Uint16Array>() ||
idof<T>() == idof<Uint32Array>() ||
idof<T>() == idof<Uint64Array>() ||
isArray<T>() ||
isArrayLike<T>() ||
false
) {
return defaultFoorprint<T>();
}
// @ts-ignore
else if (isDefined(dummy.FOOTPRINT())) {
// @ts-ignore
return dummy.FOOTPRINT();
} else if (
// @ts-ignore
value instanceof Set ||
// @ts-ignore
value instanceof Map ||
// @ts-ignore
dummy instanceof FixedArray ||
false
) {
return defaultFoorprint<T>();
} else {
// @ts-ignore
return dummy.FOOTPRINT();
}
}
39 changes: 38 additions & 1 deletion ts-packages/transform/src/visitors/spreadlayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ export class SpreadLayoutVisitor extends TransformVisitor {
}

private genSpreadLayout(node: ClassDeclaration): MethodDeclaration[] {
const res = [this.genPullSpread(node), this.genPushSpread(node), this.genClearSpread(node)];
const res = [
this.genPullSpread(node),
this.genPushSpread(node),
this.genClearSpread(node),
this.genFootprint(node),
this.genRequiresDeepClean(node),
];
return res;
}

Expand Down Expand Up @@ -113,4 +119,35 @@ export class SpreadLayoutVisitor extends TransformVisitor {
assert(methodNode.kind == NodeKind.METHODDECLARATION);
return methodNode as MethodDeclaration;
}

private genFootprint(clz: ClassDeclaration): MethodDeclaration {
const METHOD_FOOTPRINT = "FOOTPRINT";
const LANF_METHOD_FOOTPRINT = "spreadFootprint";

const superCall = this.hasBase ? `+ super.${METHOD_FOOTPRINT}()` : "";
const stmts =
this.fields.length > 0
? "+ " +
this.fields
.map(
(field) =>
`__lang.${LANF_METHOD_FOOTPRINT}<${field.type?.range.toString()}>()`,
)
.join("+")
: "";

const methodDecl = `${METHOD_FOOTPRINT}(): u64 { return 1 ${superCall} ${stmts}; }`;
const methodNode = SimpleParser.parseClassMember(methodDecl, clz);
assert(methodNode.kind == NodeKind.METHODDECLARATION);
return methodNode as MethodDeclaration;
}

private genRequiresDeepClean(clz: ClassDeclaration): MethodDeclaration {
const METHOD_FOOTPRINT = "REQUIRES_DEEP_CLEAN_UP";

const methodDecl = `${METHOD_FOOTPRINT}(): bool { return true; }`;
const methodNode = SimpleParser.parseClassMember(methodDecl, clz);
assert(methodNode.kind == NodeKind.METHODDECLARATION);
return methodNode as MethodDeclaration;
}
}

0 comments on commit 8671900

Please sign in to comment.