New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Struct encoder #2433

Closed
wants to merge 13 commits into
base: develop
from

Conversation

Projects
None yet
2 participants
@chriseth
Contributor

chriseth commented Jun 21, 2017

  • reduce duplication of generated code
  • simple JULIA optimizer stage
  • check where ABI encoders from storage are used, verify code coverage and add tests if needed

Currently, we can only reduce duplication if all encoders are handled in a single pass of the JULIA parser, because only then we can have different JULIA functions referencing themselves. This is only possible if the ABI encoder has a label we can jump to. This requires the following refactorings:

Each call to encodeToMemory has to be changed to an actual function call and for that, the return label has to be put onto the stack before the values to encode are put onto the stack.

Furthermore, we have to have a way to reference a label in a piece of JULIA code from outside of that JULIA code and this also has to be possible before that code is even parsed.

I think the best solution to this problem is to provide a string as a hint to AbstractAssembly::newLabelID so that the EVM assembly can specially prepare some label ids to be linked properly.

Depends on #1673 and #2704.

@chriseth chriseth changed the title from Struct encoder to [WIP] Struct encoder Jun 21, 2017

@axic

This comment has been minimized.

Show comment
Hide comment
@axic

axic Jun 26, 2017

Member

Please rebase to use Whiskers 😉

Member

axic commented Jun 26, 2017

Please rebase to use Whiskers 😉

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Jun 29, 2017

Contributor

Only fails 105 out of 422 end to end test! :-)

Contributor

chriseth commented Jun 29, 2017

Only fails 105 out of 422 end to end test! :-)

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Jun 29, 2017

Contributor

Down to 69

Contributor

chriseth commented Jun 29, 2017

Down to 69

@chriseth chriseth referenced this pull request Jun 29, 2017

Closed

Support returning structs #1601

0 of 2 tasks complete
@@ -311,7 +311,7 @@ void ContractCompiler::appendCalldataUnpacker(TypePointers const& _typeParameter
{
// stack: v1 v2 ... v(k-1) base_offset current_offset
TypePointer type = parameterType->decodingType();
solAssert(type, "No decoding type found.");
solUnimplementedAssert(type, "No decoding type found.");

This comment has been minimized.

@axic

axic Jun 30, 2017

Member

Perhaps take this with the other change too (in general I like those specific solUnimplementedAsserts better from a user's perspective).

@axic

axic Jun 30, 2017

Member

Perhaps take this with the other change too (in general I like those specific solUnimplementedAsserts better from a user's perspective).

This comment has been minimized.

@chriseth

chriseth Jun 30, 2017

Contributor

No, this has to be an assert in current develop, I changed it to an unimplemented because of the new struct types.

@chriseth

chriseth Jun 30, 2017

Contributor

No, this has to be an assert in current develop, I changed it to an unimplemented because of the new struct types.

@axic

This comment has been minimized.

Show comment
Hide comment
@axic

axic Jun 30, 2017

Member

Please rebase.

Member

axic commented Jun 30, 2017

Please rebase.

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Jul 1, 2017

Contributor

Down to 61 errors in SolidityEndToEndTests.

Contributor

chriseth commented Jul 1, 2017

Down to 61 errors in SolidityEndToEndTests.

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Jul 1, 2017

Contributor

By the way, an example encoder now looks as follows:

{
        let dynFree := add($headStart, 64)
        dynFree := abi_encode_t_bytes2_to_t_bytes3($value0, $headStart, add($headStart, 0), dynFree)
        dynFree := abi_encode_t_bool_to_t_bool($value1, $headStart, add($headStart, 32), dynFree)
        $value0 := dynFree
        function abi_encode_t_bool_to_t_bool(value, headStart, headPos, dyn) -> newDyn
        {
            newDyn := dyn
            mstore(headPos, cleanup_assert_t_bool(value))
        }
        function abi_encode_t_bytes2_to_t_bytes3(value, headStart, headPos, dyn) -> newDyn
        {
            newDyn := dyn
            mstore(headPos, convert_t_bytes2_to_t_bytes3(value))
        }
        function cleanup_assert_t_bool(value) -> cleaned
        {
            cleaned := iszero(iszero(value))
        }
        function cleanup_assert_t_bytes2(value) -> cleaned
        {
            cleaned := and(value, 0xFFFF000000000000000000000000000000000000000000000000000000000000)
        }
        function convert_t_bytes2_to_t_bytes3(value) -> converted
        {
            converted := cleanup_assert_t_bytes2(value)
        }
    }

I.e. it has very detailed "convert" and "cleanup" calls which makes it very visible what happens and those can also probably be easily inlined.

Contributor

chriseth commented Jul 1, 2017

By the way, an example encoder now looks as follows:

{
        let dynFree := add($headStart, 64)
        dynFree := abi_encode_t_bytes2_to_t_bytes3($value0, $headStart, add($headStart, 0), dynFree)
        dynFree := abi_encode_t_bool_to_t_bool($value1, $headStart, add($headStart, 32), dynFree)
        $value0 := dynFree
        function abi_encode_t_bool_to_t_bool(value, headStart, headPos, dyn) -> newDyn
        {
            newDyn := dyn
            mstore(headPos, cleanup_assert_t_bool(value))
        }
        function abi_encode_t_bytes2_to_t_bytes3(value, headStart, headPos, dyn) -> newDyn
        {
            newDyn := dyn
            mstore(headPos, convert_t_bytes2_to_t_bytes3(value))
        }
        function cleanup_assert_t_bool(value) -> cleaned
        {
            cleaned := iszero(iszero(value))
        }
        function cleanup_assert_t_bytes2(value) -> cleaned
        {
            cleaned := and(value, 0xFFFF000000000000000000000000000000000000000000000000000000000000)
        }
        function convert_t_bytes2_to_t_bytes3(value) -> converted
        {
            converted := cleanup_assert_t_bytes2(value)
        }
    }

I.e. it has very detailed "convert" and "cleanup" calls which makes it very visible what happens and those can also probably be easily inlined.

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Jul 3, 2017

Contributor

59!

Contributor

chriseth commented Jul 3, 2017

59!

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Aug 2, 2017

Contributor

24!

Contributor

chriseth commented Aug 2, 2017

24!

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Aug 2, 2017

Contributor

14!

Contributor

chriseth commented Aug 2, 2017

14!

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Aug 3, 2017

Contributor

Only one failing test left, but this is due to the fact that we do not use codecopy for constants, but I think this will also turn green once we have deduplication.

Still, more test coverage is needed.

Contributor

chriseth commented Aug 3, 2017

Only one failing test left, but this is due to the fact that we do not use codecopy for constants, but I think this will also turn green once we have deduplication.

Still, more test coverage is needed.

@chriseth

This comment has been minimized.

Show comment
Hide comment
@chriseth

chriseth Aug 3, 2017

Contributor

Oh and it turns out, the storage-to-ABI-encoder is actually used, but it seems there are only few tests for it.

Contributor

chriseth commented Aug 3, 2017

Oh and it turns out, the storage-to-ABI-encoder is actually used, but it seems there are only few tests for it.

@axic

This comment has been minimized.

Show comment
Hide comment
@axic

axic Aug 3, 2017

Member

Can you pull the tests which should succeed on the current encoder into a separate PR and merge them first?

Member

axic commented Aug 3, 2017

Can you pull the tests which should succeed on the current encoder into a separate PR and merge them first?

@chriseth chriseth referenced this pull request Aug 7, 2017

Merged

New ABI encoder #2704

@axic axic referenced this pull request Aug 25, 2017

Merged

Returning structs #1673

2 of 2 tasks complete

@chriseth chriseth closed this Sep 14, 2017

@axic axic deleted the structEncoder branch Sep 14, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment