From ebd72d920352f287a12f82448871c75f23f35902 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Thu, 1 Sep 2022 15:31:23 +0300 Subject: [PATCH 01/13] Return mapping from variables to registers --- src/aeso_compiler.erl | 5 +++-- src/aeso_fcode_to_fate.erl | 32 +++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index d49c47d..0bc1329 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -115,7 +115,7 @@ from_string1(ContractString, Options) -> , fcode_env := #{child_con_env := ChildContracts} , folded_typed_ast := FoldedTypedAst , warnings := Warnings } = string_to_code(ContractString, Options), - FateCode = aeso_fcode_to_fate:compile(ChildContracts, FCode, Options), + {FateCode, VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, FCode, Options), pp_assembler(FateCode, Options), ByteCode = aeb_fate_code:serialize(FateCode, []), {ok, Version} = version(), @@ -126,6 +126,7 @@ from_string1(ContractString, Options) -> fate_code => FateCode, abi_version => aeb_fate_abi:abi_version(), payable => maps:get(payable, FCode), + variables_registers => VarsRegs, warnings => Warnings }, {ok, maybe_generate_aci(Res, FoldedTypedAst, Options)}. @@ -185,7 +186,7 @@ check_call1(ContractString0, FunName, Args, Options) -> #{fcode := OrgFcode , fcode_env := #{child_con_env := ChildContracts} , ast := Ast} = string_to_code(ContractString0, Options), - FateCode = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, []), + {FateCode, _VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, []), %% collect all hashes and compute the first name without hash collision to SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)), CallName = first_none_match(?CALL_NAME, SymbolHashes, diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index cdf0c8f..0712f44 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -76,13 +76,18 @@ compile(FCode, Options) -> compile(ChildContracts, FCode, Options) -> #{ contract_name := ContractName, functions := Functions } = FCode, - SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options), - SFuns1 = optimize_scode(SFuns, Options), - FateCode = to_basic_blocks(SFuns1), - ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), - case proplists:get_value(include_child_contract_symbols, Options, false) of - false -> FateCode; - true -> add_child_symbols(ChildContracts, FateCode) + try + SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options), + SFuns1 = optimize_scode(SFuns, Options), + FateCode = to_basic_blocks(SFuns1), + ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), + FateCode1 = case proplists:get_value(include_child_contract_symbols, Options, false) of + false -> FateCode; + true -> add_child_symbols(ChildContracts, FateCode) + end, + {FateCode1, get_variables_registers()} + after + put(variables_registers, undefined) end. make_function_id(X) -> @@ -110,9 +115,21 @@ function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, B {ArgTypes, ResType1} = typesig_to_scode(Args, ResType), Attrs = Attrs0 -- [stateful], %% Only track private and payable from here. Env = init_env(ChildContracts, ContractName, Functions, Name, Args, Options), + [ add_variables_register(Env, Arg, Register) || {Arg, Register} <- Env#env.vars ], SCode = to_scode(Env, Body), {Attrs, {ArgTypes, ResType1}, SCode}. +get_variables_registers() -> + case get(variables_registers) of + undefined -> []; + Vs -> Vs + end. + +add_variables_register(Env, Name, Register) -> + Olds = get_variables_registers(), + New = {Env#env.contract, Env#env.current_function, Name, Register}, + put(variables_registers, [New | Olds]). + -define(tvars, '$tvars'). typesig_to_scode(Args, Res) -> @@ -170,6 +187,7 @@ next_var(#env{ vars = Vars }) -> 1 + lists:max([-1 | [J || {_, {var, J}} <- Vars]]). bind_var(Name, Var, Env = #env{ vars = Vars }) -> + add_variables_register(Env, Name, Var), Env#env{ vars = [{Name, Var} | Vars] }. bind_local(Name, Env) -> -- 2.30.2 From 49200a6c55a4cbb81a2c222b911d8f1f87039b69 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Thu, 13 Oct 2022 11:28:44 +0300 Subject: [PATCH 02/13] Fix dialyzer issues --- src/aeso_ast_infer_types.erl | 14 +++++++------- src/aeso_fcode_to_fate.erl | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 03cbe2f..2387779 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -1487,7 +1487,7 @@ check_reserved_entrypoints(Funs) -> check_fundecl(Env, {fun_decl, Ann, Id = {id, _, Name}, Type = {fun_t, _, _, _, _}}) -> Type1 = {fun_t, _, Named, Args, Ret} = check_type(Env, Type), TypeSig = {type_sig, Ann, none, Named, Args, Ret}, - register_implementation(Env, Name), + register_implementation(Name), {{Name, TypeSig}, {fun_decl, Ann, Id, Type1}}; check_fundecl(Env, {fun_decl, Ann, Id = {id, _, Name}, Type}) -> type_error({fundecl_must_have_funtype, Ann, Id, Type}), @@ -1495,11 +1495,11 @@ check_fundecl(Env, {fun_decl, Ann, Id = {id, _, Name}, Type}) -> %% Register the function FunName as implemented by deleting it from the functions %% to be implemented table if it is included there, or return true otherwise. --spec register_implementation(env(), FunName) -> true | no_return() when +-spec register_implementation(FunName) -> true | no_return() when FunName :: string(). -register_implementation(Env, Name) -> +register_implementation(Name) -> case ets_lookup(functions_to_implement, Name) of - [{Name, _, {fun_decl, _, _, DeclType}}] -> + [{Name, _, {fun_decl, _, _, _}}] -> ets_delete(functions_to_implement, Name); [] -> true; @@ -1509,9 +1509,9 @@ register_implementation(Env, Name) -> infer_nonrec(Env, LetFun) -> create_constraints(), - NewLetFun = {{FunName, FunSig}, _} = infer_letfun(Env, LetFun), + NewLetFun = {{FunName, _}, _} = infer_letfun(Env, LetFun), check_special_funs(Env, NewLetFun), - register_implementation(Env, FunName), + register_implementation(FunName), solve_then_destroy_and_report_unsolved_constraints(Env), Result = {TypeSig, _} = instantiate(NewLetFun), print_typesig(TypeSig), @@ -1541,7 +1541,7 @@ infer_letrec(Env, Defs) -> Inferred = [ begin Res = {{Name, TypeSig}, _} = infer_letfun(ExtendEnv, LF), - register_implementation(Env, Name), + register_implementation(Name), Got = proplists:get_value(Name, Funs), Expect = typesig_to_fun_t(TypeSig), unify(Env, Got, Expect, {check_typesig, Name, Got, Expect}), diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 0712f44..3282790 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -213,7 +213,7 @@ serialize_contract_code(Env, C) -> none -> Options = Env#env.options, FCode = maps:get(C, Env#env.child_contracts), - FateCode = compile(Env#env.child_contracts, FCode, Options), + {FateCode, _} = compile(Env#env.child_contracts, FCode, Options), ByteCode = aeb_fate_code:serialize(FateCode, []), {ok, Version} = aeso_compiler:version(), OriginalSourceCode = proplists:get_value(original_src, Options, ""), -- 2.30.2 From f8f67ced4791296a1fb2b0e0e82be4a0ec551f26 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Mon, 17 Oct 2022 19:13:37 +0300 Subject: [PATCH 03/13] Record real names --- src/aeso_ast_to_fcode.erl | 33 +++++++++++++++++++++++++-------- src/aeso_fcode_to_fate.erl | 38 ++++++++++++++++++++++++-------------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 1e0138e..d2ff835 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -122,12 +122,13 @@ return := ftype(), body := fexpr() }. --type fcode() :: #{ contract_name := string(), - state_type := ftype(), - state_layout := state_layout(), - event_type := ftype() | none, - functions := #{ fun_name() => fun_def() }, - payable := boolean() }. +-type fcode() :: #{ contract_name := string(), + state_type := ftype(), + state_layout := state_layout(), + event_type := ftype() | none, + functions := #{ fun_name() => fun_def() }, + payable := boolean(), + saved_fresh_names := #{ var_name() => var_name() } }. -type type_def() :: fun(([ftype()]) -> ftype()). @@ -171,6 +172,7 @@ -spec ast_to_fcode(aeso_syntax:ast(), [option()]) -> {env(), fcode()}. ast_to_fcode(Code, Options) -> init_fresh_names(), + init_saved_fresh_names(), {Env1, FCode1} = to_fcode(init_env(Options), Code), FCode2 = optimize(FCode1, Options), Env2 = Env1#{ child_con_env := @@ -178,8 +180,10 @@ ast_to_fcode(Code, Options) -> fun (_, FC) -> optimize(FC, Options) end, maps:get(child_con_env, Env1) )}, + FCode3 = FCode2#{saved_fresh_names => get(saved_fresh_names)}, clear_fresh_names(), - {Env2, FCode2}. + clear_saved_fresh_names(), + {Env2, FCode3}. optimize(FCode1, Options) -> Verbose = lists:member(pp_fcode, Options), @@ -1734,6 +1738,19 @@ init_fresh_names() -> clear_fresh_names() -> erase('%fresh'). +init_saved_fresh_names() -> + put(saved_fresh_names, #{}). + +clear_saved_fresh_names() -> + erase(saved_fresh_names). + +-spec fresh_name_save(string()) -> var_name(). +fresh_name_save(Name) -> + Fresh = fresh_name(), + Old = get(saved_fresh_names), + New = put(saved_fresh_names, Old#{Fresh => Name}), + Fresh. + -spec fresh_name() -> var_name(). fresh_name() -> fresh_name("%"). @@ -1862,7 +1879,7 @@ bottom_up(F, Env, Expr) -> (_) -> true end, case ShouldFreshen(X) of true -> - Z = fresh_name(), + Z = fresh_name_save(X), Env1 = Env#{ Z => E1 }, {'let', Z, E1, bottom_up(F, Env1, rename([{X, Z}], Body))}; false -> diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 3282790..5f276c0 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -45,7 +45,14 @@ -define(s(N), {store, N}). -define(void, {var, 9999}). --record(env, { contract, vars = [], locals = [], current_function, tailpos = true, child_contracts = #{}, options = []}). +-record(env, { contract, + vars = [], + locals = [], + current_function, + tailpos = true, + child_contracts = #{}, + saved_fresh_names = #{}, + options = [] }). %% -- Debugging -------------------------------------------------------------- @@ -74,10 +81,11 @@ code_error(Err) -> compile(FCode, Options) -> compile(#{}, FCode, Options). compile(ChildContracts, FCode, Options) -> - #{ contract_name := ContractName, - functions := Functions } = FCode, + #{ contract_name := ContractName, + functions := Functions, + saved_fresh_names := SavedFreshNames } = FCode, try - SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options), + SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options), SFuns1 = optimize_scode(SFuns, Options), FateCode = to_basic_blocks(SFuns1), ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), @@ -102,33 +110,34 @@ add_child_symbols(ChildContracts, FateCode) -> Symbols = maps:from_list([ {make_function_id(FName), make_function_name(FName)} || FName <- Funs ]), aeb_fate_code:update_symbols(FateCode, Symbols). -functions_to_scode(ChildContracts, ContractName, Functions, Options) -> +functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options) -> FunNames = maps:keys(Functions), maps:from_list( - [ {make_function_name(Name), function_to_scode(ChildContracts, ContractName, FunNames, Name, Attrs, Args, Body, Type, Options)} + [ {make_function_name(Name), function_to_scode(ChildContracts, ContractName, FunNames, Name, Attrs, Args, Body, Type, SavedFreshNames, Options)} || {Name, #{args := Args, body := Body, attrs := Attrs, return := Type}} <- maps:to_list(Functions)]). -function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, Body, ResType, Options) -> +function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, Body, ResType, SavedFreshNames, Options) -> {ArgTypes, ResType1} = typesig_to_scode(Args, ResType), Attrs = Attrs0 -- [stateful], %% Only track private and payable from here. - Env = init_env(ChildContracts, ContractName, Functions, Name, Args, Options), + Env = init_env(ChildContracts, ContractName, Functions, Name, Args, SavedFreshNames, Options), [ add_variables_register(Env, Arg, Register) || {Arg, Register} <- Env#env.vars ], SCode = to_scode(Env, Body), {Attrs, {ArgTypes, ResType1}, SCode}. get_variables_registers() -> case get(variables_registers) of - undefined -> []; + undefined -> #{}; Vs -> Vs end. -add_variables_register(Env, Name, Register) -> +add_variables_register(Env = #env{saved_fresh_names = SavedFreshNames}, Name, Register) -> Olds = get_variables_registers(), - New = {Env#env.contract, Env#env.current_function, Name, Register}, - put(variables_registers, [New | Olds]). + RealName = maps:get(Name, SavedFreshNames, Name), + New = {Env#env.contract, Env#env.current_function, RealName}, + put(variables_registers, Olds#{New => Register}). -define(tvars, '$tvars'). @@ -174,14 +183,15 @@ types_to_scode(Ts) -> lists:map(fun type_to_scode/1, Ts). %% -- Environment functions -- -init_env(ChildContracts, ContractName, FunNames, Name, Args, Options) -> +init_env(ChildContracts, ContractName, FunNames, Name, Args, SavedFreshNames, Options) -> #env{ vars = [ {X, {arg, I}} || {I, {X, _}} <- with_ixs(Args) ], contract = ContractName, child_contracts = ChildContracts, locals = FunNames, current_function = Name, options = Options, - tailpos = true }. + tailpos = true, + saved_fresh_names = SavedFreshNames }. next_var(#env{ vars = Vars }) -> 1 + lists:max([-1 | [J || {_, {var, J}} <- Vars]]). -- 2.30.2 From 4715894471b9e731c7324b9da90953e5c5d86f07 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sun, 23 Oct 2022 11:02:48 +0300 Subject: [PATCH 04/13] Report saved fresh names as part of fcode env --- src/aeso_ast_to_fcode.erl | 32 ++++++++++++++--------------- src/aeso_compiler.erl | 8 ++++---- src/aeso_fcode_to_fate.erl | 41 ++++++++++++++++++++------------------ 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index d2ff835..6821871 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -127,8 +127,7 @@ state_layout := state_layout(), event_type := ftype() | none, functions := #{ fun_name() => fun_def() }, - payable := boolean(), - saved_fresh_names := #{ var_name() => var_name() } }. + payable := boolean() }. -type type_def() :: fun(([ftype()]) -> ftype()). @@ -150,17 +149,18 @@ -type state_layout() :: {tuple, [state_layout()]} | {reg, state_reg()}. --type env() :: #{ type_env := type_env(), - fun_env := fun_env(), - con_env := con_env(), - child_con_env := child_con_env(), - event_type => aeso_syntax:typedef(), - builtins := builtins(), - options := [option()], - state_layout => state_layout(), - context => context(), - vars => [var_name()], - functions := #{ fun_name() => fun_def() } +-type env() :: #{ type_env := type_env(), + fun_env := fun_env(), + con_env := con_env(), + child_con_env := child_con_env(), + event_type => aeso_syntax:typedef(), + builtins := builtins(), + options := [option()], + state_layout => state_layout(), + context => context(), + vars => [var_name()], + functions := #{ fun_name() => fun_def() }, + saved_fresh_names := #{ var_name() => var_name() } }. -define(HASH_BYTES, 32). @@ -180,10 +180,10 @@ ast_to_fcode(Code, Options) -> fun (_, FC) -> optimize(FC, Options) end, maps:get(child_con_env, Env1) )}, - FCode3 = FCode2#{saved_fresh_names => get(saved_fresh_names)}, + Env3 = Env2#{ saved_fresh_names => get(saved_fresh_names) }, clear_fresh_names(), clear_saved_fresh_names(), - {Env2, FCode3}. + {Env3, FCode2}. optimize(FCode1, Options) -> Verbose = lists:member(pp_fcode, Options), @@ -1748,7 +1748,7 @@ clear_saved_fresh_names() -> fresh_name_save(Name) -> Fresh = fresh_name(), Old = get(saved_fresh_names), - New = put(saved_fresh_names, Old#{Fresh => Name}), + put(saved_fresh_names, Old#{Fresh => Name}), Fresh. -spec fresh_name() -> var_name(). diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 0bc1329..389d057 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -112,10 +112,10 @@ from_string(ContractString, Options) -> from_string1(ContractString, Options) -> #{ fcode := FCode - , fcode_env := #{child_con_env := ChildContracts} + , fcode_env := #{child_con_env := ChildContracts, saved_fresh_names := SavedFreshNames} , folded_typed_ast := FoldedTypedAst , warnings := Warnings } = string_to_code(ContractString, Options), - {FateCode, VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, FCode, Options), + {FateCode, VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options), pp_assembler(FateCode, Options), ByteCode = aeb_fate_code:serialize(FateCode, []), {ok, Version} = version(), @@ -184,9 +184,9 @@ check_call1(ContractString0, FunName, Args, Options) -> try %% First check the contract without the __call function #{fcode := OrgFcode - , fcode_env := #{child_con_env := ChildContracts} + , fcode_env := #{child_con_env := ChildContracts, saved_fresh_names := SavedFreshNames} , ast := Ast} = string_to_code(ContractString0, Options), - {FateCode, _VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, []), + {FateCode, _VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, SavedFreshNames, []), %% collect all hashes and compute the first name without hash collision to SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)), CallName = first_none_match(?CALL_NAME, SymbolHashes, diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 5f276c0..03559c1 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -9,7 +9,7 @@ %%%------------------------------------------------------------------- -module(aeso_fcode_to_fate). --export([compile/2, compile/3, term_to_fate/1, term_to_fate/2]). +-export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]). -ifdef(TEST). -export([optimize_fun/4, to_basic_blocks/1]). @@ -78,26 +78,28 @@ code_error(Err) -> %% -- Main ------------------------------------------------------------------- %% @doc Main entry point. -compile(FCode, Options) -> - compile(#{}, FCode, Options). -compile(ChildContracts, FCode, Options) -> - #{ contract_name := ContractName, - functions := Functions, - saved_fresh_names := SavedFreshNames } = FCode, +compile(FCode, SavedFreshNames, Options) -> + compile(#{}, FCode, SavedFreshNames, Options). +compile(ChildContracts, FCode, SavedFreshNames, Options) -> try - SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options), - SFuns1 = optimize_scode(SFuns, Options), - FateCode = to_basic_blocks(SFuns1), - ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), - FateCode1 = case proplists:get_value(include_child_contract_symbols, Options, false) of - false -> FateCode; - true -> add_child_symbols(ChildContracts, FateCode) - end, - {FateCode1, get_variables_registers()} + compile1(ChildContracts, FCode, SavedFreshNames, Options) after put(variables_registers, undefined) end. +compile1(ChildContracts, FCode, SavedFreshNames, Options) -> + #{ contract_name := ContractName, + functions := Functions } = FCode, + SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options), + SFuns1 = optimize_scode(SFuns, Options), + FateCode = to_basic_blocks(SFuns1), + ?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), + FateCode1 = case proplists:get_value(include_child_contract_symbols, Options, false) of + false -> FateCode; + true -> add_child_symbols(ChildContracts, FateCode) + end, + {FateCode1, get_variables_registers()}. + make_function_id(X) -> aeb_fate_code:symbol_identifier(make_function_name(X)). @@ -221,9 +223,10 @@ serialize_contract_code(Env, C) -> end, case maps:get(C, Cache, none) of none -> - Options = Env#env.options, - FCode = maps:get(C, Env#env.child_contracts), - {FateCode, _} = compile(Env#env.child_contracts, FCode, Options), + Options = Env#env.options, + SavedFreshNames = Env#env.saved_fresh_names, + FCode = maps:get(C, Env#env.child_contracts), + {FateCode, _} = compile1(Env#env.child_contracts, FCode, SavedFreshNames, Options), ByteCode = aeb_fate_code:serialize(FateCode, []), {ok, Version} = aeso_compiler:version(), OriginalSourceCode = proplists:get_value(original_src, Options, ""), -- 2.30.2 From ce24f0bc67c42d43d7b5357dd5d3475106aa29b0 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sun, 23 Oct 2022 11:18:19 +0300 Subject: [PATCH 05/13] Undo whitespace changes --- src/aeso_ast_to_fcode.erl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 6821871..ad9ed37 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -122,12 +122,12 @@ return := ftype(), body := fexpr() }. --type fcode() :: #{ contract_name := string(), - state_type := ftype(), - state_layout := state_layout(), - event_type := ftype() | none, - functions := #{ fun_name() => fun_def() }, - payable := boolean() }. +-type fcode() :: #{ contract_name := string(), + state_type := ftype(), + state_layout := state_layout(), + event_type := ftype() | none, + functions := #{ fun_name() => fun_def() }, + payable := boolean() }. -type type_def() :: fun(([ftype()]) -> ftype()). -- 2.30.2 From f9b8114c0c18f075b58606ed30ef834d50730f40 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sun, 23 Oct 2022 11:23:28 +0300 Subject: [PATCH 06/13] Fix dialyzer warnings --- src/aeso_ast_to_fcode.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index ad9ed37..c2bbe41 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -180,7 +180,7 @@ ast_to_fcode(Code, Options) -> fun (_, FC) -> optimize(FC, Options) end, maps:get(child_con_env, Env1) )}, - Env3 = Env2#{ saved_fresh_names => get(saved_fresh_names) }, + Env3 = Env2#{ saved_fresh_names := get(saved_fresh_names) }, clear_fresh_names(), clear_saved_fresh_names(), {Env3, FCode2}. @@ -237,8 +237,9 @@ init_env(Options) -> ["Chain", "ContractCallTx"] => #con_tag{ tag = 20, arities = ChainTxArities }, ["Chain", "GAAttachTx"] => #con_tag{ tag = 21, arities = ChainTxArities } }, - options => Options, - functions => #{} + options => Options, + functions => #{}, + saved_fresh_names => #{} }. -spec builtins() -> builtins(). -- 2.30.2 From 4aa3a6b5051359bb19aff0721bbb03f30a7ce7b9 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sun, 23 Oct 2022 11:26:22 +0300 Subject: [PATCH 07/13] Formatting fix --- src/aeso_fcode_to_fate.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 03559c1..6797bb8 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -46,13 +46,13 @@ -define(void, {var, 9999}). -record(env, { contract, - vars = [], - locals = [], + vars = [], + locals = [], current_function, - tailpos = true, - child_contracts = #{}, + tailpos = true, + child_contracts = #{}, saved_fresh_names = #{}, - options = [] }). + options = [] }). %% -- Debugging -------------------------------------------------------------- -- 2.30.2 From 20f6d0d130867bbd920f1a34d313f1108f3d2afe Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sun, 23 Oct 2022 12:12:29 +0300 Subject: [PATCH 08/13] Use function names as strings --- src/aeso_fcode_to_fate.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 6797bb8..541cb74 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -138,7 +138,8 @@ get_variables_registers() -> add_variables_register(Env = #env{saved_fresh_names = SavedFreshNames}, Name, Register) -> Olds = get_variables_registers(), RealName = maps:get(Name, SavedFreshNames, Name), - New = {Env#env.contract, Env#env.current_function, RealName}, + FunName = binary_to_list(make_function_name(Env#env.current_function)), + New = {Env#env.contract, FunName, RealName}, put(variables_registers, Olds#{New => Register}). -define(tvars, '$tvars'). -- 2.30.2 From cb588dc04be1804d7cca5216c2e66f1aba9af015 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sun, 23 Oct 2022 12:45:38 +0300 Subject: [PATCH 09/13] Manually handle making function names --- src/aeso_fcode_to_fate.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 541cb74..59f1f72 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -138,7 +138,12 @@ get_variables_registers() -> add_variables_register(Env = #env{saved_fresh_names = SavedFreshNames}, Name, Register) -> Olds = get_variables_registers(), RealName = maps:get(Name, SavedFreshNames, Name), - FunName = binary_to_list(make_function_name(Env#env.current_function)), + FunName = + case Env#env.current_function of + event -> "Chain.event"; + {entrypoint, BinName} -> binary_to_list(BinName); + {local_fun, QualName} -> lists:last(QualName) + end, New = {Env#env.contract, FunName, RealName}, put(variables_registers, Olds#{New => Register}). -- 2.30.2 From d84e21a5ada46f488027699f3d4301ab36f5455e Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sun, 23 Oct 2022 12:59:37 +0300 Subject: [PATCH 10/13] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab4867a..63e2043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 entrypoint spend(x : int) : int = x entrypoint f(c : Main) : int = c.spend(10) ``` +- Return a mapping from variables to FATE registers in the compilation output. ### Changed ### Removed ### Fixed -- 2.30.2 From ee37e187e892c32303370919ee048a21ec18e25f Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Tue, 25 Oct 2022 08:14:40 +0300 Subject: [PATCH 11/13] Make variables registers optional --- src/aeso_ast_to_fcode.erl | 26 ++++++++++++++++---------- src/aeso_compiler.erl | 17 ++++++++++++----- src/aeso_fcode_to_fate.erl | 6 ++++-- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index c2bbe41..c2cf586 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -160,7 +160,7 @@ context => context(), vars => [var_name()], functions := #{ fun_name() => fun_def() }, - saved_fresh_names := #{ var_name() => var_name() } + saved_fresh_names => #{ var_name() => var_name() } }. -define(HASH_BYTES, 32). @@ -171,8 +171,7 @@ %% and produces Fate intermediate code. -spec ast_to_fcode(aeso_syntax:ast(), [option()]) -> {env(), fcode()}. ast_to_fcode(Code, Options) -> - init_fresh_names(), - init_saved_fresh_names(), + init_fresh_names(Options), {Env1, FCode1} = to_fcode(init_env(Options), Code), FCode2 = optimize(FCode1, Options), Env2 = Env1#{ child_con_env := @@ -180,9 +179,12 @@ ast_to_fcode(Code, Options) -> fun (_, FC) -> optimize(FC, Options) end, maps:get(child_con_env, Env1) )}, - Env3 = Env2#{ saved_fresh_names := get(saved_fresh_names) }, - clear_fresh_names(), - clear_saved_fresh_names(), + Env3 = + case proplists:get_value(debug_info, Options, false) of + true -> Env2#{ saved_fresh_names => get(saved_fresh_names) }; + false -> Env2 + end, + clear_fresh_names(Options), {Env3, FCode2}. optimize(FCode1, Options) -> @@ -1733,10 +1735,12 @@ resolve_fun(#{ fun_env := Funs, builtins := Builtin } = Env, Q) -> {{Fun, Ar}, _} -> {def_u, Fun, Ar} end. -init_fresh_names() -> +init_fresh_names(Options) -> + proplists:get_value(debug_info, Options, false) andalso init_saved_fresh_names(), put('%fresh', 0). -clear_fresh_names() -> +clear_fresh_names(Options) -> + proplists:get_value(debug_info, Options, false) andalso clear_saved_fresh_names(), erase('%fresh'). init_saved_fresh_names() -> @@ -1748,8 +1752,10 @@ clear_saved_fresh_names() -> -spec fresh_name_save(string()) -> var_name(). fresh_name_save(Name) -> Fresh = fresh_name(), - Old = get(saved_fresh_names), - put(saved_fresh_names, Old#{Fresh => Name}), + case get(saved_fresh_names) of + undefined -> ok; + Old -> put(saved_fresh_names, Old#{Fresh => Name}) + end, Fresh. -spec fresh_name() -> var_name(). diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 389d057..31b4ef8 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -112,9 +112,11 @@ from_string(ContractString, Options) -> from_string1(ContractString, Options) -> #{ fcode := FCode - , fcode_env := #{child_con_env := ChildContracts, saved_fresh_names := SavedFreshNames} + , fcode_env := FCodeEnv , folded_typed_ast := FoldedTypedAst , warnings := Warnings } = string_to_code(ContractString, Options), + #{ child_con_env := ChildContracts } = FCodeEnv, + SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}), {FateCode, VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options), pp_assembler(FateCode, Options), ByteCode = aeb_fate_code:serialize(FateCode, []), @@ -126,10 +128,15 @@ from_string1(ContractString, Options) -> fate_code => FateCode, abi_version => aeb_fate_abi:abi_version(), payable => maps:get(payable, FCode), - variables_registers => VarsRegs, warnings => Warnings }, - {ok, maybe_generate_aci(Res, FoldedTypedAst, Options)}. + ResDbg = Res#{variables_registers => VarsRegs}, + FinalRes = + case proplists:get_value(debug_info, Options, false) of + true -> ResDbg; + false -> Res + end, + {ok, maybe_generate_aci(FinalRes, FoldedTypedAst, Options)}. maybe_generate_aci(Result, FoldedTypedAst, Options) -> case proplists:get_value(aci, Options) of @@ -184,9 +191,9 @@ check_call1(ContractString0, FunName, Args, Options) -> try %% First check the contract without the __call function #{fcode := OrgFcode - , fcode_env := #{child_con_env := ChildContracts, saved_fresh_names := SavedFreshNames} + , fcode_env := #{child_con_env := ChildContracts} , ast := Ast} = string_to_code(ContractString0, Options), - {FateCode, _VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, SavedFreshNames, []), + {FateCode, _} = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, #{}, []), %% collect all hashes and compute the first name without hash collision to SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)), CallName = first_none_match(?CALL_NAME, SymbolHashes, diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 59f1f72..ebc4ebf 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -125,7 +125,9 @@ function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, B {ArgTypes, ResType1} = typesig_to_scode(Args, ResType), Attrs = Attrs0 -- [stateful], %% Only track private and payable from here. Env = init_env(ChildContracts, ContractName, Functions, Name, Args, SavedFreshNames, Options), - [ add_variables_register(Env, Arg, Register) || {Arg, Register} <- Env#env.vars ], + [ add_variables_register(Env, Arg, Register) || + proplists:get_value(debug_info, Options, false), + {Arg, Register} <- Env#env.vars ], SCode = to_scode(Env, Body), {Attrs, {ArgTypes, ResType1}, SCode}. @@ -205,7 +207,7 @@ next_var(#env{ vars = Vars }) -> 1 + lists:max([-1 | [J || {_, {var, J}} <- Vars]]). bind_var(Name, Var, Env = #env{ vars = Vars }) -> - add_variables_register(Env, Name, Var), + proplists:get_value(debug_info, Env#env.options, false) andalso add_variables_register(Env, Name, Var), Env#env{ vars = [{Name, Var} | Vars] }. bind_local(Name, Env) -> -- 2.30.2 From 99f20f25234f5ef1ee31579e83b965b3e5fad787 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Tue, 25 Oct 2022 08:17:38 +0300 Subject: [PATCH 12/13] Update docs about the new flag --- docs/aeso_compiler.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/aeso_compiler.md b/docs/aeso_compiler.md index 4798ad4..61ee7aa 100644 --- a/docs/aeso_compiler.md +++ b/docs/aeso_compiler.md @@ -53,6 +53,8 @@ The **pp_** options all print to standard output the following: The option `include_child_contract_symbols` includes the symbols of child contracts functions in the generated fate code. It is turned off by default to avoid making contracts bigger on chain. +The option `debug_info` includes information related to debugging in the compiler output. Currently this option only includes the mapping from variables to registers. + #### Options to control which compiler optimizations should run: By default all optimizations are turned on, to disable an optimization, it should be -- 2.30.2 From 2c6afd5ee068b6c18f2dcdcb14f824c0906ba984 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Tue, 25 Oct 2022 08:20:30 +0300 Subject: [PATCH 13/13] Remove empty saved_fresh_names map from fcode env --- src/aeso_ast_to_fcode.erl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index c2cf586..f3dd9cc 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -239,9 +239,8 @@ init_env(Options) -> ["Chain", "ContractCallTx"] => #con_tag{ tag = 20, arities = ChainTxArities }, ["Chain", "GAAttachTx"] => #con_tag{ tag = 21, arities = ChainTxArities } }, - options => Options, - functions => #{}, - saved_fresh_names => #{} + options => Options, + functions => #{} }. -spec builtins() -> builtins(). -- 2.30.2