Commit 15f5679e authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[no-wasm] Split off runtime-test-wasm.cc

This moves all wasm-related runtime functions from runtime-test.cc to
runtime-test-wasm.cc, which makes it easier to fully exclude them later.

R=ahaas@chromium.org

Bug: v8:11238
Change-Id: I3bc1c175b8db8837097308ed09aab69725dcf5aa
Cq-Include-Trybots: luci.v8.try:v8_linux64_no_wasm_compile_rel
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2739648
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73236}
parent c2a1d633
......@@ -3854,6 +3854,7 @@ v8_source_set("v8_base_without_compiler") {
"src/runtime/runtime-scopes.cc",
"src/runtime/runtime-strings.cc",
"src/runtime/runtime-symbol.cc",
"src/runtime/runtime-test-wasm.cc",
"src/runtime/runtime-test.cc",
"src/runtime/runtime-trace.cc",
"src/runtime/runtime-typedarray.cc",
......
// Copyright 2021 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 "src/base/memory.h"
#include "src/base/platform/mutex.h"
#include "src/execution/arguments-inl.h"
#include "src/execution/frames-inl.h"
#include "src/logging/counters.h"
#include "src/objects/smi.h"
#include "src/runtime/runtime-utils.h"
#include "src/trap-handler/trap-handler.h"
#include "src/utils/ostreams.h"
#include "src/wasm/memory-tracing.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-serialization.h"
namespace v8 {
namespace internal {
namespace {
struct WasmCompileControls {
uint32_t MaxWasmBufferSize = std::numeric_limits<uint32_t>::max();
bool AllowAnySizeForAsync = true;
};
using WasmCompileControlsMap = std::map<v8::Isolate*, WasmCompileControls>;
// We need per-isolate controls, because we sometimes run tests in multiple
// isolates concurrently. Methods need to hold the accompanying mutex on access.
// To avoid upsetting the static initializer count, we lazy initialize this.
DEFINE_LAZY_LEAKY_OBJECT_GETTER(WasmCompileControlsMap,
GetPerIsolateWasmControls)
base::LazyMutex g_PerIsolateWasmControlsMutex = LAZY_MUTEX_INITIALIZER;
bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value,
bool is_async) {
base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
return (is_async && ctrls.AllowAnySizeForAsync) ||
(value->IsArrayBuffer() && value.As<v8::ArrayBuffer>()->ByteLength() <=
ctrls.MaxWasmBufferSize) ||
(value->IsArrayBufferView() &&
value.As<v8::ArrayBufferView>()->ByteLength() <=
ctrls.MaxWasmBufferSize);
}
// Use the compile controls for instantiation, too
bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
v8::Local<v8::Value> module_or_bytes,
bool is_async) {
base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
if (is_async && ctrls.AllowAnySizeForAsync) return true;
if (!module_or_bytes->IsWasmModuleObject()) {
return IsWasmCompileAllowed(isolate, module_or_bytes, is_async);
}
v8::Local<v8::WasmModuleObject> module =
v8::Local<v8::WasmModuleObject>::Cast(module_or_bytes);
return static_cast<uint32_t>(
module->GetCompiledModule().GetWireBytesRef().size()) <=
ctrls.MaxWasmBufferSize;
}
v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate,
const char* message) {
return v8::Exception::RangeError(
v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(message))
.ToLocalChecked());
}
void ThrowRangeException(v8::Isolate* isolate, const char* message) {
isolate->ThrowException(NewRangeException(isolate, message));
}
bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (IsWasmCompileAllowed(args.GetIsolate(), args[0], false)) return false;
ThrowRangeException(args.GetIsolate(), "Sync compile not allowed");
return true;
}
bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], false)) return false;
ThrowRangeException(args.GetIsolate(), "Sync instantiate not allowed");
return true;
}
} // namespace
// Returns a callable object. The object returns the difference of its two
// parameters when it is called.
RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) {
HandleScope scope(isolate);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
CHECK_EQ(args.length(), 2);
CONVERT_ARG_HANDLE_CHECKED(Smi, block_size, 0);
CONVERT_BOOLEAN_ARG_CHECKED(allow_async, 1);
base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
WasmCompileControls& ctrl = (*GetPerIsolateWasmControls())[v8_isolate];
ctrl.AllowAnySizeForAsync = allow_async;
ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value());
v8_isolate->SetWasmModuleCallback(WasmModuleOverride);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) {
HandleScope scope(isolate);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
CHECK_EQ(args.length(), 0);
v8_isolate->SetWasmInstanceCallback(WasmInstanceOverride);
return ReadOnlyRoots(isolate).undefined_value();
}
namespace {
void PrintIndentation(int stack_size) {
const int max_display = 80;
if (stack_size <= max_display) {
PrintF("%4d:%*s", stack_size, stack_size, "");
} else {
PrintF("%4d:%*s", stack_size, max_display, "...");
}
}
int WasmStackSize(Isolate* isolate) {
// TODO(wasm): Fix this for mixed JS/Wasm stacks with both --trace and
// --trace-wasm.
int n = 0;
for (StackTraceFrameIterator it(isolate); !it.done(); it.Advance()) {
if (it.is_wasm()) n++;
}
return n;
}
} // namespace
RUNTIME_FUNCTION(Runtime_WasmTraceEnter) {
HandleScope shs(isolate);
DCHECK_EQ(0, args.length());
PrintIndentation(WasmStackSize(isolate));
// Find the caller wasm frame.
wasm::WasmCodeRefScope wasm_code_ref_scope;
StackTraceFrameIterator it(isolate);
DCHECK(!it.done());
DCHECK(it.is_wasm());
WasmFrame* frame = WasmFrame::cast(it.frame());
// Find the function name.
int func_index = frame->function_index();
const wasm::WasmModule* module = frame->wasm_instance().module();
wasm::ModuleWireBytes wire_bytes =
wasm::ModuleWireBytes(frame->native_module()->wire_bytes());
wasm::WireBytesRef name_ref =
module->lazily_generated_names.LookupFunctionName(
wire_bytes, func_index, VectorOf(module->export_table));
wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
wasm::WasmCode* code = frame->wasm_code();
PrintF(code->is_liftoff() ? "~" : "*");
if (name.empty()) {
PrintF("wasm-function[%d] {\n", func_index);
} else {
PrintF("wasm-function[%d] \"%.*s\" {\n", func_index, name.length(),
name.begin());
}
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTraceExit) {
HandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Smi, value_addr_smi, 0);
PrintIndentation(WasmStackSize(isolate));
PrintF("}");
// Find the caller wasm frame.
wasm::WasmCodeRefScope wasm_code_ref_scope;
StackTraceFrameIterator it(isolate);
DCHECK(!it.done());
DCHECK(it.is_wasm());
WasmFrame* frame = WasmFrame::cast(it.frame());
int func_index = frame->function_index();
const wasm::FunctionSig* sig =
frame->wasm_instance().module()->functions[func_index].sig;
size_t num_returns = sig->return_count();
if (num_returns == 1) {
wasm::ValueType return_type = sig->GetReturn(0);
switch (return_type.kind()) {
case wasm::kI32: {
int32_t value = base::ReadUnalignedValue<int32_t>(value_addr_smi.ptr());
PrintF(" -> %d\n", value);
break;
}
case wasm::kI64: {
int64_t value = base::ReadUnalignedValue<int64_t>(value_addr_smi.ptr());
PrintF(" -> %" PRId64 "\n", value);
break;
}
case wasm::kF32: {
float_t value = base::ReadUnalignedValue<float_t>(value_addr_smi.ptr());
PrintF(" -> %f\n", value);
break;
}
case wasm::kF64: {
double_t value =
base::ReadUnalignedValue<double_t>(value_addr_smi.ptr());
PrintF(" -> %f\n", value);
break;
}
default:
PrintF(" -> Unsupported type\n");
break;
}
} else {
// TODO(wasm) Handle multiple return values.
PrintF("\n");
}
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_IsAsmWasmCode) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(JSFunction, function, 0);
if (!function.shared().HasAsmWasmData()) {
return ReadOnlyRoots(isolate).false_value();
}
if (function.shared().HasBuiltinId() &&
function.shared().builtin_id() == Builtins::kInstantiateAsmJs) {
// Hasn't been compiled yet.
return ReadOnlyRoots(isolate).false_value();
}
return ReadOnlyRoots(isolate).true_value();
}
namespace {
bool DisallowWasmCodegenFromStringsCallback(v8::Local<v8::Context> context,
v8::Local<v8::String> source) {
return false;
}
} // namespace
RUNTIME_FUNCTION(Runtime_DisallowWasmCodegen) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8_isolate->SetAllowWasmCodeGenerationCallback(
flag ? DisallowWasmCodegenFromStringsCallback : nullptr);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_IsWasmCode) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(JSFunction, function, 0);
bool is_js_to_wasm =
function.code().kind() == CodeKind::JS_TO_WASM_FUNCTION ||
(function.code().is_builtin() &&
function.code().builtin_index() == Builtins::kGenericJSToWasmWrapper);
return isolate->heap()->ToBoolean(is_js_to_wasm);
}
RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) {
DisallowGarbageCollection no_gc;
DCHECK_EQ(0, args.length());
return isolate->heap()->ToBoolean(trap_handler::IsTrapHandlerEnabled());
}
RUNTIME_FUNCTION(Runtime_IsThreadInWasm) {
DisallowGarbageCollection no_gc;
DCHECK_EQ(0, args.length());
return isolate->heap()->ToBoolean(trap_handler::IsThreadInWasm());
}
RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
size_t trap_count = trap_handler::GetRecoveredTrapCount();
return *isolate->factory()->NewNumberFromSize(trap_count);
}
RUNTIME_FUNCTION(Runtime_GetWasmExceptionId) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmExceptionPackage, exception, 0);
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 1);
Handle<Object> tag =
WasmExceptionPackage::GetExceptionTag(isolate, exception);
CHECK(tag->IsWasmExceptionTag());
Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate);
for (int index = 0; index < exceptions_table->length(); ++index) {
if (exceptions_table->get(index) == *tag) return Smi::FromInt(index);
}
UNREACHABLE();
}
RUNTIME_FUNCTION(Runtime_GetWasmExceptionValues) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmExceptionPackage, exception, 0);
Handle<Object> values_obj =
WasmExceptionPackage::GetExceptionValues(isolate, exception);
CHECK(values_obj->IsFixedArray()); // Only called with correct input.
Handle<FixedArray> values = Handle<FixedArray>::cast(values_obj);
return *isolate->factory()->NewJSArrayWithElements(values);
}
// Wait until the given module is fully tiered up, then serialize it into an
// array buffer.
RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
wasm::NativeModule* native_module = module_obj->native_module();
native_module->compilation_state()->WaitForTopTierFinished();
DCHECK(!native_module->compilation_state()->failed());
wasm::WasmSerializer wasm_serializer(native_module);
size_t byte_length = wasm_serializer.GetSerializedNativeModuleSize();
Handle<JSArrayBuffer> array_buffer =
isolate->factory()
->NewJSArrayBufferAndBackingStore(byte_length,
InitializedFlag::kUninitialized)
.ToHandleChecked();
CHECK(wasm_serializer.SerializeNativeModule(
{static_cast<uint8_t*>(array_buffer->backing_store()), byte_length}));
return *array_buffer;
}
// Take an array buffer and attempt to reconstruct a compiled wasm module.
// Return undefined if unsuccessful.
RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, wire_bytes, 1);
CHECK(!buffer->was_detached());
CHECK(!wire_bytes->WasDetached());
Handle<JSArrayBuffer> wire_bytes_buffer = wire_bytes->GetBuffer();
Vector<const uint8_t> wire_bytes_vec{
reinterpret_cast<const uint8_t*>(wire_bytes_buffer->backing_store()) +
wire_bytes->byte_offset(),
wire_bytes->byte_length()};
Vector<uint8_t> buffer_vec{
reinterpret_cast<uint8_t*>(buffer->backing_store()),
buffer->byte_length()};
// Note that {wasm::DeserializeNativeModule} will allocate. We assume the
// JSArrayBuffer backing store doesn't get relocated.
MaybeHandle<WasmModuleObject> maybe_module_object =
wasm::DeserializeNativeModule(isolate, buffer_vec, wire_bytes_vec, {});
Handle<WasmModuleObject> module_object;
if (!maybe_module_object.ToHandle(&module_object)) {
return ReadOnlyRoots(isolate).undefined_value();
}
return *module_object;
}
RUNTIME_FUNCTION(Runtime_WasmGetNumberOfInstances) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
int instance_count = 0;
WeakArrayList weak_instance_list =
module_obj->script().wasm_weak_instance_list();
for (int i = 0; i < weak_instance_list.length(); ++i) {
if (weak_instance_list.Get(i)->IsWeak()) instance_count++;
}
return Smi::FromInt(instance_count);
}
RUNTIME_FUNCTION(Runtime_WasmNumCodeSpaces) {
DCHECK_EQ(1, args.length());
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSObject, argument, 0);
Handle<WasmModuleObject> module;
if (argument->IsWasmInstanceObject()) {
module = handle(Handle<WasmInstanceObject>::cast(argument)->module_object(),
isolate);
} else if (argument->IsWasmModuleObject()) {
module = Handle<WasmModuleObject>::cast(argument);
}
size_t num_spaces =
module->native_module()->GetNumberOfCodeSpacesForTesting();
return *isolate->factory()->NewNumberFromSize(num_spaces);
}
RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Smi, info_addr, 0);
wasm::MemoryTracingInfo* info =
reinterpret_cast<wasm::MemoryTracingInfo*>(info_addr.ptr());
// Find the caller wasm frame.
wasm::WasmCodeRefScope wasm_code_ref_scope;
StackTraceFrameIterator it(isolate);
DCHECK(!it.done());
DCHECK(it.is_wasm());
WasmFrame* frame = WasmFrame::cast(it.frame());
uint8_t* mem_start = reinterpret_cast<uint8_t*>(
frame->wasm_instance().memory_object().array_buffer().backing_store());
int func_index = frame->function_index();
int pos = frame->position();
// TODO(titzer): eliminate dependency on WasmModule definition here.
int func_start =
frame->wasm_instance().module()->functions[func_index].code.offset();
wasm::ExecutionTier tier = frame->wasm_code()->is_liftoff()
? wasm::ExecutionTier::kLiftoff
: wasm::ExecutionTier::kTurbofan;
wasm::TraceMemoryOperation(tier, info, func_index, pos - func_start,
mem_start);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierUpFunction) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
CONVERT_SMI_ARG_CHECKED(function_index, 1);
auto* native_module = instance->module_object().native_module();
isolate->wasm_engine()->CompileFunction(
isolate, native_module, function_index, wasm::ExecutionTier::kTurbofan);
CHECK(!native_module->compilation_state()->failed());
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierDown) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
isolate->wasm_engine()->TierDownAllModulesPerIsolate(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierUp) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
isolate->wasm_engine()->TierUpAllModulesPerIsolate(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
Handle<WasmExportedFunction> exp_fun =
Handle<WasmExportedFunction>::cast(function);
wasm::NativeModule* native_module =
exp_fun->instance().module_object().native_module();
uint32_t func_index = exp_fun->function_index();
wasm::WasmCodeRefScope code_ref_scope;
wasm::WasmCode* code = native_module->GetCode(func_index);
return isolate->heap()->ToBoolean(code && code->is_liftoff());
}
RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) {
DCHECK_EQ(1, args.length());
DisallowGarbageCollection no_gc;
CONVERT_ARG_CHECKED(WasmInstanceObject, instance, 0);
instance.module_object().native_module()->set_lazy_compile_frozen(true);
return ReadOnlyRoots(isolate).undefined_value();
}
} // namespace internal
} // namespace v8
......@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <sstream>
#include "src/api/api-inl.h"
#include "src/base/platform/mutex.h"
#include "src/codegen/assembler-inl.h"
......@@ -30,88 +27,15 @@
#include "src/regexp/regexp.h"
#include "src/runtime/runtime-utils.h"
#include "src/snapshot/snapshot.h"
#include "src/trap-handler/trap-handler.h"
#include "src/utils/ostreams.h"
#include "src/wasm/memory-tracing.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-code-manager.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-serialization.h"
#endif // V8_ENABLE_WEBASSEMBLY
namespace v8 {
namespace internal {
namespace {
struct WasmCompileControls {
uint32_t MaxWasmBufferSize = std::numeric_limits<uint32_t>::max();
bool AllowAnySizeForAsync = true;
};
using WasmCompileControlsMap = std::map<v8::Isolate*, WasmCompileControls>;
// We need per-isolate controls, because we sometimes run tests in multiple
// isolates concurrently. Methods need to hold the accompanying mutex on access.
// To avoid upsetting the static initializer count, we lazy initialize this.
DEFINE_LAZY_LEAKY_OBJECT_GETTER(WasmCompileControlsMap,
GetPerIsolateWasmControls)
base::LazyMutex g_PerIsolateWasmControlsMutex = LAZY_MUTEX_INITIALIZER;
bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value,
bool is_async) {
base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
return (is_async && ctrls.AllowAnySizeForAsync) ||
(value->IsArrayBuffer() && value.As<v8::ArrayBuffer>()->ByteLength() <=
ctrls.MaxWasmBufferSize) ||
(value->IsArrayBufferView() &&
value.As<v8::ArrayBufferView>()->ByteLength() <=
ctrls.MaxWasmBufferSize);
}
// Use the compile controls for instantiation, too
bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
v8::Local<v8::Value> module_or_bytes,
bool is_async) {
base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
if (is_async && ctrls.AllowAnySizeForAsync) return true;
if (!module_or_bytes->IsWasmModuleObject()) {
return IsWasmCompileAllowed(isolate, module_or_bytes, is_async);
}
v8::Local<v8::WasmModuleObject> module =
v8::Local<v8::WasmModuleObject>::Cast(module_or_bytes);
return static_cast<uint32_t>(
module->GetCompiledModule().GetWireBytesRef().size()) <=
ctrls.MaxWasmBufferSize;
}
v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate,
const char* message) {
return v8::Exception::RangeError(
v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(message))
.ToLocalChecked());
}
void ThrowRangeException(v8::Isolate* isolate, const char* message) {
isolate->ThrowException(NewRangeException(isolate, message));
}
bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (IsWasmCompileAllowed(args.GetIsolate(), args[0], false)) return false;
ThrowRangeException(args.GetIsolate(), "Sync compile not allowed");
return true;
}
bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], false)) return false;
ThrowRangeException(args.GetIsolate(), "Sync instantiate not allowed");
return true;
}
V8_WARN_UNUSED_RESULT Object CrashUnlessFuzzing(Isolate* isolate) {
CHECK(FLAG_fuzzing);
return ReadOnlyRoots(isolate).undefined_value();
......@@ -708,28 +632,6 @@ RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) {
HandleScope scope(isolate);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
CHECK_EQ(args.length(), 2);
CONVERT_ARG_HANDLE_CHECKED(Smi, block_size, 0);
CONVERT_BOOLEAN_ARG_CHECKED(allow_async, 1);
base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
WasmCompileControls& ctrl = (*GetPerIsolateWasmControls())[v8_isolate];
ctrl.AllowAnySizeForAsync = allow_async;
ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value());
v8_isolate->SetWasmModuleCallback(WasmModuleOverride);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) {
HandleScope scope(isolate);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
CHECK_EQ(args.length(), 0);
v8_isolate->SetWasmInstanceCallback(WasmInstanceOverride);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
......@@ -1045,109 +947,6 @@ RUNTIME_FUNCTION(Runtime_TraceExit) {
return obj; // return TOS
}
namespace {
int WasmStackSize(Isolate* isolate) {
// TODO(wasm): Fix this for mixed JS/Wasm stacks with both --trace and
// --trace-wasm.
int n = 0;
for (StackTraceFrameIterator it(isolate); !it.done(); it.Advance()) {
if (it.is_wasm()) n++;
}
return n;
}
} // namespace
RUNTIME_FUNCTION(Runtime_WasmTraceEnter) {
HandleScope shs(isolate);
DCHECK_EQ(0, args.length());
PrintIndentation(WasmStackSize(isolate));
// Find the caller wasm frame.
wasm::WasmCodeRefScope wasm_code_ref_scope;
StackTraceFrameIterator it(isolate);
DCHECK(!it.done());
DCHECK(it.is_wasm());
WasmFrame* frame = WasmFrame::cast(it.frame());
// Find the function name.
int func_index = frame->function_index();
const wasm::WasmModule* module = frame->wasm_instance().module();
wasm::ModuleWireBytes wire_bytes =
wasm::ModuleWireBytes(frame->native_module()->wire_bytes());
wasm::WireBytesRef name_ref =
module->lazily_generated_names.LookupFunctionName(
wire_bytes, func_index, VectorOf(module->export_table));
wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
wasm::WasmCode* code = frame->wasm_code();
PrintF(code->is_liftoff() ? "~" : "*");
if (name.empty()) {
PrintF("wasm-function[%d] {\n", func_index);
} else {
PrintF("wasm-function[%d] \"%.*s\" {\n", func_index, name.length(),
name.begin());
}
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTraceExit) {
HandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Smi, value_addr_smi, 0);
PrintIndentation(WasmStackSize(isolate));
PrintF("}");
// Find the caller wasm frame.
wasm::WasmCodeRefScope wasm_code_ref_scope;
StackTraceFrameIterator it(isolate);
DCHECK(!it.done());
DCHECK(it.is_wasm());
WasmFrame* frame = WasmFrame::cast(it.frame());
int func_index = frame->function_index();
const wasm::FunctionSig* sig =
frame->wasm_instance().module()->functions[func_index].sig;
size_t num_returns = sig->return_count();
if (num_returns == 1) {
wasm::ValueType return_type = sig->GetReturn(0);
switch (return_type.kind()) {
case wasm::kI32: {
int32_t value = ReadUnalignedValue<int32_t>(value_addr_smi.ptr());
PrintF(" -> %d\n", value);
break;
}
case wasm::kI64: {
int64_t value = ReadUnalignedValue<int64_t>(value_addr_smi.ptr());
PrintF(" -> %" PRId64 "\n", value);
break;
}
case wasm::kF32: {
float_t value = ReadUnalignedValue<float_t>(value_addr_smi.ptr());
PrintF(" -> %f\n", value);
break;
}
case wasm::kF64: {
double_t value = ReadUnalignedValue<double_t>(value_addr_smi.ptr());
PrintF(" -> %f\n", value);
break;
}
default:
PrintF(" -> Unsupported type\n");
break;
}
} else {
// TODO(wasm) Handle multiple return values.
PrintF("\n");
}
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_HaveSameMap) {
SealHandleScope shs(isolate);
DCHECK_EQ(2, args.length());
......@@ -1183,21 +982,6 @@ RUNTIME_FUNCTION(Runtime_InYoungGeneration) {
return isolate->heap()->ToBoolean(ObjectInYoungGeneration(obj));
}
RUNTIME_FUNCTION(Runtime_IsAsmWasmCode) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(JSFunction, function, 0);
if (!function.shared().HasAsmWasmData()) {
return ReadOnlyRoots(isolate).false_value();
}
if (function.shared().HasBuiltinId() &&
function.shared().builtin_id() == Builtins::kInstantiateAsmJs) {
// Hasn't been compiled yet.
return ReadOnlyRoots(isolate).false_value();
}
return ReadOnlyRoots(isolate).true_value();
}
namespace {
v8::ModifyCodeGenerationFromStringsResult DisallowCodegenFromStringsCallback(
......@@ -1206,11 +990,6 @@ v8::ModifyCodeGenerationFromStringsResult DisallowCodegenFromStringsCallback(
return {false, {}};
}
bool DisallowWasmCodegenFromStringsCallback(v8::Local<v8::Context> context,
v8::Local<v8::String> source) {
return false;
}
} // namespace
RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings) {
......@@ -1223,72 +1002,6 @@ RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_DisallowWasmCodegen) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8_isolate->SetAllowWasmCodeGenerationCallback(
flag ? DisallowWasmCodegenFromStringsCallback : nullptr);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_IsWasmCode) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(JSFunction, function, 0);
bool is_js_to_wasm =
function.code().kind() == CodeKind::JS_TO_WASM_FUNCTION ||
(function.code().is_builtin() &&
function.code().builtin_index() == Builtins::kGenericJSToWasmWrapper);
return isolate->heap()->ToBoolean(is_js_to_wasm);
}
RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) {
DisallowGarbageCollection no_gc;
DCHECK_EQ(0, args.length());
return isolate->heap()->ToBoolean(trap_handler::IsTrapHandlerEnabled());
}
RUNTIME_FUNCTION(Runtime_IsThreadInWasm) {
DisallowGarbageCollection no_gc;
DCHECK_EQ(0, args.length());
return isolate->heap()->ToBoolean(trap_handler::IsThreadInWasm());
}
RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
size_t trap_count = trap_handler::GetRecoveredTrapCount();
return *isolate->factory()->NewNumberFromSize(trap_count);
}
RUNTIME_FUNCTION(Runtime_GetWasmExceptionId) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmExceptionPackage, exception, 0);
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 1);
Handle<Object> tag =
WasmExceptionPackage::GetExceptionTag(isolate, exception);
CHECK(tag->IsWasmExceptionTag());
Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate);
for (int index = 0; index < exceptions_table->length(); ++index) {
if (exceptions_table->get(index) == *tag) return Smi::FromInt(index);
}
UNREACHABLE();
}
RUNTIME_FUNCTION(Runtime_GetWasmExceptionValues) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmExceptionPackage, exception, 0);
Handle<Object> values_obj =
WasmExceptionPackage::GetExceptionValues(isolate, exception);
CHECK(values_obj->IsFixedArray()); // Only called with correct input.
Handle<FixedArray> values = Handle<FixedArray>::cast(values_obj);
return *isolate->factory()->NewJSArrayWithElements(values);
}
RUNTIME_FUNCTION(Runtime_RegexpHasBytecode) {
SealHandleScope shs(isolate);
DCHECK_EQ(2, args.length());
......@@ -1455,61 +1168,6 @@ RUNTIME_FUNCTION(Runtime_SerializeDeserializeNow) {
return ReadOnlyRoots(isolate).undefined_value();
}
// Wait until the given module is fully tiered up, then serialize it into an
// array buffer.
RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
wasm::NativeModule* native_module = module_obj->native_module();
native_module->compilation_state()->WaitForTopTierFinished();
DCHECK(!native_module->compilation_state()->failed());
wasm::WasmSerializer wasm_serializer(native_module);
size_t byte_length = wasm_serializer.GetSerializedNativeModuleSize();
Handle<JSArrayBuffer> array_buffer =
isolate->factory()
->NewJSArrayBufferAndBackingStore(byte_length,
InitializedFlag::kUninitialized)
.ToHandleChecked();
CHECK(wasm_serializer.SerializeNativeModule(
{static_cast<uint8_t*>(array_buffer->backing_store()), byte_length}));
return *array_buffer;
}
// Take an array buffer and attempt to reconstruct a compiled wasm module.
// Return undefined if unsuccessful.
RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, wire_bytes, 1);
CHECK(!buffer->was_detached());
CHECK(!wire_bytes->WasDetached());
Handle<JSArrayBuffer> wire_bytes_buffer = wire_bytes->GetBuffer();
Vector<const uint8_t> wire_bytes_vec{
reinterpret_cast<const uint8_t*>(wire_bytes_buffer->backing_store()) +
wire_bytes->byte_offset(),
wire_bytes->byte_length()};
Vector<uint8_t> buffer_vec{
reinterpret_cast<uint8_t*>(buffer->backing_store()),
buffer->byte_length()};
// Note that {wasm::DeserializeNativeModule} will allocate. We assume the
// JSArrayBuffer backing store doesn't get relocated.
MaybeHandle<WasmModuleObject> maybe_module_object =
wasm::DeserializeNativeModule(isolate, buffer_vec, wire_bytes_vec, {});
Handle<WasmModuleObject> module_object;
if (!maybe_module_object.ToHandle(&module_object)) {
return ReadOnlyRoots(isolate).undefined_value();
}
return *module_object;
}
RUNTIME_FUNCTION(Runtime_HeapObjectVerify) {
HandleScope shs(isolate);
DCHECK_EQ(1, args.length());
......@@ -1539,106 +1197,6 @@ RUNTIME_FUNCTION(Runtime_TypedArrayMaxLength) {
return *isolate->factory()->NewNumber(JSTypedArray::kMaxLength);
}
RUNTIME_FUNCTION(Runtime_WasmGetNumberOfInstances) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
int instance_count = 0;
WeakArrayList weak_instance_list =
module_obj->script().wasm_weak_instance_list();
for (int i = 0; i < weak_instance_list.length(); ++i) {
if (weak_instance_list.Get(i)->IsWeak()) instance_count++;
}
return Smi::FromInt(instance_count);
}
RUNTIME_FUNCTION(Runtime_WasmNumCodeSpaces) {
DCHECK_EQ(1, args.length());
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSObject, argument, 0);
Handle<WasmModuleObject> module;
if (argument->IsWasmInstanceObject()) {
module = handle(Handle<WasmInstanceObject>::cast(argument)->module_object(),
isolate);
} else if (argument->IsWasmModuleObject()) {
module = Handle<WasmModuleObject>::cast(argument);
}
size_t num_spaces =
module->native_module()->GetNumberOfCodeSpacesForTesting();
return *isolate->factory()->NewNumberFromSize(num_spaces);
}
RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Smi, info_addr, 0);
wasm::MemoryTracingInfo* info =
reinterpret_cast<wasm::MemoryTracingInfo*>(info_addr.ptr());
// Find the caller wasm frame.
wasm::WasmCodeRefScope wasm_code_ref_scope;
StackTraceFrameIterator it(isolate);
DCHECK(!it.done());
DCHECK(it.is_wasm());
WasmFrame* frame = WasmFrame::cast(it.frame());
uint8_t* mem_start = reinterpret_cast<uint8_t*>(
frame->wasm_instance().memory_object().array_buffer().backing_store());
int func_index = frame->function_index();
int pos = frame->position();
// TODO(titzer): eliminate dependency on WasmModule definition here.
int func_start =
frame->wasm_instance().module()->functions[func_index].code.offset();
wasm::ExecutionTier tier = frame->wasm_code()->is_liftoff()
? wasm::ExecutionTier::kLiftoff
: wasm::ExecutionTier::kTurbofan;
wasm::TraceMemoryOperation(tier, info, func_index, pos - func_start,
mem_start);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierUpFunction) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
CONVERT_SMI_ARG_CHECKED(function_index, 1);
auto* native_module = instance->module_object().native_module();
isolate->wasm_engine()->CompileFunction(
isolate, native_module, function_index, wasm::ExecutionTier::kTurbofan);
CHECK(!native_module->compilation_state()->failed());
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierDown) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
isolate->wasm_engine()->TierDownAllModulesPerIsolate(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmTierUp) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
isolate->wasm_engine()->TierUpAllModulesPerIsolate(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
Handle<WasmExportedFunction> exp_fun =
Handle<WasmExportedFunction>::cast(function);
wasm::NativeModule* native_module =
exp_fun->instance().module_object().native_module();
uint32_t func_index = exp_fun->function_index();
wasm::WasmCodeRefScope code_ref_scope;
wasm::WasmCode* code = native_module->GetCode(func_index);
return isolate->heap()->ToBoolean(code && code->is_liftoff());
}
RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......@@ -1649,15 +1207,6 @@ RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) {
DCHECK_EQ(1, args.length());
DisallowGarbageCollection no_gc;
CONVERT_ARG_CHECKED(WasmInstanceObject, instance, 0);
instance.module_object().native_module()->set_lazy_compile_frozen(true);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_TurbofanStaticAssert) {
SealHandleScope shs(isolate);
// Always lowered to StaticAssert node in Turbofan, so we never get here in
......@@ -1711,7 +1260,9 @@ RUNTIME_FUNCTION(Runtime_EnableCodeLoggingForTesting) {
bool is_listening_to_code_events() final { return true; }
};
static base::LeakyObject<NoopListener> noop_listener;
#if V8_ENABLE_WEBASSEMBLY
isolate->wasm_engine()->EnableCodeLogging(isolate);
#endif // V8_ENABLE_WEBASSEMBLY
isolate->code_event_dispatcher()->AddListener(noop_listener.get());
return ReadOnlyRoots(isolate).undefined_value();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment