Skip to content

Commit 8490563

Browse files
committed
wip cfg
1 parent 55a90aa commit 8490563

14 files changed

Lines changed: 504 additions & 294 deletions

src/ast.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { Block } from './sevm.ts';
1+
import type { State } from './sevm.ts';
22

3-
export function buildAST(bbs: Map<number, Block[]>) {
3+
export function buildAST(bbs: Map<number, State[]>) {
44
const preds = f(bbs);
55
const { tree } = domTree(preds);
66
return ast(0, tree, preds);
@@ -112,12 +112,12 @@ function domTree(cfg: Map<number, Set<number>>) {
112112
}
113113
}
114114

115-
function f(bbs: Map<number, Block[]>) {
115+
function f(bbs: Map<number, State[]>) {
116116
const cfg = new Map<number, Set<number>>();
117117

118118
for (const [pc, bs] of bbs.entries()) {
119119
for (const b of bs) {
120-
for (const t of b.targets) {
120+
for (const t of b.branches) {
121121
let entry = cfg.get(t.pc);
122122
if (entry === undefined) {
123123
entry = new Set();

src/bytes.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,16 @@ export function arrayify(data: Uint8Array | ArrayLike<number> | string): Uint8Ar
4444
export function hexlify(data: Uint8Array): string {
4545
return data.reduce((str, elem) => str + elem.toString(16).padStart(2, '0'), '');
4646
}
47+
48+
/**
49+
*
50+
* @param data
51+
* @returns
52+
*/
53+
export function bigintify(data: Uint8Array): bigint {
54+
let result = 0n;
55+
for (let i = data.length - 1, s = 0n; i >= 0; i--, s += 8n)
56+
result += BigInt(data[i]) << s;
57+
58+
return result;
59+
}

src/contract.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { arrayify } from './bytes.ts';
22
import { type Metadata, parseMetadata } from './metadata.ts';
3-
import { type Block, Sevm } from './sevm.ts';
3+
import { type State, Sevm } from './sevm.ts';
44
import { Shanghai } from './forks.ts';
55
// import { buildAST } from './ast.ts';
66
// import { yul } from './yul.ts';
7-
import { Selectors } from './selectors.ts';
7+
// import { Selectors } from './selectors.ts';
88

99
// export function x(bytecode: Uint8Array) {
1010
// return sevm(bytecode, 0, undefined as unknown as State, new Frontier());
@@ -22,23 +22,29 @@ export class Contract {
2222
*/
2323
readonly metadata: Metadata | undefined;
2424

25-
readonly states: Map<number, Block[]>;
25+
readonly step;
26+
27+
readonly states: Map<number, State[]>;
2628

2729
/**
2830
*
2931
* @param bytecode the Contract's bytecode to analyze.
3032
*/
31-
constructor(bytecode: Parameters<typeof arrayify>[0]) {
33+
constructor(bytecode: Parameters<typeof arrayify>[0], Step = /*Selectors*/(Shanghai)) {
3234
this.bytecode = arrayify(bytecode);
3335
this.metadata = parseMetadata(this.bytecode).metadata;
34-
this.states = new Sevm(new (Selectors(Shanghai))(), this.bytecode).run();
35-
36-
// const K = Selectors(Shanghai);
37-
// const s = new K();
38-
// s.decode()
39-
// s.publicBranches
36+
this.step = new Step();
37+
// this.states = new Sevm(this.step, this.bytecode).run();
38+
this.states = new Sevm(this.step, this.bytecode).go();
4039
}
4140

41+
/**
42+
*
43+
*/
44+
// get selectors(): string[] {
45+
// return [...this.step.publicBranches.keys()];
46+
// }
47+
4248
/**
4349
* https://docs.soliditylang.org/en/latest/yul.html
4450
*/

src/forks.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
11
import { mapValues, range, zip } from './lib/object.ts';
2-
import { hexlify } from './bytes.ts';
2+
import { bigintify } from './bytes.ts';
33
import { Dispatch, type Opcode } from './decode.ts';
44
import { Inst, Local, Lit, SExpr, Def } from './sexpr.ts';
55
import type { State, StepFn, Step } from './sevm.ts';
66

7-
function addLocal({ insts, stack }: State, expr: SExpr, pc: number) {
8-
const local = new Local(insts.length, expr);
9-
insts.push(new Def(local, pc));
10-
stack.push(local);
7+
const sexpr = (inputs: number) => function (this: IAddLocal, state: State, op: Opcode) {
8+
return this.addLocal(state, new SExpr(op.mnemonic.toLowerCase(), state.stack.popn(inputs)), op.pc);
119
}
1210

13-
const sexpr = (inputs: number) => function (state: State, op: Opcode) {
14-
addLocal(state, new SExpr(op.mnemonic.toLowerCase(), state.stack.popn(inputs)), op.pc);
11+
const sinst = (inputs: number) => function (state: State, op: Opcode) {
12+
return new Inst(op.mnemonic.toLowerCase(), state.stack.popn(inputs), op.pc);
1513
}
1614

17-
const sinst = (inputs: number) => function ({ insts, stack }: State, op: Opcode) {
18-
insts.push(new Inst(op.mnemonic.toLowerCase(), stack.popn(inputs), op.pc));
15+
interface IAddLocal {
16+
addLocal(state: State, expr: SExpr, pc: number): Inst;
1917
}
2018

2119
function ForkFactory<M extends string>(
2220
def: { [m in M]: { op: number, size?: number, step: StepFn } },
2321
invalid: NoInfer<M>,
2422
): new () => Dispatch<M> & Step<M> {
25-
class Fork extends Dispatch<M> {
23+
class Fork extends Dispatch<M> implements IAddLocal {
24+
readonly #locals = new WeakMap<State, number>();
25+
2626
constructor() {
2727
super(def, invalid);
2828
}
2929

30-
decode1() {
31-
return this.decode(null as unknown as Uint8Array, 0);
32-
}
33-
*decode2() {
34-
yield this.decode(null as unknown as Uint8Array, 0);
30+
addLocal(state: State, expr: SExpr, pc: number) {
31+
const id = this.#locals.get(state) ?? 0;
32+
this.#locals.set(state, id + 1);
33+
34+
const local = new Local(state.pcbegin, id, expr);
35+
state.stack.push(local);
36+
// state.insts.push(new Def(local, pc));
37+
return new Def(local, pc);
3538
}
36-
// *decode3(pc0: number): Generator<Opcode & {mnemonic: number}, void, unknown> {
37-
// yield* this.decode(null as unknown as Uint8Array, pc0);
38-
// }
3939
}
4040
Object.assign(Fork.prototype, mapValues(def, op => op.step));
4141
return Fork as (new () => Dispatch<M> & Step<M>);
@@ -48,15 +48,20 @@ const FlowDef = {
4848
JUMPDEST: { op: 0x5B, step: sinst(0) },
4949
...zip(range(32).map(i => [
5050
`PUSH${i + 1 as Size<32>}`,
51-
{ op: 0x60 + i, size: i + 1, step: (state, op) => addLocal(state, new Lit(BigInt('0x' + hexlify(op.data!))), op.pc) }
51+
{
52+
op: 0x60 + i, size: i + 1, step: function (this: IAddLocal, state, op) {
53+
// return this.addLocal(state, new Lit(BigInt('0x' + hexlify(op.data!))), op.pc);
54+
return this.addLocal(state, new Lit(bigintify(op.data!)), op.pc);
55+
}
56+
}
5257
] as const)),
5358
...zip(range(16).map(i => [
5459
`DUP${i + 1 as Size<16>}`,
55-
{ op: 0x80 + i, step: ({ stack }) => stack.dup(i) }
60+
{ op: 0x80 + i, step: ({ stack }) => (stack.dup(i), undefined) }
5661
] as const)),
5762
...zip(range(16).map(i => [
5863
`SWAP${i + 1 as Size<16>}`,
59-
{ op: 0x90 + i, step: ({ stack }) => stack.swap(i + 1) }
64+
{ op: 0x90 + i, step: ({ stack }) => (stack.swap(i + 1), undefined) }
6065
] as const)),
6166
INVALID: { op: 0xfe, step: sinst(0) },
6267
} satisfies Parameters<typeof ForkFactory>[0];
@@ -157,7 +162,11 @@ const ParisDef = {
157162

158163
const ShanghaiDef = {
159164
...ParisDef,
160-
PUSH0: { op: 0x5F, step: (state, op) => addLocal(state, new Lit(0n), op.pc) },
165+
PUSH0: {
166+
op: 0x5F, step: function (this: IAddLocal, state, op) {
167+
this.addLocal(state, new Lit(0n), op.pc)
168+
}
169+
},
161170
} satisfies Parameters<typeof ForkFactory>[0];
162171

163172
export const Flow = ForkFactory(FlowDef, 'INVALID');

src/selectors.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { Opcode } from './decode.ts';
2-
import { Lit, type Local, type SExpr } from './sexpr.ts';
2+
import { type Inst, Lit, type Local, type SExpr } from './sexpr.ts';
33
import type { State, Step } from './sevm.ts';
44

5-
interface IPublicBranches {
5+
export interface IPublicBranches {
66

77
/**
88
*
@@ -25,19 +25,21 @@ function JMP<T extends Cons<Step<'JUMPI'>>>(Klass: T): T & Cons<IPublicBranches>
2525
readonly selectors: IPublicBranches['selectors'] = new WeakMap();
2626
readonly publicBranches: IPublicBranches['publicBranches'] = new Map();
2727

28-
JUMPI = (state: State, opcode: Opcode) => {
29-
super.JUMPI(state, opcode);
30-
const [offset, cond] = state.insts.at(-1)!.args;
28+
JUMPI = (state: State, opcode: Opcode): Inst => {
29+
const inst = super.JUMPI(state, opcode)!;
30+
const [offset, cond] = inst.args;
3131

32-
// const selector = cond.props['selector'];
3332
const selector = this.selectors.get(cond);
3433
if (typeof selector === 'string') {
34+
console.log('selector')
3535
// const [pc, contBranch] = cond.positive ? [destpc, fallBranch] : [opcode.pc + 1, destBranch];
3636
if (offset.expr instanceof Lit) {
3737
const pc = Number(offset.expr.value);
3838
this.publicBranches.set(selector, { pc, state });
3939
}
4040
}
41+
42+
return inst;
4143
}
4244
};
4345
}
@@ -49,9 +51,8 @@ function JMP<T extends Cons<Step<'JUMPI'>>>(Klass: T): T & Cons<IPublicBranches>
4951
*/
5052
function DivExpEQ<T extends Cons<Step<'EQ'>>>(Klass: T): T {
5153
return class extends Klass {
52-
EQ = (state: State, opcode: Opcode) => {
53-
super.EQ(state, opcode);
54-
54+
EQ = (state: State, opcode: Opcode): Inst => {
55+
const inst = super.EQ(state, opcode)!;
5556
const [left, right] = state.stack.top!;
5657

5758
const rr = right.args[1];
@@ -71,6 +72,8 @@ function DivExpEQ<T extends Cons<Step<'EQ'>>>(Klass: T): T {
7172
console.log(s);
7273
}
7374
}
75+
76+
return inst;
7477
}
7578
};
7679
}
@@ -91,8 +94,8 @@ function isSelectorCallData(expr: SExpr) {
9194

9295
function ShrEQ<T extends Cons<IPublicBranches & Step<'EQ'>>>(Klass: T): T {
9396
return class extends Klass {
94-
override EQ = (state: State, opcode: Opcode) => {
95-
super.EQ(state, opcode);
97+
override EQ = (state: State, opcode: Opcode): Inst => {
98+
const inst = super.EQ(state, opcode)!;
9699

97100
const SHRsig = (left: SExpr, right: SExpr): string | undefined => {
98101
return left instanceof Lit && isSelectorCallData(right)
@@ -105,6 +108,8 @@ function ShrEQ<T extends Cons<IPublicBranches & Step<'EQ'>>>(Klass: T): T {
105108
this.selectors.set(state.stack.top!, sig);
106109
// state.stack.top!.props['selector'] = sig;
107110
}
111+
112+
return inst;
108113
}
109114
};
110115
}

0 commit comments

Comments
 (0)