Skip to content
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

Add support for sign extension instructions. #400

Merged
merged 5 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions haskell-src/Concordium/Types/ProtocolVersion.hs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ module Concordium.Types.ProtocolVersion (
supportsChainQueryContracts,
supportsAccountAliases,
supportsDelegationPV,
supportsSignExtensionInstructions,
supportsGlobalsInInitSections,

-- * Defunctionalisation symbols
P1Sym0,
Expand Down Expand Up @@ -500,3 +502,25 @@ supportsChainQueryContracts spv = case spv of
SP4 -> False
SP5 -> True
SP6 -> True

-- |Whether the protocol version supports sign extension instructions for V1
-- contracts. (Supported in 'P6' and onwards)
supportsSignExtensionInstructions :: SProtocolVersion pv -> Bool
supportsSignExtensionInstructions spv = case spv of
SP1 -> False
SP2 -> False
SP3 -> False
SP4 -> False
SP5 -> False
SP6 -> True

-- |Whether the protocol version allows globals in data and element sections of
-- Wasm modules for V1 contracts. (Supported before 'P6')
supportsGlobalsInInitSections :: SProtocolVersion pv -> Bool
supportsGlobalsInInitSections spv = case spv of
SP1 -> True
SP2 -> True
SP3 -> True
SP4 -> True
SP5 -> True
SP6 -> False
Binary file not shown.
8 changes: 8 additions & 0 deletions smart-contracts/testdata/contracts/v1/i32.extend16_s.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
;; The only purpose of this contract is to check
;; whether i32.extend16_s instruction is allowed in the module.
(module
;; Init contract
(func $init_contract (export "init_contract") (param i64) (result i32)
(i32.extend16_s (i32.const 3))
(return (i32.const 0))) ;; Successful init
)
Binary file not shown.
8 changes: 8 additions & 0 deletions smart-contracts/testdata/contracts/v1/i32.extend8_s.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
;; The only purpose of this contract is to check
;; whether i32.extend8_s instruction is allowed in the module.
(module
;; Init contract
(func $init_contract (export "init_contract") (param i64) (result i32)
(i32.extend8_s (i32.const 3))
(return (i32.const 0))) ;; Successful init
)
Binary file not shown.
8 changes: 8 additions & 0 deletions smart-contracts/testdata/contracts/v1/i64.extend16_s.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
;; The only purpose of this contract is to check
;; whether i64.extend16_s instruction is allowed in the module.
(module
;; Init contract
(func $init_contract (export "init_contract") (param i64) (result i32)
(i64.extend16_s (i64.const 3))
(return (i32.const 0))) ;; Successful init
)
Binary file not shown.
8 changes: 8 additions & 0 deletions smart-contracts/testdata/contracts/v1/i64.extend32_s.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
;; The only purpose of this contract is to check
;; whether i64.extend32_s instruction is allowed in the module.
(module
;; Init contract
(func $init_contract (export "init_contract") (param i64) (result i32)
(i64.extend32_s (i64.const 3))
(return (i32.const 0))) ;; Successful init
)
Binary file not shown.
8 changes: 8 additions & 0 deletions smart-contracts/testdata/contracts/v1/i64.extend8_s.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
;; The only purpose of this contract is to check
;; whether i64.extend8_s instruction is allowed in the module.
(module
;; Init contract
(func $init_contract (export "init_contract") (param i64) (result i32)
(i64.extend8_s (i64.const 3))
(return (i32.const 0))) ;; Successful init
)
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,40 @@
)
)

(func (export "i32.extend8_s")
(loop $loop
(i32.extend8_s (i32.const 312312))
(br $loop)
)
)

(func (export "i32.extend16_s")
(loop $loop
(i32.extend16_s (i32.const 312312))
(br $loop)
)
)

(func (export "i64.extend8_s")
(loop $loop
(i64.extend8_s (i64.const 312312))
(br $loop)
)
)

(func (export "i64.extend16_s")
(loop $loop
(i64.extend16_s (i64.const 312312))
(br $loop)
)
)

(func (export "i64.extend32_s")
(loop $loop
(i64.extend32_s (i64.const 312312))
(br $loop)
)
)

;; indirectly call an empty function with 100 arguments
(func (export "call_empty_function_100")
Expand Down
5 changes: 5 additions & 0 deletions smart-contracts/wasm-chain-integration/benches/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,11 @@ pub fn criterion_benchmark(c: &mut Criterion) {
exec("i64.rem_s", &[]);
exec("i64.rem_u", &[]);
exec("i32.wrap_i64", &[]);
exec("i32.extend8_s", &[]);
exec("i32.extend16_s", &[]);
exec("i64.extend8_s", &[]);
exec("i64.extend16_s", &[]);
exec("i64.extend32_s", &[]);
group.finish();
}

Expand Down
5 changes: 4 additions & 1 deletion smart-contracts/wasm-chain-integration/src/v1/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ unsafe extern "C" fn validate_and_process_v1(
support_upgrade: u8,
// Allow globals in initialization expressions for data and element sections.
allow_globals_in_init: u8,
// Allow sign extension instructions.
allow_sign_extension_instr: u8,
wasm_bytes_ptr: *const u8,
wasm_bytes_len: size_t,
// this is the total length of the output byte array
Expand All @@ -392,7 +394,8 @@ unsafe extern "C" fn validate_and_process_v1(
let wasm_bytes = slice_from_c_bytes!(wasm_bytes_ptr, wasm_bytes_len);
match utils::instantiate_with_metering::<ProcessedImports, _>(
ValidationConfig {
allow_globals_in_init: allow_globals_in_init != 0,
allow_globals_in_init: allow_globals_in_init != 0,
allow_sign_extension_instr: allow_sign_extension_instr != 0,
},
&ConcordiumAllowedImports {
support_upgrade: support_upgrade == 1,
Expand Down
6 changes: 5 additions & 1 deletion smart-contracts/wasm-transform/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
## Unreleased changes

- `validate_module` is now parameterized by `ValidationConfig` which determines
which Wasm features should be allowed.
which Wasm features should be allowed. The currently supported configurable features are
- allow access to globals (defined in the current module) in data and element
initialization sections.
- allow instructions defined in the [sign extension operators](https://github.com/WebAssembly/sign-extension-ops/blob/master/proposals/sign-extension-ops/Overview.md)
Wasm proposal.

## concordium-wasm 2.0.0 (2023-06-16)

Expand Down
22 changes: 22 additions & 0 deletions smart-contracts/wasm-transform/src/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,13 @@ pub enum InternalOpcode {
I32WrapI64,
I64ExtendI32S,
I64ExtendI32U,

// Sign extension instructions, optionally supported depending on the protocol version.
I32Extend8S,
I32Extend16S,
I64Extend8S,
I64Extend16S,
I64Extend32S,
}

/// Result of compilation. Either Ok(_) or an error indicating the reason.
Expand Down Expand Up @@ -1147,6 +1154,21 @@ impl Handler<&OpCode> for BackPatch {
OpCode::I64ExtendI32U => {
self.out.push(I64ExtendI32U);
}
OpCode::I32Extend8S => {
self.out.push(I32Extend8S);
}
OpCode::I32Extend16S => {
self.out.push(I32Extend16S);
}
OpCode::I64Extend8S => {
self.out.push(I64Extend8S);
}
OpCode::I64Extend16S => {
self.out.push(I64Extend16S);
}
OpCode::I64Extend32S => {
self.out.push(I64Extend32S);
}
}
Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions smart-contracts/wasm-transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ pub mod validate;

#[cfg(test)]
mod metering_transformation_test;
#[cfg(test)]
mod tests;
5 changes: 5 additions & 0 deletions smart-contracts/wasm-transform/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,11 @@ impl<I: TryFromImport, R: RunnableCode> Artifact<I, R> {
// and then extend, making it so that it is extended with 0's.
top.long = unsafe { top.short } as u32 as i64;
}
InternalOpcode::I32Extend8S => unary_i32(&mut stack, |x| x as i8 as i32),
InternalOpcode::I32Extend16S => unary_i32(&mut stack, |x| x as i16 as i32),
InternalOpcode::I64Extend8S => unary_i64(&mut stack, |x| x as i8 as i64),
InternalOpcode::I64Extend16S => unary_i64(&mut stack, |x| x as i16 as i64),
InternalOpcode::I64Extend32S => unary_i64(&mut stack, |x| x as i32 as i64),
}
}

Expand Down
5 changes: 5 additions & 0 deletions smart-contracts/wasm-transform/src/metering_transformation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ pub(crate) mod cost {
I32WrapI64 => SIMPLE_UNOP,
I64ExtendI32S => SIMPLE_UNOP,
I64ExtendI32U => SIMPLE_UNOP,
I32Extend8S => SIMPLE_UNOP,
I32Extend16S => SIMPLE_UNOP,
I64Extend8S => SIMPLE_UNOP,
I64Extend16S => SIMPLE_UNOP,
I64Extend32S => SIMPLE_UNOP,
};
Ok(res)
}
Expand Down
Loading