2016-09-12 12:26:37 +00:00
|
|
|
// 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.
|
|
|
|
|
2016-09-14 10:31:23 +00:00
|
|
|
#include "test/common/wasm/wasm-module-runner.h"
|
2016-09-12 12:26:37 +00:00
|
|
|
|
2019-05-22 07:55:37 +00:00
|
|
|
#include "src/execution/isolate.h"
|
2019-05-22 12:44:24 +00:00
|
|
|
#include "src/handles/handles.h"
|
2018-12-17 17:01:48 +00:00
|
|
|
#include "src/objects/heap-number-inl.h"
|
2019-05-23 08:51:46 +00:00
|
|
|
#include "src/objects/objects-inl.h"
|
2019-05-20 08:54:18 +00:00
|
|
|
#include "src/objects/property-descriptor.h"
|
2016-09-12 12:26:37 +00:00
|
|
|
#include "src/wasm/module-decoder.h"
|
2018-01-18 10:52:52 +00:00
|
|
|
#include "src/wasm/wasm-engine.h"
|
2016-09-17 01:30:09 +00:00
|
|
|
#include "src/wasm/wasm-js.h"
|
2016-09-12 12:26:37 +00:00
|
|
|
#include "src/wasm/wasm-module.h"
|
2016-11-11 11:12:31 +00:00
|
|
|
#include "src/wasm/wasm-objects.h"
|
2016-09-12 12:26:37 +00:00
|
|
|
#include "src/wasm/wasm-result.h"
|
2020-06-23 07:48:53 +00:00
|
|
|
#include "test/common/wasm/wasm-interpreter.h"
|
2016-09-12 12:26:37 +00:00
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace wasm {
|
|
|
|
namespace testing {
|
|
|
|
|
2019-04-17 17:55:36 +00:00
|
|
|
MaybeHandle<WasmModuleObject> CompileForTesting(Isolate* isolate,
|
|
|
|
ErrorThrower* thrower,
|
|
|
|
const ModuleWireBytes& bytes) {
|
2019-11-26 16:25:14 +00:00
|
|
|
auto enabled_features = WasmFeatures::FromIsolate(isolate);
|
2018-08-08 14:54:44 +00:00
|
|
|
MaybeHandle<WasmModuleObject> module = isolate->wasm_engine()->SyncCompile(
|
|
|
|
isolate, enabled_features, thrower, bytes);
|
2018-01-18 10:52:52 +00:00
|
|
|
DCHECK_EQ(thrower->error(), module.is_null());
|
2019-04-17 17:55:36 +00:00
|
|
|
return module;
|
|
|
|
}
|
2018-01-18 10:52:52 +00:00
|
|
|
|
2019-04-17 17:55:36 +00:00
|
|
|
MaybeHandle<WasmInstanceObject> CompileAndInstantiateForTesting(
|
|
|
|
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) {
|
|
|
|
MaybeHandle<WasmModuleObject> module =
|
|
|
|
CompileForTesting(isolate, thrower, bytes);
|
|
|
|
if (module.is_null()) return {};
|
2018-01-18 10:52:52 +00:00
|
|
|
return isolate->wasm_engine()->SyncInstantiate(
|
|
|
|
isolate, thrower, module.ToHandleChecked(), {}, {});
|
|
|
|
}
|
|
|
|
|
2020-08-11 10:05:04 +00:00
|
|
|
std::unique_ptr<WasmValue[]> MakeDefaultArguments(Isolate* isolate,
|
|
|
|
const FunctionSig* sig) {
|
|
|
|
size_t param_count = sig->parameter_count();
|
|
|
|
auto arguments = std::make_unique<WasmValue[]>(param_count);
|
2017-09-07 09:48:34 +00:00
|
|
|
|
|
|
|
// Fill the parameters up with default values.
|
2020-08-11 10:05:04 +00:00
|
|
|
for (size_t i = 0; i < param_count; ++i) {
|
|
|
|
switch (sig->GetParam(i).kind()) {
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kI32:
|
2017-09-07 09:48:34 +00:00
|
|
|
arguments[i] = WasmValue(int32_t{0});
|
|
|
|
break;
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kI64:
|
2017-09-07 09:48:34 +00:00
|
|
|
arguments[i] = WasmValue(int64_t{0});
|
|
|
|
break;
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kF32:
|
2017-09-07 09:48:34 +00:00
|
|
|
arguments[i] = WasmValue(0.0f);
|
|
|
|
break;
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kF64:
|
2017-09-07 09:48:34 +00:00
|
|
|
arguments[i] = WasmValue(0.0);
|
|
|
|
break;
|
2020-04-17 19:44:04 +00:00
|
|
|
case ValueType::kOptRef:
|
2019-09-04 10:19:30 +00:00
|
|
|
arguments[i] =
|
|
|
|
WasmValue(Handle<Object>::cast(isolate->factory()->null_value()));
|
|
|
|
break;
|
[wasm-gc] Change ValueType representation to account for new types
Motivation:
Changes to the typed function references and gc proposals solidified
the notion of heap type, clarified nullable vs. non-nullable reference
types, and introduced rtts, which contain an integer depth field in
addition to a heap type. This required us to overhaul our ValueType
representation, which results in extensive changes.
To keep this CL "small", we do not try to implement the binary encoding
as described in the proposals, but rather devise a simpler one of our
own (see below). Also, we do not try to implement additional
functionality for the new types.
Changes:
- Introduce HeapType. Move heap types from ValueType to HeapType.
- Introduce Nullability for reference types.
- Rework ValueType helper methods.
- Introduce rtts in ValueType with an integer depth field. Include depth
in the ValueType encoding.
- Make the constructor of ValueType private, instead expose static
functions which explicitly state what they create.
- Change every switch statement on ValueType::Kind. Sometimes, we need
nested switches.
- Introduce temporary constants in ValueTypeCode for nullable types,
use them for decoding.
- In WasmGlobalObject, split 'flags' into 'raw_type' and 'is_mutable'.
- Change IsSubtypeOfRef to IsSubtypeOfHeap and implement changes in
subtyping.
- kWasmFuncRef initializers are now non-nullable. Initializers are
only required to be subtypes of the declared global type.
- Change tests and fuzzers as needed.
Bug: v8:7748
Change-Id: If41f783bd4128443b07e94188cea7dd53ab0bfa5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2247657
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68408}
2020-06-18 11:24:07 +00:00
|
|
|
case ValueType::kRef:
|
|
|
|
case ValueType::kRtt:
|
2020-05-26 06:45:30 +00:00
|
|
|
case ValueType::kI8:
|
|
|
|
case ValueType::kI16:
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kStmt:
|
|
|
|
case ValueType::kBottom:
|
|
|
|
case ValueType::kS128:
|
2017-09-07 09:48:34 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-11 10:05:04 +00:00
|
|
|
return arguments;
|
2017-09-07 09:48:34 +00:00
|
|
|
}
|
|
|
|
|
2016-09-12 12:26:37 +00:00
|
|
|
int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
|
2017-06-09 18:37:54 +00:00
|
|
|
const byte* module_end) {
|
2016-09-12 12:26:37 +00:00
|
|
|
HandleScope scope(isolate);
|
2016-10-13 10:56:48 +00:00
|
|
|
ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
|
2018-01-18 10:52:52 +00:00
|
|
|
MaybeHandle<WasmInstanceObject> instance = CompileAndInstantiateForTesting(
|
|
|
|
isolate, &thrower, ModuleWireBytes(module_start, module_end));
|
2016-09-12 12:26:37 +00:00
|
|
|
if (instance.is_null()) {
|
|
|
|
return -1;
|
|
|
|
}
|
2020-08-11 08:48:31 +00:00
|
|
|
return CallWasmFunctionForTesting(isolate, instance.ToHandleChecked(), "main",
|
|
|
|
0, nullptr);
|
2017-06-09 18:37:54 +00:00
|
|
|
}
|
|
|
|
|
2018-11-20 14:39:29 +00:00
|
|
|
WasmInterpretationResult InterpretWasmModule(
|
|
|
|
Isolate* isolate, Handle<WasmInstanceObject> instance,
|
|
|
|
int32_t function_index, WasmValue* args) {
|
2017-04-06 10:57:24 +00:00
|
|
|
// Don't execute more than 16k steps.
|
|
|
|
constexpr int kMaxNumSteps = 16 * 1024;
|
|
|
|
|
2016-10-17 12:12:30 +00:00
|
|
|
Zone zone(isolate->allocator(), ZONE_NAME);
|
2016-09-12 12:26:37 +00:00
|
|
|
v8::internal::HandleScope scope(isolate);
|
2020-08-13 09:10:51 +00:00
|
|
|
const WasmFunction* func = &instance->module()->functions[function_index];
|
2016-09-12 12:26:37 +00:00
|
|
|
|
2020-06-08 20:47:45 +00:00
|
|
|
WasmInterpreter interpreter{
|
|
|
|
isolate, instance->module(),
|
|
|
|
ModuleWireBytes{instance->module_object().native_module()->wire_bytes()},
|
|
|
|
instance};
|
2020-08-13 09:10:51 +00:00
|
|
|
interpreter.InitFrame(func, args);
|
2020-06-08 20:47:45 +00:00
|
|
|
WasmInterpreter::State interpreter_result = interpreter.Run(kMaxNumSteps);
|
2017-06-12 11:13:15 +00:00
|
|
|
|
2020-08-11 10:05:04 +00:00
|
|
|
bool stack_overflow = isolate->has_pending_exception();
|
|
|
|
isolate->clear_pending_exception();
|
|
|
|
|
|
|
|
if (stack_overflow) return WasmInterpretationResult::Failed();
|
|
|
|
|
|
|
|
if (interpreter.state() == WasmInterpreter::TRAPPED) {
|
|
|
|
return WasmInterpretationResult::Trapped(
|
|
|
|
interpreter.PossibleNondeterminism());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (interpreter_result == WasmInterpreter::FINISHED) {
|
2020-08-13 09:10:51 +00:00
|
|
|
// Get the result as an {int32_t}. Keep this in sync with
|
|
|
|
// {CallWasmFunctionForTesting}, because fuzzers will compare the results.
|
|
|
|
int32_t result = -1;
|
|
|
|
if (func->sig->return_count() > 0) {
|
|
|
|
WasmValue return_value = interpreter.GetReturnValue();
|
|
|
|
switch (func->sig->GetReturn(0).kind()) {
|
|
|
|
case ValueType::kI32:
|
|
|
|
result = return_value.to<int32_t>();
|
|
|
|
break;
|
|
|
|
case ValueType::kI64:
|
|
|
|
result = static_cast<int32_t>(return_value.to<int64_t>());
|
|
|
|
break;
|
|
|
|
case ValueType::kF32:
|
|
|
|
result = static_cast<int32_t>(return_value.to<float>());
|
|
|
|
break;
|
|
|
|
case ValueType::kF64:
|
|
|
|
result = static_cast<int32_t>(return_value.to<double>());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-08-11 10:05:04 +00:00
|
|
|
return WasmInterpretationResult::Finished(
|
2020-08-13 09:10:51 +00:00
|
|
|
result, interpreter.PossibleNondeterminism());
|
2020-08-11 10:05:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The interpreter did not finish within the limited number of steps, so it
|
|
|
|
// might execute an infinite loop or infinite recursion. Return "failed"
|
|
|
|
// status in that case.
|
|
|
|
return WasmInterpretationResult::Failed();
|
2016-09-12 12:26:37 +00:00
|
|
|
}
|
|
|
|
|
2017-10-11 12:52:26 +00:00
|
|
|
MaybeHandle<WasmExportedFunction> GetExportedFunction(
|
|
|
|
Isolate* isolate, Handle<WasmInstanceObject> instance, const char* name) {
|
2016-09-12 12:26:37 +00:00
|
|
|
Handle<JSObject> exports_object;
|
2017-06-21 09:24:03 +00:00
|
|
|
Handle<Name> exports = isolate->factory()->InternalizeUtf8String("exports");
|
|
|
|
exports_object = Handle<JSObject>::cast(
|
2018-06-19 09:00:37 +00:00
|
|
|
JSObject::GetProperty(isolate, instance, exports).ToHandleChecked());
|
2017-06-21 09:24:03 +00:00
|
|
|
|
2016-09-12 12:26:37 +00:00
|
|
|
Handle<Name> main_name = isolate->factory()->NewStringFromAsciiChecked(name);
|
|
|
|
PropertyDescriptor desc;
|
|
|
|
Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor(
|
|
|
|
isolate, exports_object, main_name, &desc);
|
2017-09-07 09:48:34 +00:00
|
|
|
if (!property_found.FromMaybe(false)) return {};
|
2017-09-11 11:03:05 +00:00
|
|
|
if (!desc.value()->IsJSFunction()) return {};
|
2016-09-12 12:26:37 +00:00
|
|
|
|
2017-09-07 09:48:34 +00:00
|
|
|
return Handle<WasmExportedFunction>::cast(desc.value());
|
|
|
|
}
|
|
|
|
|
2017-10-11 12:52:26 +00:00
|
|
|
int32_t CallWasmFunctionForTesting(Isolate* isolate,
|
|
|
|
Handle<WasmInstanceObject> instance,
|
2020-08-11 08:48:31 +00:00
|
|
|
const char* name, int argc,
|
2020-08-14 18:31:09 +00:00
|
|
|
Handle<Object> argv[]) {
|
2017-09-07 09:48:34 +00:00
|
|
|
MaybeHandle<WasmExportedFunction> maybe_export =
|
|
|
|
GetExportedFunction(isolate, instance, name);
|
|
|
|
Handle<WasmExportedFunction> main_export;
|
|
|
|
if (!maybe_export.ToHandle(&main_export)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-09-12 12:26:37 +00:00
|
|
|
|
|
|
|
// Call the JS function.
|
|
|
|
Handle<Object> undefined = isolate->factory()->undefined_value();
|
|
|
|
MaybeHandle<Object> retval =
|
|
|
|
Execution::Call(isolate, main_export, undefined, argc, argv);
|
|
|
|
|
|
|
|
// The result should be a number.
|
|
|
|
if (retval.is_null()) {
|
[wasm] Use pending exceptions consistently
In our internal code, we should only use pending exceptions. They will
be converted to scheduled exceptions on the API boundary.
Hence, the ErrorThrower just sets a pending exception; it should never
have to think about scheduled exceptions. The new
ScheduledErrorThrower inherits from ErrorThrower and reschedules any
pending exceptions in its destructor (turning them into scheduled
exceptions).
In some situations, there might already be a scheduled exception, e.g.
when calling other API methods (v8::Value::Get). In this case, the
ErrorThrower should also not set another pending exception. For the
reasons mentioned above, this can only be handled in the
ScheduledErrorThrower, which is used the API methods.
This fixes one DCHECK failure and one TODO about scheduled exceptions
if no instance can be created, because the start function throws.
R=mtrofin@chromium.org, mstarzinger@chromium.org
BUG=v8:6232,chromium:736256
Change-Id: I4905be04c565df9495de18fb26adbb5c05d193d2
Reviewed-on: https://chromium-review.googlesource.com/548641
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Mircea Trofin <mtrofin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46314}
2017-06-29 08:16:29 +00:00
|
|
|
DCHECK(isolate->has_pending_exception());
|
|
|
|
isolate->clear_pending_exception();
|
2016-09-12 12:26:37 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
Handle<Object> result = retval.ToHandleChecked();
|
|
|
|
if (result->IsSmi()) {
|
2017-07-10 12:58:27 +00:00
|
|
|
return Smi::ToInt(*result);
|
2016-09-12 12:26:37 +00:00
|
|
|
}
|
|
|
|
if (result->IsHeapNumber()) {
|
|
|
|
return static_cast<int32_t>(HeapNumber::cast(*result).value());
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-09-17 01:30:09 +00:00
|
|
|
void SetupIsolateForWasmModule(Isolate* isolate) {
|
2017-09-04 12:15:18 +00:00
|
|
|
WasmJs::Install(isolate, true);
|
2016-09-17 01:30:09 +00:00
|
|
|
}
|
2017-06-12 11:13:15 +00:00
|
|
|
|
2016-09-12 12:26:37 +00:00
|
|
|
} // namespace testing
|
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|