[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:
Ben L. Titzer 2018-08-08 16:54:44 +02:00 committed by Commit Bot
parent 3b2b858f11
commit 6aa2a25313
44 changed files with 680 additions and 355 deletions

View File

@ -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",

View File

@ -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()));
} }

View File

@ -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: "

View File

@ -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,

View File

@ -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.

View File

@ -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>();
} }

View File

@ -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();

View File

@ -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);

View File

@ -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++) {

View File

@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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>());

View File

@ -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_;
}; };

View File

@ -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_);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View 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
View 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
View 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_

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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.

View File

@ -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) {

View File

@ -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 << ")";

View File

@ -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) {

View File

@ -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);
} }

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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.

View File

@ -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) {

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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) {