Skip to content

Commit

Permalink
Merge pull request #1314 from topos-protocol/refactor_wcopy
Browse files Browse the repository at this point in the history
Refactor `%wcopy` and unify {ext}codecopy related code
  • Loading branch information
Nashtare authored Oct 27, 2023
2 parents 666a155 + 6f52b76 commit 0258ad4
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 202 deletions.
104 changes: 0 additions & 104 deletions evm/src/cpu/kernel/asm/account_code.asm
Original file line number Diff line number Diff line change
Expand Up @@ -80,110 +80,6 @@ global extcodesize:
// stack: extcodesize(address), retdest
SWAP1 JUMP

%macro extcodecopy
// stack: address, dest_offset, offset, size
%stack (address, dest_offset, offset, size) -> (address, dest_offset, offset, size, %%after)
%jump(extcodecopy)
%%after:
%endmacro

// Pre stack: kexit_info, address, dest_offset, offset, size
// Post stack: (empty)
global sys_extcodecopy:
%stack (kexit_info, address, dest_offset, offset, size)
-> (address, dest_offset, offset, size, kexit_info)
%u256_to_addr DUP1 %insert_accessed_addresses
// stack: cold_access, address, dest_offset, offset, size, kexit_info
PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS
MUL
PUSH @GAS_WARMACCESS
ADD
// stack: Gaccess, address, dest_offset, offset, size, kexit_info

DUP5
// stack: size, Gaccess, address, dest_offset, offset, size, kexit_info
ISZERO %jumpi(sys_extcodecopy_empty)

// stack: Gaccess, address, dest_offset, offset, size, kexit_info
DUP5 %num_bytes_to_num_words %mul_const(@GAS_COPY) ADD
%stack (gas, address, dest_offset, offset, size, kexit_info) -> (gas, kexit_info, address, dest_offset, offset, size)
%charge_gas

%stack (kexit_info, address, dest_offset, offset, size) -> (dest_offset, size, kexit_info, address, dest_offset, offset, size)
%add_or_fault
// stack: expanded_num_bytes, kexit_info, address, dest_offset, offset, size
DUP1 %ensure_reasonable_offset
%update_mem_bytes

%stack (kexit_info, address, dest_offset, offset, size) -> (address, dest_offset, offset, size, kexit_info)
%extcodecopy
// stack: kexit_info
EXIT_KERNEL

sys_extcodecopy_empty:
%stack (Gaccess, address, dest_offset, offset, size, kexit_info) -> (Gaccess, kexit_info)
%charge_gas
EXIT_KERNEL


// Pre stack: address, dest_offset, offset, size, retdest
// Post stack: (empty)
global extcodecopy:
// stack: address, dest_offset, offset, size, retdest
%stack (address, dest_offset, offset, size, retdest)
-> (address, 0, @SEGMENT_KERNEL_ACCOUNT_CODE, extcodecopy_contd, size, offset, dest_offset, retdest)
%jump(load_code)

extcodecopy_contd:
// stack: code_size, size, offset, dest_offset, retdest
DUP1 DUP4
// stack: offset, code_size, code_size, size, offset, dest_offset, retdest
GT %jumpi(extcodecopy_large_offset)

// stack: code_size, size, offset, dest_offset, retdest
DUP3 DUP3 ADD
// stack: offset + size, code_size, size, offset, dest_offset, retdest
DUP2 GT %jumpi(extcodecopy_within_bounds)

// stack: code_size, size, offset, dest_offset, retdest
DUP3 DUP3 ADD
// stack: offset + size, code_size, size, offset, dest_offset, retdest
SUB
// stack: extra_size = offset + size - code_size, size, offset, dest_offset, retdest
DUP1 DUP3 SUB
// stack: copy_size = size - extra_size, extra_size, size, offset, dest_offset, retdest

// Compute the new dest_offset after actual copies, at which we will start padding with zeroes.
DUP1 DUP6 ADD
// stack: new_dest_offset, copy_size, extra_size, size, offset, dest_offset, retdest

GET_CONTEXT
%stack (context, new_dest_offset, copy_size, extra_size, size, offset, dest_offset, retdest) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, 0, @SEGMENT_KERNEL_ACCOUNT_CODE, offset, copy_size, extcodecopy_end, new_dest_offset, extra_size, retdest)
%jump(memcpy_bytes)

extcodecopy_within_bounds:
// stack: code_size, size, offset, dest_offset, retdest
GET_CONTEXT
%stack (context, code_size, size, offset, dest_offset, retdest) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, 0, @SEGMENT_KERNEL_ACCOUNT_CODE, offset, size, retdest)
%jump(memcpy_bytes)

// Same as extcodecopy_large_offset, but without `offset` in the stack.
extcodecopy_end:
// stack: dest_offset, size, retdest
GET_CONTEXT
%stack (context, dest_offset, size, retdest) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, size, retdest)
%jump(memset)

extcodecopy_large_offset:
// offset is larger than the code size. So we just have to write zeros.
// stack: code_size, size, offset, dest_offset, retdest
GET_CONTEXT
%stack (context, code_size, size, offset, dest_offset, retdest) -> (context, @SEGMENT_MAIN_MEMORY, dest_offset, size, retdest)
%jump(memset)

// Loads the code at `address` into memory, at the given context and segment, starting at offset 0.
// Checks that the hash of the loaded code corresponds to the `codehash` in the state trie.
// Pre stack: address, ctx, segment, retdest
Expand Down
16 changes: 3 additions & 13 deletions evm/src/cpu/kernel/asm/memory/memcpy.asm
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ global memcpy:
// Continue the loop.
%jump(memcpy)

memcpy_finish:
// stack: DST, SRC, count, retdest
%pop7
// stack: retdest
JUMP

%macro memcpy
%stack (dst: 3, src: 3, count) -> (dst, src, count, %%after)
%jump(memcpy)
Expand All @@ -63,7 +57,7 @@ global memcpy_bytes:
// stack: count, DST, SRC, count, retdest
ISZERO
// stack: count == 0, DST, SRC, count, retdest
%jumpi(memcpy_bytes_empty)
%jumpi(memcpy_finish)

// stack: DST, SRC, count, retdest

Expand Down Expand Up @@ -126,12 +120,8 @@ memcpy_bytes_finish:
MSTORE_32BYTES
// stack: DST, SRC, count, retdest

%pop7
// stack: retdest
JUMP

memcpy_bytes_empty:
// stack: DST, SRC, 0, retdest
memcpy_finish:
// stack: DST, SRC, count, retdest
%pop7
// stack: retdest
JUMP
Expand Down
192 changes: 110 additions & 82 deletions evm/src/cpu/kernel/asm/memory/syscalls.asm
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,10 @@ calldataload_large_offset:
%stack (kexit_info, i) -> (kexit_info, 0)
EXIT_KERNEL

// Macro for {CALLDATA,CODE,RETURNDATA}COPY (W_copy in Yellow Paper).
// Macro for {CALLDATA, RETURNDATA}COPY (W_copy in Yellow Paper).
%macro wcopy(segment, context_metadata_size)
// stack: kexit_info, dest_offset, offset, size
PUSH @GAS_VERYLOW
DUP5
// stack: size, Gverylow, kexit_info, dest_offset, offset, size
ISZERO %jumpi(wcopy_empty)
// stack: Gverylow, kexit_info, dest_offset, offset, size
DUP5 %num_bytes_to_num_words %mul_const(@GAS_COPY) ADD %charge_gas
%wcopy_charge_gas

%stack (kexit_info, dest_offset, offset, size) -> (dest_offset, size, kexit_info, dest_offset, offset, size)
%add_or_fault
Expand All @@ -92,54 +87,44 @@ calldataload_large_offset:
// stack: offset, total_size, kexit_info, dest_offset, offset, size
GT %jumpi(wcopy_large_offset)

// stack: kexit_info, dest_offset, offset, size
GET_CONTEXT
PUSH $segment
%mload_context_metadata($context_metadata_size)
// stack: total_size, segment, kexit_info, dest_offset, offset, size
DUP6 DUP6 ADD
// stack: offset + size, total_size, segment, kexit_info, dest_offset, offset, size
LT %jumpi(wcopy_within_bounds)

%mload_context_metadata($context_metadata_size)
// stack: total_size, segment, kexit_info, dest_offset, offset, size
DUP6 DUP6 ADD
// stack: offset + size, total_size, segment, kexit_info, dest_offset, offset, size
SUB // extra_size = offset + size - total_size
// stack: extra_size, segment, kexit_info, dest_offset, offset, size
DUP1 DUP7 SUB
// stack: copy_size = size - extra_size, extra_size, segment, kexit_info, dest_offset, offset, size

// Compute the new dest_offset after actual copies, at which we will start padding with zeroes.
DUP1 DUP6 ADD
// stack: new_dest_offset, copy_size, extra_size, segment, kexit_info, dest_offset, offset, size
// stack: segment, context, kexit_info, dest_offset, offset, size
%jump(wcopy_within_bounds)
%endmacro

GET_CONTEXT
%stack (context, new_dest_offset, copy_size, extra_size, segment, kexit_info, dest_offset, offset, size) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, context, segment, offset, copy_size, wcopy_over_range, new_dest_offset, extra_size, kexit_info)
%jump(memcpy_bytes)
%macro wcopy_charge_gas
// stack: kexit_info, dest_offset, offset, size
PUSH @GAS_VERYLOW
DUP5
// stack: size, Gverylow, kexit_info, dest_offset, offset, size
ISZERO %jumpi(wcopy_empty)
// stack: Gverylow, kexit_info, dest_offset, offset, size
DUP5 %num_bytes_to_num_words %mul_const(@GAS_COPY) ADD %charge_gas
%endmacro


codecopy_within_bounds:
// stack: total_size, segment, src_ctx, kexit_info, dest_offset, offset, size
POP
wcopy_within_bounds:
// stack: segment, kexit_info, dest_offset, offset, size
// stack: segment, src_ctx, kexit_info, dest_offset, offset, size
GET_CONTEXT
%stack (context, segment, kexit_info, dest_offset, offset, size) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, context, segment, offset, size, wcopy_after, kexit_info)
%stack (context, segment, src_ctx, kexit_info, dest_offset, offset, size) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, src_ctx, segment, offset, size, wcopy_after, kexit_info)
%jump(memcpy_bytes)


// Same as wcopy_large_offset, but without `offset` in the stack.
wcopy_over_range:
// stack: dest_offset, size, kexit_info
GET_CONTEXT
%stack (context, dest_offset, size, kexit_info) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, size, wcopy_after, kexit_info)
%jump(memset)

wcopy_empty:
// stack: Gverylow, kexit_info, dest_offset, offset, size
%charge_gas
%stack (kexit_info, dest_offset, offset, size) -> (kexit_info)
EXIT_KERNEL


codecopy_large_offset:
// stack: total_size, src_ctx, kexit_info, dest_offset, offset, size
%pop2
wcopy_large_offset:
// offset is larger than the size of the {CALLDATA,CODE,RETURNDATA}. So we just have to write zeros.
// stack: kexit_info, dest_offset, offset, size
Expand All @@ -152,64 +137,107 @@ wcopy_after:
// stack: kexit_info
EXIT_KERNEL

// Pre stack: kexit_info, dest_offset, offset, size
// Post stack: (empty)
global sys_calldatacopy:
%wcopy(@SEGMENT_CALLDATA, @CTX_METADATA_CALLDATA_SIZE)

global sys_codecopy:
%wcopy(@SEGMENT_CODE, @CTX_METADATA_CODE_SIZE)

// Same as %wcopy but with overflow checks.
// Pre stack: kexit_info, dest_offset, offset, size
// Post stack: (empty)
global sys_returndatacopy:
DUP4 DUP4 %add_or_fault // Overflow check
%mload_context_metadata(@CTX_METADATA_RETURNDATA_SIZE) LT %jumpi(fault_exception) // Data len check

%wcopy(@SEGMENT_RETURNDATA, @CTX_METADATA_RETURNDATA_SIZE)

// Pre stack: kexit_info, dest_offset, offset, size
// Post stack: (empty)
global sys_codecopy:
// stack: kexit_info, dest_offset, offset, size
PUSH @GAS_VERYLOW
// stack: Gverylow, kexit_info, dest_offset, offset, size
DUP5 %num_bytes_to_num_words %mul_const(@GAS_COPY) ADD %charge_gas
%wcopy_charge_gas

%stack (kexit_info, dest_offset, offset, size) -> (dest_offset, size, kexit_info, dest_offset, offset, size)
%add_or_fault
// stack: expanded_num_bytes, kexit_info, dest_offset, offset, size, kexit_info
DUP1 %ensure_reasonable_offset
%update_mem_bytes
// stack: kexit_info, dest_offset, offset, size, kexit_info
DUP4 DUP4 %add_or_fault // Overflow check
%mload_context_metadata(@CTX_METADATA_RETURNDATA_SIZE) LT %jumpi(fault_exception) // Data len check

// stack: kexit_info, dest_offset, offset, size
DUP4
// stack: size, kexit_info, dest_offset, offset, size
ISZERO %jumpi(returndatacopy_empty)
GET_CONTEXT
%mload_context_metadata(@CTX_METADATA_CODE_SIZE)
// stack: code_size, ctx, kexit_info, dest_offset, offset, size
%codecopy_after_checks(@SEGMENT_CODE)


// Pre stack: kexit_info, address, dest_offset, offset, size
// Post stack: (empty)
global sys_extcodecopy:
%stack (kexit_info, address, dest_offset, offset, size)
-> (address, dest_offset, offset, size, kexit_info)
%u256_to_addr DUP1 %insert_accessed_addresses
// stack: cold_access, address, dest_offset, offset, size, kexit_info
PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS
MUL
PUSH @GAS_WARMACCESS
ADD
// stack: Gaccess, address, dest_offset, offset, size, kexit_info

%mload_context_metadata(@CTX_METADATA_RETURNDATA_SIZE)
// stack: total_size, kexit_info, dest_offset, offset, size
DUP4
// stack: offset, total_size, kexit_info, dest_offset, offset, size
GT %jumpi(wcopy_large_offset)
DUP5
// stack: size, Gaccess, address, dest_offset, offset, size, kexit_info
ISZERO %jumpi(sys_extcodecopy_empty)

// stack: Gaccess, address, dest_offset, offset, size, kexit_info
DUP5 %num_bytes_to_num_words %mul_const(@GAS_COPY) ADD
%stack (gas, address, dest_offset, offset, size, kexit_info) -> (gas, kexit_info, address, dest_offset, offset, size)
%charge_gas

%stack (kexit_info, address, dest_offset, offset, size) -> (dest_offset, size, kexit_info, address, dest_offset, offset, size)
%add_or_fault
// stack: expanded_num_bytes, kexit_info, address, dest_offset, offset, size
DUP1 %ensure_reasonable_offset
%update_mem_bytes

%stack (kexit_info, address, dest_offset, offset, size) ->
(address, 0, @SEGMENT_KERNEL_ACCOUNT_CODE, extcodecopy_contd, 0, kexit_info, dest_offset, offset, size)
%jump(load_code)

sys_extcodecopy_empty:
%stack (Gaccess, address, dest_offset, offset, size, kexit_info) -> (Gaccess, kexit_info)
%charge_gas
EXIT_KERNEL

PUSH @SEGMENT_RETURNDATA
%mload_context_metadata(@CTX_METADATA_RETURNDATA_SIZE)
// stack: total_size, returndata_segment, kexit_info, dest_offset, offset, size
DUP6 DUP6 ADD
// stack: offset + size, total_size, returndata_segment, kexit_info, dest_offset, offset, size
LT %jumpi(wcopy_within_bounds)

%mload_context_metadata(@CTX_METADATA_RETURNDATA_SIZE)
// stack: total_size, returndata_segment, kexit_info, dest_offset, offset, size
DUP6 DUP6 ADD
// stack: offset + size, total_size, returndata_segment, kexit_info, dest_offset, offset, size
extcodecopy_contd:
// stack: code_size, src_ctx, kexit_info, dest_offset, offset, size
%codecopy_after_checks(@SEGMENT_KERNEL_ACCOUNT_CODE)


// The internal logic is similar to wcopy, but handles range overflow differently.
// It is used for both CODECOPY and EXTCODECOPY.
%macro codecopy_after_checks(segment)
// stack: total_size, src_ctx, kexit_info, dest_offset, offset, size
DUP1 DUP6
// stack: offset, total_size, total_size, src_ctx, kexit_info, dest_offset, offset, size
GT %jumpi(codecopy_large_offset)

PUSH $segment SWAP1
// stack: total_size, segment, src_ctx, kexit_info, dest_offset, offset, size
DUP1 DUP8 DUP8 ADD
// stack: offset + size, total_size, total_size, segment, src_ctx, kexit_info, dest_offset, offset, size
LT %jumpi(codecopy_within_bounds)

// stack: total_size, segment, src_ctx, kexit_info, dest_offset, offset, size
DUP7 DUP7 ADD
// stack: offset + size, total_size, segment, src_ctx, kexit_info, dest_offset, offset, size
SUB // extra_size = offset + size - total_size
// stack: extra_size, returndata_segment, kexit_info, dest_offset, offset, size
DUP1 DUP7 SUB
// stack: copy_size = size - extra_size, extra_size, returndata_segment, kexit_info, dest_offset, offset, size
// stack: extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size
DUP1 DUP8 SUB
// stack: copy_size = size - extra_size, extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size

// Compute the new dest_offset after actual copies, at which we will start padding with zeroes.
DUP1 DUP6 ADD
// stack: new_dest_offset, copy_size, extra_size, returndata_segment, kexit_info, dest_offset, offset, size
DUP1 DUP7 ADD
// stack: new_dest_offset, copy_size, extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size

GET_CONTEXT
%stack (context, new_dest_offset, copy_size, extra_size, returndata_segment, kexit_info, dest_offset, offset, size) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, context, returndata_segment, offset, copy_size, wcopy_over_range, new_dest_offset, extra_size, kexit_info)
%stack (context, new_dest_offset, copy_size, extra_size, segment, src_ctx, kexit_info, dest_offset, offset, size) ->
(context, @SEGMENT_MAIN_MEMORY, dest_offset, src_ctx, segment, offset, copy_size, wcopy_large_offset, kexit_info, new_dest_offset, offset, extra_size)
%jump(memcpy_bytes)

returndatacopy_empty:
%stack (kexit_info, dest_offset, offset, size) -> (kexit_info)
EXIT_KERNEL
%endmacro
Loading

0 comments on commit 0258ad4

Please sign in to comment.