mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	It changes all hashes, since the compiler needs to manipulate the stack in a different way now.
		
			
				
	
	
		
			239 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
;; Here we test "functions that just wrap other functions" (camelCase in particular):
 | 
						|
;; > builder beginCell() { return begin_cell(); }
 | 
						|
;; Such functions, when called, are explicitly inlined during code generation (even without `inline` modifier).
 | 
						|
;; It means, that `beginCell()` is replaced to `begin_cell()` (and effectively to `NEWC`).
 | 
						|
;; Moreover, body of `beginCell` is NOT codegenerated at all.
 | 
						|
;; Hence, we can write camelCase wrappers (as well as more intelligible namings around stdlib functions)
 | 
						|
;; without affecting performance and even bytecode hashes.
 | 
						|
;; This works with ~functions also. And even works with wrappers of wrappers.
 | 
						|
;; Moreover, such wrappers can reorder input parameters, see a separate test camel2.fc.
 | 
						|
 | 
						|
builder begin_cell() pure asm "NEWC";
 | 
						|
cell end_cell(builder b) pure asm "ENDC";
 | 
						|
builder store_ref(builder b, cell c) pure asm(c b) "STREF";
 | 
						|
slice begin_parse(cell c) pure asm "CTOS";
 | 
						|
slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST";
 | 
						|
(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST";
 | 
						|
 | 
						|
builder beginCell() { return begin_cell(); }
 | 
						|
cell endCell(builder b) { return end_cell(b); }
 | 
						|
builder storeRef(builder b, cell c) { return store_ref(b, c); }
 | 
						|
builder storeUint(builder b, int i, int bw) { return store_uint(b, i, bw); }
 | 
						|
 | 
						|
;; 'inline' is not needed actually, but if it exists, it's just ignored
 | 
						|
slice beginParse(cell c) pure inline { return begin_parse(c); }
 | 
						|
slice skipBits(slice s, int len) pure inline { return skip_bits(s, len); }
 | 
						|
(slice, ()) ~skipBits(slice s, int len) pure inline { return ~skip_bits(s, len); }
 | 
						|
(slice, int) ~loadUint(slice s, int len) pure inline { return load_uint(s, len); }
 | 
						|
 | 
						|
(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE";
 | 
						|
(int, int, int) computeDataSize(cell c, int maxCells) { return compute_data_size(c, maxCells); }
 | 
						|
 | 
						|
cell new_dict() pure asm "NEWDICT";
 | 
						|
cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET";
 | 
						|
(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET";
 | 
						|
(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT";
 | 
						|
(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
 | 
						|
 | 
						|
cell dict::new() { return new_dict(); }
 | 
						|
cell dict::iset(cell dict, int keyLen, int index, slice value) { return idict_set(dict, keyLen, index, value); }
 | 
						|
(cell, ()) ~dict::iset(cell dict, int keyLen, int index, slice value) { return ~idict_set(dict, keyLen, index, value); }
 | 
						|
(slice, int) dict::tryIGet(cell dict, int keyLen, int index) { return idict_get?(dict, keyLen, index); }
 | 
						|
(int, slice, int) dict::tryIGetMin(cell dict, int keyLen) { return idict_get_min?(dict, keyLen); }
 | 
						|
 | 
						|
tuple empty_tuple() pure asm "NIL";
 | 
						|
forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH";
 | 
						|
forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH";
 | 
						|
forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND";
 | 
						|
forall X -> X null() pure asm "PUSHNULL";
 | 
						|
 | 
						|
tuple emptyTuple() { return empty_tuple(); }
 | 
						|
tuple emptyTuple1() { return emptyTuple(); }
 | 
						|
tuple emptyTuple11() { return emptyTuple1(); }
 | 
						|
forall X -> tuple tuplePush(tuple t, X value) { return tpush(t, value); }
 | 
						|
forall X -> (tuple, ()) ~tuplePush(tuple t, X value) { return ~tpush(t, value); }
 | 
						|
forall X -> X tupleAt(tuple t, int index) { return at(t, index); }
 | 
						|
forall X1, Y2, Z3 -> Y2 tripleSecond([X1, Y2, Z3] p) { return triple_second(p); }
 | 
						|
forall X -> X nullValue() pure asm "PUSHNULL";
 | 
						|
 | 
						|
() throwIf(int excNo, int condition) { return throw_if(excNo, condition); }
 | 
						|
 | 
						|
tuple initial1(tuple x) { return x; }
 | 
						|
_ initial2(x) { return initial1(x); }
 | 
						|
 | 
						|
int add(int x, int y) { return x + y; } ;; this is also a wrapper, as its body is _+_(x,y)
 | 
						|
 | 
						|
() fake1(int a, int b, int c) asm(a b c) "DROP DROP DROP";
 | 
						|
() fake2(int a, int b, int c) asm(b c a) "DROP DROP DROP";
 | 
						|
() fake3(int a, int b, int c) asm(c a b) "DROP DROP DROP";
 | 
						|
() fake4(int a, int b, int c) asm(c b a) "DROP DROP DROP";
 | 
						|
 | 
						|
() fake1Wrapper(int a, int b, int c) { return fake1(a, b, c); }
 | 
						|
() fake2Wrapper(int a, int b, int c) { return fake2(a, b, c); }
 | 
						|
() fake3Wrapper(int a, int b, int c) { return fake3(a, b, c); }
 | 
						|
() fake4Wrapper(int a, int b, int c) { return fake4(a, b, c); }
 | 
						|
 | 
						|
[int, int, int] test1() method_id(101) {
 | 
						|
    int x = 1;
 | 
						|
    int y = 1;
 | 
						|
    cell to_be_ref = beginCell().endCell();
 | 
						|
    builder in_c = beginCell().storeUint(123, 8);
 | 
						|
    in_c = storeRef(in_c, to_be_ref);
 | 
						|
    var (a, b, c) = computeDataSize(in_c.endCell(), 10);
 | 
						|
    throwIf(101, b != 8);
 | 
						|
    throwIf(101, c != 1);
 | 
						|
    return [a, add(b, x), add(c, y)];
 | 
						|
}
 | 
						|
 | 
						|
[[int, int, int], int, int, int] test2() method_id(102) {
 | 
						|
    cell dict = dict::new();
 | 
						|
    dict = dict::iset(dict, 32, 456, beginCell().storeUint(4560, 32).endCell().beginParse());
 | 
						|
    dict.dict::iset(32, 789, beginCell().storeUint(7890, 32).endCell().beginParse());
 | 
						|
    dict~dict::iset(32, 123, beginCell().storeUint(0, 64).storeUint(1230, 32).storeUint(1231, 32).storeUint(1232, 32).endCell().beginParse());
 | 
						|
 | 
						|
    var (mink, minv, _) = dict::tryIGetMin(dict, 32);
 | 
						|
    ;; skip 64 bits
 | 
						|
    minv~skipBits(16);
 | 
						|
    minv = minv.skipBits(16);
 | 
						|
    minv.skipBits(11);             ;; does nothing
 | 
						|
    (minv, _) = ~skipBits(minv, 16);
 | 
						|
    skipBits(minv, 11);         ;; does nothing
 | 
						|
    minv~skipBits(16);
 | 
						|
    ;; load 3*32
 | 
						|
    var minv1 = minv~loadUint(32);
 | 
						|
    var minv2 = minv~loadUint(32);
 | 
						|
    var minv3 = minv~loadUint(32);
 | 
						|
 | 
						|
    var (_, found123) = dict::tryIGet(dict, 32, 123);
 | 
						|
    var (_, found456) = dict::tryIGet(dict, 32, 456);
 | 
						|
    var (_, found789) = dict::tryIGet(dict, 32, 789);
 | 
						|
    return [[minv1, minv2, minv3], found123, found456, found789];
 | 
						|
}
 | 
						|
 | 
						|
tuple test3() method_id(103) {
 | 
						|
    tuple with34 = initial2(emptyTuple1());
 | 
						|
    with34~tuplePush(34);
 | 
						|
 | 
						|
    tuple t = emptyTuple11();
 | 
						|
    t = tuplePush(t, 12);
 | 
						|
    tuplePush(t, emptyTuple11());    ;; does nothing
 | 
						|
    t~tuplePush(emptyTuple1());
 | 
						|
    t~tuplePush(with34.tupleAt(0));
 | 
						|
    t.tuplePush("123"s);   ;; does nothing
 | 
						|
 | 
						|
    [cell, int, cell] tri = [nullValue(), 90 + 1, null()];
 | 
						|
    int f = tripleSecond(tri);
 | 
						|
    (t, _) = ~tuplePush(t, f);
 | 
						|
 | 
						|
    return t;
 | 
						|
}
 | 
						|
 | 
						|
(int) test4(int a, int b, int c) method_id(104) {
 | 
						|
    fake1Wrapper(a, b, c);
 | 
						|
    fake2Wrapper(a, b, c);
 | 
						|
    fake3Wrapper(a, b, c);
 | 
						|
    fake4Wrapper(a, b, c);
 | 
						|
    return 10;
 | 
						|
}
 | 
						|
 | 
						|
int main() {
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
{-
 | 
						|
    method_id  | in | out
 | 
						|
TESTCASE | 101 |    | [ 2 9 2 ]
 | 
						|
TESTCASE | 102 |    | [ [ 1230 1231 1232 ] -1 -1 0 ]
 | 
						|
TESTCASE | 103 |    | [ 12 [] 34 91 ]
 | 
						|
 | 
						|
@fif_codegen
 | 
						|
"""
 | 
						|
  test1 PROC:<{
 | 
						|
    //
 | 
						|
    NEWC        //  _5
 | 
						|
    ENDC        //  to_be_ref
 | 
						|
    NEWC        //  to_be_ref _8
 | 
						|
    123 PUSHINT //  to_be_ref _8 _9=123
 | 
						|
    SWAP        //  to_be_ref _9=123 _8
 | 
						|
    8 STU       //  to_be_ref in_c
 | 
						|
    STREF       //  in_c
 | 
						|
    ENDC        //  _16
 | 
						|
    10 PUSHINT  //  _16 _17=10
 | 
						|
    CDATASIZE   //  a b c
 | 
						|
    OVER        //  a b c b
 | 
						|
    8 NEQINT    //  a b c _21
 | 
						|
    101 THROWIF
 | 
						|
    DUP //  a b c c
 | 
						|
    1 NEQINT    //  a b c _25
 | 
						|
    101 THROWIF
 | 
						|
    SWAP        //  a c b
 | 
						|
    INC //  a c _28
 | 
						|
    SWAP        //  a _28 c
 | 
						|
    INC //  a _28 _29
 | 
						|
    TRIPLE      //  _27
 | 
						|
  }>
 | 
						|
"""
 | 
						|
 | 
						|
@fif_codegen
 | 
						|
"""
 | 
						|
  test2 PROC:<{
 | 
						|
    ...
 | 
						|
    16 PUSHINT	//  dict minv _45=16
 | 
						|
    SDSKIPFIRST	//  dict minv
 | 
						|
    16 PUSHINT	//  dict minv _47=16
 | 
						|
    SDSKIPFIRST	//  dict minv
 | 
						|
    16 PUSHINT	//  dict minv _52=16
 | 
						|
    SDSKIPFIRST	//  dict minv
 | 
						|
    16 PUSHINT	//  dict minv _57=16
 | 
						|
    SDSKIPFIRST	//  dict minv
 | 
						|
    ...
 | 
						|
    32 PUSHINT  //  dict minv1 minv2 minv3 found123 found456 _83=32
 | 
						|
    789 PUSHINT //  dict minv1 minv2 minv3 found123 found456 _83=32 _84=789
 | 
						|
    s0 s7 s7 XCHG3      //  found456 minv1 minv2 minv3 found123 _84=789 dict _83=32
 | 
						|
    DICTIGET
 | 
						|
    NULLSWAPIFNOT       //  found456 minv1 minv2 minv3 found123 _101 _102
 | 
						|
    NIP //  found456 minv1 minv2 minv3 found123 found789
 | 
						|
    ...
 | 
						|
    4 TUPLE	//  _86
 | 
						|
  }>
 | 
						|
"""
 | 
						|
 | 
						|
@fif_codegen
 | 
						|
"""
 | 
						|
  test3 PROC:<{
 | 
						|
    //
 | 
						|
    NIL	//  _1
 | 
						|
    initial1 CALLDICT // with34
 | 
						|
    ...
 | 
						|
    TRIPLE	//  t tri
 | 
						|
    SECOND	//  t f
 | 
						|
    TPUSH	//  t
 | 
						|
  }>
 | 
						|
"""
 | 
						|
 | 
						|
@fif_codegen
 | 
						|
"""
 | 
						|
  test4 PROC:<{
 | 
						|
    //  a b c
 | 
						|
    s2 s1 s0 PUSH3	//  a b c a b c
 | 
						|
    DROP DROP DROP
 | 
						|
    s1 s0 s2 PUSH3	//  a b c b c a
 | 
						|
    DROP DROP DROP
 | 
						|
    s0 s2 s1 PUSH3	//  a b c c a b
 | 
						|
    DROP DROP DROP
 | 
						|
    s0 s2 XCHG	//  c b a
 | 
						|
    DROP DROP DROP
 | 
						|
    10 PUSHINT	//  _7=10
 | 
						|
  }>
 | 
						|
"""
 | 
						|
 | 
						|
@fif_codegen_avoid DECLPROC beginCell
 | 
						|
@fif_codegen_avoid DECLPROC storeUint
 | 
						|
@fif_codegen_avoid DECLPROC storeRef
 | 
						|
@fif_codegen_avoid DECLPROC computeDataSize
 | 
						|
@fif_codegen_avoid DECLPROC tryIdictGet
 | 
						|
@fif_codegen_avoid DECLPROC emptyTuple
 | 
						|
@fif_codegen_avoid DECLPROC storeUint1
 | 
						|
@fif_codegen_avoid DECLPROC initial2
 | 
						|
@fif_codegen_avoid DECLPROC add
 | 
						|
-}
 |