| // Copyright 2016 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "test/common/wasm/wasm-module-runner.h" |
| |
| #include "src/execution/isolate.h" |
| #include "src/handles/handles.h" |
| #include "src/objects/heap-number-inl.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/objects/property-descriptor.h" |
| #include "src/wasm/module-decoder.h" |
| #include "src/wasm/wasm-engine.h" |
| #include "src/wasm/wasm-js.h" |
| #include "src/wasm/wasm-module.h" |
| #include "src/wasm/wasm-objects.h" |
| #include "src/wasm/wasm-opcodes.h" |
| #include "src/wasm/wasm-result.h" |
| |
| namespace v8::internal::wasm::testing { |
| |
| MaybeDirectHandle<WasmModuleObject> CompileForTesting( |
| Isolate* isolate, ErrorThrower* thrower, |
| base::Vector<const uint8_t> bytes) { |
| auto enabled_features = WasmEnabledFeatures::FromIsolate(isolate); |
| MaybeDirectHandle<WasmModuleObject> module = GetWasmEngine()->SyncCompile( |
| isolate, enabled_features, CompileTimeImports{}, thrower, |
| base::OwnedCopyOf(bytes)); |
| DCHECK_EQ(thrower->error(), module.is_null()); |
| return module; |
| } |
| |
| MaybeDirectHandle<WasmInstanceObject> CompileAndInstantiateForTesting( |
| Isolate* isolate, ErrorThrower* thrower, |
| base::Vector<const uint8_t> bytes) { |
| MaybeDirectHandle<WasmModuleObject> module = |
| CompileForTesting(isolate, thrower, bytes); |
| if (module.is_null()) return {}; |
| return GetWasmEngine()->SyncInstantiate(isolate, thrower, |
| module.ToHandleChecked(), {}, {}); |
| } |
| |
| DirectHandleVector<Object> MakeDefaultArguments(Isolate* isolate, |
| const FunctionSig* sig) { |
| size_t param_count = sig->parameter_count(); |
| DirectHandleVector<Object> arguments(isolate, param_count); |
| |
| for (size_t i = 0; i < param_count; ++i) { |
| switch (sig->GetParam(i).kind()) { |
| case kI32: |
| case kF32: |
| case kF64: |
| case kS128: |
| // Argument here for kS128 does not matter as we should error out before |
| // hitting this case. |
| arguments[i] = |
| direct_handle(Smi::FromInt(static_cast<int>(i)), isolate); |
| break; |
| case kI64: |
| arguments[i] = BigInt::FromInt64(isolate, static_cast<int64_t>(i)); |
| break; |
| case kRefNull: |
| arguments[i] = isolate->factory()->null_value(); |
| break; |
| case kRef: |
| arguments[i] = isolate->factory()->undefined_value(); |
| break; |
| case kI8: |
| case kI16: |
| case kF16: |
| case kVoid: |
| case kTop: |
| case kBottom: |
| UNREACHABLE(); |
| } |
| } |
| |
| return arguments; |
| } |
| |
| int32_t CompileAndRunWasmModule(Isolate* isolate, const uint8_t* module_start, |
| const uint8_t* module_end) { |
| HandleScope scope(isolate); |
| ErrorThrower thrower(isolate, "CompileAndRunWasmModule"); |
| MaybeDirectHandle<WasmInstanceObject> instance = |
| CompileAndInstantiateForTesting( |
| isolate, &thrower, |
| base::VectorOf(module_start, module_end - module_start)); |
| if (instance.is_null()) { |
| return -1; |
| } |
| return CallWasmFunctionForTesting(isolate, instance.ToHandleChecked(), "main", |
| {}); |
| } |
| |
| MaybeDirectHandle<WasmExportedFunction> GetExportedFunction( |
| Isolate* isolate, DirectHandle<WasmInstanceObject> instance, |
| const char* name) { |
| DirectHandle<JSObject> exports_object; |
| DirectHandle<Name> exports = |
| isolate->factory()->InternalizeUtf8String("exports"); |
| exports_object = Cast<JSObject>( |
| JSObject::GetProperty(isolate, instance, exports).ToHandleChecked()); |
| |
| DirectHandle<Name> main_name = |
| isolate->factory()->NewStringFromAsciiChecked(name); |
| PropertyDescriptor desc; |
| Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor( |
| isolate, exports_object, main_name, &desc); |
| if (!property_found.FromMaybe(false)) return {}; |
| if (!IsJSFunction(*desc.value())) return {}; |
| |
| return Cast<WasmExportedFunction>(desc.value()); |
| } |
| |
| int32_t CallWasmFunctionForTesting( |
| Isolate* isolate, DirectHandle<WasmInstanceObject> instance, |
| const char* name, base::Vector<const DirectHandle<Object>> args, |
| std::unique_ptr<const char[]>* exception) { |
| DCHECK_IMPLIES(exception != nullptr, *exception == nullptr); |
| MaybeDirectHandle<WasmExportedFunction> maybe_export = |
| GetExportedFunction(isolate, instance, name); |
| DirectHandle<WasmExportedFunction> exported_function; |
| if (!maybe_export.ToHandle(&exported_function)) { |
| return -1; |
| } |
| |
| // Call the JS function. |
| DirectHandle<Object> undefined = isolate->factory()->undefined_value(); |
| MaybeDirectHandle<Object> retval = |
| Execution::Call(isolate, exported_function, undefined, args); |
| |
| // The result should be a number. |
| if (retval.is_null()) { |
| DCHECK(isolate->has_exception()); |
| if (exception && !isolate->is_execution_terminating()) { |
| DirectHandle<String> exception_string = Object::NoSideEffectsToString( |
| isolate, direct_handle(isolate->exception(), isolate)); |
| *exception = exception_string->ToCString(); |
| } |
| isolate->clear_internal_exception(); |
| return -1; |
| } |
| DirectHandle<Object> result = retval.ToHandleChecked(); |
| |
| // Multi-value returns, get the first return value (see InterpretWasmModule). |
| if (IsJSArray(*result)) { |
| auto receiver = Cast<JSReceiver>(result); |
| result = JSObject::GetElement(isolate, receiver, 0).ToHandleChecked(); |
| } |
| |
| if (IsSmi(*result)) { |
| return Smi::ToInt(*result); |
| } |
| if (IsHeapNumber(*result)) { |
| return static_cast<int32_t>(Cast<HeapNumber>(*result)->value()); |
| } |
| if (IsBigInt(*result)) { |
| return static_cast<int32_t>(Cast<BigInt>(*result)->AsInt64()); |
| } |
| return -1; |
| } |
| |
| } // namespace v8::internal::wasm::testing |