diff --git a/executor/executor.go b/executor/executor.go index f3c35390b..6da8dea11 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -21,8 +21,8 @@ type CompilationOptions struct { type Executor interface { check.NilInterfaceChecker - // SetOpcodeCosts sets gas costs globally inside an executor. - SetOpcodeCosts(opcodeCosts *WASMOpcodeCost) + // SetOpcodeConfig sets gas costs globally inside an executor. + SetOpcodeConfig(opcodeVersion OpcodeVersion, wasmOps *WASMOpcodeCost) // FunctionNames return the low-level function names provided to contracts. FunctionNames() vmcommon.FunctionNames diff --git a/executor/executorFactory.go b/executor/executorFactory.go index 28b4b13d6..368b4cc3d 100644 --- a/executor/executorFactory.go +++ b/executor/executorFactory.go @@ -5,6 +5,7 @@ import "github.com/multiversx/mx-chain-core-go/core/check" // ExecutorFactoryArgs define the Executor configurations that come from the VM, especially the hooks and the gas costs. type ExecutorFactoryArgs struct { VMHooks VMHooks + OpcodeVersion OpcodeVersion OpcodeCosts *WASMOpcodeCost RkyvSerializationEnabled bool WasmerSIGSEGVPassthrough bool diff --git a/executor/executorOpcodeVersion.go b/executor/executorOpcodeVersion.go new file mode 100644 index 000000000..501562597 --- /dev/null +++ b/executor/executorOpcodeVersion.go @@ -0,0 +1,8 @@ +package executor + +type OpcodeVersion uint32 + +const ( + OpcodeVersionV1 OpcodeVersion = iota + OpcodeVersionV2 +) diff --git a/executor/wrapper/wrapperExecutor.go b/executor/wrapper/wrapperExecutor.go index a8d146dde..3877011db 100644 --- a/executor/wrapper/wrapperExecutor.go +++ b/executor/wrapper/wrapperExecutor.go @@ -15,9 +15,9 @@ type WrapperExecutor struct { WrappedInstances map[string][]executor.Instance } -// SetOpcodeCosts wraps the call to the underlying executor. -func (wexec *WrapperExecutor) SetOpcodeCosts(opcodeCosts *executor.WASMOpcodeCost) { - wexec.wrappedExecutor.SetOpcodeCosts(opcodeCosts) +// SetOpcodeConfig wraps the call to the underlying executor. +func (wexec *WrapperExecutor) SetOpcodeConfig(opcodeVersion executor.OpcodeVersion, wasmOps *executor.WASMOpcodeCost) { + wexec.wrappedExecutor.SetOpcodeConfig(opcodeVersion, wasmOps) } // FunctionNames wraps the call to the underlying executor. diff --git a/integrationTests/json/scenariosFeatures_test.go b/integrationTests/json/scenariosFeatures_test.go index a347fa9d7..3dde9edf4 100644 --- a/integrationTests/json/scenariosFeatures_test.go +++ b/integrationTests/json/scenariosFeatures_test.go @@ -95,6 +95,17 @@ func TestRustPayableFeatures(t *testing.T) { CheckNoError() } +func TestRustPanicMessageFeatures(t *testing.T) { + if testing.Short() { + t.Skip("not a short test") + } + + ScenariosTest(t). + Folder("features/panic-message-features/scenarios"). + Run(). + CheckNoError() +} + func TestRustComposability(t *testing.T) { ScenariosTest(t). Folder("features/composability/scenarios"). diff --git a/mock/context/executorMock.go b/mock/context/executorMock.go index 41d0bdcee..903f3900e 100644 --- a/mock/context/executorMock.go +++ b/mock/context/executorMock.go @@ -55,8 +55,8 @@ func NewExecutorMock(world *worldmock.MockWorld) *ExecutorMock { } } -// SetOpcodeCosts should set gas costs, but it does nothing in the case of this mock. -func (executorMock *ExecutorMock) SetOpcodeCosts(_ *executor.WASMOpcodeCost) { +// SetOpcodeConfig should set gas costs, but it does nothing in the case of this mock. +func (executorMock *ExecutorMock) SetOpcodeConfig(_ executor.OpcodeVersion, _ *executor.WASMOpcodeCost) { } // FunctionNames mocked method diff --git a/test/features/panic-message-features/scenarios/should-panic-call.scen.json b/test/features/panic-message-features/scenarios/should-panic-call.scen.json deleted file mode 100644 index 3461f74aa..000000000 --- a/test/features/panic-message-features/scenarios/should-panic-call.scen.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "panic", - "gasSchedule": "v3", - "steps": [ - { - "step": "setState", - "accounts": { - "sc:panic_features": { - "nonce": "0", - "balance": "0", - "code": "mxsc:../output/panic-message-features.mxsc.json" - }, - "address:an_account": { - "nonce": "0", - "balance": "0" - } - } - }, - { - "step": "scCall", - "id": "1", - "tx": { - "from": "address:an_account", - "to": "sc:panic_features", - "function": "panicWithMessage", - "arguments": [ - "123" - ], - "gasLimit": "50,000,000", - "gasPrice": "0" - }, - "expect": { - "out": [], - "status": "" - } - } - ] -} diff --git a/test/features/panic-message-features/scenarios/should-panic-deploy.scen.json b/test/features/panic-message-features/scenarios/should-panic-deploy.scen.json deleted file mode 100644 index c59995ec7..000000000 --- a/test/features/panic-message-features/scenarios/should-panic-deploy.scen.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "panic", - "gasSchedule": "v3", - "steps": [ - { - "step": "setState", - "accounts": { - "address:an_account": { - "nonce": "0", - "balance": "0" - } - } - }, - { - "step": "scDeploy", - "id": "fail-deploy", - "tx": { - "from": "address:an_account", - "arguments": [ - "true" - ], - "code": "mxsc:../output/panic-message-features.mxsc.json", - "gasLimit": "50,000,000", - "gasPrice": "0" - }, - "expect": { - "out": [], - "status": "" - } - } - ] -} diff --git a/test/features/panic-message-features/scenarios/should-panic-query.scen.json b/test/features/panic-message-features/scenarios/should-panic-query.scen.json deleted file mode 100644 index 64f7e1bfc..000000000 --- a/test/features/panic-message-features/scenarios/should-panic-query.scen.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "panic", - "gasSchedule": "v3", - "steps": [ - { - "step": "setState", - "accounts": { - "sc:panic_features": { - "nonce": "0", - "balance": "0", - "code": "mxsc:../output/panic-message-features.mxsc.json" - }, - "address:an_account": { - "nonce": "0", - "balance": "0" - } - } - }, - { - "step": "scQuery", - "id": "fail-query", - "tx": { - "from": "address:an_account", - "to": "sc:panic_features", - "function": "panicWithMessage", - "arguments": [ - "123" - ], - "gasLimit": "50,000,000", - "gasPrice": "0" - }, - "expect": { - "out": [], - "status": "" - } - } - ] -} diff --git a/vmhost/contexts/async_test.go b/vmhost/contexts/async_test.go index 579693bdc..8ab7f980a 100644 --- a/vmhost/contexts/async_test.go +++ b/vmhost/contexts/async_test.go @@ -2,10 +2,11 @@ package contexts import ( "errors" - "github.com/multiversx/mx-chain-vm-go/wasmer2" "math/big" "testing" + "github.com/multiversx/mx-chain-vm-go/wasmer2" + "github.com/multiversx/mx-chain-core-go/data/vm" "github.com/multiversx/mx-chain-core-go/marshal" "github.com/multiversx/mx-chain-scenario-go/worldmock" @@ -59,7 +60,7 @@ func initializeVMAndWasmerAsyncContextWithBuiltIn(tb testing.TB, isBuiltinFunc b gasCostConfig, err := config.CreateGasConfig(gasSchedule) require.Nil(tb, err) wasmerExecutor, _ := wasmer2.CreateExecutor() - wasmerExecutor.SetOpcodeCosts(gasCostConfig.WASMOpcodeCost) + wasmerExecutor.SetOpcodeConfig(executor.OpcodeVersionV2, gasCostConfig.WASMOpcodeCost) host := &contextmock.VMHostMock{ EnableEpochsHandlerField: &worldmock.EnableEpochsHandlerStub{}, diff --git a/vmhost/contexts/runtime_test.go b/vmhost/contexts/runtime_test.go index 8099ba7dc..f5e61bbf0 100644 --- a/vmhost/contexts/runtime_test.go +++ b/vmhost/contexts/runtime_test.go @@ -34,7 +34,7 @@ func InitializeVMAndWasmer() *contextmock.VMHostMock { gasSchedule := config.MakeGasMapForTests() gasCostConfig, _ := config.CreateGasConfig(gasSchedule) wasmerExecutor, _ := wasmer2.CreateExecutor() - wasmerExecutor.SetOpcodeCosts(gasCostConfig.WASMOpcodeCost) + wasmerExecutor.SetOpcodeConfig(executor.OpcodeVersionV2, gasCostConfig.WASMOpcodeCost) host := &contextmock.VMHostMock{} diff --git a/vmhost/hostCore/host.go b/vmhost/hostCore/host.go index c1b4c6b13..8c36791d2 100644 --- a/vmhost/hostCore/host.go +++ b/vmhost/hostCore/host.go @@ -220,8 +220,10 @@ func (host *vmHost) createExecutor(hostParameters *vmhost.VMHostParameters) (exe } else { vmExecutorFactory = wasmer2.ExecutorFactory() } + vmExecutorFactoryArgs := executor.ExecutorFactoryArgs{ VMHooks: vmHooks, + OpcodeVersion: host.getOpcodeVersionForCurrentEpoch(), OpcodeCosts: gasCostConfig.WASMOpcodeCost, RkyvSerializationEnabled: true, WasmerSIGSEGVPassthrough: hostParameters.WasmerSIGSEGVPassthrough, @@ -348,6 +350,14 @@ func (host *vmHost) ClearContextStateStack() { host.blockchainContext.ClearStateStack() } +func (host *vmHost) getOpcodeVersionForCurrentEpoch() executor.OpcodeVersion { + if host.enableEpochsHandler.IsFlagEnabled(vmhost.AsyncV3Flag) { + return executor.OpcodeVersionV2 + } + + return executor.OpcodeVersionV1 +} + // GasScheduleChange applies a new gas schedule to the host func (host *vmHost) GasScheduleChange(newGasSchedule config.GasScheduleMap) { host.mutExecution.Lock() @@ -360,7 +370,9 @@ func (host *vmHost) GasScheduleChange(newGasSchedule config.GasScheduleMap) { return } - host.runtimeContext.GetVMExecutor().SetOpcodeCosts(gasCostConfig.WASMOpcodeCost) + opcodeVersion := host.getOpcodeVersionForCurrentEpoch() + + host.runtimeContext.GetVMExecutor().SetOpcodeConfig(opcodeVersion, gasCostConfig.WASMOpcodeCost) host.meteringContext.SetGasSchedule(newGasSchedule) host.runtimeContext.ClearWarmInstanceCache() diff --git a/vmhost/hosttest/forbidden_opcodes_test.go b/vmhost/hosttest/forbidden_opcodes_test.go index 0fafc2b03..4e83f73e2 100644 --- a/vmhost/hosttest/forbidden_opcodes_test.go +++ b/vmhost/hosttest/forbidden_opcodes_test.go @@ -11,7 +11,7 @@ import ( ) func TestForbiddenOps_BulkAndSIMD(t *testing.T) { - wasmModules := []string{"data-drop", "memory-init", "memory-fill", "memory-copy", "simd"} + wasmModules := []string{"data-drop", "memory-init", "simd"} for _, moduleName := range wasmModules { testCase := testcommon.BuildInstanceCallTest(t). @@ -61,3 +61,38 @@ func TestBarnardOpcodesActivation(t *testing.T) { ContractInvalid() }) } + +func TestBulkMemoryOpcodesActivation(t *testing.T) { + wasmModules := []string{"memory-copy", "memory-fill"} + + for _, moduleName := range wasmModules { + testcommon.BuildInstanceCreatorTest(t). + WithInput(testcommon.CreateTestContractCreateInputBuilder(). + WithGasProvided(100000000). + WithContractCode(testcommon.GetTestSCCodeModule("forbidden-opcodes/"+moduleName, moduleName, "../../")). + Build()). + WithEnableEpochsHandler(&worldmock.EnableEpochsHandlerStub{ + IsFlagEnabledCalled: func(flag core.EnableEpochFlag) bool { + return flag != vmhost.AsyncV3Flag + }, + }). + AndAssertResults(func(stubBlockchainHook *contextmock.BlockchainHookStub, verify *testcommon.VMOutputVerifier) { + verify. + ContractInvalid() + }) + + testcommon.BuildInstanceCreatorTest(t). + WithInput(testcommon.CreateTestContractCreateInputBuilder(). + WithGasProvided(100000000). + WithContractCode(testcommon.GetTestSCCodeModule("forbidden-opcodes/"+moduleName, moduleName, "../../")). + Build()). + WithEnableEpochsHandler(&worldmock.EnableEpochsHandlerStub{ + IsFlagEnabledCalled: func(flag core.EnableEpochFlag) bool { + return true + }, + }). + AndAssertResults(func(stubBlockchainHook *contextmock.BlockchainHookStub, verify *testcommon.VMOutputVerifier) { + verify.FunctionNotFound() + }) + } +} diff --git a/vmhost/vmhooks/generate/cmd/.gitignore b/vmhost/vmhooks/generate/cmd/.gitignore index 6f9c86958..b0b305dec 100644 --- a/vmhost/vmhooks/generate/cmd/.gitignore +++ b/vmhost/vmhooks/generate/cmd/.gitignore @@ -1,5 +1,9 @@ # generated files that belong to other repos: output -# optional path where to copy rust files +# optional path where to copy rust files (deprecated) wasm-vm-executor-rs-path.txt + +# optional path where to copy rust files +path-to-mx-sdk-rs.txt +path-to-vm-executor-rs.txt diff --git a/vmhost/vmhooks/generate/cmd/eiGenMain.go b/vmhost/vmhooks/generate/cmd/eiGenMain.go index 7a8cbb682..839c2d05b 100644 --- a/vmhost/vmhooks/generate/cmd/eiGenMain.go +++ b/vmhost/vmhooks/generate/cmd/eiGenMain.go @@ -14,7 +14,8 @@ import ( ) const pathToApiPackage = "./" -const pathToRustRepoConfigFile = "wasm-vm-executor-rs-path.txt" +const pathVmExecutorRsFile = "path-to-vm-executor-rs.txt" +const pathToMxSdkRsFile = "path-to-mx-sdk-rs.txt" func initEIMetadata() *eapigen.EIMetadata { return &eapigen.EIMetadata{ @@ -55,6 +56,7 @@ func main() { writeRustVMHooksTrait(eiMetadata) writeRustVMHooksLegacyTrait(eiMetadata) writeRustVMHooksLegacyAdapter(eiMetadata) + writeRustVMHooksSignatures(eiMetadata) writeRustCapiVMHooks(eiMetadata) writeRustCapiVMHooksPointers(eiMetadata) writeRustWasmerProdImports(eiMetadata) @@ -67,13 +69,15 @@ func main() { writeWasmer2OpcodeCost() writeWASMOpcodeCostFuncHelpers() writeWASMOpcodeCostConfigHelpers() - writeOpcodeCostFuncHelpers() writeRustOpcodeCost() - writeRustWasmerMeteringHelpers() + writeRustWasmerOpcodeCost() + writeOpcodeWhitelisted() + writeRustWasmerExperimentalOpcodeCost() fmt.Println("Generated code for opcodes and metering helpers.") - tryCopyFilesToRustExecutorRepo() + tryCopyFilesToMxExecutorRsRepo() + tryCopyFilesToMxSdkRsRepo() } func writeVMHooks(eiMetadata *eapigen.EIMetadata) { @@ -173,6 +177,12 @@ func writeRustVHDispatcherLegacy(eiMetadata *eapigen.EIMetadata) { eapigen.WriteRustVHDispatcherLegacy(out, eiMetadata) } +func writeRustVMHooksSignatures(eiMetadata *eapigen.EIMetadata) { + out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/vm_hook_signature_list.rs") + defer out.Close() + eapigen.WriteRustVMHooksSignatures(out, eiMetadata) +} + func writeExecutorOpcodeCosts() { out := eapigen.NewEIGenWriter(pathToApiPackage, "../../executor/gasCostWASM.go") defer out.Close() @@ -197,27 +207,33 @@ func writeWasmer2OpcodeCost() { eapigen.WriteWasmer2OpcodeCost(out) } -func writeOpcodeCostFuncHelpers() { - out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/extractOpcodeCost.txt") - defer out.Close() - eapigen.WriteOpcodeCostFuncHelpers(out) -} - func writeRustOpcodeCost() { out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/opcode_cost.rs") defer out.Close() eapigen.WriteRustOpcodeCost(out) } -func writeRustWasmerMeteringHelpers() { - out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/wasmer_metering_helpers.rs") +func writeRustWasmerOpcodeCost() { + out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/wasmer_opcode_cost.rs") + defer out.Close() + eapigen.WriteRustWasmerOpcodeCost(out) +} + +func writeOpcodeWhitelisted() { + out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/opcode_whitelist.rs") defer out.Close() - eapigen.WriteRustWasmerMeteringHelpers(out) + eapigen.WriteOpcodeWhitelisted(out) } -func tryCopyFilesToRustExecutorRepo() { - fullPathToRustRepoConfigFile := filepath.Join(pathToApiPackage, "generate/cmd/", pathToRustRepoConfigFile) - contentBytes, err := os.ReadFile(fullPathToRustRepoConfigFile) +func writeRustWasmerExperimentalOpcodeCost() { + out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/we_opcode_cost.rs") + defer out.Close() + eapigen.WriteRustWasmerExperimentalOpcodeCost(out) +} + +func tryCopyFilesToMxExecutorRsRepo() { + fullPathToConfigFile := filepath.Join(pathToApiPackage, "generate/cmd/", pathVmExecutorRsFile) + contentBytes, err := os.ReadFile(fullPathToConfigFile) if err != nil { // this feature is optional fmt.Println("Rust files not copied to wasm-vm-executor-rs. Add a wasm-vm-executor-rs-path.txt with the path to enable feature.") @@ -259,8 +275,33 @@ func tryCopyFilesToRustExecutorRepo() { filepath.Join(rustExecutorPath, "vm-executor-experimental/src/we_imports.rs"), ) copyFile( - filepath.Join(pathToApiPackage, "generate/cmd/output/wasmer_metering_helpers.rs"), - filepath.Join(rustExecutorPath, "vm-executor-wasmer/src/wasmer_metering_helpers.rs"), + filepath.Join(pathToApiPackage, "generate/cmd/output/wasmer_opcode_cost.rs"), + filepath.Join(rustExecutorPath, "vm-executor-wasmer/src/wasmer_opcode_cost.rs"), + ) + copyFile( + filepath.Join(pathToApiPackage, "generate/cmd/output/we_opcode_cost.rs"), + filepath.Join(rustExecutorPath, "vm-executor-experimental/src/middlewares/we_opcode_cost.rs"), + ) +} + +func tryCopyFilesToMxSdkRsRepo() { + fullPathToConfigFile := filepath.Join(pathToApiPackage, "generate/cmd/", pathToMxSdkRsFile) + contentBytes, err := os.ReadFile(fullPathToConfigFile) + if err != nil { + // this feature is optional + fmt.Println("Rust files not copied to wasm-vm-executor-rs. Add a wasm-vm-executor-rs-path.txt with the path to enable feature.") + return + } + rustExecutorPath := strings.Trim(string(contentBytes), " \n\t") + + fmt.Printf("Copying generated Rust files to '%s':\n", rustExecutorPath) + copyFile( + filepath.Join(pathToApiPackage, "generate/cmd/output/opcode_whitelist.rs"), + filepath.Join(rustExecutorPath, "framework/meta-lib/src/tools/wasm_extractor/opcode_whitelist.rs"), + ) + copyFile( + filepath.Join(pathToApiPackage, "generate/cmd/output/vm_hook_signature_list.rs"), + filepath.Join(rustExecutorPath, "framework/meta-lib/src/ei/vm_hook_signature_list.rs"), ) } diff --git a/vmhost/vmhooks/generate/cmd/input/wasmer2_opcodes_short.txt b/vmhost/vmhooks/generate/cmd/input/wasmer2_allowed_opcodes_v1.txt similarity index 98% rename from vmhost/vmhooks/generate/cmd/input/wasmer2_opcodes_short.txt rename to vmhost/vmhooks/generate/cmd/input/wasmer2_allowed_opcodes_v1.txt index 6ca6bb4e7..82660681f 100644 --- a/vmhost/vmhooks/generate/cmd/input/wasmer2_opcodes_short.txt +++ b/vmhost/vmhooks/generate/cmd/input/wasmer2_allowed_opcodes_v1.txt @@ -103,7 +103,6 @@ If LocalGet LocalSet LocalTee -LocalAllocate Loop MemoryGrow MemorySize diff --git a/vmhost/vmhooks/generate/cmd/input/wasmer2_allowed_opcodes_v2.txt b/vmhost/vmhooks/generate/cmd/input/wasmer2_allowed_opcodes_v2.txt new file mode 100644 index 000000000..015d9d4b3 --- /dev/null +++ b/vmhost/vmhooks/generate/cmd/input/wasmer2_allowed_opcodes_v2.txt @@ -0,0 +1,128 @@ +Block +Br +BrIf +BrTable +Call +CallIndirect +Catch +CatchAll +Delegate +Drop +Else +End +GlobalGet +GlobalSet +I32Add +I32And +I32Clz +I32Const +I32Ctz +I32DivS +I32DivU +I32Eq +I32Eqz +I32Extend16S +I32Extend8S +I32GeS +I32GeU +I32GtS +I32GtU +I32LeS +I32LeU +I32Load +I32Load16S +I32Load16U +I32Load8S +I32Load8U +I32LtS +I32LtU +I32Mul +I32Ne +I32Or +I32Popcnt +I32RemS +I32RemU +I32Rotl +I32Rotr +I32Shl +I32ShrS +I32ShrU +I32Store +I32Store16 +I32Store8 +I32Sub +I32WrapI64 +I32Xor +I64Add +I64And +I64Clz +I64Const +I64Ctz +I64DivS +I64DivU +I64Eq +I64Eqz +I64Extend16S +I64Extend32S +I64Extend8S +I64ExtendI32S +I64ExtendI32U +I64GeS +I64GeU +I64GtS +I64GtU +I64LeS +I64LeU +I64Load +I64Load16S +I64Load16U +I64Load32S +I64Load32U +I64Load8S +I64Load8U +I64LtS +I64LtU +I64Mul +I64Ne +I64Or +I64Popcnt +I64RemS +I64RemU +I64Rotl +I64Rotr +I64Shl +I64ShrS +I64ShrU +I64Store +I64Store16 +I64Store32 +I64Store8 +I64Sub +I64Xor +If +LocalGet +LocalSet +LocalTee +Loop +MemoryGrow +MemorySize +Nop +RefFunc +RefIsNull +RefNull +Rethrow +Return +ReturnCall +ReturnCallIndirect +Select +TableGet +TableGrow +TableInit +TableSet +TableSize +Throw +Try +TypedSelect +Unreachable +MemoryCopy +MemoryFill \ No newline at end of file diff --git a/vmhost/vmhooks/generate/cmd/input/wasmer2_relevant_opcodes.txt b/vmhost/vmhooks/generate/cmd/input/wasmer2_relevant_opcodes.txt new file mode 100644 index 000000000..a17a5045a --- /dev/null +++ b/vmhost/vmhooks/generate/cmd/input/wasmer2_relevant_opcodes.txt @@ -0,0 +1,130 @@ +Block +Br +BrIf +BrTable +Call +CallIndirect +Catch +CatchAll +Delegate +Drop +Else +End +GlobalGet +GlobalSet +I32Add +I32And +I32Clz +I32Const +I32Ctz +I32DivS +I32DivU +I32Eq +I32Eqz +I32Extend16S +I32Extend8S +I32GeS +I32GeU +I32GtS +I32GtU +I32LeS +I32LeU +I32Load +I32Load16S +I32Load16U +I32Load8S +I32Load8U +I32LtS +I32LtU +I32Mul +I32Ne +I32Or +I32Popcnt +I32RemS +I32RemU +I32Rotl +I32Rotr +I32Shl +I32ShrS +I32ShrU +I32Store +I32Store16 +I32Store8 +I32Sub +I32WrapI64 +I32Xor +I64Add +I64And +I64Clz +I64Const +I64Ctz +I64DivS +I64DivU +I64Eq +I64Eqz +I64Extend16S +I64Extend32S +I64Extend8S +I64ExtendI32S +I64ExtendI32U +I64GeS +I64GeU +I64GtS +I64GtU +I64LeS +I64LeU +I64Load +I64Load16S +I64Load16U +I64Load32S +I64Load32U +I64Load8S +I64Load8U +I64LtS +I64LtU +I64Mul +I64Ne +I64Or +I64Popcnt +I64RemS +I64RemU +I64Rotl +I64Rotr +I64Shl +I64ShrS +I64ShrU +I64Store +I64Store16 +I64Store32 +I64Store8 +I64Sub +I64Xor +If +LocalGet +LocalSet +LocalTee +LocalAllocate +Loop +MemoryGrow +MemorySize +MemoryCopy +MemoryFill +Nop +RefFunc +RefIsNull +RefNull +Rethrow +Return +ReturnCall +ReturnCallIndirect +Select +TableGet +TableGrow +TableInit +TableSet +TableSize +Throw +Try +TypedSelect +Unreachable +Unwind \ No newline at end of file diff --git a/vmhost/vmhooks/generate/eiGenOpcodeNames.go b/vmhost/vmhooks/generate/eiGenOpcodeNames.go new file mode 100644 index 000000000..20baf8c10 --- /dev/null +++ b/vmhost/vmhooks/generate/eiGenOpcodeNames.go @@ -0,0 +1,51 @@ +package vmhooksgenerate + +import ( + "bufio" + "os" +) + +type OpcodeNames struct { + AllowedV1 []string + AllowedV2 []string + RelevantCodes []string +} + +func loadOpcodeNamesForVersion(filePath string) []string { + var names []string + + readFile, err := os.Open(filePath) + if err != nil { + panic(err) + } + defer readFile.Close() + + fileScanner := bufio.NewScanner(readFile) + fileScanner.Split(bufio.ScanLines) + + for fileScanner.Scan() { + line := fileScanner.Text() + names = append(names, line) + } + + return names +} + +func LoadOpcodeNames() *OpcodeNames { + return &OpcodeNames{ + AllowedV1: loadOpcodeNamesForVersion("generate/cmd/input/wasmer2_allowed_opcodes_v1.txt"), + AllowedV2: loadOpcodeNamesForVersion("generate/cmd/input/wasmer2_allowed_opcodes_v2.txt"), + RelevantCodes: loadOpcodeNamesForVersion("generate/cmd/input/wasmer2_relevant_opcodes.txt"), + } +} + +// MaxNameLength helps with aligning to the right +func (on *OpcodeNames) MaxNameLength() int { + var max int + for _, name := range on.RelevantCodes { + if len(name) > max { + max = len(name) + } + } + return max +} diff --git a/vmhost/vmhooks/generate/eiGenWriteOpcodeCost.go b/vmhost/vmhooks/generate/eiGenWriteOpcodeCost.go index be01aeef9..6fd8dc948 100644 --- a/vmhost/vmhooks/generate/eiGenWriteOpcodeCost.go +++ b/vmhost/vmhooks/generate/eiGenWriteOpcodeCost.go @@ -1,35 +1,47 @@ package vmhooksgenerate -import ( - "bufio" - "fmt" - "os" -) - // WriteWasmer2OpcodeCost generates code for wasmer2/opcodeCost.go func WriteWasmer2OpcodeCost(out *eiGenWriter) { - out.WriteString(`// Code generated by vmhooks generator. DO NOT EDIT. + allowedOpcodes := LoadOpcodeNames() + maxNameLength := allowedOpcodes.MaxNameLength() + + autoGeneratedHeader(out) + + out.WriteString(` +package wasmer2 -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +import "github.com/multiversx/mx-chain-vm-go/executor" -`) - out.WriteString("package wasmer2\n\n") - out.WriteString("type OpcodeCost struct {\n") +type OpcodeCost struct {`) - readFile, err := os.Open("generate/cmd/input/wasmer2_opcodes_short.txt") - if err != nil { - panic(err) + for _, opcode := range allowedOpcodes.RelevantCodes { + out.WriteString("\n\t") + out.WriteString(opcode) + for i := len(opcode); i < maxNameLength; i++ { + out.WriteString(" ") + } + out.WriteString(" uint32") } - defer readFile.Close() - fileScanner := bufio.NewScanner(readFile) - fileScanner.Split(bufio.ScanLines) + out.WriteString(` +} + +func (wasmerExecutor *Wasmer2Executor) extractOpcodeCost(wasmOps *executor.WASMOpcodeCost) *OpcodeCost { + return &OpcodeCost{`) - for fileScanner.Scan() { - opcode := fileScanner.Text() - out.WriteString(fmt.Sprintf("\t%-30suint32\n", opcode)) + for _, opcode := range allowedOpcodes.RelevantCodes { + out.WriteString("\n\t\t") + out.WriteString(opcode) + out.WriteString(":") + for i := len(opcode); i < maxNameLength; i++ { + out.WriteString(" ") + } + out.WriteString(" wasmOps.") + out.WriteString(opcode) + out.WriteString(",") + // out.WriteString(fmt.Sprintf("\t\t%s: wasmOps.%s,\n", opcode, opcode)) } + + out.WriteString("\n\t}\n") out.WriteString("}\n") } diff --git a/vmhost/vmhooks/generate/eiGenWriteOpcodeCostFuncHelpers.go b/vmhost/vmhooks/generate/eiGenWriteOpcodeCostFuncHelpers.go deleted file mode 100644 index 26206712f..000000000 --- a/vmhost/vmhooks/generate/eiGenWriteOpcodeCostFuncHelpers.go +++ /dev/null @@ -1,39 +0,0 @@ -package vmhooksgenerate - -import ( - "bufio" - "fmt" - "os" -) - -// WriteOpcodeCostFuncHelpers generates code for extractOpcodeCost.txt -// (to be copied manually in wasmer2/wasmer2Executor.go) -func WriteOpcodeCostFuncHelpers(out *eiGenWriter) { - out.WriteString(`// Code generated by vmhooks generator. DO NOT EDIT. - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -// !!!!!!!!!!!!!!! USE IN wasmer2/wasmer2Executor.go !!!!!!!!!!!!!!! - -`) - out.WriteString("func (wasmerExecutor *Wasmer2Executor) extractOpcodeCost(wasmOps *executor.WASMOpcodeCost) *OpcodeCost {\n") - out.WriteString("\treturn &OpcodeCost {\n") - - readFile, err := os.Open("generate/cmd/input/wasmer2_opcodes_short.txt") - if err != nil { - panic(err) - } - defer readFile.Close() - - fileScanner := bufio.NewScanner(readFile) - fileScanner.Split(bufio.ScanLines) - - for fileScanner.Scan() { - opcode := fileScanner.Text() - out.WriteString(fmt.Sprintf("\t\t%s: wasmOps.%s,\n", opcode, opcode)) - } - out.WriteString("\t}\n") - out.WriteString("}\n") -} diff --git a/vmhost/vmhooks/generate/eiGenWriteRustOpcodeCost.go b/vmhost/vmhooks/generate/eiGenWriteRustOpcodeCost.go index acfe54aba..09a64f1c8 100644 --- a/vmhost/vmhooks/generate/eiGenWriteRustOpcodeCost.go +++ b/vmhost/vmhooks/generate/eiGenWriteRustOpcodeCost.go @@ -1,9 +1,7 @@ package vmhooksgenerate import ( - "bufio" "fmt" - "os" "strings" ) @@ -25,19 +23,12 @@ func WriteRustOpcodeCost(out *eiGenWriter) { out.WriteString("#[serde(default)]\n") out.WriteString("pub struct OpcodeCost {\n") - readFile, err := os.Open("generate/cmd/input/wasmer2_opcodes_short.txt") - if err != nil { - panic(err) - } - defer readFile.Close() - - fileScanner := bufio.NewScanner(readFile) - fileScanner.Split(bufio.ScanLines) + allowedOpcodes := LoadOpcodeNames() - for fileScanner.Scan() { - line := fileScanner.Text() - out.WriteString(fmt.Sprintf(" #[serde(rename = \"%s\", default)]\n", line)) - out.WriteString(fmt.Sprintf(" pub opcode_%s: u32,\n", strings.ToLower(line))) + for _, opcode := range allowedOpcodes.RelevantCodes { + out.WriteString(fmt.Sprintf(" #[serde(rename = \"%s\", default)]\n", opcode)) + out.WriteString(fmt.Sprintf(" pub opcode_%s: u32,\n", strings.ToLower(opcode))) } + out.WriteString("}\n") } diff --git a/vmhost/vmhooks/generate/eiGenWriteRustOpcodeWhitelisted.go b/vmhost/vmhooks/generate/eiGenWriteRustOpcodeWhitelisted.go new file mode 100644 index 000000000..545f119d4 --- /dev/null +++ b/vmhost/vmhooks/generate/eiGenWriteRustOpcodeWhitelisted.go @@ -0,0 +1,62 @@ +package vmhooksgenerate + +import ( + "fmt" +) + +// WriteOpcodeWhitelisted generates code for opcode_whitelisted.rs +func WriteOpcodeWhitelisted(out *eiGenWriter) { + autoGeneratedHeader(out) + allowUnwind := false + allowedOpcodes := LoadOpcodeNames() + + out.WriteString(` +use wasmparser::Operator; + +use super::OpcodeVersion; + +pub fn is_opcode_whitelisted(op: &Operator, opcode_version: OpcodeVersion) -> bool { + match opcode_version { + OpcodeVersion::V1 => is_opcode_whitelisted_v1(op), + OpcodeVersion::V2 => is_opcode_whitelisted_v2(op), + } +} + +fn is_opcode_whitelisted_v1(op: &Operator) -> bool { + matches!( + op, +`) + + for i, opcodeName := range allowedOpcodes.AllowedV1 { + writeOperatorWhitelistMatchArm(out, allowUnwind, i, opcodeName) + } + + out.WriteString(` ) +} + +fn is_opcode_whitelisted_v2(op: &Operator) -> bool { + matches!( + op, +`) + + for i, opcodeName := range allowedOpcodes.AllowedV2 { + writeOperatorWhitelistMatchArm(out, allowUnwind, i, opcodeName) + } + + out.WriteString(` ) +} +`) + +} + +func writeOperatorWhitelistMatchArm(out *eiGenWriter, allowUnwind bool, i int, opcodeName string) { + if !allowUnwind && opcodeName == "Unwind" { + return + } + + if i == 0 { + out.WriteString(fmt.Sprintf(" Operator::%s { .. }\n", opcodeName)) + return + } + out.WriteString(fmt.Sprintf(" | Operator::%s { .. }\n", opcodeName)) +} diff --git a/vmhost/vmhooks/generate/eiGenWriteRustUtil.go b/vmhost/vmhooks/generate/eiGenWriteRustUtil.go index 9721a7339..5ce772792 100644 --- a/vmhost/vmhooks/generate/eiGenWriteRustUtil.go +++ b/vmhost/vmhooks/generate/eiGenWriteRustUtil.go @@ -53,6 +53,21 @@ func rustWasmerType(eiType EIType) string { return rustCapiType(eiType) } +func rustWasmparserValType(eiType EIType) string { + switch eiType { + case EITypeMemPtr: + fallthrough + case EITypeMemLength: + fallthrough + case EITypeInt32: + return "ValType::I32" + case EITypeInt64: + return "ValType::I64" + default: + panic("invalid type") + } +} + func rustWasmerProdConvertArg(arg *EIFunctionArg) string { argRustName := snakeCase(arg.Name) switch arg.Type { diff --git a/vmhost/vmhooks/generate/eiGenWriteRustVMHooksSignatures.go b/vmhost/vmhooks/generate/eiGenWriteRustVMHooksSignatures.go new file mode 100644 index 000000000..34704acf1 --- /dev/null +++ b/vmhost/vmhooks/generate/eiGenWriteRustVMHooksSignatures.go @@ -0,0 +1,40 @@ +package vmhooksgenerate + +// WriteRustVMHooksLegacyTrait autogenerate data in the provided file +func WriteRustVMHooksSignatures(out *eiGenWriter, eiMetadata *EIMetadata) { + autoGeneratedHeader(out) + out.WriteString(` +use wasmparser::ValType; + +use super::VmHookSignature; + +#[rustfmt::skip] +pub const VM_HOOK_SIGNATURES: &[VmHookSignature] = &[ +`) + + for _, funcMetadata := range eiMetadata.AllFunctions { + out.WriteString(` VmHookSignature::new("`) + out.WriteString(lowerInitial(funcMetadata.Name)) + out.WriteString(`", &[`) + for i, arg := range funcMetadata.Arguments { + if i > 0 { + out.WriteString(", ") + } + out.WriteString(rustWasmparserValType(arg.Type)) + } + out.WriteString("], ") + if funcMetadata.Result == nil { + out.WriteString("None") + } else { + + out.WriteString("Some(") + out.WriteString(rustWasmparserValType(funcMetadata.Result.Type)) + out.WriteString(")") + } + out.WriteString("),\n") + } + + out.WriteString(`]; +`) + +} diff --git a/vmhost/vmhooks/generate/eiGenWriteRustWasmerMeteringHelpers.go b/vmhost/vmhooks/generate/eiGenWriteRustWasmerMeteringHelpers.go deleted file mode 100644 index 118c04a51..000000000 --- a/vmhost/vmhooks/generate/eiGenWriteRustWasmerMeteringHelpers.go +++ /dev/null @@ -1,54 +0,0 @@ -package vmhooksgenerate - -import ( - "bufio" - "os" - "strings" -) - -// Local cost name from config/config.toml (might change in the future) -const localCostName = "localallocate" - -// WriteRustWasmerMeteringHelpers generates code for wasmer_metering_helpers.rs -func WriteRustWasmerMeteringHelpers(out *eiGenWriter) { - autoGeneratedHeader(out) - out.WriteString("\nuse crate::executor_interface::OpcodeCost;\n") - out.WriteString("use wasmer::wasmparser::Operator;\n\n") - - readFile, err := os.Open("generate/cmd/input/wasmer2_opcodes_short.txt") - if err != nil { - panic(err) - } - defer readFile.Close() - - fileScanner := bufio.NewScanner(readFile) - fileScanner.Split(bufio.ScanLines) - - var content string - for fileScanner.Scan() { - line := fileScanner.Text() - if strings.ToLower(line) == localCostName { - // This operator doesn't really exist, so we skip it - continue - } - content += " Operator::" + line + " { .. } => " + "Some(opcode_cost.opcode_" + strings.ToLower(line) + "),\n" - } - - writeFnGetLocalCost(out) - writeFnGetOpcodeCost(out, content) -} - -func writeFnGetLocalCost(out *eiGenWriter) { - out.WriteString("pub fn get_local_cost(opcode_cost: &OpcodeCost) -> u32 {\n") - out.WriteString(" opcode_cost.opcode_" + localCostName + "\n") - out.WriteString("}\n\n") -} - -func writeFnGetOpcodeCost(out *eiGenWriter, content string) { - out.WriteString("pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option {\n") - out.WriteString(" match op {\n") - out.WriteString(content) - out.WriteString(" _ => None,\n") - out.WriteString(" }\n") - out.WriteString("}\n") -} diff --git a/vmhost/vmhooks/generate/eiGenWriteRustWasmerOpcodeCost.go b/vmhost/vmhooks/generate/eiGenWriteRustWasmerOpcodeCost.go new file mode 100644 index 000000000..429436621 --- /dev/null +++ b/vmhost/vmhooks/generate/eiGenWriteRustWasmerOpcodeCost.go @@ -0,0 +1,70 @@ +package vmhooksgenerate + +import ( + "fmt" + "strings" +) + +// WriteRustWasmerOpcodeCost generates code for wasmer_opcode_cost.rs +func WriteRustWasmerOpcodeCost(out *eiGenWriter) { + autoGeneratedHeader(out) + out.WriteString("\nuse crate::executor_interface::{OpcodeConfig, OpcodeCost, OpcodeVersion};") + writeOpcodeCostBody(out, true) + +} + +// WriteRustWasmerOpcodeCost generates code for we_opcode_cost.rs +func WriteRustWasmerExperimentalOpcodeCost(out *eiGenWriter) { + autoGeneratedHeader(out) + out.WriteString("\nuse multiversx_chain_vm_executor::{OpcodeConfig, OpcodeCost, OpcodeVersion};") + writeOpcodeCostBody(out, false) +} + +func writeOpcodeCostBody(out *eiGenWriter, allowUnwind bool) { + allowedOpcodes := LoadOpcodeNames() + + out.WriteString(` +use wasmer::wasmparser::Operator; + +pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option { + match opcode_config.opcode_version { + OpcodeVersion::V1 => get_opcode_cost_v1(op, &opcode_config.opcode_cost), + OpcodeVersion::V2 => get_opcode_cost_v2(op, &opcode_config.opcode_cost), + } +} + +fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option { + match op { +`) + + for _, opcodeName := range allowedOpcodes.AllowedV1 { + writeOperatorMatchArm(out, allowUnwind, opcodeName) + } + + out.WriteString(` _ => None, + } +} + +fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { + match op { +`) + + for _, opcodeName := range allowedOpcodes.AllowedV2 { + writeOperatorMatchArm(out, allowUnwind, opcodeName) + } + + out.WriteString(` _ => None, + } +} +`) + +} + +func writeOperatorMatchArm(out *eiGenWriter, allowUnwind bool, opcodeName string) { + if !allowUnwind && opcodeName == "Unwind" { + out.WriteString(" // Operator::Unwind { .. } => Some(opcode_cost.opcode_unwind), // unwind no longer available in Wasmer 6 \n") + return + } + + out.WriteString(fmt.Sprintf(" Operator::%s { .. } => Some(opcode_cost.opcode_%s),\n", opcodeName, strings.ToLower(opcodeName))) +} diff --git a/wasmer2/bridge2.go b/wasmer2/bridge2.go index c1c6204c3..dd4946a9f 100644 --- a/wasmer2/bridge2.go +++ b/wasmer2/bridge2.go @@ -41,12 +41,14 @@ func cWasmerForceInstallSighandlers() { C.vm_force_sighandler_reinstall() } -func cWasmerExecutorSetOpcodeCost( +func cWasmerExecutorSetOpcodeConfig( executor *cWasmerExecutorT, + opcodeVersion int32, opcodeCost *cWasmerOpcodeCostT, ) cWasmerResultT { - return (cWasmerResultT)(C.vm_exec_set_opcode_costs( + return (cWasmerResultT)(C.vm_exec_set_opcode_config( (*C.vm_exec_executor_t)(executor), + (C.int32_t)(opcodeVersion), (*C.vm_exec_opcode_cost_t)(opcodeCost), )) } diff --git a/wasmer2/libvmexeccapi.dylib b/wasmer2/libvmexeccapi.dylib index 26f7bfb81..8408e627b 100755 Binary files a/wasmer2/libvmexeccapi.dylib and b/wasmer2/libvmexeccapi.dylib differ diff --git a/wasmer2/libvmexeccapi.h b/wasmer2/libvmexeccapi.h index 14ab42707..de840f1ee 100644 --- a/wasmer2/libvmexeccapi.h +++ b/wasmer2/libvmexeccapi.h @@ -619,8 +619,9 @@ vm_exec_result_t vm_exec_set_log_level(uint64_t value); * * C API function, works with raw object pointers. */ -vm_exec_result_t vm_exec_set_opcode_costs(vm_exec_executor_t *executor_ptr, - const vm_exec_opcode_cost_t *opcode_cost_ptr); +vm_exec_result_t vm_exec_set_opcode_config(vm_exec_executor_t *executor_ptr, + int32_t opcode_vesion_code, + const vm_exec_opcode_cost_t *opcode_cost_ptr); /** * Returns all SC endpoint names, separated by pipes. diff --git a/wasmer2/libvmexeccapi.so b/wasmer2/libvmexeccapi.so index c024872c1..486b5f823 100755 Binary files a/wasmer2/libvmexeccapi.so and b/wasmer2/libvmexeccapi.so differ diff --git a/wasmer2/libvmexeccapi_arm.dylib b/wasmer2/libvmexeccapi_arm.dylib index 6cf080c64..66836f91e 100755 Binary files a/wasmer2/libvmexeccapi_arm.dylib and b/wasmer2/libvmexeccapi_arm.dylib differ diff --git a/wasmer2/libvmexeccapi_arm.so b/wasmer2/libvmexeccapi_arm.so index 1a31d9385..834afd164 100644 Binary files a/wasmer2/libvmexeccapi_arm.so and b/wasmer2/libvmexeccapi_arm.so differ diff --git a/wasmer2/opcodeCost.go b/wasmer2/opcodeCost.go index 3226e3ee4..f693fd83e 100644 --- a/wasmer2/opcodeCost.go +++ b/wasmer2/opcodeCost.go @@ -6,133 +6,272 @@ package wasmer2 +import "github.com/multiversx/mx-chain-vm-go/executor" + type OpcodeCost struct { - Block uint32 - Br uint32 - BrIf uint32 - BrTable uint32 - Call uint32 - CallIndirect uint32 - Catch uint32 - CatchAll uint32 - Delegate uint32 - Drop uint32 - Else uint32 - End uint32 - GlobalGet uint32 - GlobalSet uint32 - I32Add uint32 - I32And uint32 - I32Clz uint32 - I32Const uint32 - I32Ctz uint32 - I32DivS uint32 - I32DivU uint32 - I32Eq uint32 - I32Eqz uint32 - I32Extend16S uint32 - I32Extend8S uint32 - I32GeS uint32 - I32GeU uint32 - I32GtS uint32 - I32GtU uint32 - I32LeS uint32 - I32LeU uint32 - I32Load uint32 - I32Load16S uint32 - I32Load16U uint32 - I32Load8S uint32 - I32Load8U uint32 - I32LtS uint32 - I32LtU uint32 - I32Mul uint32 - I32Ne uint32 - I32Or uint32 - I32Popcnt uint32 - I32RemS uint32 - I32RemU uint32 - I32Rotl uint32 - I32Rotr uint32 - I32Shl uint32 - I32ShrS uint32 - I32ShrU uint32 - I32Store uint32 - I32Store16 uint32 - I32Store8 uint32 - I32Sub uint32 - I32WrapI64 uint32 - I32Xor uint32 - I64Add uint32 - I64And uint32 - I64Clz uint32 - I64Const uint32 - I64Ctz uint32 - I64DivS uint32 - I64DivU uint32 - I64Eq uint32 - I64Eqz uint32 - I64Extend16S uint32 - I64Extend32S uint32 - I64Extend8S uint32 - I64ExtendI32S uint32 - I64ExtendI32U uint32 - I64GeS uint32 - I64GeU uint32 - I64GtS uint32 - I64GtU uint32 - I64LeS uint32 - I64LeU uint32 - I64Load uint32 - I64Load16S uint32 - I64Load16U uint32 - I64Load32S uint32 - I64Load32U uint32 - I64Load8S uint32 - I64Load8U uint32 - I64LtS uint32 - I64LtU uint32 - I64Mul uint32 - I64Ne uint32 - I64Or uint32 - I64Popcnt uint32 - I64RemS uint32 - I64RemU uint32 - I64Rotl uint32 - I64Rotr uint32 - I64Shl uint32 - I64ShrS uint32 - I64ShrU uint32 - I64Store uint32 - I64Store16 uint32 - I64Store32 uint32 - I64Store8 uint32 - I64Sub uint32 - I64Xor uint32 - If uint32 - LocalGet uint32 - LocalSet uint32 - LocalTee uint32 - LocalAllocate uint32 - Loop uint32 - MemoryGrow uint32 - MemorySize uint32 - Nop uint32 - RefFunc uint32 - RefIsNull uint32 - RefNull uint32 - Rethrow uint32 - Return uint32 - ReturnCall uint32 - ReturnCallIndirect uint32 - Select uint32 - TableGet uint32 - TableGrow uint32 - TableInit uint32 - TableSet uint32 - TableSize uint32 - Throw uint32 - Try uint32 - TypedSelect uint32 - Unreachable uint32 - Unwind uint32 + Block uint32 + Br uint32 + BrIf uint32 + BrTable uint32 + Call uint32 + CallIndirect uint32 + Catch uint32 + CatchAll uint32 + Delegate uint32 + Drop uint32 + Else uint32 + End uint32 + GlobalGet uint32 + GlobalSet uint32 + I32Add uint32 + I32And uint32 + I32Clz uint32 + I32Const uint32 + I32Ctz uint32 + I32DivS uint32 + I32DivU uint32 + I32Eq uint32 + I32Eqz uint32 + I32Extend16S uint32 + I32Extend8S uint32 + I32GeS uint32 + I32GeU uint32 + I32GtS uint32 + I32GtU uint32 + I32LeS uint32 + I32LeU uint32 + I32Load uint32 + I32Load16S uint32 + I32Load16U uint32 + I32Load8S uint32 + I32Load8U uint32 + I32LtS uint32 + I32LtU uint32 + I32Mul uint32 + I32Ne uint32 + I32Or uint32 + I32Popcnt uint32 + I32RemS uint32 + I32RemU uint32 + I32Rotl uint32 + I32Rotr uint32 + I32Shl uint32 + I32ShrS uint32 + I32ShrU uint32 + I32Store uint32 + I32Store16 uint32 + I32Store8 uint32 + I32Sub uint32 + I32WrapI64 uint32 + I32Xor uint32 + I64Add uint32 + I64And uint32 + I64Clz uint32 + I64Const uint32 + I64Ctz uint32 + I64DivS uint32 + I64DivU uint32 + I64Eq uint32 + I64Eqz uint32 + I64Extend16S uint32 + I64Extend32S uint32 + I64Extend8S uint32 + I64ExtendI32S uint32 + I64ExtendI32U uint32 + I64GeS uint32 + I64GeU uint32 + I64GtS uint32 + I64GtU uint32 + I64LeS uint32 + I64LeU uint32 + I64Load uint32 + I64Load16S uint32 + I64Load16U uint32 + I64Load32S uint32 + I64Load32U uint32 + I64Load8S uint32 + I64Load8U uint32 + I64LtS uint32 + I64LtU uint32 + I64Mul uint32 + I64Ne uint32 + I64Or uint32 + I64Popcnt uint32 + I64RemS uint32 + I64RemU uint32 + I64Rotl uint32 + I64Rotr uint32 + I64Shl uint32 + I64ShrS uint32 + I64ShrU uint32 + I64Store uint32 + I64Store16 uint32 + I64Store32 uint32 + I64Store8 uint32 + I64Sub uint32 + I64Xor uint32 + If uint32 + LocalGet uint32 + LocalSet uint32 + LocalTee uint32 + LocalAllocate uint32 + Loop uint32 + MemoryGrow uint32 + MemorySize uint32 + MemoryCopy uint32 + MemoryFill uint32 + Nop uint32 + RefFunc uint32 + RefIsNull uint32 + RefNull uint32 + Rethrow uint32 + Return uint32 + ReturnCall uint32 + ReturnCallIndirect uint32 + Select uint32 + TableGet uint32 + TableGrow uint32 + TableInit uint32 + TableSet uint32 + TableSize uint32 + Throw uint32 + Try uint32 + TypedSelect uint32 + Unreachable uint32 + Unwind uint32 +} + +func (wasmerExecutor *Wasmer2Executor) extractOpcodeCost(wasmOps *executor.WASMOpcodeCost) *OpcodeCost { + return &OpcodeCost{ + Block: wasmOps.Block, + Br: wasmOps.Br, + BrIf: wasmOps.BrIf, + BrTable: wasmOps.BrTable, + Call: wasmOps.Call, + CallIndirect: wasmOps.CallIndirect, + Catch: wasmOps.Catch, + CatchAll: wasmOps.CatchAll, + Delegate: wasmOps.Delegate, + Drop: wasmOps.Drop, + Else: wasmOps.Else, + End: wasmOps.End, + GlobalGet: wasmOps.GlobalGet, + GlobalSet: wasmOps.GlobalSet, + I32Add: wasmOps.I32Add, + I32And: wasmOps.I32And, + I32Clz: wasmOps.I32Clz, + I32Const: wasmOps.I32Const, + I32Ctz: wasmOps.I32Ctz, + I32DivS: wasmOps.I32DivS, + I32DivU: wasmOps.I32DivU, + I32Eq: wasmOps.I32Eq, + I32Eqz: wasmOps.I32Eqz, + I32Extend16S: wasmOps.I32Extend16S, + I32Extend8S: wasmOps.I32Extend8S, + I32GeS: wasmOps.I32GeS, + I32GeU: wasmOps.I32GeU, + I32GtS: wasmOps.I32GtS, + I32GtU: wasmOps.I32GtU, + I32LeS: wasmOps.I32LeS, + I32LeU: wasmOps.I32LeU, + I32Load: wasmOps.I32Load, + I32Load16S: wasmOps.I32Load16S, + I32Load16U: wasmOps.I32Load16U, + I32Load8S: wasmOps.I32Load8S, + I32Load8U: wasmOps.I32Load8U, + I32LtS: wasmOps.I32LtS, + I32LtU: wasmOps.I32LtU, + I32Mul: wasmOps.I32Mul, + I32Ne: wasmOps.I32Ne, + I32Or: wasmOps.I32Or, + I32Popcnt: wasmOps.I32Popcnt, + I32RemS: wasmOps.I32RemS, + I32RemU: wasmOps.I32RemU, + I32Rotl: wasmOps.I32Rotl, + I32Rotr: wasmOps.I32Rotr, + I32Shl: wasmOps.I32Shl, + I32ShrS: wasmOps.I32ShrS, + I32ShrU: wasmOps.I32ShrU, + I32Store: wasmOps.I32Store, + I32Store16: wasmOps.I32Store16, + I32Store8: wasmOps.I32Store8, + I32Sub: wasmOps.I32Sub, + I32WrapI64: wasmOps.I32WrapI64, + I32Xor: wasmOps.I32Xor, + I64Add: wasmOps.I64Add, + I64And: wasmOps.I64And, + I64Clz: wasmOps.I64Clz, + I64Const: wasmOps.I64Const, + I64Ctz: wasmOps.I64Ctz, + I64DivS: wasmOps.I64DivS, + I64DivU: wasmOps.I64DivU, + I64Eq: wasmOps.I64Eq, + I64Eqz: wasmOps.I64Eqz, + I64Extend16S: wasmOps.I64Extend16S, + I64Extend32S: wasmOps.I64Extend32S, + I64Extend8S: wasmOps.I64Extend8S, + I64ExtendI32S: wasmOps.I64ExtendI32S, + I64ExtendI32U: wasmOps.I64ExtendI32U, + I64GeS: wasmOps.I64GeS, + I64GeU: wasmOps.I64GeU, + I64GtS: wasmOps.I64GtS, + I64GtU: wasmOps.I64GtU, + I64LeS: wasmOps.I64LeS, + I64LeU: wasmOps.I64LeU, + I64Load: wasmOps.I64Load, + I64Load16S: wasmOps.I64Load16S, + I64Load16U: wasmOps.I64Load16U, + I64Load32S: wasmOps.I64Load32S, + I64Load32U: wasmOps.I64Load32U, + I64Load8S: wasmOps.I64Load8S, + I64Load8U: wasmOps.I64Load8U, + I64LtS: wasmOps.I64LtS, + I64LtU: wasmOps.I64LtU, + I64Mul: wasmOps.I64Mul, + I64Ne: wasmOps.I64Ne, + I64Or: wasmOps.I64Or, + I64Popcnt: wasmOps.I64Popcnt, + I64RemS: wasmOps.I64RemS, + I64RemU: wasmOps.I64RemU, + I64Rotl: wasmOps.I64Rotl, + I64Rotr: wasmOps.I64Rotr, + I64Shl: wasmOps.I64Shl, + I64ShrS: wasmOps.I64ShrS, + I64ShrU: wasmOps.I64ShrU, + I64Store: wasmOps.I64Store, + I64Store16: wasmOps.I64Store16, + I64Store32: wasmOps.I64Store32, + I64Store8: wasmOps.I64Store8, + I64Sub: wasmOps.I64Sub, + I64Xor: wasmOps.I64Xor, + If: wasmOps.If, + LocalGet: wasmOps.LocalGet, + LocalSet: wasmOps.LocalSet, + LocalTee: wasmOps.LocalTee, + LocalAllocate: wasmOps.LocalAllocate, + Loop: wasmOps.Loop, + MemoryGrow: wasmOps.MemoryGrow, + MemorySize: wasmOps.MemorySize, + MemoryCopy: wasmOps.MemoryCopy, + MemoryFill: wasmOps.MemoryFill, + Nop: wasmOps.Nop, + RefFunc: wasmOps.RefFunc, + RefIsNull: wasmOps.RefIsNull, + RefNull: wasmOps.RefNull, + Rethrow: wasmOps.Rethrow, + Return: wasmOps.Return, + ReturnCall: wasmOps.ReturnCall, + ReturnCallIndirect: wasmOps.ReturnCallIndirect, + Select: wasmOps.Select, + TableGet: wasmOps.TableGet, + TableGrow: wasmOps.TableGrow, + TableInit: wasmOps.TableInit, + TableSet: wasmOps.TableSet, + TableSize: wasmOps.TableSize, + Throw: wasmOps.Throw, + Try: wasmOps.Try, + TypedSelect: wasmOps.TypedSelect, + Unreachable: wasmOps.Unreachable, + Unwind: wasmOps.Unwind, + } } diff --git a/wasmer2/wasmer2Executor.go b/wasmer2/wasmer2Executor.go index 159b0d567..2aa71bd6d 100644 --- a/wasmer2/wasmer2Executor.go +++ b/wasmer2/wasmer2Executor.go @@ -48,12 +48,13 @@ func CreateExecutor() (*Wasmer2Executor, error) { return wasmerExecutor, nil } -// SetOpcodeCosts sets gas costs globally inside the Wasmer executor. -func (wasmerExecutor *Wasmer2Executor) SetOpcodeCosts(wasmOps *executor.WASMOpcodeCost) { +// SetOpcodeConfig sets the opcode version and opcode costs, based on the gas schedule. +func (wasmerExecutor *Wasmer2Executor) SetOpcodeConfig(opcodeVersion executor.OpcodeVersion, wasmOps *executor.WASMOpcodeCost) { // extract only wasmer2 opcodes wasmerExecutor.opcodeCost = wasmerExecutor.extractOpcodeCost(wasmOps) - cWasmerExecutorSetOpcodeCost( + cWasmerExecutorSetOpcodeConfig( wasmerExecutor.cgoExecutor, + (int32)(opcodeVersion), (*cWasmerOpcodeCostT)(unsafe.Pointer(wasmerExecutor.opcodeCost)), ) } @@ -139,136 +140,3 @@ func (wasmerExecutor *Wasmer2Executor) initVMHooks(vmHooks executor.VMHooks) { wasmerExecutor.vmHooksPtrPtr = unsafe.Pointer(&localPtr) cWasmerExecutorContextDataSet(wasmerExecutor.cgoExecutor, wasmerExecutor.vmHooksPtrPtr) } - -func (wasmerExecutor *Wasmer2Executor) extractOpcodeCost(wasmOps *executor.WASMOpcodeCost) *OpcodeCost { - return &OpcodeCost{ - Block: wasmOps.Block, - Br: wasmOps.Br, - BrIf: wasmOps.BrIf, - BrTable: wasmOps.BrTable, - Call: wasmOps.Call, - CallIndirect: wasmOps.CallIndirect, - Catch: wasmOps.Catch, - CatchAll: wasmOps.CatchAll, - Delegate: wasmOps.Delegate, - Drop: wasmOps.Drop, - Else: wasmOps.Else, - End: wasmOps.End, - GlobalGet: wasmOps.GlobalGet, - GlobalSet: wasmOps.GlobalSet, - I32Add: wasmOps.I32Add, - I32And: wasmOps.I32And, - I32Clz: wasmOps.I32Clz, - I32Const: wasmOps.I32Const, - I32Ctz: wasmOps.I32Ctz, - I32DivS: wasmOps.I32DivS, - I32DivU: wasmOps.I32DivU, - I32Eq: wasmOps.I32Eq, - I32Eqz: wasmOps.I32Eqz, - I32Extend16S: wasmOps.I32Extend16S, - I32Extend8S: wasmOps.I32Extend8S, - I32GeS: wasmOps.I32GeS, - I32GeU: wasmOps.I32GeU, - I32GtS: wasmOps.I32GtS, - I32GtU: wasmOps.I32GtU, - I32LeS: wasmOps.I32LeS, - I32LeU: wasmOps.I32LeU, - I32Load: wasmOps.I32Load, - I32Load16S: wasmOps.I32Load16S, - I32Load16U: wasmOps.I32Load16U, - I32Load8S: wasmOps.I32Load8S, - I32Load8U: wasmOps.I32Load8U, - I32LtS: wasmOps.I32LtS, - I32LtU: wasmOps.I32LtU, - I32Mul: wasmOps.I32Mul, - I32Ne: wasmOps.I32Ne, - I32Or: wasmOps.I32Or, - I32Popcnt: wasmOps.I32Popcnt, - I32RemS: wasmOps.I32RemS, - I32RemU: wasmOps.I32RemU, - I32Rotl: wasmOps.I32Rotl, - I32Rotr: wasmOps.I32Rotr, - I32Shl: wasmOps.I32Shl, - I32ShrS: wasmOps.I32ShrS, - I32ShrU: wasmOps.I32ShrU, - I32Store: wasmOps.I32Store, - I32Store16: wasmOps.I32Store16, - I32Store8: wasmOps.I32Store8, - I32Sub: wasmOps.I32Sub, - I32WrapI64: wasmOps.I32WrapI64, - I32Xor: wasmOps.I32Xor, - I64Add: wasmOps.I64Add, - I64And: wasmOps.I64And, - I64Clz: wasmOps.I64Clz, - I64Const: wasmOps.I64Const, - I64Ctz: wasmOps.I64Ctz, - I64DivS: wasmOps.I64DivS, - I64DivU: wasmOps.I64DivU, - I64Eq: wasmOps.I64Eq, - I64Eqz: wasmOps.I64Eqz, - I64Extend16S: wasmOps.I64Extend16S, - I64Extend32S: wasmOps.I64Extend32S, - I64Extend8S: wasmOps.I64Extend8S, - I64ExtendI32S: wasmOps.I64ExtendI32S, - I64ExtendI32U: wasmOps.I64ExtendI32U, - I64GeS: wasmOps.I64GeS, - I64GeU: wasmOps.I64GeU, - I64GtS: wasmOps.I64GtS, - I64GtU: wasmOps.I64GtU, - I64LeS: wasmOps.I64LeS, - I64LeU: wasmOps.I64LeU, - I64Load: wasmOps.I64Load, - I64Load16S: wasmOps.I64Load16S, - I64Load16U: wasmOps.I64Load16U, - I64Load32S: wasmOps.I64Load32S, - I64Load32U: wasmOps.I64Load32U, - I64Load8S: wasmOps.I64Load8S, - I64Load8U: wasmOps.I64Load8U, - I64LtS: wasmOps.I64LtS, - I64LtU: wasmOps.I64LtU, - I64Mul: wasmOps.I64Mul, - I64Ne: wasmOps.I64Ne, - I64Or: wasmOps.I64Or, - I64Popcnt: wasmOps.I64Popcnt, - I64RemS: wasmOps.I64RemS, - I64RemU: wasmOps.I64RemU, - I64Rotl: wasmOps.I64Rotl, - I64Rotr: wasmOps.I64Rotr, - I64Shl: wasmOps.I64Shl, - I64ShrS: wasmOps.I64ShrS, - I64ShrU: wasmOps.I64ShrU, - I64Store: wasmOps.I64Store, - I64Store16: wasmOps.I64Store16, - I64Store32: wasmOps.I64Store32, - I64Store8: wasmOps.I64Store8, - I64Sub: wasmOps.I64Sub, - I64Xor: wasmOps.I64Xor, - If: wasmOps.If, - LocalGet: wasmOps.LocalGet, - LocalSet: wasmOps.LocalSet, - LocalTee: wasmOps.LocalTee, - LocalAllocate: wasmOps.LocalAllocate, - Loop: wasmOps.Loop, - MemoryGrow: wasmOps.MemoryGrow, - MemorySize: wasmOps.MemorySize, - Nop: wasmOps.Nop, - RefFunc: wasmOps.RefFunc, - RefIsNull: wasmOps.RefIsNull, - RefNull: wasmOps.RefNull, - Rethrow: wasmOps.Rethrow, - Return: wasmOps.Return, - ReturnCall: wasmOps.ReturnCall, - ReturnCallIndirect: wasmOps.ReturnCallIndirect, - Select: wasmOps.Select, - TableGet: wasmOps.TableGet, - TableGrow: wasmOps.TableGrow, - TableInit: wasmOps.TableInit, - TableSet: wasmOps.TableSet, - TableSize: wasmOps.TableSize, - Throw: wasmOps.Throw, - Try: wasmOps.Try, - TypedSelect: wasmOps.TypedSelect, - Unreachable: wasmOps.Unreachable, - Unwind: wasmOps.Unwind, - } -} diff --git a/wasmer2/wasmer2ExecutorFactory.go b/wasmer2/wasmer2ExecutorFactory.go index b3b28a549..3953e6ef6 100644 --- a/wasmer2/wasmer2ExecutorFactory.go +++ b/wasmer2/wasmer2ExecutorFactory.go @@ -27,7 +27,7 @@ func (wef *Wasmer2ExecutorFactory) CreateExecutor(args executor.ExecutorFactoryA executor.initVMHooks(args.VMHooks) if args.OpcodeCosts != nil { // opcode costs are sometimes not initialized at this point in certain tests - executor.SetOpcodeCosts(args.OpcodeCosts) + executor.SetOpcodeConfig(args.OpcodeVersion, args.OpcodeCosts) } return executor, nil