[wasm] Add WasmFeatures to enable/detect features
This CL introduces a set of configuration options implemented as a struct of booleans that together comprise the set of enabled or detected features. The configuration options replace command-line flags that were checked deep in the implementation. As such, it is necessary to plumb them through multiple levels of abstraction. R=ahaas@chromium.org CC=mstarzinger@chromium.org BUG=chromium:868844 Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng Change-Id: I1b82f5826e4fd263f68e8cafcd923bac5818a637 Reviewed-on: https://chromium-review.googlesource.com/1163670 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#55018}
This commit is contained in:
parent
3b2b858f11
commit
6aa2a25313
3
BUILD.gn
3
BUILD.gn
@ -2508,6 +2508,9 @@ v8_source_set("v8_base") {
|
|||||||
"src/wasm/wasm-engine.h",
|
"src/wasm/wasm-engine.h",
|
||||||
"src/wasm/wasm-external-refs.cc",
|
"src/wasm/wasm-external-refs.cc",
|
||||||
"src/wasm/wasm-external-refs.h",
|
"src/wasm/wasm-external-refs.h",
|
||||||
|
"src/wasm/wasm-feature-flags.h",
|
||||||
|
"src/wasm/wasm-features.cc",
|
||||||
|
"src/wasm/wasm-features.h",
|
||||||
"src/wasm/wasm-interpreter.cc",
|
"src/wasm/wasm-interpreter.cc",
|
||||||
"src/wasm/wasm-interpreter.h",
|
"src/wasm/wasm-interpreter.h",
|
||||||
"src/wasm/wasm-js.cc",
|
"src/wasm/wasm-js.cc",
|
||||||
|
@ -7738,9 +7738,11 @@ MaybeLocal<WasmCompiledModule> WasmCompiledModule::Compile(Isolate* isolate,
|
|||||||
if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
|
if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
|
||||||
return MaybeLocal<WasmCompiledModule>();
|
return MaybeLocal<WasmCompiledModule>();
|
||||||
}
|
}
|
||||||
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
i::MaybeHandle<i::JSObject> maybe_compiled =
|
i::MaybeHandle<i::JSObject> maybe_compiled =
|
||||||
i_isolate->wasm_engine()->SyncCompile(
|
i_isolate->wasm_engine()->SyncCompile(
|
||||||
i_isolate, &thrower, i::wasm::ModuleWireBytes(start, start + length));
|
i_isolate, enabled_features, &thrower,
|
||||||
|
i::wasm::ModuleWireBytes(start, start + length));
|
||||||
if (maybe_compiled.is_null()) return MaybeLocal<WasmCompiledModule>();
|
if (maybe_compiled.is_null()) return MaybeLocal<WasmCompiledModule>();
|
||||||
return Local<WasmCompiledModule>::Cast(
|
return Local<WasmCompiledModule>::Cast(
|
||||||
Utils::ToLocal(maybe_compiled.ToHandleChecked()));
|
Utils::ToLocal(maybe_compiled.ToHandleChecked()));
|
||||||
@ -7787,8 +7789,9 @@ WasmModuleObjectBuilderStreaming::WasmModuleObjectBuilderStreaming(
|
|||||||
promise_.Reset(isolate, resolver->GetPromise());
|
promise_.Reset(isolate, resolver->GetPromise());
|
||||||
|
|
||||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||||
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation(
|
streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation(
|
||||||
i_isolate, handle(i_isolate->context(), i_isolate),
|
i_isolate, enabled_features, handle(i_isolate->context(), i_isolate),
|
||||||
base::make_unique<AsyncCompilationResolver>(isolate, GetPromise()));
|
base::make_unique<AsyncCompilationResolver>(isolate, GetPromise()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2889,7 +2889,6 @@ void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type,
|
|||||||
Node** offset_node) {
|
Node** offset_node) {
|
||||||
DCHECK_NOT_NULL(instance_node_);
|
DCHECK_NOT_NULL(instance_node_);
|
||||||
if (global.mutability && global.imported) {
|
if (global.mutability && global.imported) {
|
||||||
DCHECK(FLAG_experimental_wasm_mut_global);
|
|
||||||
if (imported_mutable_globals_ == nullptr) {
|
if (imported_mutable_globals_ == nullptr) {
|
||||||
// Load imported_mutable_globals_ from the instance object at runtime.
|
// Load imported_mutable_globals_ from the instance object at runtime.
|
||||||
imported_mutable_globals_ = graph()->NewNode(
|
imported_mutable_globals_ = graph()->NewNode(
|
||||||
@ -5035,9 +5034,14 @@ SourcePositionTable* TurbofanWasmCompilationUnit::BuildGraphForWasmFunction(
|
|||||||
new (mcgraph->zone()) SourcePositionTable(mcgraph->graph());
|
new (mcgraph->zone()) SourcePositionTable(mcgraph->graph());
|
||||||
WasmGraphBuilder builder(wasm_unit_->env_, mcgraph->zone(), mcgraph,
|
WasmGraphBuilder builder(wasm_unit_->env_, mcgraph->zone(), mcgraph,
|
||||||
wasm_unit_->func_body_.sig, source_position_table);
|
wasm_unit_->func_body_.sig, source_position_table);
|
||||||
graph_construction_result_ =
|
// TODO(titzer): gather detected features into a per-module location
|
||||||
wasm::BuildTFGraph(wasm_unit_->wasm_engine_->allocator(), &builder,
|
// in order to increment an embedder feature use count.
|
||||||
wasm_unit_->func_body_, node_origins);
|
wasm::WasmFeatures unused_detected_features;
|
||||||
|
graph_construction_result_ = wasm::BuildTFGraph(
|
||||||
|
wasm_unit_->wasm_engine_->allocator(),
|
||||||
|
wasm_unit_->native_module_->enabled_features(), wasm_unit_->env_->module,
|
||||||
|
&builder, &unused_detected_features, wasm_unit_->func_body_,
|
||||||
|
node_origins);
|
||||||
if (graph_construction_result_.failed()) {
|
if (graph_construction_result_.failed()) {
|
||||||
if (FLAG_trace_wasm_compiler) {
|
if (FLAG_trace_wasm_compiler) {
|
||||||
StdoutStream{} << "Compilation failed: "
|
StdoutStream{} << "Compilation failed: "
|
||||||
|
@ -596,22 +596,18 @@ DEFINE_DEBUG_BOOL(dump_wasm_module, false, "dump wasm module bytes")
|
|||||||
DEFINE_STRING(dump_wasm_module_path, nullptr,
|
DEFINE_STRING(dump_wasm_module_path, nullptr,
|
||||||
"directory to dump wasm modules to")
|
"directory to dump wasm modules to")
|
||||||
|
|
||||||
DEFINE_BOOL(experimental_wasm_simd, false,
|
// Declare command-line flags for WASM features. Warning: avoid using these
|
||||||
"enable prototype simd opcodes for wasm")
|
// flags directly in the implementation. Instead accept wasm::WasmFeatures
|
||||||
DEFINE_BOOL(experimental_wasm_eh, false,
|
// for configurability.
|
||||||
"enable prototype exception handling opcodes for wasm")
|
#include "src/wasm/wasm-feature-flags.h"
|
||||||
DEFINE_BOOL(experimental_wasm_mv, false,
|
|
||||||
"enable prototype multi-value support for wasm")
|
#define SPACE
|
||||||
DEFINE_BOOL(experimental_wasm_threads, false,
|
#define DECL_WASM_FLAG(feat, desc, val) \
|
||||||
"enable prototype threads for wasm")
|
DEFINE_BOOL(experimental_wasm_##feat, val, \
|
||||||
DEFINE_BOOL(experimental_wasm_sat_f2i_conversions, false,
|
"enable prototype " desc " for wasm")
|
||||||
"enable non-trapping float-to-int conversions for wasm")
|
FOREACH_WASM_FEATURE_FLAG(DECL_WASM_FLAG, SPACE)
|
||||||
DEFINE_BOOL(experimental_wasm_se, true,
|
#undef DECL_WASM_FLAG
|
||||||
"enable prototype sign extension opcodes for wasm")
|
#undef SPACE
|
||||||
DEFINE_BOOL(experimental_wasm_anyref, false,
|
|
||||||
"enable prototype anyref support for wasm")
|
|
||||||
DEFINE_BOOL(experimental_wasm_mut_global, true,
|
|
||||||
"enable prototype import/export mutable global support for wasm")
|
|
||||||
|
|
||||||
DEFINE_BOOL(wasm_opt, false, "enable wasm optimization")
|
DEFINE_BOOL(wasm_opt, false, "enable wasm optimization")
|
||||||
DEFINE_BOOL(wasm_no_bounds_checks, false,
|
DEFINE_BOOL(wasm_no_bounds_checks, false,
|
||||||
|
@ -1124,6 +1124,8 @@ void ReportBootstrappingException(Handle<Object> exception,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Isolate::is_catchable_by_wasm(Object* exception) {
|
bool Isolate::is_catchable_by_wasm(Object* exception) {
|
||||||
|
// TODO(titzer): thread WASM features here, or just remove this check?
|
||||||
|
if (!FLAG_experimental_wasm_eh) return false;
|
||||||
if (!is_catchable_by_javascript(exception) || !exception->IsJSError())
|
if (!is_catchable_by_javascript(exception) || !exception->IsJSError())
|
||||||
return false;
|
return false;
|
||||||
HandleScope scope(this);
|
HandleScope scope(this);
|
||||||
@ -1307,7 +1309,7 @@ Object* Isolate::UnwindAndFindHandler() {
|
|||||||
trap_handler::ClearThreadInWasm();
|
trap_handler::ClearThreadInWasm();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAG_experimental_wasm_eh || !is_catchable_by_wasm(exception)) {
|
if (!is_catchable_by_wasm(exception)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int stack_slots = 0; // Will contain stack slot count of frame.
|
int stack_slots = 0; // Will contain stack slot count of frame.
|
||||||
|
@ -522,11 +522,13 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
|
|||||||
return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver));
|
return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WASM_MEMORY_TYPE:
|
case WASM_MEMORY_TYPE: {
|
||||||
if (FLAG_experimental_wasm_threads) {
|
auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
|
||||||
|
if (enabled_features.threads) {
|
||||||
return WriteWasmMemory(Handle<WasmMemoryObject>::cast(receiver));
|
return WriteWasmMemory(Handle<WasmMemoryObject>::cast(receiver));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1805,8 +1807,11 @@ MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
|
|||||||
wasm::DeserializeNativeModule(isolate_, compiled_bytes, wire_bytes);
|
wasm::DeserializeNativeModule(isolate_, compiled_bytes, wire_bytes);
|
||||||
if (result.is_null()) {
|
if (result.is_null()) {
|
||||||
wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
|
wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
|
||||||
|
// TODO(titzer): are the current features appropriate for deserializing?
|
||||||
|
auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
|
||||||
result = isolate_->wasm_engine()->SyncCompile(
|
result = isolate_->wasm_engine()->SyncCompile(
|
||||||
isolate_, &thrower, wasm::ModuleWireBytes(wire_bytes));
|
isolate_, enabled_features, &thrower,
|
||||||
|
wasm::ModuleWireBytes(wire_bytes));
|
||||||
}
|
}
|
||||||
uint32_t id = next_id_++;
|
uint32_t id = next_id_++;
|
||||||
if (!result.is_null()) {
|
if (!result.is_null()) {
|
||||||
@ -1818,7 +1823,8 @@ MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
|
|||||||
MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
|
MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
|
||||||
uint32_t id = next_id_++;
|
uint32_t id = next_id_++;
|
||||||
|
|
||||||
if (!FLAG_experimental_wasm_threads) {
|
auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
|
||||||
|
if (!enabled_features.threads) {
|
||||||
return MaybeHandle<WasmMemoryObject>();
|
return MaybeHandle<WasmMemoryObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1135,7 +1135,6 @@ class LiftoffCompiler {
|
|||||||
uint32_t* offset) {
|
uint32_t* offset) {
|
||||||
LiftoffRegister addr = pinned.set(__ GetUnusedRegister(kGpReg));
|
LiftoffRegister addr = pinned.set(__ GetUnusedRegister(kGpReg));
|
||||||
if (global->mutability && global->imported) {
|
if (global->mutability && global->imported) {
|
||||||
DCHECK(FLAG_experimental_wasm_mut_global);
|
|
||||||
LOAD_INSTANCE_FIELD(addr, ImportedMutableGlobals, kPointerLoadType);
|
LOAD_INSTANCE_FIELD(addr, ImportedMutableGlobals, kPointerLoadType);
|
||||||
__ Load(addr, addr.gp(), no_reg, global->index * sizeof(Address),
|
__ Load(addr, addr.gp(), no_reg, global->index * sizeof(Address),
|
||||||
kPointerLoadType, pinned);
|
kPointerLoadType, pinned);
|
||||||
@ -1851,9 +1850,11 @@ bool LiftoffCompilationUnit::ExecuteCompilation() {
|
|||||||
compiler::GetWasmCallDescriptor(&zone, wasm_unit_->func_body_.sig);
|
compiler::GetWasmCallDescriptor(&zone, wasm_unit_->func_body_.sig);
|
||||||
base::Optional<TimedHistogramScope> liftoff_compile_time_scope(
|
base::Optional<TimedHistogramScope> liftoff_compile_time_scope(
|
||||||
base::in_place, wasm_unit_->counters_->liftoff_compile_time());
|
base::in_place, wasm_unit_->counters_->liftoff_compile_time());
|
||||||
|
WasmFeatures unused_detected_features;
|
||||||
WasmFullDecoder<Decoder::kValidate, LiftoffCompiler> decoder(
|
WasmFullDecoder<Decoder::kValidate, LiftoffCompiler> decoder(
|
||||||
&zone, module, wasm_unit_->func_body_, call_descriptor, wasm_unit_->env_,
|
&zone, module, wasm_unit_->native_module_->enabled_features(),
|
||||||
&zone);
|
&unused_detected_features, wasm_unit_->func_body_, call_descriptor,
|
||||||
|
wasm_unit_->env_, &zone);
|
||||||
decoder.Decode();
|
decoder.Decode();
|
||||||
liftoff_compile_time_scope.reset();
|
liftoff_compile_time_scope.reset();
|
||||||
LiftoffCompiler* compiler = &decoder.interface();
|
LiftoffCompiler* compiler = &decoder.interface();
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "src/bit-vector.h"
|
#include "src/bit-vector.h"
|
||||||
#include "src/wasm/decoder.h"
|
#include "src/wasm/decoder.h"
|
||||||
#include "src/wasm/function-body-decoder.h"
|
#include "src/wasm/function-body-decoder.h"
|
||||||
|
#include "src/wasm/wasm-features.h"
|
||||||
#include "src/wasm/wasm-limits.h"
|
#include "src/wasm/wasm-limits.h"
|
||||||
#include "src/wasm/wasm-module.h"
|
#include "src/wasm/wasm-module.h"
|
||||||
#include "src/wasm/wasm-opcodes.h"
|
#include "src/wasm/wasm-opcodes.h"
|
||||||
@ -38,17 +39,21 @@ struct WasmException;
|
|||||||
return true; \
|
return true; \
|
||||||
}())
|
}())
|
||||||
|
|
||||||
#define RET_ON_PROTOTYPE_OPCODE(flag) \
|
#define RET_ON_PROTOTYPE_OPCODE(feat) \
|
||||||
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
|
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
|
||||||
if (!FLAG_experimental_wasm_##flag) { \
|
if (!this->enabled_.feat) { \
|
||||||
this->error("Invalid opcode (enable with --experimental-wasm-" #flag ")"); \
|
this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
|
||||||
|
} else { \
|
||||||
|
this->detected_->feat = true; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_PROTOTYPE_OPCODE(flag) \
|
#define CHECK_PROTOTYPE_OPCODE(feat) \
|
||||||
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
|
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
|
||||||
if (!FLAG_experimental_wasm_##flag) { \
|
if (!this->enabled_.feat) { \
|
||||||
this->error("Invalid opcode (enable with --experimental-wasm-" #flag ")"); \
|
this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
|
||||||
break; \
|
break; \
|
||||||
|
} else { \
|
||||||
|
this->detected_->feat = true; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OPCODE_ERROR(opcode, message) \
|
#define OPCODE_ERROR(opcode, message) \
|
||||||
@ -209,11 +214,12 @@ struct BlockTypeImmediate {
|
|||||||
uint32_t sig_index = 0;
|
uint32_t sig_index = 0;
|
||||||
FunctionSig* sig = nullptr;
|
FunctionSig* sig = nullptr;
|
||||||
|
|
||||||
inline BlockTypeImmediate(Decoder* decoder, const byte* pc) {
|
inline BlockTypeImmediate(const WasmFeatures& enabled, Decoder* decoder,
|
||||||
|
const byte* pc) {
|
||||||
uint8_t val = decoder->read_u8<validate>(pc + 1, "block type");
|
uint8_t val = decoder->read_u8<validate>(pc + 1, "block type");
|
||||||
if (!decode_local_type(val, &type)) {
|
if (!decode_local_type(val, &type)) {
|
||||||
// Handle multi-value blocks.
|
// Handle multi-value blocks.
|
||||||
if (!VALIDATE(FLAG_experimental_wasm_mv)) {
|
if (!VALIDATE(enabled.mv)) {
|
||||||
decoder->error(pc + 1, "invalid block type");
|
decoder->error(pc + 1, "invalid block type");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -661,13 +667,18 @@ struct ControlWithNamedConstructors : public ControlBase<Value> {
|
|||||||
template <Decoder::ValidateFlag validate>
|
template <Decoder::ValidateFlag validate>
|
||||||
class WasmDecoder : public Decoder {
|
class WasmDecoder : public Decoder {
|
||||||
public:
|
public:
|
||||||
WasmDecoder(const WasmModule* module, FunctionSig* sig, const byte* start,
|
WasmDecoder(const WasmModule* module, const WasmFeatures& enabled,
|
||||||
|
WasmFeatures* detected, FunctionSig* sig, const byte* start,
|
||||||
const byte* end, uint32_t buffer_offset = 0)
|
const byte* end, uint32_t buffer_offset = 0)
|
||||||
: Decoder(start, end, buffer_offset),
|
: Decoder(start, end, buffer_offset),
|
||||||
module_(module),
|
module_(module),
|
||||||
|
enabled_(enabled),
|
||||||
|
detected_(detected),
|
||||||
sig_(sig),
|
sig_(sig),
|
||||||
local_types_(nullptr) {}
|
local_types_(nullptr) {}
|
||||||
const WasmModule* module_;
|
const WasmModule* module_;
|
||||||
|
const WasmFeatures enabled_;
|
||||||
|
WasmFeatures* detected_;
|
||||||
FunctionSig* sig_;
|
FunctionSig* sig_;
|
||||||
|
|
||||||
ZoneVector<ValueType>* local_types_;
|
ZoneVector<ValueType>* local_types_;
|
||||||
@ -678,7 +689,8 @@ class WasmDecoder : public Decoder {
|
|||||||
: static_cast<uint32_t>(local_types_->size());
|
: static_cast<uint32_t>(local_types_->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool DecodeLocals(Decoder* decoder, const FunctionSig* sig,
|
static bool DecodeLocals(const WasmFeatures& enabled, Decoder* decoder,
|
||||||
|
const FunctionSig* sig,
|
||||||
ZoneVector<ValueType>* type_list) {
|
ZoneVector<ValueType>* type_list) {
|
||||||
DCHECK_NOT_NULL(type_list);
|
DCHECK_NOT_NULL(type_list);
|
||||||
DCHECK_EQ(0, type_list->size());
|
DCHECK_EQ(0, type_list->size());
|
||||||
@ -718,14 +730,14 @@ class WasmDecoder : public Decoder {
|
|||||||
type = kWasmF64;
|
type = kWasmF64;
|
||||||
break;
|
break;
|
||||||
case kLocalAnyRef:
|
case kLocalAnyRef:
|
||||||
if (FLAG_experimental_wasm_anyref) {
|
if (enabled.anyref) {
|
||||||
type = kWasmAnyRef;
|
type = kWasmAnyRef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
decoder->error(decoder->pc() - 1, "invalid local type");
|
decoder->error(decoder->pc() - 1, "invalid local type");
|
||||||
return false;
|
return false;
|
||||||
case kLocalS128:
|
case kLocalS128:
|
||||||
if (FLAG_experimental_wasm_simd) {
|
if (enabled.simd) {
|
||||||
type = kWasmS128;
|
type = kWasmS128;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1008,7 +1020,7 @@ class WasmDecoder : public Decoder {
|
|||||||
case kExprIf: // fall through
|
case kExprIf: // fall through
|
||||||
case kExprLoop:
|
case kExprLoop:
|
||||||
case kExprBlock: {
|
case kExprBlock: {
|
||||||
BlockTypeImmediate<validate> imm(decoder, pc);
|
BlockTypeImmediate<validate> imm(kAllWasmFeatures, decoder, pc);
|
||||||
return 1 + imm.length;
|
return 1 + imm.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1215,9 +1227,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
|||||||
public:
|
public:
|
||||||
template <typename... InterfaceArgs>
|
template <typename... InterfaceArgs>
|
||||||
WasmFullDecoder(Zone* zone, const WasmModule* module,
|
WasmFullDecoder(Zone* zone, const WasmModule* module,
|
||||||
|
const WasmFeatures& enabled, WasmFeatures* detected,
|
||||||
const FunctionBody& body, InterfaceArgs&&... interface_args)
|
const FunctionBody& body, InterfaceArgs&&... interface_args)
|
||||||
: WasmDecoder<validate>(module, body.sig, body.start, body.end,
|
: WasmDecoder<validate>(module, enabled, detected, body.sig, body.start,
|
||||||
body.offset),
|
body.end, body.offset),
|
||||||
zone_(zone),
|
zone_(zone),
|
||||||
interface_(std::forward<InterfaceArgs>(interface_args)...),
|
interface_(std::forward<InterfaceArgs>(interface_args)...),
|
||||||
local_type_vec_(zone),
|
local_type_vec_(zone),
|
||||||
@ -1245,7 +1258,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DCHECK_EQ(0, this->local_types_->size());
|
DCHECK_EQ(0, this->local_types_->size());
|
||||||
WasmDecoder<validate>::DecodeLocals(this, this->sig_, this->local_types_);
|
WasmDecoder<validate>::DecodeLocals(this->enabled_, this, this->sig_,
|
||||||
|
this->local_types_);
|
||||||
CALL_INTERFACE(StartFunction);
|
CALL_INTERFACE(StartFunction);
|
||||||
DecodeFunctionBody();
|
DecodeFunctionBody();
|
||||||
if (!this->failed()) CALL_INTERFACE(FinishFunction);
|
if (!this->failed()) CALL_INTERFACE(FinishFunction);
|
||||||
@ -1433,7 +1447,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
|||||||
case kExprNop:
|
case kExprNop:
|
||||||
break;
|
break;
|
||||||
case kExprBlock: {
|
case kExprBlock: {
|
||||||
BlockTypeImmediate<validate> imm(this, this->pc_);
|
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
|
||||||
if (!this->Validate(imm)) break;
|
if (!this->Validate(imm)) break;
|
||||||
PopArgs(imm.sig);
|
PopArgs(imm.sig);
|
||||||
auto* block = PushBlock();
|
auto* block = PushBlock();
|
||||||
@ -1462,7 +1476,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
|||||||
}
|
}
|
||||||
case kExprTry: {
|
case kExprTry: {
|
||||||
CHECK_PROTOTYPE_OPCODE(eh);
|
CHECK_PROTOTYPE_OPCODE(eh);
|
||||||
BlockTypeImmediate<validate> imm(this, this->pc_);
|
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
|
||||||
if (!this->Validate(imm)) break;
|
if (!this->Validate(imm)) break;
|
||||||
PopArgs(imm.sig);
|
PopArgs(imm.sig);
|
||||||
auto* try_block = PushTry();
|
auto* try_block = PushTry();
|
||||||
@ -1515,7 +1529,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprLoop: {
|
case kExprLoop: {
|
||||||
BlockTypeImmediate<validate> imm(this, this->pc_);
|
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
|
||||||
if (!this->Validate(imm)) break;
|
if (!this->Validate(imm)) break;
|
||||||
PopArgs(imm.sig);
|
PopArgs(imm.sig);
|
||||||
auto* block = PushLoop();
|
auto* block = PushLoop();
|
||||||
@ -1526,7 +1540,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprIf: {
|
case kExprIf: {
|
||||||
BlockTypeImmediate<validate> imm(this, this->pc_);
|
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
|
||||||
if (!this->Validate(imm)) break;
|
if (!this->Validate(imm)) break;
|
||||||
auto cond = Pop(0, kWasmI32);
|
auto cond = Pop(0, kWasmI32);
|
||||||
PopArgs(imm.sig);
|
PopArgs(imm.sig);
|
||||||
|
@ -809,10 +809,10 @@ class WasmGraphBuildingInterface {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool DecodeLocalDecls(BodyLocalDecls* decls, const byte* start,
|
bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
|
||||||
const byte* end) {
|
const byte* start, const byte* end) {
|
||||||
Decoder decoder(start, end);
|
Decoder decoder(start, end);
|
||||||
if (WasmDecoder<Decoder::kValidate>::DecodeLocals(&decoder, nullptr,
|
if (WasmDecoder<Decoder::kValidate>::DecodeLocals(enabled, &decoder, nullptr,
|
||||||
&decls->type_list)) {
|
&decls->type_list)) {
|
||||||
DCHECK(decoder.ok());
|
DCHECK(decoder.ok());
|
||||||
decls->encoded_size = decoder.pc_offset();
|
decls->encoded_size = decoder.pc_offset();
|
||||||
@ -825,7 +825,7 @@ BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
|
|||||||
BodyLocalDecls* decls)
|
BodyLocalDecls* decls)
|
||||||
: Decoder(start, end) {
|
: Decoder(start, end) {
|
||||||
if (decls != nullptr) {
|
if (decls != nullptr) {
|
||||||
if (DecodeLocalDecls(decls, start, end)) {
|
if (DecodeLocalDecls(kAllWasmFeatures, decls, start, end)) {
|
||||||
pc_ += decls->encoded_size;
|
pc_ += decls->encoded_size;
|
||||||
if (pc_ > end_) pc_ = end_;
|
if (pc_ > end_) pc_ = end_;
|
||||||
}
|
}
|
||||||
@ -833,20 +833,24 @@ BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
|
DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
|
||||||
const WasmModule* module, FunctionBody& body) {
|
const WasmFeatures& enabled,
|
||||||
|
const WasmModule* module, WasmFeatures* detected,
|
||||||
|
FunctionBody& body) {
|
||||||
Zone zone(allocator, ZONE_NAME);
|
Zone zone(allocator, ZONE_NAME);
|
||||||
WasmFullDecoder<Decoder::kValidate, EmptyInterface> decoder(&zone, module,
|
WasmFullDecoder<Decoder::kValidate, EmptyInterface> decoder(
|
||||||
body);
|
&zone, module, enabled, detected, body);
|
||||||
decoder.Decode();
|
decoder.Decode();
|
||||||
return decoder.toResult(nullptr);
|
return decoder.toResult(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
|
DecodeResult BuildTFGraph(AccountingAllocator* allocator,
|
||||||
FunctionBody& body,
|
const WasmFeatures& enabled,
|
||||||
|
const wasm::WasmModule* module, TFBuilder* builder,
|
||||||
|
WasmFeatures* detected, FunctionBody& body,
|
||||||
compiler::NodeOriginTable* node_origins) {
|
compiler::NodeOriginTable* node_origins) {
|
||||||
Zone zone(allocator, ZONE_NAME);
|
Zone zone(allocator, ZONE_NAME);
|
||||||
WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder(
|
WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder(
|
||||||
&zone, builder->module(), body, builder);
|
&zone, module, enabled, detected, body, builder);
|
||||||
if (node_origins) {
|
if (node_origins) {
|
||||||
builder->AddBytecodePositionDecorator(node_origins, &decoder);
|
builder->AddBytecodePositionDecorator(node_origins, &decoder);
|
||||||
}
|
}
|
||||||
@ -865,7 +869,9 @@ unsigned OpcodeLength(const byte* pc, const byte* end) {
|
|||||||
std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
|
std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
|
||||||
FunctionSig* sig, const byte* pc,
|
FunctionSig* sig, const byte* pc,
|
||||||
const byte* end) {
|
const byte* end) {
|
||||||
WasmDecoder<Decoder::kNoValidate> decoder(module, sig, pc, end);
|
WasmFeatures unused_detected_features;
|
||||||
|
WasmDecoder<Decoder::kNoValidate> decoder(
|
||||||
|
module, kAllWasmFeatures, &unused_detected_features, sig, pc, end);
|
||||||
return decoder.StackEffect(pc);
|
return decoder.StackEffect(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -900,8 +906,10 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
|||||||
const WasmModule* module, PrintLocals print_locals,
|
const WasmModule* module, PrintLocals print_locals,
|
||||||
std::ostream& os, std::vector<int>* line_numbers) {
|
std::ostream& os, std::vector<int>* line_numbers) {
|
||||||
Zone zone(allocator, ZONE_NAME);
|
Zone zone(allocator, ZONE_NAME);
|
||||||
WasmDecoder<Decoder::kNoValidate> decoder(module, body.sig, body.start,
|
WasmFeatures unused_detected_features;
|
||||||
body.end);
|
WasmDecoder<Decoder::kNoValidate> decoder(module, kAllWasmFeatures,
|
||||||
|
&unused_detected_features, body.sig,
|
||||||
|
body.start, body.end);
|
||||||
int line_nr = 0;
|
int line_nr = 0;
|
||||||
constexpr int kNoByteCode = -1;
|
constexpr int kNoByteCode = -1;
|
||||||
|
|
||||||
@ -999,7 +1007,8 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
|||||||
case kExprIf:
|
case kExprIf:
|
||||||
case kExprBlock:
|
case kExprBlock:
|
||||||
case kExprTry: {
|
case kExprTry: {
|
||||||
BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
|
||||||
|
i.pc());
|
||||||
os << " // @" << i.pc_offset();
|
os << " // @" << i.pc_offset();
|
||||||
if (decoder.Complete(imm)) {
|
if (decoder.Complete(imm)) {
|
||||||
for (unsigned i = 0; i < imm.out_arity(); i++) {
|
for (unsigned i = 0; i < imm.out_arity(); i++) {
|
||||||
|
@ -25,8 +25,10 @@ class WasmGraphBuilder;
|
|||||||
|
|
||||||
namespace wasm {
|
namespace wasm {
|
||||||
|
|
||||||
typedef compiler::WasmGraphBuilder TFBuilder;
|
|
||||||
struct WasmModule; // forward declaration of module interface.
|
struct WasmModule; // forward declaration of module interface.
|
||||||
|
struct WasmFeatures;
|
||||||
|
|
||||||
|
typedef compiler::WasmGraphBuilder TFBuilder;
|
||||||
|
|
||||||
// A wrapper around the signature and bytes of a function.
|
// A wrapper around the signature and bytes of a function.
|
||||||
struct FunctionBody {
|
struct FunctionBody {
|
||||||
@ -41,10 +43,14 @@ struct FunctionBody {
|
|||||||
};
|
};
|
||||||
|
|
||||||
V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
|
V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
|
||||||
|
const WasmFeatures& enabled,
|
||||||
const WasmModule* module,
|
const WasmModule* module,
|
||||||
|
WasmFeatures* detected,
|
||||||
FunctionBody& body);
|
FunctionBody& body);
|
||||||
|
|
||||||
DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
|
DecodeResult BuildTFGraph(AccountingAllocator* allocator,
|
||||||
|
const WasmFeatures& enabled, const WasmModule* module,
|
||||||
|
TFBuilder* builder, WasmFeatures* detected,
|
||||||
FunctionBody& body,
|
FunctionBody& body,
|
||||||
compiler::NodeOriginTable* node_origins);
|
compiler::NodeOriginTable* node_origins);
|
||||||
enum PrintLocals { kPrintLocals, kOmitLocals };
|
enum PrintLocals { kPrintLocals, kOmitLocals };
|
||||||
@ -61,20 +67,6 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
|||||||
// A simplified form of AST printing, e.g. from a debugger.
|
// A simplified form of AST printing, e.g. from a debugger.
|
||||||
void PrintRawWasmCode(const byte* start, const byte* end);
|
void PrintRawWasmCode(const byte* start, const byte* end);
|
||||||
|
|
||||||
inline DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
|
|
||||||
const WasmModule* module, FunctionSig* sig,
|
|
||||||
const byte* start, const byte* end) {
|
|
||||||
FunctionBody body(sig, 0, start, end);
|
|
||||||
return VerifyWasmCode(allocator, module, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline DecodeResult BuildTFGraph(AccountingAllocator* allocator,
|
|
||||||
TFBuilder* builder, FunctionSig* sig,
|
|
||||||
const byte* start, const byte* end) {
|
|
||||||
FunctionBody body(sig, 0, start, end);
|
|
||||||
return BuildTFGraph(allocator, builder, body, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BodyLocalDecls {
|
struct BodyLocalDecls {
|
||||||
// The size of the encoded declarations.
|
// The size of the encoded declarations.
|
||||||
uint32_t encoded_size = 0; // size of encoded declarations
|
uint32_t encoded_size = 0; // size of encoded declarations
|
||||||
@ -84,7 +76,8 @@ struct BodyLocalDecls {
|
|||||||
explicit BodyLocalDecls(Zone* zone) : type_list(zone) {}
|
explicit BodyLocalDecls(Zone* zone) : type_list(zone) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
V8_EXPORT_PRIVATE bool DecodeLocalDecls(BodyLocalDecls* decls,
|
V8_EXPORT_PRIVATE bool DecodeLocalDecls(const WasmFeatures& enabled,
|
||||||
|
BodyLocalDecls* decls,
|
||||||
const byte* start, const byte* end);
|
const byte* start, const byte* end);
|
||||||
|
|
||||||
V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone,
|
V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone,
|
||||||
|
@ -223,6 +223,7 @@ class InstanceBuilder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Isolate* isolate_;
|
Isolate* isolate_;
|
||||||
|
const WasmFeatures enabled_;
|
||||||
const WasmModule* const module_;
|
const WasmModule* const module_;
|
||||||
ErrorThrower* thrower_;
|
ErrorThrower* thrower_;
|
||||||
Handle<WasmModuleObject> module_object_;
|
Handle<WasmModuleObject> module_object_;
|
||||||
@ -688,7 +689,10 @@ void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
|
|||||||
wasm_decode, function_time);
|
wasm_decode, function_time);
|
||||||
|
|
||||||
TimedHistogramScope wasm_decode_function_time_scope(time_counter);
|
TimedHistogramScope wasm_decode_function_time_scope(time_counter);
|
||||||
result = VerifyWasmCode(isolate->allocator(), module, body);
|
WasmFeatures detected;
|
||||||
|
result = VerifyWasmCode(isolate->allocator(),
|
||||||
|
native_module->enabled_features(), module,
|
||||||
|
&detected, body);
|
||||||
}
|
}
|
||||||
if (result.failed()) {
|
if (result.failed()) {
|
||||||
TruncatedUserString<> name(wire_bytes.GetName(&func, module));
|
TruncatedUserString<> name(wire_bytes.GetName(&func, module));
|
||||||
@ -840,7 +844,7 @@ class BackgroundCompileTask : public CancelableTask {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MaybeHandle<WasmModuleObject> CompileToModuleObject(
|
MaybeHandle<WasmModuleObject> CompileToModuleObject(
|
||||||
Isolate* isolate, ErrorThrower* thrower,
|
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
|
||||||
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
|
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
|
||||||
Handle<Script> asm_js_script,
|
Handle<Script> asm_js_script,
|
||||||
Vector<const byte> asm_js_offset_table_bytes) {
|
Vector<const byte> asm_js_offset_table_bytes) {
|
||||||
@ -874,7 +878,6 @@ MaybeHandle<WasmModuleObject> CompileToModuleObject(
|
|||||||
// TODO(clemensh): For the same module (same bytes / same hash), we should
|
// TODO(clemensh): For the same module (same bytes / same hash), we should
|
||||||
// only have one WasmModuleObject. Otherwise, we might only set
|
// only have one WasmModuleObject. Otherwise, we might only set
|
||||||
// breakpoints on a (potentially empty) subset of the instances.
|
// breakpoints on a (potentially empty) subset of the instances.
|
||||||
|
|
||||||
ModuleEnv env = CreateDefaultModuleEnv(wasm_module);
|
ModuleEnv env = CreateDefaultModuleEnv(wasm_module);
|
||||||
|
|
||||||
// Create the compiled module object and populate with compiled functions
|
// Create the compiled module object and populate with compiled functions
|
||||||
@ -882,8 +885,8 @@ MaybeHandle<WasmModuleObject> CompileToModuleObject(
|
|||||||
// serializable. Instantiation may occur off a deserialized version of this
|
// serializable. Instantiation may occur off a deserialized version of this
|
||||||
// object.
|
// object.
|
||||||
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
|
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
|
||||||
isolate, std::move(module), env, std::move(wire_bytes_copy), script,
|
isolate, enabled, std::move(module), env, std::move(wire_bytes_copy),
|
||||||
asm_js_offset_table);
|
script, asm_js_offset_table);
|
||||||
CompileNativeModule(isolate, thrower, module_object, wasm_module, &env);
|
CompileNativeModule(isolate, thrower, module_object, wasm_module, &env);
|
||||||
if (thrower->error()) return {};
|
if (thrower->error()) return {};
|
||||||
|
|
||||||
@ -910,6 +913,7 @@ InstanceBuilder::InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
|
|||||||
MaybeHandle<JSReceiver> ffi,
|
MaybeHandle<JSReceiver> ffi,
|
||||||
MaybeHandle<JSArrayBuffer> memory)
|
MaybeHandle<JSArrayBuffer> memory)
|
||||||
: isolate_(isolate),
|
: isolate_(isolate),
|
||||||
|
enabled_(module_object->native_module()->enabled_features()),
|
||||||
module_(module_object->module()),
|
module_(module_object->module()),
|
||||||
thrower_(thrower),
|
thrower_(thrower),
|
||||||
module_object_(module_object),
|
module_object_(module_object),
|
||||||
@ -965,7 +969,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
|||||||
memory->backing_store() == nullptr ||
|
memory->backing_store() == nullptr ||
|
||||||
// TODO(836800) Remove once is_wasm_memory transfers over
|
// TODO(836800) Remove once is_wasm_memory transfers over
|
||||||
// post-message.
|
// post-message.
|
||||||
(FLAG_experimental_wasm_threads && memory->is_shared()));
|
(enabled_.threads && memory->is_shared()));
|
||||||
} else if (initial_pages > 0 || use_trap_handler()) {
|
} else if (initial_pages > 0 || use_trap_handler()) {
|
||||||
// We need to unconditionally create a guard region if using trap handlers,
|
// We need to unconditionally create a guard region if using trap handlers,
|
||||||
// even when the size is zero to prevent null-dereference issues
|
// even when the size is zero to prevent null-dereference issues
|
||||||
@ -1047,7 +1051,6 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
|||||||
// Set up the array of references to imported globals' array buffers.
|
// Set up the array of references to imported globals' array buffers.
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
if (module_->num_imported_mutable_globals > 0) {
|
if (module_->num_imported_mutable_globals > 0) {
|
||||||
DCHECK(FLAG_experimental_wasm_mut_global);
|
|
||||||
// TODO(binji): This allocates one slot for each mutable global, which is
|
// TODO(binji): This allocates one slot for each mutable global, which is
|
||||||
// more than required if multiple globals are imported from the same
|
// more than required if multiple globals are imported from the same
|
||||||
// module.
|
// module.
|
||||||
@ -1632,8 +1635,8 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
|
|||||||
|
|
||||||
// The mutable-global proposal allows importing i64 values, but only if
|
// The mutable-global proposal allows importing i64 values, but only if
|
||||||
// they are passed as a WebAssembly.Global object.
|
// they are passed as a WebAssembly.Global object.
|
||||||
if (global.type == kWasmI64 && !(FLAG_experimental_wasm_mut_global &&
|
if (global.type == kWasmI64 &&
|
||||||
value->IsWasmGlobalObject())) {
|
!(enabled_.mut_global && value->IsWasmGlobalObject())) {
|
||||||
ReportLinkError("global import cannot have type i64", index,
|
ReportLinkError("global import cannot have type i64", index,
|
||||||
module_name, import_name);
|
module_name, import_name);
|
||||||
return -1;
|
return -1;
|
||||||
@ -1654,7 +1657,7 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FLAG_experimental_wasm_mut_global) {
|
if (enabled_.mut_global) {
|
||||||
if (value->IsWasmGlobalObject()) {
|
if (value->IsWasmGlobalObject()) {
|
||||||
auto global_object = Handle<WasmGlobalObject>::cast(value);
|
auto global_object = Handle<WasmGlobalObject>::cast(value);
|
||||||
if (global_object->type() != global.type) {
|
if (global_object->type() != global.type) {
|
||||||
@ -1729,7 +1732,6 @@ T* InstanceBuilder::GetRawGlobalPtr(const WasmGlobal& global) {
|
|||||||
void InstanceBuilder::InitGlobals() {
|
void InstanceBuilder::InitGlobals() {
|
||||||
for (auto global : module_->globals) {
|
for (auto global : module_->globals) {
|
||||||
if (global.mutability && global.imported) {
|
if (global.mutability && global.imported) {
|
||||||
DCHECK(FLAG_experimental_wasm_mut_global);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1775,8 +1777,7 @@ Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t num_pages) {
|
|||||||
thrower_->RangeError("Out of memory: wasm memory too large");
|
thrower_->RangeError("Out of memory: wasm memory too large");
|
||||||
return Handle<JSArrayBuffer>::null();
|
return Handle<JSArrayBuffer>::null();
|
||||||
}
|
}
|
||||||
const bool is_shared_memory =
|
const bool is_shared_memory = module_->has_shared_memory && enabled_.threads;
|
||||||
module_->has_shared_memory && i::FLAG_experimental_wasm_threads;
|
|
||||||
i::SharedFlag shared_flag =
|
i::SharedFlag shared_flag =
|
||||||
is_shared_memory ? i::SharedFlag::kShared : i::SharedFlag::kNotShared;
|
is_shared_memory ? i::SharedFlag::kShared : i::SharedFlag::kNotShared;
|
||||||
Handle<JSArrayBuffer> mem_buffer;
|
Handle<JSArrayBuffer> mem_buffer;
|
||||||
@ -1918,7 +1919,7 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
|
|||||||
}
|
}
|
||||||
case kExternalGlobal: {
|
case kExternalGlobal: {
|
||||||
const WasmGlobal& global = module_->globals[exp.index];
|
const WasmGlobal& global = module_->globals[exp.index];
|
||||||
if (FLAG_experimental_wasm_mut_global) {
|
if (enabled_.mut_global) {
|
||||||
Handle<JSArrayBuffer> buffer;
|
Handle<JSArrayBuffer> buffer;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
|
||||||
@ -2093,10 +2094,11 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AsyncCompileJob::AsyncCompileJob(
|
AsyncCompileJob::AsyncCompileJob(
|
||||||
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
|
Isolate* isolate, const WasmFeatures& enabled,
|
||||||
Handle<Context> context,
|
std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
|
||||||
std::unique_ptr<CompilationResultResolver> resolver)
|
std::unique_ptr<CompilationResultResolver> resolver)
|
||||||
: isolate_(isolate),
|
: isolate_(isolate),
|
||||||
|
enabled_features_(enabled),
|
||||||
async_counters_(isolate->async_counters()),
|
async_counters_(isolate->async_counters()),
|
||||||
bytes_copy_(std::move(bytes_copy)),
|
bytes_copy_(std::move(bytes_copy)),
|
||||||
wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
|
wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
|
||||||
@ -2311,8 +2313,9 @@ class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
|
|||||||
// Decode the module bytes.
|
// Decode the module bytes.
|
||||||
TRACE_COMPILE("(1) Decoding module...\n");
|
TRACE_COMPILE("(1) Decoding module...\n");
|
||||||
result =
|
result =
|
||||||
DecodeWasmModule(job_->wire_bytes_.start(), job_->wire_bytes_.end(),
|
DecodeWasmModule(job_->enabled_features_, job_->wire_bytes_.start(),
|
||||||
false, kWasmOrigin, job_->async_counters().get(),
|
job_->wire_bytes_.end(), false, kWasmOrigin,
|
||||||
|
job_->async_counters().get(),
|
||||||
job_->isolate()->wasm_engine()->allocator());
|
job_->isolate()->wasm_engine()->allocator());
|
||||||
}
|
}
|
||||||
if (result.failed()) {
|
if (result.failed()) {
|
||||||
@ -2379,7 +2382,7 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
|
|||||||
// breakpoints on a (potentially empty) subset of the instances.
|
// breakpoints on a (potentially empty) subset of the instances.
|
||||||
// Create the module object.
|
// Create the module object.
|
||||||
job_->module_object_ = WasmModuleObject::New(
|
job_->module_object_ = WasmModuleObject::New(
|
||||||
job_->isolate_, job_->module_, env,
|
job_->isolate_, job_->enabled_features_, job_->module_, env,
|
||||||
{std::move(job_->bytes_copy_), job_->wire_bytes_.length()}, script,
|
{std::move(job_->bytes_copy_), job_->wire_bytes_.length()}, script,
|
||||||
asm_js_offset_table);
|
asm_js_offset_table);
|
||||||
job_->native_module_ = job_->module_object_->native_module();
|
job_->native_module_ = job_->module_object_->native_module();
|
||||||
@ -2530,7 +2533,9 @@ class AsyncCompileJob::FinishModule : public CompileStep {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
|
AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
|
||||||
: job_(job), compilation_unit_builder_(nullptr) {}
|
: decoder_(job->enabled_features_),
|
||||||
|
job_(job),
|
||||||
|
compilation_unit_builder_(nullptr) {}
|
||||||
|
|
||||||
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(ResultBase error) {
|
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(ResultBase error) {
|
||||||
// Make sure all background tasks stopped executing before we change the state
|
// Make sure all background tasks stopped executing before we change the state
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "src/cancelable-task.h"
|
#include "src/cancelable-task.h"
|
||||||
#include "src/globals.h"
|
#include "src/globals.h"
|
||||||
|
#include "src/wasm/wasm-features.h"
|
||||||
#include "src/wasm/wasm-module.h"
|
#include "src/wasm/wasm-module.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
@ -48,7 +49,7 @@ std::unique_ptr<CompilationState, CompilationStateDeleter> NewCompilationState(
|
|||||||
ModuleEnv* GetModuleEnv(CompilationState* compilation_state);
|
ModuleEnv* GetModuleEnv(CompilationState* compilation_state);
|
||||||
|
|
||||||
MaybeHandle<WasmModuleObject> CompileToModuleObject(
|
MaybeHandle<WasmModuleObject> CompileToModuleObject(
|
||||||
Isolate* isolate, ErrorThrower* thrower,
|
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
|
||||||
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
|
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
|
||||||
Handle<Script> asm_js_script, Vector<const byte> asm_js_offset_table_bytes);
|
Handle<Script> asm_js_script, Vector<const byte> asm_js_offset_table_bytes);
|
||||||
|
|
||||||
@ -77,9 +78,10 @@ Address CompileLazy(Isolate*, NativeModule*, uint32_t func_index);
|
|||||||
// TODO(wasm): factor out common parts of this with the synchronous pipeline.
|
// TODO(wasm): factor out common parts of this with the synchronous pipeline.
|
||||||
class AsyncCompileJob {
|
class AsyncCompileJob {
|
||||||
public:
|
public:
|
||||||
explicit AsyncCompileJob(Isolate* isolate, std::unique_ptr<byte[]> bytes_copy,
|
AsyncCompileJob(Isolate* isolate, const WasmFeatures& enabled_features,
|
||||||
size_t length, Handle<Context> context,
|
std::unique_ptr<byte[]> bytes_copy, size_t length,
|
||||||
std::unique_ptr<CompilationResultResolver> resolver);
|
Handle<Context> context,
|
||||||
|
std::unique_ptr<CompilationResultResolver> resolver);
|
||||||
~AsyncCompileJob();
|
~AsyncCompileJob();
|
||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
@ -138,6 +140,7 @@ class AsyncCompileJob {
|
|||||||
friend class AsyncStreamingProcessor;
|
friend class AsyncStreamingProcessor;
|
||||||
|
|
||||||
Isolate* isolate_;
|
Isolate* isolate_;
|
||||||
|
const WasmFeatures enabled_features_;
|
||||||
const std::shared_ptr<Counters> async_counters_;
|
const std::shared_ptr<Counters> async_counters_;
|
||||||
// Copy of the module wire bytes, moved into the {native_module_} on it's
|
// Copy of the module wire bytes, moved into the {native_module_} on it's
|
||||||
// creation.
|
// creation.
|
||||||
|
@ -83,8 +83,7 @@ const char* SectionName(SectionCode code) {
|
|||||||
case kNameSectionCode:
|
case kNameSectionCode:
|
||||||
return kNameString;
|
return kNameString;
|
||||||
case kExceptionSectionCode:
|
case kExceptionSectionCode:
|
||||||
if (FLAG_experimental_wasm_eh) return kExceptionString;
|
return kExceptionString;
|
||||||
return kUnknownString;
|
|
||||||
default:
|
default:
|
||||||
return kUnknownString;
|
return kUnknownString;
|
||||||
}
|
}
|
||||||
@ -247,13 +246,15 @@ class WasmSectionIterator {
|
|||||||
// The main logic for decoding the bytes of a module.
|
// The main logic for decoding the bytes of a module.
|
||||||
class ModuleDecoderImpl : public Decoder {
|
class ModuleDecoderImpl : public Decoder {
|
||||||
public:
|
public:
|
||||||
explicit ModuleDecoderImpl(ModuleOrigin origin)
|
explicit ModuleDecoderImpl(const WasmFeatures& enabled, ModuleOrigin origin)
|
||||||
: Decoder(nullptr, nullptr),
|
: Decoder(nullptr, nullptr),
|
||||||
|
enabled_features_(enabled),
|
||||||
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {}
|
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {}
|
||||||
|
|
||||||
ModuleDecoderImpl(const byte* module_start, const byte* module_end,
|
ModuleDecoderImpl(const WasmFeatures& enabled, const byte* module_start,
|
||||||
ModuleOrigin origin)
|
const byte* module_end, ModuleOrigin origin)
|
||||||
: Decoder(module_start, module_end),
|
: Decoder(module_start, module_end),
|
||||||
|
enabled_features_(enabled),
|
||||||
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
|
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
|
||||||
if (end_ < start_) {
|
if (end_ < start_) {
|
||||||
error(start_, "end is less than start");
|
error(start_, "end is less than start");
|
||||||
@ -401,7 +402,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
DecodeNameSection();
|
DecodeNameSection();
|
||||||
break;
|
break;
|
||||||
case kExceptionSectionCode:
|
case kExceptionSectionCode:
|
||||||
if (FLAG_experimental_wasm_eh) {
|
if (enabled_features_.eh) {
|
||||||
DecodeExceptionSection();
|
DecodeExceptionSection();
|
||||||
} else {
|
} else {
|
||||||
errorf(pc(), "unexpected section: %s", SectionName(section_code));
|
errorf(pc(), "unexpected section: %s", SectionName(section_code));
|
||||||
@ -479,7 +480,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
WasmTable* table = &module_->tables.back();
|
WasmTable* table = &module_->tables.back();
|
||||||
table->imported = true;
|
table->imported = true;
|
||||||
ValueType type = consume_reference_type();
|
ValueType type = consume_reference_type();
|
||||||
if (!FLAG_experimental_wasm_anyref) {
|
if (!enabled_features_.anyref) {
|
||||||
if (type != kWasmAnyFunc) {
|
if (type != kWasmAnyFunc) {
|
||||||
error(pc_ - 1, "invalid table type");
|
error(pc_ - 1, "invalid table type");
|
||||||
break;
|
break;
|
||||||
@ -512,7 +513,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
global->type = consume_value_type();
|
global->type = consume_value_type();
|
||||||
global->mutability = consume_mutability();
|
global->mutability = consume_mutability();
|
||||||
if (global->mutability) {
|
if (global->mutability) {
|
||||||
if (FLAG_experimental_wasm_mut_global) {
|
if (enabled_features_.mut_global) {
|
||||||
module_->num_imported_mutable_globals++;
|
module_->num_imported_mutable_globals++;
|
||||||
} else {
|
} else {
|
||||||
error("mutable globals cannot be imported");
|
error("mutable globals cannot be imported");
|
||||||
@ -556,7 +557,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
void DecodeTableSection() {
|
void DecodeTableSection() {
|
||||||
// TODO(ahaas): Set the correct limit to {kV8MaxWasmTables} once the
|
// TODO(ahaas): Set the correct limit to {kV8MaxWasmTables} once the
|
||||||
// implementation of AnyRef landed.
|
// implementation of AnyRef landed.
|
||||||
uint32_t max_count = FLAG_experimental_wasm_anyref ? 10 : kV8MaxWasmTables;
|
uint32_t max_count = enabled_features_.anyref ? 10 : kV8MaxWasmTables;
|
||||||
uint32_t table_count = consume_count("table count", max_count);
|
uint32_t table_count = consume_count("table count", max_count);
|
||||||
|
|
||||||
for (uint32_t i = 0; ok() && i < table_count; i++) {
|
for (uint32_t i = 0; ok() && i < table_count; i++) {
|
||||||
@ -647,7 +648,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
WasmGlobal* global = nullptr;
|
WasmGlobal* global = nullptr;
|
||||||
exp->index = consume_global_index(module_.get(), &global);
|
exp->index = consume_global_index(module_.get(), &global);
|
||||||
if (global) {
|
if (global) {
|
||||||
if (!FLAG_experimental_wasm_mut_global && global->mutability) {
|
if (!enabled_features_.mut_global && global->mutability) {
|
||||||
error("mutable globals cannot be exported");
|
error("mutable globals cannot be exported");
|
||||||
}
|
}
|
||||||
global->exported = true;
|
global->exported = true;
|
||||||
@ -710,7 +711,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
for (uint32_t i = 0; ok() && i < element_count; ++i) {
|
for (uint32_t i = 0; ok() && i < element_count; ++i) {
|
||||||
const byte* pos = pc();
|
const byte* pos = pc();
|
||||||
uint32_t table_index = consume_u32v("table index");
|
uint32_t table_index = consume_u32v("table index");
|
||||||
if (!FLAG_experimental_wasm_anyref && table_index != 0) {
|
if (!enabled_features_.anyref && table_index != 0) {
|
||||||
errorf(pos, "illegal table index %u != 0", table_index);
|
errorf(pos, "illegal table index %u != 0", table_index);
|
||||||
}
|
}
|
||||||
if (table_index >= module_->tables.size()) {
|
if (table_index >= module_->tables.size()) {
|
||||||
@ -930,6 +931,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const WasmFeatures enabled_features_;
|
||||||
std::shared_ptr<WasmModule> module_;
|
std::shared_ptr<WasmModule> module_;
|
||||||
Counters* counters_ = nullptr;
|
Counters* counters_ = nullptr;
|
||||||
// The type section is the first section in a module.
|
// The type section is the first section in a module.
|
||||||
@ -948,7 +950,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool AddTable(WasmModule* module) {
|
bool AddTable(WasmModule* module) {
|
||||||
if (FLAG_experimental_wasm_anyref) return true;
|
if (enabled_features_.anyref) return true;
|
||||||
if (module->tables.size() > 0) {
|
if (module->tables.size() > 0) {
|
||||||
error("At most one table is supported");
|
error("At most one table is supported");
|
||||||
return false;
|
return false;
|
||||||
@ -1021,7 +1023,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
for (WasmGlobal& global : module->globals) {
|
for (WasmGlobal& global : module->globals) {
|
||||||
byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(global.type));
|
byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(global.type));
|
||||||
if (global.mutability && global.imported) {
|
if (global.mutability && global.imported) {
|
||||||
DCHECK(FLAG_experimental_wasm_mut_global);
|
DCHECK(enabled_features_.mut_global);
|
||||||
global.index = num_imported_mutable_globals++;
|
global.index = num_imported_mutable_globals++;
|
||||||
} else {
|
} else {
|
||||||
offset = (offset + size - 1) & ~(size - 1); // align
|
offset = (offset + size - 1) & ~(size - 1); // align
|
||||||
@ -1053,7 +1055,9 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
wasm_decode, function_time);
|
wasm_decode, function_time);
|
||||||
|
|
||||||
TimedHistogramScope wasm_decode_function_time_scope(time_counter);
|
TimedHistogramScope wasm_decode_function_time_scope(time_counter);
|
||||||
result = VerifyWasmCode(allocator, module, body);
|
WasmFeatures unused_detected_features;
|
||||||
|
result = VerifyWasmCode(allocator, enabled_features_, module,
|
||||||
|
&unused_detected_features, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.failed()) {
|
if (result.failed()) {
|
||||||
@ -1131,7 +1135,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
uint8_t flags = consume_u8("resizable limits flags");
|
uint8_t flags = consume_u8("resizable limits flags");
|
||||||
const byte* pos = pc();
|
const byte* pos = pc();
|
||||||
*has_shared_memory = false;
|
*has_shared_memory = false;
|
||||||
if (FLAG_experimental_wasm_threads) {
|
if (enabled_features_.threads) {
|
||||||
if (flags & 0xFC) {
|
if (flags & 0xFC) {
|
||||||
errorf(pos - 1, "invalid memory limits flags");
|
errorf(pos - 1, "invalid memory limits flags");
|
||||||
} else if (flags == 3) {
|
} else if (flags == 3) {
|
||||||
@ -1249,7 +1253,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprRefNull: {
|
case kExprRefNull: {
|
||||||
if (FLAG_experimental_wasm_anyref) {
|
if (enabled_features_.anyref) {
|
||||||
expr.kind = WasmInitExpr::kAnyRefConst;
|
expr.kind = WasmInitExpr::kAnyRefConst;
|
||||||
len = 0;
|
len = 0;
|
||||||
break;
|
break;
|
||||||
@ -1298,13 +1302,13 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
if (origin_ == kWasmOrigin) {
|
if (origin_ == kWasmOrigin) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case kLocalS128:
|
case kLocalS128:
|
||||||
if (FLAG_experimental_wasm_simd) return kWasmS128;
|
if (enabled_features_.simd) return kWasmS128;
|
||||||
break;
|
break;
|
||||||
case kLocalAnyFunc:
|
case kLocalAnyFunc:
|
||||||
if (FLAG_experimental_wasm_anyref) return kWasmAnyFunc;
|
if (enabled_features_.anyref) return kWasmAnyFunc;
|
||||||
break;
|
break;
|
||||||
case kLocalAnyRef:
|
case kLocalAnyRef:
|
||||||
if (FLAG_experimental_wasm_anyref) return kWasmAnyRef;
|
if (enabled_features_.anyref) return kWasmAnyRef;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1323,7 +1327,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
case kLocalAnyFunc:
|
case kLocalAnyFunc:
|
||||||
return kWasmAnyFunc;
|
return kWasmAnyFunc;
|
||||||
case kLocalAnyRef:
|
case kLocalAnyRef:
|
||||||
if (!FLAG_experimental_wasm_anyref) {
|
if (!enabled_features_.anyref) {
|
||||||
error(pc_ - 1,
|
error(pc_ - 1,
|
||||||
"Invalid type. Set --experimental-wasm-anyref to use 'AnyRef'");
|
"Invalid type. Set --experimental-wasm-anyref to use 'AnyRef'");
|
||||||
}
|
}
|
||||||
@ -1362,7 +1366,7 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
uint32_t return_count = 0;
|
uint32_t return_count = 0;
|
||||||
if (has_return_values) {
|
if (has_return_values) {
|
||||||
// parse return types
|
// parse return types
|
||||||
const size_t max_return_count = FLAG_experimental_wasm_mv
|
const size_t max_return_count = enabled_features_.mv
|
||||||
? kV8MaxWasmFunctionMultiReturns
|
? kV8MaxWasmFunctionMultiReturns
|
||||||
: kV8MaxWasmFunctionReturns;
|
: kV8MaxWasmFunctionReturns;
|
||||||
return_count = consume_count("return count", max_return_count);
|
return_count = consume_count("return count", max_return_count);
|
||||||
@ -1385,7 +1389,8 @@ class ModuleDecoderImpl : public Decoder {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ModuleResult DecodeWasmModule(const byte* module_start, const byte* module_end,
|
ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
|
||||||
|
const byte* module_start, const byte* module_end,
|
||||||
bool verify_functions, ModuleOrigin origin,
|
bool verify_functions, ModuleOrigin origin,
|
||||||
Counters* counters,
|
Counters* counters,
|
||||||
AccountingAllocator* allocator) {
|
AccountingAllocator* allocator) {
|
||||||
@ -1402,7 +1407,7 @@ ModuleResult DecodeWasmModule(const byte* module_start, const byte* module_end,
|
|||||||
size_counter->AddSample(static_cast<int>(size));
|
size_counter->AddSample(static_cast<int>(size));
|
||||||
// Signatures are stored in zone memory, which have the same lifetime
|
// Signatures are stored in zone memory, which have the same lifetime
|
||||||
// as the {module}.
|
// as the {module}.
|
||||||
ModuleDecoderImpl decoder(module_start, module_end, origin);
|
ModuleDecoderImpl decoder(enabled, module_start, module_end, origin);
|
||||||
ModuleResult result =
|
ModuleResult result =
|
||||||
decoder.DecodeModule(counters, allocator, verify_functions);
|
decoder.DecodeModule(counters, allocator, verify_functions);
|
||||||
// TODO(bradnelson): Improve histogram handling of size_t.
|
// TODO(bradnelson): Improve histogram handling of size_t.
|
||||||
@ -1418,7 +1423,9 @@ ModuleResult DecodeWasmModule(const byte* module_start, const byte* module_end,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleDecoder::ModuleDecoder() = default;
|
ModuleDecoder::ModuleDecoder(const WasmFeatures& enabled)
|
||||||
|
: enabled_features_(enabled) {}
|
||||||
|
|
||||||
ModuleDecoder::~ModuleDecoder() = default;
|
ModuleDecoder::~ModuleDecoder() = default;
|
||||||
|
|
||||||
const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
|
const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
|
||||||
@ -1429,7 +1436,7 @@ void ModuleDecoder::StartDecoding(Counters* counters,
|
|||||||
AccountingAllocator* allocator,
|
AccountingAllocator* allocator,
|
||||||
ModuleOrigin origin) {
|
ModuleOrigin origin) {
|
||||||
DCHECK_NULL(impl_);
|
DCHECK_NULL(impl_);
|
||||||
impl_.reset(new ModuleDecoderImpl(origin));
|
impl_.reset(new ModuleDecoderImpl(enabled_features_, origin));
|
||||||
impl_->StartDecoding(counters, allocator);
|
impl_->StartDecoding(counters, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1481,21 +1488,24 @@ SectionCode ModuleDecoder::IdentifyUnknownSection(Decoder& decoder,
|
|||||||
|
|
||||||
bool ModuleDecoder::ok() { return impl_->ok(); }
|
bool ModuleDecoder::ok() { return impl_->ok(); }
|
||||||
|
|
||||||
FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
|
FunctionSig* DecodeWasmSignatureForTesting(const WasmFeatures& enabled,
|
||||||
|
Zone* zone, const byte* start,
|
||||||
const byte* end) {
|
const byte* end) {
|
||||||
ModuleDecoderImpl decoder(start, end, kWasmOrigin);
|
ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
|
||||||
return decoder.DecodeFunctionSignature(zone, start);
|
return decoder.DecodeFunctionSignature(zone, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmInitExpr DecodeWasmInitExprForTesting(const byte* start, const byte* end) {
|
WasmInitExpr DecodeWasmInitExprForTesting(const WasmFeatures& enabled,
|
||||||
|
const byte* start, const byte* end) {
|
||||||
AccountingAllocator allocator;
|
AccountingAllocator allocator;
|
||||||
ModuleDecoderImpl decoder(start, end, kWasmOrigin);
|
ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
|
||||||
return decoder.DecodeInitExpr(start);
|
return decoder.DecodeInitExpr(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionResult DecodeWasmFunctionForTesting(
|
FunctionResult DecodeWasmFunctionForTesting(
|
||||||
Zone* zone, const ModuleWireBytes& wire_bytes, const WasmModule* module,
|
const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
|
||||||
const byte* function_start, const byte* function_end, Counters* counters) {
|
const WasmModule* module, const byte* function_start,
|
||||||
|
const byte* function_end, Counters* counters) {
|
||||||
size_t size = function_end - function_start;
|
size_t size = function_end - function_start;
|
||||||
if (function_start > function_end)
|
if (function_start > function_end)
|
||||||
return FunctionResult::Error("start > end");
|
return FunctionResult::Error("start > end");
|
||||||
@ -1505,7 +1515,7 @@ FunctionResult DecodeWasmFunctionForTesting(
|
|||||||
size_histogram->AddSample(static_cast<int>(size));
|
size_histogram->AddSample(static_cast<int>(size));
|
||||||
if (size > kV8MaxWasmFunctionSize)
|
if (size > kV8MaxWasmFunctionSize)
|
||||||
return FunctionResult::Error("size > maximum function size: %zu", size);
|
return FunctionResult::Error("size > maximum function size: %zu", size);
|
||||||
ModuleDecoderImpl decoder(function_start, function_end, kWasmOrigin);
|
ModuleDecoderImpl decoder(enabled, function_start, function_end, kWasmOrigin);
|
||||||
decoder.SetCounters(counters);
|
decoder.SetCounters(counters);
|
||||||
return decoder.DecodeSingleFunction(zone, wire_bytes, module,
|
return decoder.DecodeSingleFunction(zone, wire_bytes, module,
|
||||||
base::make_unique<WasmFunction>());
|
base::make_unique<WasmFunction>());
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "src/globals.h"
|
#include "src/globals.h"
|
||||||
#include "src/wasm/function-body-decoder.h"
|
#include "src/wasm/function-body-decoder.h"
|
||||||
#include "src/wasm/wasm-constants.h"
|
#include "src/wasm/wasm-constants.h"
|
||||||
|
#include "src/wasm/wasm-features.h"
|
||||||
#include "src/wasm/wasm-module.h"
|
#include "src/wasm/wasm-module.h"
|
||||||
#include "src/wasm/wasm-result.h"
|
#include "src/wasm/wasm-result.h"
|
||||||
|
|
||||||
@ -59,23 +60,25 @@ struct LocalNames {
|
|||||||
|
|
||||||
// Decodes the bytes of a wasm module between {module_start} and {module_end}.
|
// Decodes the bytes of a wasm module between {module_start} and {module_end}.
|
||||||
V8_EXPORT_PRIVATE ModuleResult DecodeWasmModule(
|
V8_EXPORT_PRIVATE ModuleResult DecodeWasmModule(
|
||||||
const byte* module_start, const byte* module_end, bool verify_functions,
|
const WasmFeatures& enabled, const byte* module_start,
|
||||||
ModuleOrigin origin, Counters* counters, AccountingAllocator* allocator);
|
const byte* module_end, bool verify_functions, ModuleOrigin origin,
|
||||||
|
Counters* counters, AccountingAllocator* allocator);
|
||||||
|
|
||||||
// Exposed for testing. Decodes a single function signature, allocating it
|
// Exposed for testing. Decodes a single function signature, allocating it
|
||||||
// in the given zone. Returns {nullptr} upon failure.
|
// in the given zone. Returns {nullptr} upon failure.
|
||||||
V8_EXPORT_PRIVATE FunctionSig* DecodeWasmSignatureForTesting(Zone* zone,
|
V8_EXPORT_PRIVATE FunctionSig* DecodeWasmSignatureForTesting(
|
||||||
const byte* start,
|
const WasmFeatures& enabled, Zone* zone, const byte* start,
|
||||||
const byte* end);
|
const byte* end);
|
||||||
|
|
||||||
// Decodes the bytes of a wasm function between
|
// Decodes the bytes of a wasm function between
|
||||||
// {function_start} and {function_end}.
|
// {function_start} and {function_end}.
|
||||||
V8_EXPORT_PRIVATE FunctionResult DecodeWasmFunctionForTesting(
|
V8_EXPORT_PRIVATE FunctionResult DecodeWasmFunctionForTesting(
|
||||||
Zone* zone, const ModuleWireBytes& wire_bytes, const WasmModule* module,
|
const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
|
||||||
const byte* function_start, const byte* function_end, Counters* counters);
|
const WasmModule* module, const byte* function_start,
|
||||||
|
const byte* function_end, Counters* counters);
|
||||||
|
|
||||||
V8_EXPORT_PRIVATE WasmInitExpr DecodeWasmInitExprForTesting(const byte* start,
|
V8_EXPORT_PRIVATE WasmInitExpr DecodeWasmInitExprForTesting(
|
||||||
const byte* end);
|
const WasmFeatures& enabled, const byte* start, const byte* end);
|
||||||
|
|
||||||
struct CustomSectionOffset {
|
struct CustomSectionOffset {
|
||||||
WireBytesRef section;
|
WireBytesRef section;
|
||||||
@ -111,7 +114,7 @@ class ModuleDecoderImpl;
|
|||||||
|
|
||||||
class ModuleDecoder {
|
class ModuleDecoder {
|
||||||
public:
|
public:
|
||||||
ModuleDecoder();
|
explicit ModuleDecoder(const WasmFeatures& enabled);
|
||||||
~ModuleDecoder();
|
~ModuleDecoder();
|
||||||
|
|
||||||
void StartDecoding(Counters* counters, AccountingAllocator* allocator,
|
void StartDecoding(Counters* counters, AccountingAllocator* allocator,
|
||||||
@ -145,6 +148,7 @@ class ModuleDecoder {
|
|||||||
static SectionCode IdentifyUnknownSection(Decoder& decoder, const byte* end);
|
static SectionCode IdentifyUnknownSection(Decoder& decoder, const byte* end);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const WasmFeatures enabled_features_;
|
||||||
std::unique_ptr<ModuleDecoderImpl> impl_;
|
std::unique_ptr<ModuleDecoderImpl> impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -298,12 +298,13 @@ WasmCode::~WasmCode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeModule::NativeModule(Isolate* isolate, bool can_request_more,
|
NativeModule::NativeModule(Isolate* isolate, const WasmFeatures& enabled,
|
||||||
VirtualMemory* code_space,
|
bool can_request_more, VirtualMemory* code_space,
|
||||||
WasmCodeManager* code_manager,
|
WasmCodeManager* code_manager,
|
||||||
std::shared_ptr<const WasmModule> module,
|
std::shared_ptr<const WasmModule> module,
|
||||||
const ModuleEnv& env)
|
const ModuleEnv& env)
|
||||||
: module_(std::move(module)),
|
: enabled_features_(enabled),
|
||||||
|
module_(std::move(module)),
|
||||||
compilation_state_(NewCompilationState(isolate, env)),
|
compilation_state_(NewCompilationState(isolate, env)),
|
||||||
free_code_space_({code_space->address(), code_space->end()}),
|
free_code_space_({code_space->address(), code_space->end()}),
|
||||||
wasm_code_manager_(code_manager),
|
wasm_code_manager_(code_manager),
|
||||||
@ -853,8 +854,9 @@ bool WasmCodeManager::ShouldForceCriticalMemoryPressureNotification() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
|
std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
|
||||||
Isolate* isolate, size_t memory_estimate, bool can_request_more,
|
Isolate* isolate, const WasmFeatures& enabled, size_t memory_estimate,
|
||||||
std::shared_ptr<const WasmModule> module, const ModuleEnv& env) {
|
bool can_request_more, std::shared_ptr<const WasmModule> module,
|
||||||
|
const ModuleEnv& env) {
|
||||||
if (ShouldForceCriticalMemoryPressureNotification()) {
|
if (ShouldForceCriticalMemoryPressureNotification()) {
|
||||||
(reinterpret_cast<v8::Isolate*>(isolate))
|
(reinterpret_cast<v8::Isolate*>(isolate))
|
||||||
->MemoryPressureNotification(MemoryPressureLevel::kCritical);
|
->MemoryPressureNotification(MemoryPressureLevel::kCritical);
|
||||||
@ -868,8 +870,9 @@ std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
|
|||||||
Address start = mem.address();
|
Address start = mem.address();
|
||||||
size_t size = mem.size();
|
size_t size = mem.size();
|
||||||
Address end = mem.end();
|
Address end = mem.end();
|
||||||
std::unique_ptr<NativeModule> ret(new NativeModule(
|
std::unique_ptr<NativeModule> ret(
|
||||||
isolate, can_request_more, &mem, this, std::move(module), env));
|
new NativeModule(isolate, enabled, can_request_more, &mem, this,
|
||||||
|
std::move(module), env));
|
||||||
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", this, start,
|
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", this, start,
|
||||||
size);
|
size);
|
||||||
base::LockGuard<base::Mutex> lock(&native_modules_mutex_);
|
base::LockGuard<base::Mutex> lock(&native_modules_mutex_);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "src/trap-handler/trap-handler.h"
|
#include "src/trap-handler/trap-handler.h"
|
||||||
#include "src/vector.h"
|
#include "src/vector.h"
|
||||||
#include "src/wasm/module-compiler.h"
|
#include "src/wasm/module-compiler.h"
|
||||||
|
#include "src/wasm/wasm-features.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -345,13 +346,16 @@ class V8_EXPORT_PRIVATE NativeModule final {
|
|||||||
|
|
||||||
~NativeModule();
|
~NativeModule();
|
||||||
|
|
||||||
|
const WasmFeatures& enabled_features() const { return enabled_features_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class WasmCode;
|
friend class WasmCode;
|
||||||
friend class WasmCodeManager;
|
friend class WasmCodeManager;
|
||||||
friend class NativeModuleModificationScope;
|
friend class NativeModuleModificationScope;
|
||||||
|
|
||||||
NativeModule(Isolate* isolate, bool can_request_more,
|
NativeModule(Isolate* isolate, const WasmFeatures& enabled_features,
|
||||||
VirtualMemory* code_space, WasmCodeManager* code_manager,
|
bool can_request_more, VirtualMemory* code_space,
|
||||||
|
WasmCodeManager* code_manager,
|
||||||
std::shared_ptr<const WasmModule> module, const ModuleEnv& env);
|
std::shared_ptr<const WasmModule> module, const ModuleEnv& env);
|
||||||
|
|
||||||
WasmCode* AddAnonymousCode(Handle<Code>, WasmCode::Kind kind);
|
WasmCode* AddAnonymousCode(Handle<Code>, WasmCode::Kind kind);
|
||||||
@ -385,6 +389,11 @@ class V8_EXPORT_PRIVATE NativeModule final {
|
|||||||
code_table_[index - module_->num_imported_functions] = code;
|
code_table_[index - module_->num_imported_functions] = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Features enabled for this module. We keep a copy of the features that
|
||||||
|
// were enabled at the time of the creation of this native module,
|
||||||
|
// to be consistent across asynchronous compilations later.
|
||||||
|
const WasmFeatures enabled_features_;
|
||||||
|
|
||||||
// TODO(clemensh): Make this a unique_ptr (requires refactoring
|
// TODO(clemensh): Make this a unique_ptr (requires refactoring
|
||||||
// AsyncCompileJob).
|
// AsyncCompileJob).
|
||||||
std::shared_ptr<const WasmModule> module_;
|
std::shared_ptr<const WasmModule> module_;
|
||||||
@ -435,7 +444,8 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
|
|||||||
// code. The native module may later request more memory.
|
// code. The native module may later request more memory.
|
||||||
// TODO(titzer): isolate is only required here for CompilationState.
|
// TODO(titzer): isolate is only required here for CompilationState.
|
||||||
std::unique_ptr<NativeModule> NewNativeModule(
|
std::unique_ptr<NativeModule> NewNativeModule(
|
||||||
Isolate* isolate, size_t memory_estimate, bool can_request_more,
|
Isolate* isolate, const WasmFeatures& enabled_features,
|
||||||
|
size_t memory_estimate, bool can_request_more,
|
||||||
std::shared_ptr<const WasmModule> module, const ModuleEnv& env);
|
std::shared_ptr<const WasmModule> module, const ModuleEnv& env);
|
||||||
|
|
||||||
NativeModule* LookupNativeModule(Address pc) const;
|
NativeModule* LookupNativeModule(Address pc) const;
|
||||||
|
@ -25,11 +25,12 @@ WasmEngine::~WasmEngine() {
|
|||||||
DCHECK(jobs_.empty());
|
DCHECK(jobs_.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WasmEngine::SyncValidate(Isolate* isolate, const ModuleWireBytes& bytes) {
|
bool WasmEngine::SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
|
||||||
|
const ModuleWireBytes& bytes) {
|
||||||
// TODO(titzer): remove dependency on the isolate.
|
// TODO(titzer): remove dependency on the isolate.
|
||||||
if (bytes.start() == nullptr || bytes.length() == 0) return false;
|
if (bytes.start() == nullptr || bytes.length() == 0) return false;
|
||||||
ModuleResult result =
|
ModuleResult result =
|
||||||
DecodeWasmModule(bytes.start(), bytes.end(), true, kWasmOrigin,
|
DecodeWasmModule(enabled, bytes.start(), bytes.end(), true, kWasmOrigin,
|
||||||
isolate->counters(), allocator());
|
isolate->counters(), allocator());
|
||||||
return result.ok();
|
return result.ok();
|
||||||
}
|
}
|
||||||
@ -39,20 +40,22 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompileTranslatedAsmJs(
|
|||||||
Handle<Script> asm_js_script,
|
Handle<Script> asm_js_script,
|
||||||
Vector<const byte> asm_js_offset_table_bytes) {
|
Vector<const byte> asm_js_offset_table_bytes) {
|
||||||
ModuleResult result =
|
ModuleResult result =
|
||||||
DecodeWasmModule(bytes.start(), bytes.end(), false, kAsmJsOrigin,
|
DecodeWasmModule(kAsmjsWasmFeatures, bytes.start(), bytes.end(), false,
|
||||||
isolate->counters(), allocator());
|
kAsmJsOrigin, isolate->counters(), allocator());
|
||||||
CHECK(!result.failed());
|
CHECK(!result.failed());
|
||||||
|
|
||||||
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
|
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
|
||||||
// in {CompileToModuleObject}.
|
// in {CompileToModuleObject}.
|
||||||
return CompileToModuleObject(isolate, thrower, std::move(result.val), bytes,
|
return CompileToModuleObject(isolate, kAsmjsWasmFeatures, thrower,
|
||||||
asm_js_script, asm_js_offset_table_bytes);
|
std::move(result.val), bytes, asm_js_script,
|
||||||
|
asm_js_offset_table_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
|
MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
|
||||||
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) {
|
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
|
||||||
|
const ModuleWireBytes& bytes) {
|
||||||
ModuleResult result =
|
ModuleResult result =
|
||||||
DecodeWasmModule(bytes.start(), bytes.end(), false, kWasmOrigin,
|
DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
|
||||||
isolate->counters(), allocator());
|
isolate->counters(), allocator());
|
||||||
if (result.failed()) {
|
if (result.failed()) {
|
||||||
thrower->CompileFailed("Wasm decoding failed", result);
|
thrower->CompileFailed("Wasm decoding failed", result);
|
||||||
@ -61,8 +64,8 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
|
|||||||
|
|
||||||
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
|
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
|
||||||
// in {CompileToModuleObject}.
|
// in {CompileToModuleObject}.
|
||||||
return CompileToModuleObject(isolate, thrower, std::move(result.val), bytes,
|
return CompileToModuleObject(isolate, enabled, thrower, std::move(result.val),
|
||||||
Handle<Script>(), Vector<const byte>());
|
bytes, Handle<Script>(), Vector<const byte>());
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate(
|
MaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate(
|
||||||
@ -109,7 +112,8 @@ void WasmEngine::AsyncInstantiate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WasmEngine::AsyncCompile(
|
void WasmEngine::AsyncCompile(
|
||||||
Isolate* isolate, std::unique_ptr<CompilationResultResolver> resolver,
|
Isolate* isolate, const WasmFeatures& enabled,
|
||||||
|
std::unique_ptr<CompilationResultResolver> resolver,
|
||||||
const ModuleWireBytes& bytes, bool is_shared) {
|
const ModuleWireBytes& bytes, bool is_shared) {
|
||||||
if (!FLAG_wasm_async_compilation) {
|
if (!FLAG_wasm_async_compilation) {
|
||||||
// Asynchronous compilation disabled; fall back on synchronous compilation.
|
// Asynchronous compilation disabled; fall back on synchronous compilation.
|
||||||
@ -120,10 +124,10 @@ void WasmEngine::AsyncCompile(
|
|||||||
std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
|
std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
|
||||||
memcpy(copy.get(), bytes.start(), bytes.length());
|
memcpy(copy.get(), bytes.start(), bytes.length());
|
||||||
ModuleWireBytes bytes_copy(copy.get(), copy.get() + bytes.length());
|
ModuleWireBytes bytes_copy(copy.get(), copy.get() + bytes.length());
|
||||||
module_object = SyncCompile(isolate, &thrower, bytes_copy);
|
module_object = SyncCompile(isolate, enabled, &thrower, bytes_copy);
|
||||||
} else {
|
} else {
|
||||||
// The wire bytes are not shared, OK to use them directly.
|
// The wire bytes are not shared, OK to use them directly.
|
||||||
module_object = SyncCompile(isolate, &thrower, bytes);
|
module_object = SyncCompile(isolate, enabled, &thrower, bytes);
|
||||||
}
|
}
|
||||||
if (thrower.error()) {
|
if (thrower.error()) {
|
||||||
resolver->OnCompilationFailed(thrower.Reify());
|
resolver->OnCompilationFailed(thrower.Reify());
|
||||||
@ -136,8 +140,9 @@ void WasmEngine::AsyncCompile(
|
|||||||
|
|
||||||
if (FLAG_wasm_test_streaming) {
|
if (FLAG_wasm_test_streaming) {
|
||||||
std::shared_ptr<StreamingDecoder> streaming_decoder =
|
std::shared_ptr<StreamingDecoder> streaming_decoder =
|
||||||
isolate->wasm_engine()->StartStreamingCompilation(
|
StartStreamingCompilation(isolate, enabled,
|
||||||
isolate, handle(isolate->context(), isolate), std::move(resolver));
|
handle(isolate->context(), isolate),
|
||||||
|
std::move(resolver));
|
||||||
streaming_decoder->OnBytesReceived(bytes.module_bytes());
|
streaming_decoder->OnBytesReceived(bytes.module_bytes());
|
||||||
streaming_decoder->Finish();
|
streaming_decoder->Finish();
|
||||||
return;
|
return;
|
||||||
@ -148,17 +153,17 @@ void WasmEngine::AsyncCompile(
|
|||||||
memcpy(copy.get(), bytes.start(), bytes.length());
|
memcpy(copy.get(), bytes.start(), bytes.length());
|
||||||
|
|
||||||
AsyncCompileJob* job = CreateAsyncCompileJob(
|
AsyncCompileJob* job = CreateAsyncCompileJob(
|
||||||
isolate, std::move(copy), bytes.length(),
|
isolate, enabled, std::move(copy), bytes.length(),
|
||||||
handle(isolate->context(), isolate), std::move(resolver));
|
handle(isolate->context(), isolate), std::move(resolver));
|
||||||
job->Start();
|
job->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
|
std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
|
||||||
Isolate* isolate, Handle<Context> context,
|
Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
|
||||||
std::unique_ptr<CompilationResultResolver> resolver) {
|
std::unique_ptr<CompilationResultResolver> resolver) {
|
||||||
AsyncCompileJob* job =
|
AsyncCompileJob* job =
|
||||||
CreateAsyncCompileJob(isolate, std::unique_ptr<byte[]>(nullptr), 0,
|
CreateAsyncCompileJob(isolate, enabled, std::unique_ptr<byte[]>(nullptr),
|
||||||
context, std::move(resolver));
|
0, context, std::move(resolver));
|
||||||
return job->CreateStreamingDecoder();
|
return job->CreateStreamingDecoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,11 +212,12 @@ CodeTracer* WasmEngine::GetCodeTracer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
|
AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
|
||||||
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
|
Isolate* isolate, const WasmFeatures& enabled,
|
||||||
Handle<Context> context,
|
std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
|
||||||
std::unique_ptr<CompilationResultResolver> resolver) {
|
std::unique_ptr<CompilationResultResolver> resolver) {
|
||||||
AsyncCompileJob* job = new AsyncCompileJob(
|
AsyncCompileJob* job =
|
||||||
isolate, std::move(bytes_copy), length, context, std::move(resolver));
|
new AsyncCompileJob(isolate, enabled, std::move(bytes_copy), length,
|
||||||
|
context, std::move(resolver));
|
||||||
// Pass ownership to the unique_ptr in {jobs_}.
|
// Pass ownership to the unique_ptr in {jobs_}.
|
||||||
base::LockGuard<base::Mutex> guard(&mutex_);
|
base::LockGuard<base::Mutex> guard(&mutex_);
|
||||||
jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);
|
jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);
|
||||||
|
@ -22,6 +22,7 @@ class WasmInstanceObject;
|
|||||||
namespace wasm {
|
namespace wasm {
|
||||||
|
|
||||||
class ErrorThrower;
|
class ErrorThrower;
|
||||||
|
struct WasmFeatures;
|
||||||
struct ModuleWireBytes;
|
struct ModuleWireBytes;
|
||||||
|
|
||||||
class V8_EXPORT_PRIVATE CompilationResultResolver {
|
class V8_EXPORT_PRIVATE CompilationResultResolver {
|
||||||
@ -47,7 +48,8 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
|
|
||||||
// Synchronously validates the given bytes that represent an encoded WASM
|
// Synchronously validates the given bytes that represent an encoded WASM
|
||||||
// module.
|
// module.
|
||||||
bool SyncValidate(Isolate* isolate, const ModuleWireBytes& bytes);
|
bool SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
|
||||||
|
const ModuleWireBytes& bytes);
|
||||||
|
|
||||||
// Synchronously compiles the given bytes that represent a translated
|
// Synchronously compiles the given bytes that represent a translated
|
||||||
// asm.js module.
|
// asm.js module.
|
||||||
@ -59,6 +61,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
// Synchronously compiles the given bytes that represent an encoded WASM
|
// Synchronously compiles the given bytes that represent an encoded WASM
|
||||||
// module.
|
// module.
|
||||||
MaybeHandle<WasmModuleObject> SyncCompile(Isolate* isolate,
|
MaybeHandle<WasmModuleObject> SyncCompile(Isolate* isolate,
|
||||||
|
const WasmFeatures& enabled,
|
||||||
ErrorThrower* thrower,
|
ErrorThrower* thrower,
|
||||||
const ModuleWireBytes& bytes);
|
const ModuleWireBytes& bytes);
|
||||||
|
|
||||||
@ -74,7 +77,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
// encoded WASM module.
|
// encoded WASM module.
|
||||||
// The {is_shared} flag indicates if the bytes backing the module could
|
// The {is_shared} flag indicates if the bytes backing the module could
|
||||||
// be shared across threads, i.e. could be concurrently modified.
|
// be shared across threads, i.e. could be concurrently modified.
|
||||||
void AsyncCompile(Isolate* isolate,
|
void AsyncCompile(Isolate* isolate, const WasmFeatures& enabled,
|
||||||
std::unique_ptr<CompilationResultResolver> resolver,
|
std::unique_ptr<CompilationResultResolver> resolver,
|
||||||
const ModuleWireBytes& bytes, bool is_shared);
|
const ModuleWireBytes& bytes, bool is_shared);
|
||||||
|
|
||||||
@ -85,7 +88,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
MaybeHandle<JSReceiver> imports);
|
MaybeHandle<JSReceiver> imports);
|
||||||
|
|
||||||
std::shared_ptr<StreamingDecoder> StartStreamingCompilation(
|
std::shared_ptr<StreamingDecoder> StartStreamingCompilation(
|
||||||
Isolate* isolate, Handle<Context> context,
|
Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
|
||||||
std::unique_ptr<CompilationResultResolver> resolver);
|
std::unique_ptr<CompilationResultResolver> resolver);
|
||||||
|
|
||||||
// Exports the sharable parts of the given module object so that they can be
|
// Exports the sharable parts of the given module object so that they can be
|
||||||
@ -140,7 +143,8 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
AsyncCompileJob* CreateAsyncCompileJob(
|
AsyncCompileJob* CreateAsyncCompileJob(
|
||||||
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
|
Isolate* isolate, const WasmFeatures& enabled,
|
||||||
|
std::unique_ptr<byte[]> bytes_copy, size_t length,
|
||||||
Handle<Context> context,
|
Handle<Context> context,
|
||||||
std::unique_ptr<CompilationResultResolver> resolver);
|
std::unique_ptr<CompilationResultResolver> resolver);
|
||||||
|
|
||||||
|
26
src/wasm/wasm-feature-flags.h
Normal file
26
src/wasm/wasm-feature-flags.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
#ifndef V8_WASM_WASM_FEATURE_FLAGS_H_
|
||||||
|
#define V8_WASM_WASM_FEATURE_FLAGS_H_
|
||||||
|
|
||||||
|
// The SEPARATOR argument allows generating proper comma-separated lists.
|
||||||
|
#define FOREACH_WASM_FEATURE_FLAG(V, SEPARATOR) \
|
||||||
|
V(mv, "multi-value support", false) \
|
||||||
|
SEPARATOR \
|
||||||
|
V(eh, "exception handling opcodes", false) \
|
||||||
|
SEPARATOR \
|
||||||
|
V(se, "sign extension opcodes", true) \
|
||||||
|
SEPARATOR \
|
||||||
|
V(sat_f2i_conversions, "saturating float conversion opcodes", false) \
|
||||||
|
SEPARATOR \
|
||||||
|
V(threads, "thread opcodes", false) \
|
||||||
|
SEPARATOR \
|
||||||
|
V(simd, "SIMD opcodes", false) \
|
||||||
|
SEPARATOR \
|
||||||
|
V(anyref, "anyref opcodes", false) \
|
||||||
|
SEPARATOR \
|
||||||
|
V(mut_global, "import/export mutable global support", true)
|
||||||
|
|
||||||
|
#endif // V8_WASM_WASM_FEATURE_FLAGS_H_
|
38
src/wasm/wasm-features.cc
Normal file
38
src/wasm/wasm-features.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2018 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/wasm/wasm-features.h"
|
||||||
|
#include "src/flags.h"
|
||||||
|
#include "src/isolate.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
namespace wasm {
|
||||||
|
|
||||||
|
#define COMMA ,
|
||||||
|
#define SPACE
|
||||||
|
#define DO_UNION(feat, desc, val) dst->feat |= src->feat;
|
||||||
|
#define FLAG_REF(feat, desc, val) FLAG_experimental_wasm_##feat
|
||||||
|
|
||||||
|
void UnionFeaturesInto(WasmFeatures* dst, WasmFeatures* src) {
|
||||||
|
FOREACH_WASM_FEATURE(DO_UNION, SPACE)
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
inline WasmFeatures WasmFeaturesFromFlags() {
|
||||||
|
return WasmFeatures{FOREACH_WASM_FEATURE(FLAG_REF, COMMA)};
|
||||||
|
}
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate) {
|
||||||
|
return WasmFeaturesFromFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef DO_UNION
|
||||||
|
#undef FLAG_REF
|
||||||
|
#undef SPACE
|
||||||
|
#undef COMMA
|
||||||
|
} // namespace wasm
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
61
src/wasm/wasm-features.h
Normal file
61
src/wasm/wasm-features.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
#ifndef V8_WASM_WASM_FEATURES_H_
|
||||||
|
#define V8_WASM_WASM_FEATURES_H_
|
||||||
|
|
||||||
|
// The feature flags are declared in their own header.
|
||||||
|
#include "src/base/macros.h"
|
||||||
|
#include "src/wasm/wasm-feature-flags.h"
|
||||||
|
|
||||||
|
// All features, including features that do not have flags.
|
||||||
|
#define FOREACH_WASM_FEATURE FOREACH_WASM_FEATURE_FLAG
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
class Isolate;
|
||||||
|
namespace wasm {
|
||||||
|
|
||||||
|
#define COMMA ,
|
||||||
|
#define SPACE
|
||||||
|
#define DECL_FIELD(feat, desc, val) bool feat = false;
|
||||||
|
#define JUST_TRUE(feat, desc, val) true
|
||||||
|
#define JUST_FALSE(feat, desc, val) false
|
||||||
|
#define DECL_PARAM(feat, desc, val) bool p##feat
|
||||||
|
#define DO_INIT(feat, desc, val) feat(p##feat)
|
||||||
|
|
||||||
|
// Enabled or detected features.
|
||||||
|
struct WasmFeatures {
|
||||||
|
FOREACH_WASM_FEATURE(DECL_FIELD, SPACE)
|
||||||
|
|
||||||
|
constexpr WasmFeatures() = default;
|
||||||
|
|
||||||
|
explicit constexpr WasmFeatures(FOREACH_WASM_FEATURE(DECL_PARAM, COMMA))
|
||||||
|
: FOREACH_WASM_FEATURE(DO_INIT, COMMA) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr WasmFeatures kAllWasmFeatures{
|
||||||
|
FOREACH_WASM_FEATURE(JUST_TRUE, COMMA)};
|
||||||
|
|
||||||
|
static constexpr WasmFeatures kNoWasmFeatures{
|
||||||
|
FOREACH_WASM_FEATURE(JUST_FALSE, COMMA)};
|
||||||
|
|
||||||
|
#undef JUST_TRUE
|
||||||
|
#undef JUST_FALSE
|
||||||
|
#undef DECL_FIELD
|
||||||
|
#undef DECL_PARAM
|
||||||
|
#undef DO_INIT
|
||||||
|
#undef COMMA
|
||||||
|
#undef SPACE
|
||||||
|
|
||||||
|
static constexpr WasmFeatures kAsmjsWasmFeatures = kNoWasmFeatures;
|
||||||
|
|
||||||
|
V8_EXPORT_PRIVATE WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate);
|
||||||
|
V8_EXPORT_PRIVATE void UnionFeaturesInto(WasmFeatures* dst, WasmFeatures* src);
|
||||||
|
|
||||||
|
} // namespace wasm
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
||||||
|
|
||||||
|
#endif // V8_WASM_WASM_FEATURES_H_
|
@ -786,7 +786,8 @@ class SideTable : public ZoneObject {
|
|||||||
case kExprBlock:
|
case kExprBlock:
|
||||||
case kExprLoop: {
|
case kExprLoop: {
|
||||||
bool is_loop = opcode == kExprLoop;
|
bool is_loop = opcode == kExprLoop;
|
||||||
BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
|
||||||
|
i.pc());
|
||||||
if (imm.type == kWasmVar) {
|
if (imm.type == kWasmVar) {
|
||||||
imm.sig = module->signatures[imm.sig_index];
|
imm.sig = module->signatures[imm.sig_index];
|
||||||
}
|
}
|
||||||
@ -801,7 +802,8 @@ class SideTable : public ZoneObject {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprIf: {
|
case kExprIf: {
|
||||||
BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
|
||||||
|
i.pc());
|
||||||
if (imm.type == kWasmVar) {
|
if (imm.type == kWasmVar) {
|
||||||
imm.sig = module->signatures[imm.sig_index];
|
imm.sig = module->signatures[imm.sig_index];
|
||||||
}
|
}
|
||||||
@ -1664,7 +1666,6 @@ class ThreadImpl {
|
|||||||
|
|
||||||
byte* GetGlobalPtr(const WasmGlobal* global) {
|
byte* GetGlobalPtr(const WasmGlobal* global) {
|
||||||
if (global->mutability && global->imported) {
|
if (global->mutability && global->imported) {
|
||||||
DCHECK(FLAG_experimental_wasm_mut_global);
|
|
||||||
return reinterpret_cast<byte*>(
|
return reinterpret_cast<byte*>(
|
||||||
instance_object_->imported_mutable_globals()[global->index]);
|
instance_object_->imported_mutable_globals()[global->index]);
|
||||||
} else {
|
} else {
|
||||||
@ -2133,17 +2134,20 @@ class ThreadImpl {
|
|||||||
case kExprNop:
|
case kExprNop:
|
||||||
break;
|
break;
|
||||||
case kExprBlock: {
|
case kExprBlock: {
|
||||||
BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
|
||||||
|
&decoder, code->at(pc));
|
||||||
len = 1 + imm.length;
|
len = 1 + imm.length;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprLoop: {
|
case kExprLoop: {
|
||||||
BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
|
||||||
|
&decoder, code->at(pc));
|
||||||
len = 1 + imm.length;
|
len = 1 + imm.length;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kExprIf: {
|
case kExprIf: {
|
||||||
BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
|
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
|
||||||
|
&decoder, code->at(pc));
|
||||||
WasmValue cond = Pop();
|
WasmValue cond = Pop();
|
||||||
bool is_true = cond.to<uint32_t>() != 0;
|
bool is_true = cond.to<uint32_t>() != 0;
|
||||||
if (is_true) {
|
if (is_true) {
|
||||||
|
@ -400,8 +400,9 @@ void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Asynchronous compilation handles copying wire bytes if necessary.
|
// Asynchronous compilation handles copying wire bytes if necessary.
|
||||||
i_isolate->wasm_engine()->AsyncCompile(i_isolate, std::move(resolver), bytes,
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
is_shared);
|
i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
|
||||||
|
std::move(resolver), bytes, is_shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebAssembly.validate(bytes) -> bool
|
// WebAssembly.validate(bytes) -> bool
|
||||||
@ -422,6 +423,7 @@ void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
bool validated = false;
|
bool validated = false;
|
||||||
if (is_shared) {
|
if (is_shared) {
|
||||||
// Make a copy of the wire bytes to avoid concurrent modification.
|
// Make a copy of the wire bytes to avoid concurrent modification.
|
||||||
@ -429,10 +431,12 @@ void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
memcpy(copy.get(), bytes.start(), bytes.length());
|
memcpy(copy.get(), bytes.start(), bytes.length());
|
||||||
i::wasm::ModuleWireBytes bytes_copy(copy.get(),
|
i::wasm::ModuleWireBytes bytes_copy(copy.get(),
|
||||||
copy.get() + bytes.length());
|
copy.get() + bytes.length());
|
||||||
validated = i_isolate->wasm_engine()->SyncValidate(i_isolate, bytes_copy);
|
validated = i_isolate->wasm_engine()->SyncValidate(
|
||||||
|
i_isolate, enabled_features, bytes_copy);
|
||||||
} else {
|
} else {
|
||||||
// The wire bytes are not shared, OK to use them directly.
|
// The wire bytes are not shared, OK to use them directly.
|
||||||
validated = i_isolate->wasm_engine()->SyncValidate(i_isolate, bytes);
|
validated = i_isolate->wasm_engine()->SyncValidate(i_isolate,
|
||||||
|
enabled_features, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return_value.Set(Boolean::New(isolate, validated));
|
return_value.Set(Boolean::New(isolate, validated));
|
||||||
@ -462,6 +466,7 @@ void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
if (thrower.error()) {
|
if (thrower.error()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
i::MaybeHandle<i::Object> module_obj;
|
i::MaybeHandle<i::Object> module_obj;
|
||||||
if (is_shared) {
|
if (is_shared) {
|
||||||
// Make a copy of the wire bytes to avoid concurrent modification.
|
// Make a copy of the wire bytes to avoid concurrent modification.
|
||||||
@ -469,12 +474,12 @@ void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
memcpy(copy.get(), bytes.start(), bytes.length());
|
memcpy(copy.get(), bytes.start(), bytes.length());
|
||||||
i::wasm::ModuleWireBytes bytes_copy(copy.get(),
|
i::wasm::ModuleWireBytes bytes_copy(copy.get(),
|
||||||
copy.get() + bytes.length());
|
copy.get() + bytes.length());
|
||||||
module_obj =
|
module_obj = i_isolate->wasm_engine()->SyncCompile(
|
||||||
i_isolate->wasm_engine()->SyncCompile(i_isolate, &thrower, bytes_copy);
|
i_isolate, enabled_features, &thrower, bytes_copy);
|
||||||
} else {
|
} else {
|
||||||
// The wire bytes are not shared, OK to use them directly.
|
// The wire bytes are not shared, OK to use them directly.
|
||||||
module_obj =
|
module_obj = i_isolate->wasm_engine()->SyncCompile(
|
||||||
i_isolate->wasm_engine()->SyncCompile(i_isolate, &thrower, bytes);
|
i_isolate, enabled_features, &thrower, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module_obj.is_null()) return;
|
if (module_obj.is_null()) return;
|
||||||
@ -732,8 +737,10 @@ void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Asynchronous compilation handles copying wire bytes if necessary.
|
// Asynchronous compilation handles copying wire bytes if necessary.
|
||||||
i_isolate->wasm_engine()->AsyncCompile(
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
i_isolate, std::move(compilation_resolver), bytes, is_shared);
|
i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
|
||||||
|
std::move(compilation_resolver), bytes,
|
||||||
|
is_shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
|
bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
|
||||||
@ -855,7 +862,8 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_shared_memory = false;
|
bool is_shared_memory = false;
|
||||||
if (i::FLAG_experimental_wasm_threads) {
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
|
if (enabled_features.threads) {
|
||||||
// Shared property of descriptor
|
// Shared property of descriptor
|
||||||
Local<String> shared_key = v8_str(isolate, "shared");
|
Local<String> shared_key = v8_str(isolate, "shared");
|
||||||
Maybe<bool> has_shared = descriptor->Has(context, shared_key);
|
Maybe<bool> has_shared = descriptor->Has(context, shared_key);
|
||||||
@ -1468,7 +1476,8 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
|
|||||||
v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
|
v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
|
||||||
|
|
||||||
// Setup Global
|
// Setup Global
|
||||||
if (i::FLAG_experimental_wasm_mut_global) {
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
|
||||||
|
if (enabled_features.mut_global) {
|
||||||
Handle<JSFunction> global_constructor =
|
Handle<JSFunction> global_constructor =
|
||||||
InstallFunc(isolate, webassembly, "Global", WebAssemblyGlobal, 1);
|
InstallFunc(isolate, webassembly, "Global", WebAssemblyGlobal, 1);
|
||||||
context->set_wasm_global_constructor(*global_constructor);
|
context->set_wasm_global_constructor(*global_constructor);
|
||||||
|
@ -240,7 +240,6 @@ Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store,
|
|||||||
SharedFlag shared) {
|
SharedFlag shared) {
|
||||||
Handle<JSArrayBuffer> buffer =
|
Handle<JSArrayBuffer> buffer =
|
||||||
isolate->factory()->NewJSArrayBuffer(shared, TENURED);
|
isolate->factory()->NewJSArrayBuffer(shared, TENURED);
|
||||||
if (shared == SharedFlag::kShared) DCHECK(FLAG_experimental_wasm_threads);
|
|
||||||
constexpr bool is_wasm_memory = true;
|
constexpr bool is_wasm_memory = true;
|
||||||
JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store, size,
|
JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store, size,
|
||||||
shared, is_wasm_memory);
|
shared, is_wasm_memory);
|
||||||
|
@ -178,9 +178,10 @@ enum DispatchTableElements : int {
|
|||||||
|
|
||||||
// static
|
// static
|
||||||
Handle<WasmModuleObject> WasmModuleObject::New(
|
Handle<WasmModuleObject> WasmModuleObject::New(
|
||||||
Isolate* isolate, std::shared_ptr<const wasm::WasmModule> shared_module,
|
Isolate* isolate, const wasm::WasmFeatures& enabled,
|
||||||
wasm::ModuleEnv& env, OwnedVector<const uint8_t> wire_bytes,
|
std::shared_ptr<const wasm::WasmModule> shared_module, wasm::ModuleEnv& env,
|
||||||
Handle<Script> script, Handle<ByteArray> asm_js_offset_table) {
|
OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
|
||||||
|
Handle<ByteArray> asm_js_offset_table) {
|
||||||
DCHECK_EQ(shared_module.get(), env.module);
|
DCHECK_EQ(shared_module.get(), env.module);
|
||||||
|
|
||||||
// Create a new {NativeModule} first.
|
// Create a new {NativeModule} first.
|
||||||
@ -188,7 +189,7 @@ Handle<WasmModuleObject> WasmModuleObject::New(
|
|||||||
isolate->wasm_engine()->code_manager()->EstimateNativeModuleSize(
|
isolate->wasm_engine()->code_manager()->EstimateNativeModuleSize(
|
||||||
env.module);
|
env.module);
|
||||||
auto native_module = isolate->wasm_engine()->code_manager()->NewNativeModule(
|
auto native_module = isolate->wasm_engine()->code_manager()->NewNativeModule(
|
||||||
isolate, native_memory_estimate,
|
isolate, enabled, native_memory_estimate,
|
||||||
wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module),
|
wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module),
|
||||||
env);
|
env);
|
||||||
native_module->set_wire_bytes(std::move(wire_bytes));
|
native_module->set_wire_bytes(std::move(wire_bytes));
|
||||||
|
@ -30,6 +30,7 @@ class SignatureMap;
|
|||||||
class WireBytesRef;
|
class WireBytesRef;
|
||||||
class WasmInterpreter;
|
class WasmInterpreter;
|
||||||
using FunctionSig = Signature<ValueType>;
|
using FunctionSig = Signature<ValueType>;
|
||||||
|
struct WasmFeatures;
|
||||||
} // namespace wasm
|
} // namespace wasm
|
||||||
|
|
||||||
class BreakPoint;
|
class BreakPoint;
|
||||||
@ -133,9 +134,10 @@ class WasmModuleObject : public JSObject {
|
|||||||
|
|
||||||
// Creates a new {WasmModuleObject} with a new {NativeModule} underneath.
|
// Creates a new {WasmModuleObject} with a new {NativeModule} underneath.
|
||||||
static Handle<WasmModuleObject> New(
|
static Handle<WasmModuleObject> New(
|
||||||
Isolate* isolate, std::shared_ptr<const wasm::WasmModule> module,
|
Isolate* isolate, const wasm::WasmFeatures& enabled,
|
||||||
wasm::ModuleEnv& env, OwnedVector<const uint8_t> wire_bytes,
|
std::shared_ptr<const wasm::WasmModule> module, wasm::ModuleEnv& env,
|
||||||
Handle<Script> script, Handle<ByteArray> asm_js_offset_table);
|
OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
|
||||||
|
Handle<ByteArray> asm_js_offset_table);
|
||||||
|
|
||||||
// Creates a new {WasmModuleObject} for an existing {NativeModule} that is
|
// Creates a new {WasmModuleObject} for an existing {NativeModule} that is
|
||||||
// reference counted and might be shared between multiple Isolates.
|
// reference counted and might be shared between multiple Isolates.
|
||||||
|
@ -545,9 +545,11 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
|
|||||||
if (!IsSupportedVersion(isolate, data)) {
|
if (!IsSupportedVersion(isolate, data)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
// TODO(titzer): module features should be part of the serialization format.
|
||||||
|
WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
|
||||||
ModuleResult decode_result = DecodeWasmModule(
|
ModuleResult decode_result = DecodeWasmModule(
|
||||||
wire_bytes.start(), wire_bytes.end(), false, i::wasm::kWasmOrigin,
|
enabled_features, wire_bytes.start(), wire_bytes.end(), false,
|
||||||
isolate->counters(), isolate->allocator());
|
i::wasm::kWasmOrigin, isolate->counters(), isolate->allocator());
|
||||||
if (!decode_result.ok()) return {};
|
if (!decode_result.ok()) return {};
|
||||||
CHECK_NOT_NULL(decode_result.val);
|
CHECK_NOT_NULL(decode_result.val);
|
||||||
WasmModule* module = decode_result.val.get();
|
WasmModule* module = decode_result.val.get();
|
||||||
@ -563,8 +565,8 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
|
|||||||
OwnedVector<uint8_t> wire_bytes_copy = OwnedVector<uint8_t>::Of(wire_bytes);
|
OwnedVector<uint8_t> wire_bytes_copy = OwnedVector<uint8_t>::Of(wire_bytes);
|
||||||
|
|
||||||
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
|
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
|
||||||
isolate, std::move(decode_result.val), env, std::move(wire_bytes_copy),
|
isolate, enabled_features, std::move(decode_result.val), env,
|
||||||
script, Handle<ByteArray>::null());
|
std::move(wire_bytes_copy), script, Handle<ByteArray>::null());
|
||||||
NativeModule* native_module = module_object->native_module();
|
NativeModule* native_module = module_object->native_module();
|
||||||
|
|
||||||
if (FLAG_wasm_lazy_compilation) {
|
if (FLAG_wasm_lazy_compilation) {
|
||||||
|
@ -100,7 +100,8 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
|
|||||||
case kExprIf:
|
case kExprIf:
|
||||||
case kExprBlock:
|
case kExprBlock:
|
||||||
case kExprTry: {
|
case kExprTry: {
|
||||||
BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
|
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
|
||||||
|
i.pc());
|
||||||
os << WasmOpcodes::OpcodeName(opcode);
|
os << WasmOpcodes::OpcodeName(opcode);
|
||||||
if (imm.type == kWasmVar) {
|
if (imm.type == kWasmVar) {
|
||||||
os << " (type " << imm.sig_index << ")";
|
os << " (type " << imm.sig_index << ")";
|
||||||
|
@ -130,7 +130,8 @@ std::unique_ptr<wasm::NativeModule> AllocateNativeModule(Isolate* isolate,
|
|||||||
// WasmCallDescriptor assumes that code is on the native heap and not
|
// WasmCallDescriptor assumes that code is on the native heap and not
|
||||||
// within a code object.
|
// within a code object.
|
||||||
return isolate->wasm_engine()->code_manager()->NewNativeModule(
|
return isolate->wasm_engine()->code_manager()->NewNativeModule(
|
||||||
isolate, code_size, false, std::move(module), env);
|
isolate, wasm::kAllWasmFeatures, code_size, false, std::move(module),
|
||||||
|
env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestReturnMultipleValues(MachineType type) {
|
void TestReturnMultipleValues(MachineType type) {
|
||||||
|
@ -886,9 +886,11 @@ TEST(AtomicOpDisassembly) {
|
|||||||
testing::SetupIsolateForWasmModule(isolate);
|
testing::SetupIsolateForWasmModule(isolate);
|
||||||
|
|
||||||
ErrorThrower thrower(isolate, "Test");
|
ErrorThrower thrower(isolate, "Test");
|
||||||
|
auto enabled_features = WasmFeaturesFromIsolate(isolate);
|
||||||
MaybeHandle<WasmModuleObject> module_object =
|
MaybeHandle<WasmModuleObject> module_object =
|
||||||
isolate->wasm_engine()->SyncCompile(
|
isolate->wasm_engine()->SyncCompile(
|
||||||
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
|
isolate, enabled_features, &thrower,
|
||||||
|
ModuleWireBytes(buffer.begin(), buffer.end()));
|
||||||
|
|
||||||
module_object.ToHandleChecked()->DisassembleFunction(0);
|
module_object.ToHandleChecked()->DisassembleFunction(0);
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ class StreamTester {
|
|||||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||||
|
|
||||||
stream_ = i_isolate->wasm_engine()->StartStreamingCompilation(
|
stream_ = i_isolate->wasm_engine()->StartStreamingCompilation(
|
||||||
i_isolate, v8::Utils::OpenHandle(*context),
|
i_isolate, kAllWasmFeatures, v8::Utils::OpenHandle(*context),
|
||||||
base::make_unique<TestResolver>(&state_));
|
base::make_unique<TestResolver>(&state_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,9 +212,9 @@ STREAM_TEST(TestAllBytesArriveAOTCompilerFinishesFirst) {
|
|||||||
|
|
||||||
size_t GetFunctionOffset(i::Isolate* isolate, const uint8_t* buffer,
|
size_t GetFunctionOffset(i::Isolate* isolate, const uint8_t* buffer,
|
||||||
size_t size, size_t index) {
|
size_t size, size_t index) {
|
||||||
ModuleResult result =
|
ModuleResult result = DecodeWasmModule(
|
||||||
DecodeWasmModule(buffer, buffer + size, false, ModuleOrigin::kWasmOrigin,
|
kAllWasmFeatures, buffer, buffer + size, false, ModuleOrigin::kWasmOrigin,
|
||||||
isolate->counters(), isolate->allocator());
|
isolate->counters(), isolate->allocator());
|
||||||
CHECK(result.ok());
|
CHECK(result.ok());
|
||||||
const WasmFunction* func = &result.val->functions[1];
|
const WasmFunction* func = &result.val->functions[1];
|
||||||
return func->code.offset();
|
return func->code.offset();
|
||||||
|
@ -147,9 +147,10 @@ class WasmSerializationTest {
|
|||||||
HandleScope scope(serialization_isolate);
|
HandleScope scope(serialization_isolate);
|
||||||
testing::SetupIsolateForWasmModule(serialization_isolate);
|
testing::SetupIsolateForWasmModule(serialization_isolate);
|
||||||
|
|
||||||
|
auto enabled_features = WasmFeaturesFromIsolate(serialization_isolate);
|
||||||
MaybeHandle<WasmModuleObject> maybe_module_object =
|
MaybeHandle<WasmModuleObject> maybe_module_object =
|
||||||
serialization_isolate->wasm_engine()->SyncCompile(
|
serialization_isolate->wasm_engine()->SyncCompile(
|
||||||
serialization_isolate, &thrower,
|
serialization_isolate, enabled_features, &thrower,
|
||||||
ModuleWireBytes(buffer.begin(), buffer.end()));
|
ModuleWireBytes(buffer.begin(), buffer.end()));
|
||||||
Handle<WasmModuleObject> module_object =
|
Handle<WasmModuleObject> module_object =
|
||||||
maybe_module_object.ToHandleChecked();
|
maybe_module_object.ToHandleChecked();
|
||||||
@ -291,9 +292,10 @@ void TestTransferrableWasmModules(bool should_share) {
|
|||||||
Isolate* from_i_isolate = reinterpret_cast<Isolate*>(from_isolate);
|
Isolate* from_i_isolate = reinterpret_cast<Isolate*>(from_isolate);
|
||||||
testing::SetupIsolateForWasmModule(from_i_isolate);
|
testing::SetupIsolateForWasmModule(from_i_isolate);
|
||||||
ErrorThrower thrower(from_i_isolate, "TestTransferrableWasmModules");
|
ErrorThrower thrower(from_i_isolate, "TestTransferrableWasmModules");
|
||||||
|
auto enabled_features = WasmFeaturesFromIsolate(from_i_isolate);
|
||||||
MaybeHandle<WasmModuleObject> maybe_module_object =
|
MaybeHandle<WasmModuleObject> maybe_module_object =
|
||||||
from_i_isolate->wasm_engine()->SyncCompile(
|
from_i_isolate->wasm_engine()->SyncCompile(
|
||||||
from_i_isolate, &thrower,
|
from_i_isolate, enabled_features, &thrower,
|
||||||
ModuleWireBytes(buffer.begin(), buffer.end()));
|
ModuleWireBytes(buffer.begin(), buffer.end()));
|
||||||
Handle<WasmModuleObject> module_object =
|
Handle<WasmModuleObject> module_object =
|
||||||
maybe_module_object.ToHandleChecked();
|
maybe_module_object.ToHandleChecked();
|
||||||
|
@ -187,8 +187,9 @@ void PumpMessageLoop(SharedEngineIsolate& isolate) {
|
|||||||
Handle<WasmInstanceObject> CompileAndInstantiateAsync(
|
Handle<WasmInstanceObject> CompileAndInstantiateAsync(
|
||||||
SharedEngineIsolate& isolate, ZoneBuffer* buffer) {
|
SharedEngineIsolate& isolate, ZoneBuffer* buffer) {
|
||||||
Handle<Object> maybe_instance = handle(Smi::kZero, isolate.isolate());
|
Handle<Object> maybe_instance = handle(Smi::kZero, isolate.isolate());
|
||||||
|
auto enabled_features = WasmFeaturesFromIsolate(isolate.isolate());
|
||||||
isolate.isolate()->wasm_engine()->AsyncCompile(
|
isolate.isolate()->wasm_engine()->AsyncCompile(
|
||||||
isolate.isolate(),
|
isolate.isolate(), enabled_features,
|
||||||
base::make_unique<MockCompilationResolver>(isolate, &maybe_instance),
|
base::make_unique<MockCompilationResolver>(isolate, &maybe_instance),
|
||||||
ModuleWireBytes(buffer->begin(), buffer->end()), true);
|
ModuleWireBytes(buffer->begin(), buffer->end()), true);
|
||||||
while (!maybe_instance->IsWasmInstanceObject()) PumpMessageLoop(isolate);
|
while (!maybe_instance->IsWasmInstanceObject()) PumpMessageLoop(isolate);
|
||||||
|
@ -20,6 +20,7 @@ TestingModuleBuilder::TestingModuleBuilder(
|
|||||||
: test_module_(std::make_shared<WasmModule>()),
|
: test_module_(std::make_shared<WasmModule>()),
|
||||||
test_module_ptr_(test_module_.get()),
|
test_module_ptr_(test_module_.get()),
|
||||||
isolate_(CcTest::InitIsolateOnce()),
|
isolate_(CcTest::InitIsolateOnce()),
|
||||||
|
enabled_features_(WasmFeaturesFromIsolate(isolate_)),
|
||||||
execution_mode_(mode),
|
execution_mode_(mode),
|
||||||
runtime_exception_support_(exception_support),
|
runtime_exception_support_(exception_support),
|
||||||
lower_simd_(lower_simd) {
|
lower_simd_(lower_simd) {
|
||||||
@ -213,8 +214,9 @@ Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
|
|||||||
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
|
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
|
||||||
script->set_type(Script::TYPE_WASM);
|
script->set_type(Script::TYPE_WASM);
|
||||||
ModuleEnv env = CreateModuleEnv();
|
ModuleEnv env = CreateModuleEnv();
|
||||||
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
|
Handle<WasmModuleObject> module_object =
|
||||||
isolate_, test_module_, env, {}, script, Handle<ByteArray>::null());
|
WasmModuleObject::New(isolate_, enabled_features_, test_module_, env, {},
|
||||||
|
script, Handle<ByteArray>::null());
|
||||||
// This method is called when we initialize TestEnvironment. We don't
|
// This method is called when we initialize TestEnvironment. We don't
|
||||||
// have a memory yet, so we won't create it here. We'll update the
|
// have a memory yet, so we won't create it here. We'll update the
|
||||||
// interpreter when we get a memory. We do have globals, though.
|
// interpreter when we get a memory. We do have globals, though.
|
||||||
@ -229,14 +231,18 @@ Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
|
|||||||
void TestBuildingGraphWithBuilder(compiler::WasmGraphBuilder* builder,
|
void TestBuildingGraphWithBuilder(compiler::WasmGraphBuilder* builder,
|
||||||
Zone* zone, FunctionSig* sig,
|
Zone* zone, FunctionSig* sig,
|
||||||
const byte* start, const byte* end) {
|
const byte* start, const byte* end) {
|
||||||
|
WasmFeatures unused_detected_features;
|
||||||
|
FunctionBody body(sig, 0, start, end);
|
||||||
DecodeResult result =
|
DecodeResult result =
|
||||||
BuildTFGraph(zone->allocator(), builder, sig, start, end);
|
BuildTFGraph(zone->allocator(), kAllWasmFeatures, nullptr, builder,
|
||||||
|
&unused_detected_features, body, nullptr);
|
||||||
if (result.failed()) {
|
if (result.failed()) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!FLAG_trace_wasm_decoder) {
|
if (!FLAG_trace_wasm_decoder) {
|
||||||
// Retry the compilation with the tracing flag on, to help in debugging.
|
// Retry the compilation with the tracing flag on, to help in debugging.
|
||||||
FLAG_trace_wasm_decoder = true;
|
FLAG_trace_wasm_decoder = true;
|
||||||
result = BuildTFGraph(zone->allocator(), builder, sig, start, end);
|
result = BuildTFGraph(zone->allocator(), kAllWasmFeatures, nullptr,
|
||||||
|
builder, &unused_detected_features, body, nullptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -225,6 +225,7 @@ class TestingModuleBuilder {
|
|||||||
std::shared_ptr<WasmModule> test_module_;
|
std::shared_ptr<WasmModule> test_module_;
|
||||||
WasmModule* test_module_ptr_;
|
WasmModule* test_module_ptr_;
|
||||||
Isolate* isolate_;
|
Isolate* isolate_;
|
||||||
|
WasmFeatures enabled_features_;
|
||||||
uint32_t global_offset = 0;
|
uint32_t global_offset = 0;
|
||||||
byte* mem_start_ = nullptr;
|
byte* mem_start_ = nullptr;
|
||||||
uint32_t mem_size_ = 0;
|
uint32_t mem_size_ = 0;
|
||||||
|
@ -591,10 +591,12 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
|
|||||||
#define SIG_ENTRY_x(r) kWasmFunctionTypeCode, 0, 1, r
|
#define SIG_ENTRY_x(r) kWasmFunctionTypeCode, 0, 1, r
|
||||||
#define SIG_ENTRY_x_x(r, a) kWasmFunctionTypeCode, 1, a, 1, r
|
#define SIG_ENTRY_x_x(r, a) kWasmFunctionTypeCode, 1, a, 1, r
|
||||||
#define SIG_ENTRY_x_xx(r, a, b) kWasmFunctionTypeCode, 2, a, b, 1, r
|
#define SIG_ENTRY_x_xx(r, a, b) kWasmFunctionTypeCode, 2, a, b, 1, r
|
||||||
|
#define SIG_ENTRY_xx_xx(r, s, a, b) kWasmFunctionTypeCode, 2, a, b, 2, r, s
|
||||||
#define SIG_ENTRY_x_xxx(r, a, b, c) kWasmFunctionTypeCode, 3, a, b, c, 1, r
|
#define SIG_ENTRY_x_xxx(r, a, b, c) kWasmFunctionTypeCode, 3, a, b, c, 1, r
|
||||||
#define SIZEOF_SIG_ENTRY_x 4
|
#define SIZEOF_SIG_ENTRY_x 4
|
||||||
#define SIZEOF_SIG_ENTRY_x_x 5
|
#define SIZEOF_SIG_ENTRY_x_x 5
|
||||||
#define SIZEOF_SIG_ENTRY_x_xx 6
|
#define SIZEOF_SIG_ENTRY_x_xx 6
|
||||||
|
#define SIZEOF_SIG_ENTRY_xx_xx 7
|
||||||
#define SIZEOF_SIG_ENTRY_x_xxx 7
|
#define SIZEOF_SIG_ENTRY_x_xxx 7
|
||||||
|
|
||||||
#define WASM_BRV(depth, ...) __VA_ARGS__, kExprBr, static_cast<byte>(depth)
|
#define WASM_BRV(depth, ...) __VA_ARGS__, kExprBr, static_cast<byte>(depth)
|
||||||
|
@ -28,8 +28,9 @@ uint32_t GetInitialMemSize(const WasmModule* module) {
|
|||||||
|
|
||||||
MaybeHandle<WasmInstanceObject> CompileAndInstantiateForTesting(
|
MaybeHandle<WasmInstanceObject> CompileAndInstantiateForTesting(
|
||||||
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) {
|
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) {
|
||||||
MaybeHandle<WasmModuleObject> module =
|
auto enabled_features = WasmFeaturesFromIsolate(isolate);
|
||||||
isolate->wasm_engine()->SyncCompile(isolate, thrower, bytes);
|
MaybeHandle<WasmModuleObject> module = isolate->wasm_engine()->SyncCompile(
|
||||||
|
isolate, enabled_features, thrower, bytes);
|
||||||
DCHECK_EQ(thrower->error(), module.is_null());
|
DCHECK_EQ(thrower->error(), module.is_null());
|
||||||
if (module.is_null()) return {};
|
if (module.is_null()) return {};
|
||||||
|
|
||||||
@ -42,9 +43,10 @@ std::shared_ptr<WasmModule> DecodeWasmModuleForTesting(
|
|||||||
const byte* module_end, ModuleOrigin origin, bool verify_functions) {
|
const byte* module_end, ModuleOrigin origin, bool verify_functions) {
|
||||||
// Decode the module, but don't verify function bodies, since we'll
|
// Decode the module, but don't verify function bodies, since we'll
|
||||||
// be compiling them anyway.
|
// be compiling them anyway.
|
||||||
ModuleResult decoding_result =
|
auto enabled_features = WasmFeaturesFromIsolate(isolate);
|
||||||
DecodeWasmModule(module_start, module_end, verify_functions, origin,
|
ModuleResult decoding_result = DecodeWasmModule(
|
||||||
isolate->counters(), isolate->allocator());
|
enabled_features, module_start, module_end, verify_functions, origin,
|
||||||
|
isolate->counters(), isolate->allocator());
|
||||||
|
|
||||||
if (decoding_result.failed()) {
|
if (decoding_result.failed()) {
|
||||||
// Module verification failed. throw.
|
// Module verification failed. throw.
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "src/optimized-compilation-info.h"
|
#include "src/optimized-compilation-info.h"
|
||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "src/wasm/wasm-engine.h"
|
#include "src/wasm/wasm-engine.h"
|
||||||
|
#include "src/wasm/wasm-features.h"
|
||||||
#include "src/wasm/wasm-limits.h"
|
#include "src/wasm/wasm-limits.h"
|
||||||
#include "src/wasm/wasm-objects-inl.h"
|
#include "src/wasm/wasm-objects-inl.h"
|
||||||
#include "src/wasm/wasm-objects.h"
|
#include "src/wasm/wasm-objects.h"
|
||||||
@ -160,7 +161,8 @@ std::unique_ptr<wasm::NativeModule> AllocateNativeModule(i::Isolate* isolate,
|
|||||||
// WasmCallDescriptor assumes that code is on the native heap and not
|
// WasmCallDescriptor assumes that code is on the native heap and not
|
||||||
// within a code object.
|
// within a code object.
|
||||||
return isolate->wasm_engine()->code_manager()->NewNativeModule(
|
return isolate->wasm_engine()->code_manager()->NewNativeModule(
|
||||||
isolate, code_size, false, std::move(module), env);
|
isolate, i::wasm::kAllWasmFeatures, code_size, false, std::move(module),
|
||||||
|
env);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
|
@ -68,8 +68,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||||||
testing::SetupIsolateForWasmModule(i_isolate);
|
testing::SetupIsolateForWasmModule(i_isolate);
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
i_isolate->wasm_engine()->AsyncCompile(
|
i_isolate->wasm_engine()->AsyncCompile(
|
||||||
i_isolate, base::make_unique<AsyncFuzzerResolver>(i_isolate, &done),
|
i_isolate, enabled_features,
|
||||||
|
base::make_unique<AsyncFuzzerResolver>(i_isolate, &done),
|
||||||
ModuleWireBytes(data, data + size), false);
|
ModuleWireBytes(data, data + size), false);
|
||||||
|
|
||||||
// Wait for the promise to resolve.
|
// Wait for the promise to resolve.
|
||||||
|
@ -153,8 +153,9 @@ std::ostream& operator<<(std::ostream& os, const PrintName& name) {
|
|||||||
void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||||
bool compiles) {
|
bool compiles) {
|
||||||
constexpr bool kVerifyFunctions = false;
|
constexpr bool kVerifyFunctions = false;
|
||||||
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
|
||||||
ModuleResult module_res = DecodeWasmModule(
|
ModuleResult module_res = DecodeWasmModule(
|
||||||
wire_bytes.start(), wire_bytes.end(), kVerifyFunctions,
|
enabled_features, wire_bytes.start(), wire_bytes.end(), kVerifyFunctions,
|
||||||
ModuleOrigin::kWasmOrigin, isolate->counters(), isolate->allocator());
|
ModuleOrigin::kWasmOrigin, isolate->counters(), isolate->allocator());
|
||||||
CHECK(module_res.ok());
|
CHECK(module_res.ok());
|
||||||
WasmModule* module = module_res.val.get();
|
WasmModule* module = module_res.val.get();
|
||||||
@ -181,7 +182,7 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
|||||||
os << ", undefined";
|
os << ", undefined";
|
||||||
}
|
}
|
||||||
os << ", " << (module->mem_export ? "true" : "false");
|
os << ", " << (module->mem_export ? "true" : "false");
|
||||||
if (FLAG_experimental_wasm_threads && module->has_shared_memory) {
|
if (module->has_shared_memory) {
|
||||||
os << ", shared";
|
os << ", shared";
|
||||||
}
|
}
|
||||||
os << ");\n";
|
os << ");\n";
|
||||||
@ -208,7 +209,8 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
|||||||
|
|
||||||
// Add locals.
|
// Add locals.
|
||||||
BodyLocalDecls decls(&tmp_zone);
|
BodyLocalDecls decls(&tmp_zone);
|
||||||
DecodeLocalDecls(&decls, func_code.start(), func_code.end());
|
DecodeLocalDecls(enabled_features, &decls, func_code.start(),
|
||||||
|
func_code.end());
|
||||||
if (!decls.type_list.empty()) {
|
if (!decls.type_list.empty()) {
|
||||||
os << " ";
|
os << " ";
|
||||||
for (size_t pos = 0, count = 1, locals = decls.type_list.size();
|
for (size_t pos = 0, count = 1, locals = decls.type_list.size();
|
||||||
@ -284,6 +286,7 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
|
|||||||
ModuleWireBytes wire_bytes(buffer.begin(), buffer.end());
|
ModuleWireBytes wire_bytes(buffer.begin(), buffer.end());
|
||||||
|
|
||||||
// Compile with Turbofan here. Liftoff will be tested later.
|
// Compile with Turbofan here. Liftoff will be tested later.
|
||||||
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
MaybeHandle<WasmModuleObject> compiled_module;
|
MaybeHandle<WasmModuleObject> compiled_module;
|
||||||
{
|
{
|
||||||
// Explicitly enable Liftoff, disable tiering and set the tier_mask. This
|
// Explicitly enable Liftoff, disable tiering and set the tier_mask. This
|
||||||
@ -292,7 +295,7 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
|
|||||||
FlagScope<bool> no_tier_up(&FLAG_wasm_tier_up, false);
|
FlagScope<bool> no_tier_up(&FLAG_wasm_tier_up, false);
|
||||||
FlagScope<int> tier_mask_scope(&FLAG_wasm_tier_mask_for_testing, tier_mask);
|
FlagScope<int> tier_mask_scope(&FLAG_wasm_tier_mask_for_testing, tier_mask);
|
||||||
compiled_module = i_isolate->wasm_engine()->SyncCompile(
|
compiled_module = i_isolate->wasm_engine()->SyncCompile(
|
||||||
i_isolate, &interpreter_thrower, wire_bytes);
|
i_isolate, enabled_features, &interpreter_thrower, wire_bytes);
|
||||||
}
|
}
|
||||||
bool compiles = !compiled_module.is_null();
|
bool compiles = !compiled_module.is_null();
|
||||||
|
|
||||||
@ -300,8 +303,8 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
|
|||||||
GenerateTestCase(i_isolate, wire_bytes, compiles);
|
GenerateTestCase(i_isolate, wire_bytes, compiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validates =
|
bool validates = i_isolate->wasm_engine()->SyncValidate(
|
||||||
i_isolate->wasm_engine()->SyncValidate(i_isolate, wire_bytes);
|
i_isolate, enabled_features, wire_bytes);
|
||||||
|
|
||||||
CHECK_EQ(compiles, validates);
|
CHECK_EQ(compiles, validates);
|
||||||
CHECK_IMPLIES(require_valid, validates);
|
CHECK_IMPLIES(require_valid, validates);
|
||||||
|
@ -42,9 +42,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||||||
i::HandleScope scope(i_isolate);
|
i::HandleScope scope(i_isolate);
|
||||||
i::wasm::ErrorThrower thrower(i_isolate, "wasm fuzzer");
|
i::wasm::ErrorThrower thrower(i_isolate, "wasm fuzzer");
|
||||||
i::Handle<i::WasmModuleObject> module_object;
|
i::Handle<i::WasmModuleObject> module_object;
|
||||||
bool compiles = i_isolate->wasm_engine()
|
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||||
->SyncCompile(i_isolate, &thrower, wire_bytes)
|
bool compiles =
|
||||||
.ToHandle(&module_object);
|
i_isolate->wasm_engine()
|
||||||
|
->SyncCompile(i_isolate, enabled_features, &thrower, wire_bytes)
|
||||||
|
.ToHandle(&module_object);
|
||||||
|
|
||||||
if (i::FLAG_wasm_fuzzer_gen_test) {
|
if (i::FLAG_wasm_fuzzer_gen_test) {
|
||||||
i::wasm::fuzzer::GenerateTestCase(i_isolate, wire_bytes, compiles);
|
i::wasm::fuzzer::GenerateTestCase(i_isolate, wire_bytes, compiles);
|
||||||
|
@ -92,6 +92,9 @@ static const WasmOpcode kInt32BinopOpcodes[] = {
|
|||||||
class FunctionBodyDecoderTest : public TestWithZone {
|
class FunctionBodyDecoderTest : public TestWithZone {
|
||||||
public:
|
public:
|
||||||
typedef std::pair<uint32_t, ValueType> LocalsDecl;
|
typedef std::pair<uint32_t, ValueType> LocalsDecl;
|
||||||
|
// All features are disabled by default and must be activated with
|
||||||
|
// a WASM_FEATURE_SCOPE in individual tests.
|
||||||
|
WasmFeatures enabled_features_;
|
||||||
|
|
||||||
FunctionBodyDecoderTest() : module(nullptr), local_decls(zone()) {}
|
FunctionBodyDecoderTest() : module(nullptr), local_decls(zone()) {}
|
||||||
|
|
||||||
@ -133,8 +136,11 @@ class FunctionBodyDecoderTest : public TestWithZone {
|
|||||||
PrepareBytecode(&start, &end, append_end);
|
PrepareBytecode(&start, &end, append_end);
|
||||||
|
|
||||||
// Verify the code.
|
// Verify the code.
|
||||||
|
FunctionBody body(sig, 0, start, end);
|
||||||
|
WasmFeatures unused_detected_features;
|
||||||
DecodeResult result =
|
DecodeResult result =
|
||||||
VerifyWasmCode(zone()->allocator(), module, sig, start, end);
|
VerifyWasmCode(zone()->allocator(), enabled_features_, module,
|
||||||
|
&unused_detected_features, body);
|
||||||
|
|
||||||
uint32_t pc = result.error_offset();
|
uint32_t pc = result.error_offset();
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
@ -198,6 +204,17 @@ class FunctionBodyDecoderTest : public TestWithZone {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class EnableBoolScope {
|
||||||
|
public:
|
||||||
|
bool prev_;
|
||||||
|
bool* ptr_;
|
||||||
|
explicit EnableBoolScope(bool* ptr) : prev_(*ptr), ptr_(ptr) { *ptr = true; }
|
||||||
|
~EnableBoolScope() { *ptr_ = prev_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WASM_FEATURE_SCOPE(feat) \
|
||||||
|
EnableBoolScope feat##_scope(&this->enabled_features_.feat);
|
||||||
|
|
||||||
constexpr size_t kMaxByteSizedLeb128 = 127;
|
constexpr size_t kMaxByteSizedLeb128 = 127;
|
||||||
|
|
||||||
// A helper for tests that require a module environment for functions,
|
// A helper for tests that require a module environment for functions,
|
||||||
@ -263,7 +280,7 @@ TEST_F(FunctionBodyDecoderTest, Int32Const1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, RefNull) {
|
TEST_F(FunctionBodyDecoderTest, RefNull) {
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
byte code[] = {kExprRefNull};
|
byte code[] = {kExprRefNull};
|
||||||
EXPECT_VERIFIES_C(r_v, code);
|
EXPECT_VERIFIES_C(r_v, code);
|
||||||
}
|
}
|
||||||
@ -1236,8 +1253,8 @@ TEST_F(FunctionBodyDecoderTest, MacrosInt64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, AllSimpleExpressions) {
|
TEST_F(FunctionBodyDecoderTest, AllSimpleExpressions) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(se);
|
WASM_FEATURE_SCOPE(se);
|
||||||
EXPERIMENTAL_FLAG_SCOPE(anyref);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
// Test all simple expressions which are described by a signature.
|
// Test all simple expressions which are described by a signature.
|
||||||
#define DECODE_TEST(name, opcode, sig) \
|
#define DECODE_TEST(name, opcode, sig) \
|
||||||
{ \
|
{ \
|
||||||
@ -1476,7 +1493,7 @@ TEST_F(FunctionBodyDecoderTest, CallsWithMismatchedSigs3) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, MultiReturn) {
|
TEST_F(FunctionBodyDecoderTest, MultiReturn) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
ValueType storage[] = {kWasmI32, kWasmI32};
|
ValueType storage[] = {kWasmI32, kWasmI32};
|
||||||
FunctionSig sig_ii_v(2, 0, storage);
|
FunctionSig sig_ii_v(2, 0, storage);
|
||||||
FunctionSig sig_v_ii(0, 2, storage);
|
FunctionSig sig_v_ii(0, 2, storage);
|
||||||
@ -1492,7 +1509,7 @@ TEST_F(FunctionBodyDecoderTest, MultiReturn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, MultiReturnType) {
|
TEST_F(FunctionBodyDecoderTest, MultiReturnType) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
for (size_t a = 0; a < arraysize(kValueTypes); a++) {
|
for (size_t a = 0; a < arraysize(kValueTypes); a++) {
|
||||||
for (size_t b = 0; b < arraysize(kValueTypes); b++) {
|
for (size_t b = 0; b < arraysize(kValueTypes); b++) {
|
||||||
for (size_t c = 0; c < arraysize(kValueTypes); c++) {
|
for (size_t c = 0; c < arraysize(kValueTypes); c++) {
|
||||||
@ -1612,7 +1629,7 @@ TEST_F(FunctionBodyDecoderTest, IncompleteStore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, IncompleteS8x16Shuffle) {
|
TEST_F(FunctionBodyDecoderTest, IncompleteS8x16Shuffle) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(simd);
|
WASM_FEATURE_SCOPE(simd);
|
||||||
FunctionSig* sig = sigs.i_i();
|
FunctionSig* sig = sigs.i_i();
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
builder.InitializeMemory();
|
builder.InitializeMemory();
|
||||||
@ -2383,7 +2400,7 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, Throw) {
|
TEST_F(FunctionBodyDecoderTest, Throw) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
WASM_FEATURE_SCOPE(eh);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
|
|
||||||
@ -2403,7 +2420,7 @@ TEST_F(FunctionBodyDecoderTest, Throw) {
|
|||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
|
TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
|
||||||
// TODO(titzer): unreachable code after throw should validate.
|
// TODO(titzer): unreachable code after throw should validate.
|
||||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
WASM_FEATURE_SCOPE(eh);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
|
|
||||||
@ -2420,7 +2437,7 @@ TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
|
|||||||
#define WASM_CATCH(index) kExprCatch, static_cast<byte>(index)
|
#define WASM_CATCH(index) kExprCatch, static_cast<byte>(index)
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, TryCatch) {
|
TEST_F(FunctionBodyDecoderTest, TryCatch) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
WASM_FEATURE_SCOPE(eh);
|
||||||
|
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
@ -2445,7 +2462,7 @@ TEST_F(FunctionBodyDecoderTest, TryCatch) {
|
|||||||
#undef WASM_CATCH
|
#undef WASM_CATCH
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, MultiValBlock1) {
|
TEST_F(FunctionBodyDecoderTest, MultiValBlock1) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f0 = builder.AddSignature(sigs.ii_v());
|
byte f0 = builder.AddSignature(sigs.ii_v());
|
||||||
@ -2461,7 +2478,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValBlock1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, MultiValBlock2) {
|
TEST_F(FunctionBodyDecoderTest, MultiValBlock2) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f0 = builder.AddSignature(sigs.ii_v());
|
byte f0 = builder.AddSignature(sigs.ii_v());
|
||||||
@ -2479,7 +2496,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValBlock2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, MultiValBlockBr) {
|
TEST_F(FunctionBodyDecoderTest, MultiValBlockBr) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f0 = builder.AddSignature(sigs.ii_v());
|
byte f0 = builder.AddSignature(sigs.ii_v());
|
||||||
@ -2491,7 +2508,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValBlockBr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, MultiValLoop1) {
|
TEST_F(FunctionBodyDecoderTest, MultiValLoop1) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f0 = builder.AddSignature(sigs.ii_v());
|
byte f0 = builder.AddSignature(sigs.ii_v());
|
||||||
@ -2507,7 +2524,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValLoop1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, MultiValIf) {
|
TEST_F(FunctionBodyDecoderTest, MultiValIf) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f0 = builder.AddSignature(sigs.ii_v());
|
byte f0 = builder.AddSignature(sigs.ii_v());
|
||||||
@ -2570,7 +2587,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValIf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, BlockParam) {
|
TEST_F(FunctionBodyDecoderTest, BlockParam) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f1 = builder.AddSignature(sigs.i_i());
|
byte f1 = builder.AddSignature(sigs.i_i());
|
||||||
@ -2596,7 +2613,7 @@ TEST_F(FunctionBodyDecoderTest, BlockParam) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, LoopParam) {
|
TEST_F(FunctionBodyDecoderTest, LoopParam) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f1 = builder.AddSignature(sigs.i_i());
|
byte f1 = builder.AddSignature(sigs.i_i());
|
||||||
@ -2622,7 +2639,7 @@ TEST_F(FunctionBodyDecoderTest, LoopParam) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, LoopParamBr) {
|
TEST_F(FunctionBodyDecoderTest, LoopParamBr) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f1 = builder.AddSignature(sigs.i_i());
|
byte f1 = builder.AddSignature(sigs.i_i());
|
||||||
@ -2644,7 +2661,7 @@ TEST_F(FunctionBodyDecoderTest, LoopParamBr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FunctionBodyDecoderTest, IfParam) {
|
TEST_F(FunctionBodyDecoderTest, IfParam) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(mv);
|
WASM_FEATURE_SCOPE(mv);
|
||||||
TestModuleBuilder builder;
|
TestModuleBuilder builder;
|
||||||
module = builder.module();
|
module = builder.module();
|
||||||
byte f1 = builder.AddSignature(sigs.i_i());
|
byte f1 = builder.AddSignature(sigs.i_i());
|
||||||
@ -2678,8 +2695,11 @@ TEST_F(FunctionBodyDecoderTest, Regression709741) {
|
|||||||
PrepareBytecode(&start, &end, kAppendEnd);
|
PrepareBytecode(&start, &end, kAppendEnd);
|
||||||
|
|
||||||
for (const byte* i = start; i < end; i++) {
|
for (const byte* i = start; i < end; i++) {
|
||||||
|
FunctionBody body(sigs.v_v(), 0, start, i);
|
||||||
|
WasmFeatures unused_detected_features;
|
||||||
DecodeResult result =
|
DecodeResult result =
|
||||||
VerifyWasmCode(zone()->allocator(), nullptr, sigs.v_v(), start, i);
|
VerifyWasmCode(zone()->allocator(), kAllWasmFeatures, nullptr,
|
||||||
|
&unused_detected_features, body);
|
||||||
if (result.ok()) {
|
if (result.ok()) {
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
str << "Expected verification to fail";
|
str << "Expected verification to fail";
|
||||||
@ -2999,6 +3019,7 @@ typedef ZoneVector<ValueType> TypesOfLocals;
|
|||||||
class LocalDeclDecoderTest : public TestWithZone {
|
class LocalDeclDecoderTest : public TestWithZone {
|
||||||
public:
|
public:
|
||||||
v8::internal::AccountingAllocator allocator;
|
v8::internal::AccountingAllocator allocator;
|
||||||
|
WasmFeatures enabled_features_;
|
||||||
|
|
||||||
size_t ExpectRun(TypesOfLocals map, size_t pos, ValueType expected,
|
size_t ExpectRun(TypesOfLocals map, size_t pos, ValueType expected,
|
||||||
size_t count) {
|
size_t count) {
|
||||||
@ -3007,6 +3028,11 @@ class LocalDeclDecoderTest : public TestWithZone {
|
|||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DecodeLocalDecls(BodyLocalDecls* decls, const byte* start,
|
||||||
|
const byte* end) {
|
||||||
|
return i::wasm::DecodeLocalDecls(enabled_features_, decls, start, end);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(LocalDeclDecoderTest, EmptyLocals) {
|
TEST_F(LocalDeclDecoderTest, EmptyLocals) {
|
||||||
@ -3024,7 +3050,7 @@ TEST_F(LocalDeclDecoderTest, NoLocals) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LocalDeclDecoderTest, OneLocal) {
|
TEST_F(LocalDeclDecoderTest, OneLocal) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(anyref);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||||
ValueType type = kValueTypes[i];
|
ValueType type = kValueTypes[i];
|
||||||
const byte data[] = {1, 1,
|
const byte data[] = {1, 1,
|
||||||
@ -3040,7 +3066,7 @@ TEST_F(LocalDeclDecoderTest, OneLocal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LocalDeclDecoderTest, FiveLocals) {
|
TEST_F(LocalDeclDecoderTest, FiveLocals) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(anyref);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||||
ValueType type = kValueTypes[i];
|
ValueType type = kValueTypes[i];
|
||||||
const byte data[] = {1, 5,
|
const byte data[] = {1, 5,
|
||||||
@ -3180,6 +3206,7 @@ TEST_F(BytecodeIteratorTest, WithLocalDecls) {
|
|||||||
EXPECT_FALSE(iter.has_next());
|
EXPECT_FALSE(iter.has_next());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef WASM_FEATURE_SCOPE
|
||||||
#undef B1
|
#undef B1
|
||||||
#undef B2
|
#undef B2
|
||||||
#undef B3
|
#undef B3
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "src/handles.h"
|
#include "src/handles.h"
|
||||||
#include "src/objects-inl.h"
|
#include "src/objects-inl.h"
|
||||||
#include "src/wasm/module-decoder.h"
|
#include "src/wasm/module-decoder.h"
|
||||||
|
#include "src/wasm/wasm-features.h"
|
||||||
#include "src/wasm/wasm-limits.h"
|
#include "src/wasm/wasm-limits.h"
|
||||||
#include "src/wasm/wasm-opcodes.h"
|
#include "src/wasm/wasm-opcodes.h"
|
||||||
#include "test/common/wasm/flag-utils.h"
|
#include "test/common/wasm/flag-utils.h"
|
||||||
@ -146,6 +147,8 @@ struct ValueTypePair {
|
|||||||
|
|
||||||
class WasmModuleVerifyTest : public TestWithIsolateAndZone {
|
class WasmModuleVerifyTest : public TestWithIsolateAndZone {
|
||||||
public:
|
public:
|
||||||
|
WasmFeatures enabled_features_;
|
||||||
|
|
||||||
ModuleResult DecodeModule(const byte* module_start, const byte* module_end) {
|
ModuleResult DecodeModule(const byte* module_start, const byte* module_end) {
|
||||||
// Add the wasm magic and version number automatically.
|
// Add the wasm magic and version number automatically.
|
||||||
size_t size = static_cast<size_t>(module_end - module_start);
|
size_t size = static_cast<size_t>(module_end - module_start);
|
||||||
@ -154,19 +157,39 @@ class WasmModuleVerifyTest : public TestWithIsolateAndZone {
|
|||||||
auto temp = new byte[total];
|
auto temp = new byte[total];
|
||||||
memcpy(temp, header, sizeof(header));
|
memcpy(temp, header, sizeof(header));
|
||||||
memcpy(temp + sizeof(header), module_start, size);
|
memcpy(temp + sizeof(header), module_start, size);
|
||||||
ModuleResult result =
|
ModuleResult result = DecodeWasmModule(
|
||||||
DecodeWasmModule(temp, temp + total, false, kWasmOrigin,
|
enabled_features_, temp, temp + total, false, kWasmOrigin,
|
||||||
isolate()->counters(), isolate()->allocator());
|
isolate()->counters(), isolate()->allocator());
|
||||||
delete[] temp;
|
delete[] temp;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
ModuleResult DecodeModuleNoHeader(const byte* module_start,
|
ModuleResult DecodeModuleNoHeader(const byte* module_start,
|
||||||
const byte* module_end) {
|
const byte* module_end) {
|
||||||
return DecodeWasmModule(module_start, module_end, false, kWasmOrigin,
|
return DecodeWasmModule(enabled_features_, module_start, module_end, false,
|
||||||
isolate()->counters(), isolate()->allocator());
|
kWasmOrigin, isolate()->counters(),
|
||||||
|
isolate()->allocator());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class EnableBoolScope {
|
||||||
|
public:
|
||||||
|
bool prev_;
|
||||||
|
bool* ptr_;
|
||||||
|
explicit EnableBoolScope(bool* ptr, bool val = true)
|
||||||
|
: prev_(*ptr), ptr_(ptr) {
|
||||||
|
*ptr = val;
|
||||||
|
}
|
||||||
|
~EnableBoolScope() { *ptr_ = prev_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WASM_FEATURE_SCOPE(feat) \
|
||||||
|
EnableBoolScope feat##_scope(&this->enabled_features_.feat)
|
||||||
|
|
||||||
|
#define WASM_FEATURE_SCOPE_VAL(feat, val) \
|
||||||
|
EnableBoolScope feat##_scope(&this->enabled_features_.feat, val)
|
||||||
|
} // namespace
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, WrongMagic) {
|
TEST_F(WasmModuleVerifyTest, WrongMagic) {
|
||||||
for (uint32_t x = 1; x; x <<= 1) {
|
for (uint32_t x = 1; x; x <<= 1) {
|
||||||
const byte data[] = {U32_LE(kWasmMagic ^ x), U32_LE(kWasmVersion)};
|
const byte data[] = {U32_LE(kWasmMagic ^ x), U32_LE(kWasmVersion)};
|
||||||
@ -218,7 +241,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
|
TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(anyref);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
SECTION(Global, 5), // --
|
SECTION(Global, 5), // --
|
||||||
1,
|
1,
|
||||||
@ -244,7 +267,7 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) {
|
TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(anyref);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
SECTION(Import, 8), // section header
|
SECTION(Import, 8), // section header
|
||||||
1, // number of imports
|
1, // number of imports
|
||||||
@ -314,6 +337,7 @@ TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, ExportMutableGlobal) {
|
TEST_F(WasmModuleVerifyTest, ExportMutableGlobal) {
|
||||||
|
WASM_FEATURE_SCOPE(mut_global);
|
||||||
{
|
{
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
SECTION(Global, 6), // --
|
SECTION(Global, 6), // --
|
||||||
@ -445,7 +469,7 @@ TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
|
|||||||
};
|
};
|
||||||
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
||||||
|
|
||||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
WASM_FEATURE_SCOPE(eh);
|
||||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||||
EXPECT_OK(result);
|
EXPECT_OK(result);
|
||||||
EXPECT_EQ(0u, result.val->exceptions.size());
|
EXPECT_EQ(0u, result.val->exceptions.size());
|
||||||
@ -459,7 +483,7 @@ TEST_F(WasmModuleVerifyTest, OneI32Exception) {
|
|||||||
};
|
};
|
||||||
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
||||||
|
|
||||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
WASM_FEATURE_SCOPE(eh);
|
||||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||||
EXPECT_OK(result);
|
EXPECT_OK(result);
|
||||||
EXPECT_EQ(1u, result.val->exceptions.size());
|
EXPECT_EQ(1u, result.val->exceptions.size());
|
||||||
@ -477,7 +501,7 @@ TEST_F(WasmModuleVerifyTest, TwoExceptions) {
|
|||||||
1, kLocalI32};
|
1, kLocalI32};
|
||||||
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
||||||
|
|
||||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
WASM_FEATURE_SCOPE(eh);
|
||||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||||
EXPECT_OK(result);
|
EXPECT_OK(result);
|
||||||
EXPECT_EQ(2u, result.val->exceptions.size());
|
EXPECT_EQ(2u, result.val->exceptions.size());
|
||||||
@ -496,7 +520,7 @@ TEST_F(WasmModuleVerifyTest, Exception_invalid_type) {
|
|||||||
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
FAIL_IF_NO_EXPERIMENTAL_EH(data);
|
||||||
|
|
||||||
// Should fail decoding exception section.
|
// Should fail decoding exception section.
|
||||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
WASM_FEATURE_SCOPE(eh);
|
||||||
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
ModuleResult result = DecodeModule(data, data + sizeof(data));
|
||||||
EXPECT_FALSE(result.ok());
|
EXPECT_FALSE(result.ok());
|
||||||
}
|
}
|
||||||
@ -940,7 +964,7 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
|
|||||||
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
|
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
|
||||||
// Test that if we have multiple tables, in the element section we can target
|
// Test that if we have multiple tables, in the element section we can target
|
||||||
// and initialize all tables.
|
// and initialize all tables.
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
// sig#0 ---------------------------------------------------------------
|
// sig#0 ---------------------------------------------------------------
|
||||||
SIGNATURES_SECTION_VOID_VOID,
|
SIGNATURES_SECTION_VOID_VOID,
|
||||||
@ -970,7 +994,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
|
|||||||
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
|
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
|
||||||
// Test that if we have multiple tables, both imported and module-defined, in
|
// Test that if we have multiple tables, both imported and module-defined, in
|
||||||
// the element section we can target and initialize all tables.
|
// the element section we can target and initialize all tables.
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
// sig#0 ---------------------------------------------------------------
|
// sig#0 ---------------------------------------------------------------
|
||||||
SIGNATURES_SECTION_VOID_VOID,
|
SIGNATURES_SECTION_VOID_VOID,
|
||||||
@ -1027,7 +1051,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
|
|||||||
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
|
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
|
||||||
// Test that the order in which tables are targeted in the element secion
|
// Test that the order in which tables are targeted in the element secion
|
||||||
// can be arbitrary.
|
// can be arbitrary.
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
// sig#0 ---------------------------------------------------------------
|
// sig#0 ---------------------------------------------------------------
|
||||||
SIGNATURES_SECTION_VOID_VOID,
|
SIGNATURES_SECTION_VOID_VOID,
|
||||||
@ -1061,7 +1085,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
|
|||||||
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
|
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
|
||||||
// Test that the order in which tables are targeted in the element secion can
|
// Test that the order in which tables are targeted in the element secion can
|
||||||
// be arbitrary. In this test, tables can be both imported and module-defined.
|
// be arbitrary. In this test, tables can be both imported and module-defined.
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
// sig#0 ---------------------------------------------------------------
|
// sig#0 ---------------------------------------------------------------
|
||||||
SIGNATURES_SECTION_VOID_VOID,
|
SIGNATURES_SECTION_VOID_VOID,
|
||||||
@ -1118,7 +1142,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
|
|||||||
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
|
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
|
||||||
// Test that tables of type 'AnyRef' cannot be initialized by the element
|
// Test that tables of type 'AnyRef' cannot be initialized by the element
|
||||||
// section.
|
// section.
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
// sig#0 ---------------------------------------------------------------
|
// sig#0 ---------------------------------------------------------------
|
||||||
SIGNATURES_SECTION_VOID_VOID,
|
SIGNATURES_SECTION_VOID_VOID,
|
||||||
@ -1148,7 +1172,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
|
|||||||
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
|
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
|
||||||
// Test that imported tables of type AnyRef cannot be initialized in the
|
// Test that imported tables of type AnyRef cannot be initialized in the
|
||||||
// elements section.
|
// elements section.
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
// sig#0 ---------------------------------------------------------------
|
// sig#0 ---------------------------------------------------------------
|
||||||
SIGNATURES_SECTION_VOID_VOID,
|
SIGNATURES_SECTION_VOID_VOID,
|
||||||
@ -1232,7 +1256,7 @@ TEST_F(WasmModuleVerifyTest, MultipleTablesWithoutFlag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, MultipleTablesWithFlag) {
|
TEST_F(WasmModuleVerifyTest, MultipleTablesWithFlag) {
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
SECTION(Table, 7), // table section
|
SECTION(Table, 7), // table section
|
||||||
ENTRY_COUNT(2), // 2 tables
|
ENTRY_COUNT(2), // 2 tables
|
||||||
@ -1258,22 +1282,18 @@ TEST_F(WasmModuleVerifyTest, MultipleTablesWithFlag) {
|
|||||||
|
|
||||||
class WasmSignatureDecodeTest : public TestWithZone {
|
class WasmSignatureDecodeTest : public TestWithZone {
|
||||||
public:
|
public:
|
||||||
WasmSignatureDecodeTest()
|
WasmFeatures enabled_features_;
|
||||||
// In the following tests we turn on support for AnyRef by default. There
|
|
||||||
// is a test (Fail_anyref_without_flag) which explicitly turns off support
|
|
||||||
// for AnyRef.
|
|
||||||
: flag_scope(&FLAG_experimental_wasm_anyref, true) {}
|
|
||||||
|
|
||||||
private:
|
FunctionSig* DecodeSig(const byte* start, const byte* end) {
|
||||||
FlagScope<bool> flag_scope;
|
return DecodeWasmSignatureForTesting(enabled_features_, zone(), start, end);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
|
TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
|
||||||
static const byte data[] = {SIG_ENTRY_v_v};
|
static const byte data[] = {SIG_ENTRY_v_v};
|
||||||
v8::internal::AccountingAllocator allocator;
|
v8::internal::AccountingAllocator allocator;
|
||||||
Zone zone(&allocator, ZONE_NAME);
|
Zone zone(&allocator, ZONE_NAME);
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(&zone, data, data + sizeof(data));
|
|
||||||
|
|
||||||
EXPECT_TRUE(sig != nullptr);
|
EXPECT_TRUE(sig != nullptr);
|
||||||
EXPECT_EQ(0u, sig->parameter_count());
|
EXPECT_EQ(0u, sig->parameter_count());
|
||||||
@ -1281,11 +1301,11 @@ TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
|
TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
|
||||||
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||||
ValueTypePair ret_type = kValueTypes[i];
|
ValueTypePair ret_type = kValueTypes[i];
|
||||||
const byte data[] = {SIG_ENTRY_x(ret_type.code)};
|
const byte data[] = {SIG_ENTRY_x(ret_type.code)};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
|
|
||||||
EXPECT_TRUE(sig != nullptr);
|
EXPECT_TRUE(sig != nullptr);
|
||||||
EXPECT_EQ(0u, sig->parameter_count());
|
EXPECT_EQ(0u, sig->parameter_count());
|
||||||
@ -1295,11 +1315,11 @@ TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
|
TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
|
||||||
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||||
ValueTypePair param_type = kValueTypes[i];
|
ValueTypePair param_type = kValueTypes[i];
|
||||||
const byte data[] = {SIG_ENTRY_v_x(param_type.code)};
|
const byte data[] = {SIG_ENTRY_v_x(param_type.code)};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
|
|
||||||
EXPECT_TRUE(sig != nullptr);
|
EXPECT_TRUE(sig != nullptr);
|
||||||
EXPECT_EQ(1u, sig->parameter_count());
|
EXPECT_EQ(1u, sig->parameter_count());
|
||||||
@ -1309,13 +1329,13 @@ TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
|
TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
|
||||||
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||||
ValueTypePair ret_type = kValueTypes[i];
|
ValueTypePair ret_type = kValueTypes[i];
|
||||||
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
||||||
ValueTypePair param_type = kValueTypes[j];
|
ValueTypePair param_type = kValueTypes[j];
|
||||||
const byte data[] = {SIG_ENTRY_x_x(ret_type.code, param_type.code)};
|
const byte data[] = {SIG_ENTRY_x_x(ret_type.code, param_type.code)};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
|
|
||||||
EXPECT_TRUE(sig != nullptr);
|
EXPECT_TRUE(sig != nullptr);
|
||||||
EXPECT_EQ(1u, sig->parameter_count());
|
EXPECT_EQ(1u, sig->parameter_count());
|
||||||
@ -1327,14 +1347,15 @@ TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Ok_i_tt) {
|
TEST_F(WasmSignatureDecodeTest, Ok_i_tt) {
|
||||||
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
|
WASM_FEATURE_SCOPE(mv);
|
||||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||||
ValueTypePair p0_type = kValueTypes[i];
|
ValueTypePair p0_type = kValueTypes[i];
|
||||||
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
||||||
ValueTypePair p1_type = kValueTypes[j];
|
ValueTypePair p1_type = kValueTypes[j];
|
||||||
const byte data[] = {
|
const byte data[] = {
|
||||||
SIG_ENTRY_x_xx(kLocalI32, p0_type.code, p1_type.code)};
|
SIG_ENTRY_x_xx(kLocalI32, p0_type.code, p1_type.code)};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
|
|
||||||
EXPECT_TRUE(sig != nullptr);
|
EXPECT_TRUE(sig != nullptr);
|
||||||
EXPECT_EQ(2u, sig->parameter_count());
|
EXPECT_EQ(2u, sig->parameter_count());
|
||||||
@ -1345,25 +1366,45 @@ TEST_F(WasmSignatureDecodeTest, Ok_i_tt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WasmSignatureDecodeTest, Ok_tt_tt) {
|
||||||
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
|
WASM_FEATURE_SCOPE(mv);
|
||||||
|
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||||
|
ValueTypePair p0_type = kValueTypes[i];
|
||||||
|
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
||||||
|
ValueTypePair p1_type = kValueTypes[j];
|
||||||
|
const byte data[] = {SIG_ENTRY_xx_xx(p0_type.code, p1_type.code,
|
||||||
|
p0_type.code, p1_type.code)};
|
||||||
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
|
|
||||||
|
EXPECT_TRUE(sig != nullptr);
|
||||||
|
EXPECT_EQ(2u, sig->parameter_count());
|
||||||
|
EXPECT_EQ(2u, sig->return_count());
|
||||||
|
EXPECT_EQ(p0_type.type, sig->GetParam(0));
|
||||||
|
EXPECT_EQ(p1_type.type, sig->GetParam(1));
|
||||||
|
EXPECT_EQ(p0_type.type, sig->GetReturn(0));
|
||||||
|
EXPECT_EQ(p1_type.type, sig->GetReturn(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, TooManyParams) {
|
TEST_F(WasmSignatureDecodeTest, TooManyParams) {
|
||||||
static const byte data[] = {kWasmFunctionTypeCode,
|
static const byte data[] = {kWasmFunctionTypeCode,
|
||||||
WASM_I32V_3(kV8MaxWasmFunctionParams + 1),
|
WASM_I32V_3(kV8MaxWasmFunctionParams + 1),
|
||||||
kLocalI32, 0};
|
kLocalI32, 0};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
EXPECT_FALSE(sig != nullptr);
|
EXPECT_FALSE(sig != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, TooManyReturns) {
|
TEST_F(WasmSignatureDecodeTest, TooManyReturns) {
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_mv, i != 0);
|
bool enable_mv = i != 0;
|
||||||
|
WASM_FEATURE_SCOPE_VAL(mv, enable_mv);
|
||||||
const int max_return_count = static_cast<int>(
|
const int max_return_count = static_cast<int>(
|
||||||
FLAG_experimental_wasm_mv ? kV8MaxWasmFunctionMultiReturns
|
enable_mv ? kV8MaxWasmFunctionMultiReturns : kV8MaxWasmFunctionReturns);
|
||||||
: kV8MaxWasmFunctionReturns);
|
|
||||||
byte data[] = {kWasmFunctionTypeCode, 0, WASM_I32V_3(max_return_count + 1),
|
byte data[] = {kWasmFunctionTypeCode, 0, WASM_I32V_3(max_return_count + 1),
|
||||||
kLocalI32};
|
kLocalI32};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
EXPECT_EQ(nullptr, sig);
|
EXPECT_EQ(nullptr, sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1376,7 +1417,7 @@ TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
|
|||||||
|
|
||||||
for (int i = 0; i < p + 1; i++) {
|
for (int i = 0; i < p + 1; i++) {
|
||||||
// Should fall off the end for all signatures.
|
// Should fall off the end for all signatures.
|
||||||
FunctionSig* sig = DecodeWasmSignatureForTesting(zone(), data, data + i);
|
FunctionSig* sig = DecodeSig(data, data + i);
|
||||||
EXPECT_EQ(nullptr, sig);
|
EXPECT_EQ(nullptr, sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1384,14 +1425,13 @@ TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
|
|||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Fail_anyref_without_flag) {
|
TEST_F(WasmSignatureDecodeTest, Fail_anyref_without_flag) {
|
||||||
// Disable AnyRef support and check that decoding fails.
|
// Disable AnyRef support and check that decoding fails.
|
||||||
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, false);
|
WASM_FEATURE_SCOPE_VAL(anyref, false);
|
||||||
byte ref_types[] = {kLocalAnyFunc, kLocalAnyRef};
|
byte ref_types[] = {kLocalAnyFunc, kLocalAnyRef};
|
||||||
for (byte invalid_type : ref_types) {
|
for (byte invalid_type : ref_types) {
|
||||||
for (size_t i = 0; i < SIZEOF_SIG_ENTRY_x_xx; i++) {
|
for (size_t i = 0; i < SIZEOF_SIG_ENTRY_x_xx; i++) {
|
||||||
byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)};
|
byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)};
|
||||||
data[i] = invalid_type;
|
data[i] = invalid_type;
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
EXPECT_EQ(nullptr, sig);
|
EXPECT_EQ(nullptr, sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1402,41 +1442,43 @@ TEST_F(WasmSignatureDecodeTest, Fail_invalid_type) {
|
|||||||
for (size_t i = 0; i < SIZEOF_SIG_ENTRY_x_xx; i++) {
|
for (size_t i = 0; i < SIZEOF_SIG_ENTRY_x_xx; i++) {
|
||||||
byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)};
|
byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)};
|
||||||
data[i] = kInvalidType;
|
data[i] = kInvalidType;
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
EXPECT_EQ(nullptr, sig);
|
EXPECT_EQ(nullptr, sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Fail_invalid_ret_type1) {
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_ret_type1) {
|
||||||
static const byte data[] = {SIG_ENTRY_x_x(kLocalVoid, kLocalI32)};
|
static const byte data[] = {SIG_ENTRY_x_x(kLocalVoid, kLocalI32)};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
EXPECT_EQ(nullptr, sig);
|
EXPECT_EQ(nullptr, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type1) {
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type1) {
|
||||||
static const byte data[] = {SIG_ENTRY_x_x(kLocalI32, kLocalVoid)};
|
static const byte data[] = {SIG_ENTRY_x_x(kLocalI32, kLocalVoid)};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
EXPECT_EQ(nullptr, sig);
|
EXPECT_EQ(nullptr, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type2) {
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type2) {
|
||||||
static const byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalVoid)};
|
static const byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalVoid)};
|
||||||
FunctionSig* sig =
|
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
|
||||||
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
|
|
||||||
EXPECT_EQ(nullptr, sig);
|
EXPECT_EQ(nullptr, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
class WasmFunctionVerifyTest : public TestWithIsolateAndZone {
|
class WasmFunctionVerifyTest : public TestWithIsolateAndZone {
|
||||||
public:
|
public:
|
||||||
WasmFunctionVerifyTest() {}
|
WasmFeatures enabled_features_;
|
||||||
virtual ~WasmFunctionVerifyTest() {}
|
|
||||||
|
|
||||||
WasmModule module;
|
WasmModule module;
|
||||||
Vector<const byte> bytes;
|
Vector<const byte> bytes;
|
||||||
DISALLOW_COPY_AND_ASSIGN(WasmFunctionVerifyTest);
|
|
||||||
|
FunctionResult DecodeWasmFunction(const ModuleWireBytes& wire_bytes,
|
||||||
|
const WasmModule* module,
|
||||||
|
const byte* function_start,
|
||||||
|
const byte* function_end) {
|
||||||
|
return DecodeWasmFunctionForTesting(enabled_features_, zone(), wire_bytes,
|
||||||
|
module, function_start, function_end,
|
||||||
|
isolate()->counters());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
||||||
@ -1454,8 +1496,8 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
|||||||
kExprEnd // body
|
kExprEnd // body
|
||||||
};
|
};
|
||||||
|
|
||||||
FunctionResult result = DecodeWasmFunctionForTesting(
|
FunctionResult result =
|
||||||
zone(), bytes, &module, data, data + sizeof(data), isolate()->counters());
|
DecodeWasmFunction(bytes, &module, data, data + sizeof(data));
|
||||||
EXPECT_OK(result);
|
EXPECT_OK(result);
|
||||||
|
|
||||||
if (result.val && result.ok()) {
|
if (result.val && result.ok()) {
|
||||||
@ -1584,6 +1626,7 @@ TEST_F(WasmModuleVerifyTest, ImportTable_nosigs1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, ImportTable_mutable_global) {
|
TEST_F(WasmModuleVerifyTest, ImportTable_mutable_global) {
|
||||||
|
WASM_FEATURE_SCOPE(mut_global);
|
||||||
{
|
{
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
SECTION(Import, 8), // section header
|
SECTION(Import, 8), // section header
|
||||||
@ -1615,6 +1658,7 @@ TEST_F(WasmModuleVerifyTest, ImportTable_mutable_global) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, ImportTable_mutability_malformed) {
|
TEST_F(WasmModuleVerifyTest, ImportTable_mutability_malformed) {
|
||||||
|
WASM_FEATURE_SCOPE(mut_global);
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
SECTION(Import, 8),
|
SECTION(Import, 8),
|
||||||
1, // --
|
1, // --
|
||||||
@ -2022,61 +2066,68 @@ TEST_F(WasmModuleVerifyTest, Regression684855) {
|
|||||||
EXPECT_VERIFIES(data);
|
EXPECT_VERIFIES(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EXPECT_INIT_EXPR(Type, type, value, ...) \
|
class WasmInitExprDecodeTest : public TestWithZone {
|
||||||
{ \
|
public:
|
||||||
static const byte data[] = {__VA_ARGS__, kExprEnd}; \
|
WasmInitExprDecodeTest() {}
|
||||||
WasmInitExpr expr = \
|
|
||||||
DecodeWasmInitExprForTesting(data, data + sizeof(data)); \
|
WasmFeatures enabled_features_;
|
||||||
EXPECT_EQ(WasmInitExpr::k##Type##Const, expr.kind); \
|
|
||||||
EXPECT_EQ(value, expr.val.type##_const); \
|
WasmInitExpr DecodeInitExpr(const byte* start, const byte* end) {
|
||||||
|
return DecodeWasmInitExprForTesting(enabled_features_, start, end);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EXPECT_INIT_EXPR(Type, type, value, ...) \
|
||||||
|
{ \
|
||||||
|
static const byte data[] = {__VA_ARGS__, kExprEnd}; \
|
||||||
|
WasmInitExpr expr = DecodeInitExpr(data, data + sizeof(data)); \
|
||||||
|
EXPECT_EQ(WasmInitExpr::k##Type##Const, expr.kind); \
|
||||||
|
EXPECT_EQ(value, expr.val.type##_const); \
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, InitExpr_i32) {
|
#define EXPECT_INIT_EXPR_FAIL(...) \
|
||||||
|
{ \
|
||||||
|
static const byte data[] = {__VA_ARGS__, kExprEnd}; \
|
||||||
|
WasmInitExpr expr = DecodeInitExpr(data, data + sizeof(data)); \
|
||||||
|
EXPECT_EQ(WasmInitExpr::kNone, expr.kind); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WasmInitExprDecodeTest, InitExpr_i32) {
|
||||||
EXPECT_INIT_EXPR(I32, i32, 33, WASM_I32V_1(33));
|
EXPECT_INIT_EXPR(I32, i32, 33, WASM_I32V_1(33));
|
||||||
EXPECT_INIT_EXPR(I32, i32, -21, WASM_I32V_1(-21));
|
EXPECT_INIT_EXPR(I32, i32, -21, WASM_I32V_1(-21));
|
||||||
EXPECT_INIT_EXPR(I32, i32, 437, WASM_I32V_2(437));
|
EXPECT_INIT_EXPR(I32, i32, 437, WASM_I32V_2(437));
|
||||||
EXPECT_INIT_EXPR(I32, i32, 77777, WASM_I32V_3(77777));
|
EXPECT_INIT_EXPR(I32, i32, 77777, WASM_I32V_3(77777));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, InitExpr_f32) {
|
TEST_F(WasmInitExprDecodeTest, InitExpr_f32) {
|
||||||
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(13.1), WASM_F32(13.1));
|
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(13.1), WASM_F32(13.1));
|
||||||
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(-21.1), WASM_F32(-21.1));
|
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(-21.1), WASM_F32(-21.1));
|
||||||
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(437.2), WASM_F32(437.2));
|
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(437.2), WASM_F32(437.2));
|
||||||
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(77777.3), WASM_F32(77777.3));
|
EXPECT_INIT_EXPR(F32, f32, static_cast<float>(77777.3), WASM_F32(77777.3));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, InitExpr_i64) {
|
TEST_F(WasmInitExprDecodeTest, InitExpr_i64) {
|
||||||
EXPECT_INIT_EXPR(I64, i64, 33, WASM_I64V_1(33));
|
EXPECT_INIT_EXPR(I64, i64, 33, WASM_I64V_1(33));
|
||||||
EXPECT_INIT_EXPR(I64, i64, -21, WASM_I64V_2(-21));
|
EXPECT_INIT_EXPR(I64, i64, -21, WASM_I64V_2(-21));
|
||||||
EXPECT_INIT_EXPR(I64, i64, 437, WASM_I64V_5(437));
|
EXPECT_INIT_EXPR(I64, i64, 437, WASM_I64V_5(437));
|
||||||
EXPECT_INIT_EXPR(I64, i64, 77777, WASM_I64V_7(77777));
|
EXPECT_INIT_EXPR(I64, i64, 77777, WASM_I64V_7(77777));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, InitExpr_f64) {
|
TEST_F(WasmInitExprDecodeTest, InitExpr_f64) {
|
||||||
EXPECT_INIT_EXPR(F64, f64, 83.22, WASM_F64(83.22));
|
EXPECT_INIT_EXPR(F64, f64, 83.22, WASM_F64(83.22));
|
||||||
EXPECT_INIT_EXPR(F64, f64, -771.3, WASM_F64(-771.3));
|
EXPECT_INIT_EXPR(F64, f64, -771.3, WASM_F64(-771.3));
|
||||||
EXPECT_INIT_EXPR(F64, f64, 43703.0, WASM_F64(43703.0));
|
EXPECT_INIT_EXPR(F64, f64, 43703.0, WASM_F64(43703.0));
|
||||||
EXPECT_INIT_EXPR(F64, f64, 77999.1, WASM_F64(77999.1));
|
EXPECT_INIT_EXPR(F64, f64, 77999.1, WASM_F64(77999.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, InitExpr_AnyRef) {
|
TEST_F(WasmInitExprDecodeTest, InitExpr_AnyRef) {
|
||||||
EXPERIMENTAL_FLAG_SCOPE(anyref);
|
WASM_FEATURE_SCOPE(anyref);
|
||||||
static const byte data[] = {kExprRefNull, kExprEnd};
|
static const byte data[] = {kExprRefNull, kExprEnd};
|
||||||
WasmInitExpr expr = DecodeWasmInitExprForTesting(data, data + sizeof(data));
|
WasmInitExpr expr = DecodeInitExpr(data, data + sizeof(data));
|
||||||
EXPECT_EQ(WasmInitExpr::kAnyRefConst, expr.kind);
|
EXPECT_EQ(WasmInitExpr::kAnyRefConst, expr.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef EXPECT_INIT_EXPR
|
TEST_F(WasmInitExprDecodeTest, InitExpr_illegal) {
|
||||||
|
|
||||||
#define EXPECT_INIT_EXPR_FAIL(...) \
|
|
||||||
{ \
|
|
||||||
static const byte data[] = {__VA_ARGS__, kExprEnd}; \
|
|
||||||
WasmInitExpr expr = \
|
|
||||||
DecodeWasmInitExprForTesting(data, data + sizeof(data)); \
|
|
||||||
EXPECT_EQ(WasmInitExpr::kNone, expr.kind); \
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, InitExpr_illegal) {
|
|
||||||
EXPECT_INIT_EXPR_FAIL(WASM_I32V_1(0), WASM_I32V_1(0));
|
EXPECT_INIT_EXPR_FAIL(WASM_I32V_1(0), WASM_I32V_1(0));
|
||||||
EXPECT_INIT_EXPR_FAIL(WASM_GET_LOCAL(0));
|
EXPECT_INIT_EXPR_FAIL(WASM_GET_LOCAL(0));
|
||||||
EXPECT_INIT_EXPR_FAIL(WASM_SET_LOCAL(0, WASM_I32V_1(0)));
|
EXPECT_INIT_EXPR_FAIL(WASM_SET_LOCAL(0, WASM_I32V_1(0)));
|
||||||
@ -2084,8 +2135,6 @@ TEST_F(WasmModuleVerifyTest, InitExpr_illegal) {
|
|||||||
EXPECT_INIT_EXPR_FAIL(WASM_IF_ELSE(WASM_ZERO, WASM_ZERO, WASM_ZERO));
|
EXPECT_INIT_EXPR_FAIL(WASM_IF_ELSE(WASM_ZERO, WASM_ZERO, WASM_ZERO));
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef EXPECT_INIT_EXPR_FAIL
|
|
||||||
|
|
||||||
TEST_F(WasmModuleVerifyTest, Multiple_Named_Sections) {
|
TEST_F(WasmModuleVerifyTest, Multiple_Named_Sections) {
|
||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
SECTION(Unknown, 4), 1, 'X', 17, 18, // --
|
SECTION(Unknown, 4), 1, 'X', 17, 18, // --
|
||||||
@ -2174,6 +2223,10 @@ TEST_F(WasmModuleCustomSectionTest, TwoKnownTwoUnknownSections) {
|
|||||||
CheckSections(data, data + sizeof(data), expected, arraysize(expected));
|
CheckSections(data, data + sizeof(data), expected, arraysize(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef WASM_FEATURE_SCOPE
|
||||||
|
#undef WASM_FEATURE_SCOPE_VAL
|
||||||
|
#undef EXPECT_INIT_EXPR
|
||||||
|
#undef EXPECT_INIT_EXPR_FAIL
|
||||||
#undef WASM_INIT_EXPR_I32V_1
|
#undef WASM_INIT_EXPR_I32V_1
|
||||||
#undef WASM_INIT_EXPR_I32V_2
|
#undef WASM_INIT_EXPR_I32V_2
|
||||||
#undef WASM_INIT_EXPR_I32V_3
|
#undef WASM_INIT_EXPR_I32V_3
|
||||||
|
@ -168,8 +168,8 @@ class WasmCodeManagerTest : public TestWithContext,
|
|||||||
bool can_request_more = style == Growable;
|
bool can_request_more = style == Growable;
|
||||||
ModuleEnv env(module.get(), UseTrapHandler::kNoTrapHandler,
|
ModuleEnv env(module.get(), UseTrapHandler::kNoTrapHandler,
|
||||||
RuntimeExceptionSupport::kNoRuntimeExceptionSupport);
|
RuntimeExceptionSupport::kNoRuntimeExceptionSupport);
|
||||||
return manager->NewNativeModule(i_isolate(), size, can_request_more,
|
return manager->NewNativeModule(i_isolate(), kAllWasmFeatures, size,
|
||||||
std::move(module), env);
|
can_request_more, std::move(module), env);
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmCode* AddCode(NativeModule* native_module, uint32_t index, size_t size) {
|
WasmCode* AddCode(NativeModule* native_module, uint32_t index, size_t size) {
|
||||||
|
Loading…
Reference in New Issue
Block a user