[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-external-refs.cc",
"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.h",
"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())) {
return MaybeLocal<WasmCompiledModule>();
}
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
i::MaybeHandle<i::JSObject> maybe_compiled =
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>();
return Local<WasmCompiledModule>::Cast(
Utils::ToLocal(maybe_compiled.ToHandleChecked()));
@ -7787,8 +7789,9 @@ WasmModuleObjectBuilderStreaming::WasmModuleObjectBuilderStreaming(
promise_.Reset(isolate, resolver->GetPromise());
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
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()));
}

View File

@ -2889,7 +2889,6 @@ void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type,
Node** offset_node) {
DCHECK_NOT_NULL(instance_node_);
if (global.mutability && global.imported) {
DCHECK(FLAG_experimental_wasm_mut_global);
if (imported_mutable_globals_ == nullptr) {
// Load imported_mutable_globals_ from the instance object at runtime.
imported_mutable_globals_ = graph()->NewNode(
@ -5035,9 +5034,14 @@ SourcePositionTable* TurbofanWasmCompilationUnit::BuildGraphForWasmFunction(
new (mcgraph->zone()) SourcePositionTable(mcgraph->graph());
WasmGraphBuilder builder(wasm_unit_->env_, mcgraph->zone(), mcgraph,
wasm_unit_->func_body_.sig, source_position_table);
graph_construction_result_ =
wasm::BuildTFGraph(wasm_unit_->wasm_engine_->allocator(), &builder,
wasm_unit_->func_body_, node_origins);
// TODO(titzer): gather detected features into a per-module location
// in order to increment an embedder feature use count.
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 (FLAG_trace_wasm_compiler) {
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,
"directory to dump wasm modules to")
DEFINE_BOOL(experimental_wasm_simd, false,
"enable prototype simd opcodes for wasm")
DEFINE_BOOL(experimental_wasm_eh, false,
"enable prototype exception handling opcodes for wasm")
DEFINE_BOOL(experimental_wasm_mv, false,
"enable prototype multi-value support for wasm")
DEFINE_BOOL(experimental_wasm_threads, false,
"enable prototype threads for wasm")
DEFINE_BOOL(experimental_wasm_sat_f2i_conversions, false,
"enable non-trapping float-to-int conversions for wasm")
DEFINE_BOOL(experimental_wasm_se, true,
"enable prototype sign extension opcodes for wasm")
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")
// Declare command-line flags for WASM features. Warning: avoid using these
// flags directly in the implementation. Instead accept wasm::WasmFeatures
// for configurability.
#include "src/wasm/wasm-feature-flags.h"
#define SPACE
#define DECL_WASM_FLAG(feat, desc, val) \
DEFINE_BOOL(experimental_wasm_##feat, val, \
"enable prototype " desc " for wasm")
FOREACH_WASM_FEATURE_FLAG(DECL_WASM_FLAG, SPACE)
#undef DECL_WASM_FLAG
#undef SPACE
DEFINE_BOOL(wasm_opt, false, "enable wasm optimization")
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) {
// 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())
return false;
HandleScope scope(this);
@ -1307,7 +1309,7 @@ Object* Isolate::UnwindAndFindHandler() {
trap_handler::ClearThreadInWasm();
}
if (!FLAG_experimental_wasm_eh || !is_catchable_by_wasm(exception)) {
if (!is_catchable_by_wasm(exception)) {
break;
}
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));
}
break;
case WASM_MEMORY_TYPE:
if (FLAG_experimental_wasm_threads) {
case WASM_MEMORY_TYPE: {
auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
if (enabled_features.threads) {
return WriteWasmMemory(Handle<WasmMemoryObject>::cast(receiver));
}
break;
}
default:
break;
}
@ -1805,8 +1807,11 @@ MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
wasm::DeserializeNativeModule(isolate_, compiled_bytes, wire_bytes);
if (result.is_null()) {
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(
isolate_, &thrower, wasm::ModuleWireBytes(wire_bytes));
isolate_, enabled_features, &thrower,
wasm::ModuleWireBytes(wire_bytes));
}
uint32_t id = next_id_++;
if (!result.is_null()) {
@ -1818,7 +1823,8 @@ MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
uint32_t id = next_id_++;
if (!FLAG_experimental_wasm_threads) {
auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
if (!enabled_features.threads) {
return MaybeHandle<WasmMemoryObject>();
}

View File

@ -1135,7 +1135,6 @@ class LiftoffCompiler {
uint32_t* offset) {
LiftoffRegister addr = pinned.set(__ GetUnusedRegister(kGpReg));
if (global->mutability && global->imported) {
DCHECK(FLAG_experimental_wasm_mut_global);
LOAD_INSTANCE_FIELD(addr, ImportedMutableGlobals, kPointerLoadType);
__ Load(addr, addr.gp(), no_reg, global->index * sizeof(Address),
kPointerLoadType, pinned);
@ -1851,9 +1850,11 @@ bool LiftoffCompilationUnit::ExecuteCompilation() {
compiler::GetWasmCallDescriptor(&zone, wasm_unit_->func_body_.sig);
base::Optional<TimedHistogramScope> liftoff_compile_time_scope(
base::in_place, wasm_unit_->counters_->liftoff_compile_time());
WasmFeatures unused_detected_features;
WasmFullDecoder<Decoder::kValidate, LiftoffCompiler> decoder(
&zone, module, wasm_unit_->func_body_, call_descriptor, wasm_unit_->env_,
&zone);
&zone, module, wasm_unit_->native_module_->enabled_features(),
&unused_detected_features, wasm_unit_->func_body_, call_descriptor,
wasm_unit_->env_, &zone);
decoder.Decode();
liftoff_compile_time_scope.reset();
LiftoffCompiler* compiler = &decoder.interface();

View File

@ -12,6 +12,7 @@
#include "src/bit-vector.h"
#include "src/wasm/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-module.h"
#include "src/wasm/wasm-opcodes.h"
@ -38,17 +39,21 @@ struct WasmException;
return true; \
}())
#define RET_ON_PROTOTYPE_OPCODE(flag) \
#define RET_ON_PROTOTYPE_OPCODE(feat) \
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
if (!FLAG_experimental_wasm_##flag) { \
this->error("Invalid opcode (enable with --experimental-wasm-" #flag ")"); \
if (!this->enabled_.feat) { \
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); \
if (!FLAG_experimental_wasm_##flag) { \
this->error("Invalid opcode (enable with --experimental-wasm-" #flag ")"); \
if (!this->enabled_.feat) { \
this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
break; \
} else { \
this->detected_->feat = true; \
}
#define OPCODE_ERROR(opcode, message) \
@ -209,11 +214,12 @@ struct BlockTypeImmediate {
uint32_t sig_index = 0;
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");
if (!decode_local_type(val, &type)) {
// Handle multi-value blocks.
if (!VALIDATE(FLAG_experimental_wasm_mv)) {
if (!VALIDATE(enabled.mv)) {
decoder->error(pc + 1, "invalid block type");
return;
}
@ -661,13 +667,18 @@ struct ControlWithNamedConstructors : public ControlBase<Value> {
template <Decoder::ValidateFlag validate>
class WasmDecoder : public Decoder {
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)
: Decoder(start, end, buffer_offset),
module_(module),
enabled_(enabled),
detected_(detected),
sig_(sig),
local_types_(nullptr) {}
const WasmModule* module_;
const WasmFeatures enabled_;
WasmFeatures* detected_;
FunctionSig* sig_;
ZoneVector<ValueType>* local_types_;
@ -678,7 +689,8 @@ class WasmDecoder : public Decoder {
: 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) {
DCHECK_NOT_NULL(type_list);
DCHECK_EQ(0, type_list->size());
@ -718,14 +730,14 @@ class WasmDecoder : public Decoder {
type = kWasmF64;
break;
case kLocalAnyRef:
if (FLAG_experimental_wasm_anyref) {
if (enabled.anyref) {
type = kWasmAnyRef;
break;
}
decoder->error(decoder->pc() - 1, "invalid local type");
return false;
case kLocalS128:
if (FLAG_experimental_wasm_simd) {
if (enabled.simd) {
type = kWasmS128;
break;
}
@ -1008,7 +1020,7 @@ class WasmDecoder : public Decoder {
case kExprIf: // fall through
case kExprLoop:
case kExprBlock: {
BlockTypeImmediate<validate> imm(decoder, pc);
BlockTypeImmediate<validate> imm(kAllWasmFeatures, decoder, pc);
return 1 + imm.length;
}
@ -1215,9 +1227,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
public:
template <typename... InterfaceArgs>
WasmFullDecoder(Zone* zone, const WasmModule* module,
const WasmFeatures& enabled, WasmFeatures* detected,
const FunctionBody& body, InterfaceArgs&&... interface_args)
: WasmDecoder<validate>(module, body.sig, body.start, body.end,
body.offset),
: WasmDecoder<validate>(module, enabled, detected, body.sig, body.start,
body.end, body.offset),
zone_(zone),
interface_(std::forward<InterfaceArgs>(interface_args)...),
local_type_vec_(zone),
@ -1245,7 +1258,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
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);
DecodeFunctionBody();
if (!this->failed()) CALL_INTERFACE(FinishFunction);
@ -1433,7 +1447,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
case kExprNop:
break;
case kExprBlock: {
BlockTypeImmediate<validate> imm(this, this->pc_);
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
if (!this->Validate(imm)) break;
PopArgs(imm.sig);
auto* block = PushBlock();
@ -1462,7 +1476,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
case kExprTry: {
CHECK_PROTOTYPE_OPCODE(eh);
BlockTypeImmediate<validate> imm(this, this->pc_);
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
if (!this->Validate(imm)) break;
PopArgs(imm.sig);
auto* try_block = PushTry();
@ -1515,7 +1529,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break;
}
case kExprLoop: {
BlockTypeImmediate<validate> imm(this, this->pc_);
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
if (!this->Validate(imm)) break;
PopArgs(imm.sig);
auto* block = PushLoop();
@ -1526,7 +1540,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break;
}
case kExprIf: {
BlockTypeImmediate<validate> imm(this, this->pc_);
BlockTypeImmediate<validate> imm(this->enabled_, this, this->pc_);
if (!this->Validate(imm)) break;
auto cond = Pop(0, kWasmI32);
PopArgs(imm.sig);

View File

@ -809,10 +809,10 @@ class WasmGraphBuildingInterface {
} // namespace
bool DecodeLocalDecls(BodyLocalDecls* decls, const byte* start,
const byte* end) {
bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
const byte* start, const byte* end) {
Decoder decoder(start, end);
if (WasmDecoder<Decoder::kValidate>::DecodeLocals(&decoder, nullptr,
if (WasmDecoder<Decoder::kValidate>::DecodeLocals(enabled, &decoder, nullptr,
&decls->type_list)) {
DCHECK(decoder.ok());
decls->encoded_size = decoder.pc_offset();
@ -825,7 +825,7 @@ BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
BodyLocalDecls* decls)
: Decoder(start, end) {
if (decls != nullptr) {
if (DecodeLocalDecls(decls, start, end)) {
if (DecodeLocalDecls(kAllWasmFeatures, decls, start, end)) {
pc_ += decls->encoded_size;
if (pc_ > end_) pc_ = end_;
}
@ -833,20 +833,24 @@ BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
}
DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
const WasmModule* module, FunctionBody& body) {
const WasmFeatures& enabled,
const WasmModule* module, WasmFeatures* detected,
FunctionBody& body) {
Zone zone(allocator, ZONE_NAME);
WasmFullDecoder<Decoder::kValidate, EmptyInterface> decoder(&zone, module,
body);
WasmFullDecoder<Decoder::kValidate, EmptyInterface> decoder(
&zone, module, enabled, detected, body);
decoder.Decode();
return decoder.toResult(nullptr);
}
DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
FunctionBody& body,
DecodeResult BuildTFGraph(AccountingAllocator* allocator,
const WasmFeatures& enabled,
const wasm::WasmModule* module, TFBuilder* builder,
WasmFeatures* detected, FunctionBody& body,
compiler::NodeOriginTable* node_origins) {
Zone zone(allocator, ZONE_NAME);
WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder(
&zone, builder->module(), body, builder);
&zone, module, enabled, detected, body, builder);
if (node_origins) {
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,
FunctionSig* sig, const byte* pc,
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);
}
@ -900,8 +906,10 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
const WasmModule* module, PrintLocals print_locals,
std::ostream& os, std::vector<int>* line_numbers) {
Zone zone(allocator, ZONE_NAME);
WasmDecoder<Decoder::kNoValidate> decoder(module, body.sig, body.start,
body.end);
WasmFeatures unused_detected_features;
WasmDecoder<Decoder::kNoValidate> decoder(module, kAllWasmFeatures,
&unused_detected_features, body.sig,
body.start, body.end);
int line_nr = 0;
constexpr int kNoByteCode = -1;
@ -999,7 +1007,8 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
case kExprIf:
case kExprBlock:
case kExprTry: {
BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
i.pc());
os << " // @" << i.pc_offset();
if (decoder.Complete(imm)) {
for (unsigned i = 0; i < imm.out_arity(); i++) {

View File

@ -25,8 +25,10 @@ class WasmGraphBuilder;
namespace wasm {
typedef compiler::WasmGraphBuilder TFBuilder;
struct WasmModule; // forward declaration of module interface.
struct WasmFeatures;
typedef compiler::WasmGraphBuilder TFBuilder;
// A wrapper around the signature and bytes of a function.
struct FunctionBody {
@ -41,10 +43,14 @@ struct FunctionBody {
};
V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
const WasmFeatures& enabled,
const WasmModule* module,
WasmFeatures* detected,
FunctionBody& body);
DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder,
DecodeResult BuildTFGraph(AccountingAllocator* allocator,
const WasmFeatures& enabled, const WasmModule* module,
TFBuilder* builder, WasmFeatures* detected,
FunctionBody& body,
compiler::NodeOriginTable* node_origins);
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.
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 {
// The size of the encoded declarations.
uint32_t encoded_size = 0; // size of encoded declarations
@ -84,7 +76,8 @@ struct BodyLocalDecls {
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);
V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone,

View File

@ -223,6 +223,7 @@ class InstanceBuilder {
};
Isolate* isolate_;
const WasmFeatures enabled_;
const WasmModule* const module_;
ErrorThrower* thrower_;
Handle<WasmModuleObject> module_object_;
@ -688,7 +689,10 @@ void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
wasm_decode, function_time);
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()) {
TruncatedUserString<> name(wire_bytes.GetName(&func, module));
@ -840,7 +844,7 @@ class BackgroundCompileTask : public CancelableTask {
} // namespace
MaybeHandle<WasmModuleObject> CompileToModuleObject(
Isolate* isolate, ErrorThrower* thrower,
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
Handle<Script> asm_js_script,
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
// only have one WasmModuleObject. Otherwise, we might only set
// breakpoints on a (potentially empty) subset of the instances.
ModuleEnv env = CreateDefaultModuleEnv(wasm_module);
// 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
// object.
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
isolate, std::move(module), env, std::move(wire_bytes_copy), script,
asm_js_offset_table);
isolate, enabled, std::move(module), env, std::move(wire_bytes_copy),
script, asm_js_offset_table);
CompileNativeModule(isolate, thrower, module_object, wasm_module, &env);
if (thrower->error()) return {};
@ -910,6 +913,7 @@ InstanceBuilder::InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
MaybeHandle<JSReceiver> ffi,
MaybeHandle<JSArrayBuffer> memory)
: isolate_(isolate),
enabled_(module_object->native_module()->enabled_features()),
module_(module_object->module()),
thrower_(thrower),
module_object_(module_object),
@ -965,7 +969,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
memory->backing_store() == nullptr ||
// TODO(836800) Remove once is_wasm_memory transfers over
// post-message.
(FLAG_experimental_wasm_threads && memory->is_shared()));
(enabled_.threads && memory->is_shared()));
} else if (initial_pages > 0 || use_trap_handler()) {
// We need to unconditionally create a guard region if using trap handlers,
// 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.
//--------------------------------------------------------------------------
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
// more than required if multiple globals are imported from the same
// module.
@ -1632,8 +1635,8 @@ int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
// The mutable-global proposal allows importing i64 values, but only if
// they are passed as a WebAssembly.Global object.
if (global.type == kWasmI64 && !(FLAG_experimental_wasm_mut_global &&
value->IsWasmGlobalObject())) {
if (global.type == kWasmI64 &&
!(enabled_.mut_global && value->IsWasmGlobalObject())) {
ReportLinkError("global import cannot have type i64", index,
module_name, import_name);
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()) {
auto global_object = Handle<WasmGlobalObject>::cast(value);
if (global_object->type() != global.type) {
@ -1729,7 +1732,6 @@ T* InstanceBuilder::GetRawGlobalPtr(const WasmGlobal& global) {
void InstanceBuilder::InitGlobals() {
for (auto global : module_->globals) {
if (global.mutability && global.imported) {
DCHECK(FLAG_experimental_wasm_mut_global);
continue;
}
@ -1775,8 +1777,7 @@ Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t num_pages) {
thrower_->RangeError("Out of memory: wasm memory too large");
return Handle<JSArrayBuffer>::null();
}
const bool is_shared_memory =
module_->has_shared_memory && i::FLAG_experimental_wasm_threads;
const bool is_shared_memory = module_->has_shared_memory && enabled_.threads;
i::SharedFlag shared_flag =
is_shared_memory ? i::SharedFlag::kShared : i::SharedFlag::kNotShared;
Handle<JSArrayBuffer> mem_buffer;
@ -1918,7 +1919,7 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
}
case kExternalGlobal: {
const WasmGlobal& global = module_->globals[exp.index];
if (FLAG_experimental_wasm_mut_global) {
if (enabled_.mut_global) {
Handle<JSArrayBuffer> buffer;
uint32_t offset;
@ -2093,10 +2094,11 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
}
AsyncCompileJob::AsyncCompileJob(
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
Handle<Context> context,
Isolate* isolate, const WasmFeatures& enabled,
std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
std::unique_ptr<CompilationResultResolver> resolver)
: isolate_(isolate),
enabled_features_(enabled),
async_counters_(isolate->async_counters()),
bytes_copy_(std::move(bytes_copy)),
wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
@ -2311,8 +2313,9 @@ class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
// Decode the module bytes.
TRACE_COMPILE("(1) Decoding module...\n");
result =
DecodeWasmModule(job_->wire_bytes_.start(), job_->wire_bytes_.end(),
false, kWasmOrigin, job_->async_counters().get(),
DecodeWasmModule(job_->enabled_features_, job_->wire_bytes_.start(),
job_->wire_bytes_.end(), false, kWasmOrigin,
job_->async_counters().get(),
job_->isolate()->wasm_engine()->allocator());
}
if (result.failed()) {
@ -2379,7 +2382,7 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
// breakpoints on a (potentially empty) subset of the instances.
// Create the module object.
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,
asm_js_offset_table);
job_->native_module_ = job_->module_object_->native_module();
@ -2530,7 +2533,9 @@ class AsyncCompileJob::FinishModule : public CompileStep {
};
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) {
// 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/globals.h"
#include "src/wasm/wasm-features.h"
#include "src/wasm/wasm-module.h"
namespace v8 {
@ -48,7 +49,7 @@ std::unique_ptr<CompilationState, CompilationStateDeleter> NewCompilationState(
ModuleEnv* GetModuleEnv(CompilationState* compilation_state);
MaybeHandle<WasmModuleObject> CompileToModuleObject(
Isolate* isolate, ErrorThrower* thrower,
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_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.
class AsyncCompileJob {
public:
explicit AsyncCompileJob(Isolate* isolate, std::unique_ptr<byte[]> bytes_copy,
size_t length, Handle<Context> context,
std::unique_ptr<CompilationResultResolver> resolver);
AsyncCompileJob(Isolate* isolate, const WasmFeatures& enabled_features,
std::unique_ptr<byte[]> bytes_copy, size_t length,
Handle<Context> context,
std::unique_ptr<CompilationResultResolver> resolver);
~AsyncCompileJob();
void Start();
@ -138,6 +140,7 @@ class AsyncCompileJob {
friend class AsyncStreamingProcessor;
Isolate* isolate_;
const WasmFeatures enabled_features_;
const std::shared_ptr<Counters> async_counters_;
// Copy of the module wire bytes, moved into the {native_module_} on it's
// creation.

View File

@ -83,8 +83,7 @@ const char* SectionName(SectionCode code) {
case kNameSectionCode:
return kNameString;
case kExceptionSectionCode:
if (FLAG_experimental_wasm_eh) return kExceptionString;
return kUnknownString;
return kExceptionString;
default:
return kUnknownString;
}
@ -247,13 +246,15 @@ class WasmSectionIterator {
// The main logic for decoding the bytes of a module.
class ModuleDecoderImpl : public Decoder {
public:
explicit ModuleDecoderImpl(ModuleOrigin origin)
explicit ModuleDecoderImpl(const WasmFeatures& enabled, ModuleOrigin origin)
: Decoder(nullptr, nullptr),
enabled_features_(enabled),
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {}
ModuleDecoderImpl(const byte* module_start, const byte* module_end,
ModuleOrigin origin)
ModuleDecoderImpl(const WasmFeatures& enabled, const byte* module_start,
const byte* module_end, ModuleOrigin origin)
: Decoder(module_start, module_end),
enabled_features_(enabled),
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
if (end_ < start_) {
error(start_, "end is less than start");
@ -401,7 +402,7 @@ class ModuleDecoderImpl : public Decoder {
DecodeNameSection();
break;
case kExceptionSectionCode:
if (FLAG_experimental_wasm_eh) {
if (enabled_features_.eh) {
DecodeExceptionSection();
} else {
errorf(pc(), "unexpected section: %s", SectionName(section_code));
@ -479,7 +480,7 @@ class ModuleDecoderImpl : public Decoder {
WasmTable* table = &module_->tables.back();
table->imported = true;
ValueType type = consume_reference_type();
if (!FLAG_experimental_wasm_anyref) {
if (!enabled_features_.anyref) {
if (type != kWasmAnyFunc) {
error(pc_ - 1, "invalid table type");
break;
@ -512,7 +513,7 @@ class ModuleDecoderImpl : public Decoder {
global->type = consume_value_type();
global->mutability = consume_mutability();
if (global->mutability) {
if (FLAG_experimental_wasm_mut_global) {
if (enabled_features_.mut_global) {
module_->num_imported_mutable_globals++;
} else {
error("mutable globals cannot be imported");
@ -556,7 +557,7 @@ class ModuleDecoderImpl : public Decoder {
void DecodeTableSection() {
// TODO(ahaas): Set the correct limit to {kV8MaxWasmTables} once the
// 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);
for (uint32_t i = 0; ok() && i < table_count; i++) {
@ -647,7 +648,7 @@ class ModuleDecoderImpl : public Decoder {
WasmGlobal* global = nullptr;
exp->index = consume_global_index(module_.get(), &global);
if (global) {
if (!FLAG_experimental_wasm_mut_global && global->mutability) {
if (!enabled_features_.mut_global && global->mutability) {
error("mutable globals cannot be exported");
}
global->exported = true;
@ -710,7 +711,7 @@ class ModuleDecoderImpl : public Decoder {
for (uint32_t i = 0; ok() && i < element_count; ++i) {
const byte* pos = pc();
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);
}
if (table_index >= module_->tables.size()) {
@ -930,6 +931,7 @@ class ModuleDecoderImpl : public Decoder {
}
private:
const WasmFeatures enabled_features_;
std::shared_ptr<WasmModule> module_;
Counters* counters_ = nullptr;
// The type section is the first section in a module.
@ -948,7 +950,7 @@ class ModuleDecoderImpl : public Decoder {
}
bool AddTable(WasmModule* module) {
if (FLAG_experimental_wasm_anyref) return true;
if (enabled_features_.anyref) return true;
if (module->tables.size() > 0) {
error("At most one table is supported");
return false;
@ -1021,7 +1023,7 @@ class ModuleDecoderImpl : public Decoder {
for (WasmGlobal& global : module->globals) {
byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(global.type));
if (global.mutability && global.imported) {
DCHECK(FLAG_experimental_wasm_mut_global);
DCHECK(enabled_features_.mut_global);
global.index = num_imported_mutable_globals++;
} else {
offset = (offset + size - 1) & ~(size - 1); // align
@ -1053,7 +1055,9 @@ class ModuleDecoderImpl : public Decoder {
wasm_decode, function_time);
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()) {
@ -1131,7 +1135,7 @@ class ModuleDecoderImpl : public Decoder {
uint8_t flags = consume_u8("resizable limits flags");
const byte* pos = pc();
*has_shared_memory = false;
if (FLAG_experimental_wasm_threads) {
if (enabled_features_.threads) {
if (flags & 0xFC) {
errorf(pos - 1, "invalid memory limits flags");
} else if (flags == 3) {
@ -1249,7 +1253,7 @@ class ModuleDecoderImpl : public Decoder {
break;
}
case kExprRefNull: {
if (FLAG_experimental_wasm_anyref) {
if (enabled_features_.anyref) {
expr.kind = WasmInitExpr::kAnyRefConst;
len = 0;
break;
@ -1298,13 +1302,13 @@ class ModuleDecoderImpl : public Decoder {
if (origin_ == kWasmOrigin) {
switch (t) {
case kLocalS128:
if (FLAG_experimental_wasm_simd) return kWasmS128;
if (enabled_features_.simd) return kWasmS128;
break;
case kLocalAnyFunc:
if (FLAG_experimental_wasm_anyref) return kWasmAnyFunc;
if (enabled_features_.anyref) return kWasmAnyFunc;
break;
case kLocalAnyRef:
if (FLAG_experimental_wasm_anyref) return kWasmAnyRef;
if (enabled_features_.anyref) return kWasmAnyRef;
break;
default:
break;
@ -1323,7 +1327,7 @@ class ModuleDecoderImpl : public Decoder {
case kLocalAnyFunc:
return kWasmAnyFunc;
case kLocalAnyRef:
if (!FLAG_experimental_wasm_anyref) {
if (!enabled_features_.anyref) {
error(pc_ - 1,
"Invalid type. Set --experimental-wasm-anyref to use 'AnyRef'");
}
@ -1362,7 +1366,7 @@ class ModuleDecoderImpl : public Decoder {
uint32_t return_count = 0;
if (has_return_values) {
// parse return types
const size_t max_return_count = FLAG_experimental_wasm_mv
const size_t max_return_count = enabled_features_.mv
? kV8MaxWasmFunctionMultiReturns
: kV8MaxWasmFunctionReturns;
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,
Counters* counters,
AccountingAllocator* allocator) {
@ -1402,7 +1407,7 @@ ModuleResult DecodeWasmModule(const byte* module_start, const byte* module_end,
size_counter->AddSample(static_cast<int>(size));
// Signatures are stored in zone memory, which have the same lifetime
// as the {module}.
ModuleDecoderImpl decoder(module_start, module_end, origin);
ModuleDecoderImpl decoder(enabled, module_start, module_end, origin);
ModuleResult result =
decoder.DecodeModule(counters, allocator, verify_functions);
// TODO(bradnelson): Improve histogram handling of size_t.
@ -1418,7 +1423,9 @@ ModuleResult DecodeWasmModule(const byte* module_start, const byte* module_end,
return result;
}
ModuleDecoder::ModuleDecoder() = default;
ModuleDecoder::ModuleDecoder(const WasmFeatures& enabled)
: enabled_features_(enabled) {}
ModuleDecoder::~ModuleDecoder() = default;
const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
@ -1429,7 +1436,7 @@ void ModuleDecoder::StartDecoding(Counters* counters,
AccountingAllocator* allocator,
ModuleOrigin origin) {
DCHECK_NULL(impl_);
impl_.reset(new ModuleDecoderImpl(origin));
impl_.reset(new ModuleDecoderImpl(enabled_features_, origin));
impl_->StartDecoding(counters, allocator);
}
@ -1481,21 +1488,24 @@ SectionCode ModuleDecoder::IdentifyUnknownSection(Decoder& decoder,
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) {
ModuleDecoderImpl decoder(start, end, kWasmOrigin);
ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
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;
ModuleDecoderImpl decoder(start, end, kWasmOrigin);
ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
return decoder.DecodeInitExpr(start);
}
FunctionResult DecodeWasmFunctionForTesting(
Zone* zone, const ModuleWireBytes& wire_bytes, const WasmModule* module,
const byte* function_start, const byte* function_end, Counters* counters) {
const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
const WasmModule* module, const byte* function_start,
const byte* function_end, Counters* counters) {
size_t size = function_end - function_start;
if (function_start > function_end)
return FunctionResult::Error("start > end");
@ -1505,7 +1515,7 @@ FunctionResult DecodeWasmFunctionForTesting(
size_histogram->AddSample(static_cast<int>(size));
if (size > kV8MaxWasmFunctionSize)
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);
return decoder.DecodeSingleFunction(zone, wire_bytes, module,
base::make_unique<WasmFunction>());

View File

@ -8,6 +8,7 @@
#include "src/globals.h"
#include "src/wasm/function-body-decoder.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-features.h"
#include "src/wasm/wasm-module.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}.
V8_EXPORT_PRIVATE ModuleResult DecodeWasmModule(
const byte* module_start, const byte* module_end, bool verify_functions,
ModuleOrigin origin, Counters* counters, AccountingAllocator* allocator);
const WasmFeatures& enabled, const byte* module_start,
const byte* module_end, bool verify_functions, ModuleOrigin origin,
Counters* counters, AccountingAllocator* allocator);
// Exposed for testing. Decodes a single function signature, allocating it
// in the given zone. Returns {nullptr} upon failure.
V8_EXPORT_PRIVATE FunctionSig* DecodeWasmSignatureForTesting(Zone* zone,
const byte* start,
const byte* end);
V8_EXPORT_PRIVATE FunctionSig* DecodeWasmSignatureForTesting(
const WasmFeatures& enabled, Zone* zone, const byte* start,
const byte* end);
// Decodes the bytes of a wasm function between
// {function_start} and {function_end}.
V8_EXPORT_PRIVATE FunctionResult DecodeWasmFunctionForTesting(
Zone* zone, const ModuleWireBytes& wire_bytes, const WasmModule* module,
const byte* function_start, const byte* function_end, Counters* counters);
const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
const WasmModule* module, const byte* function_start,
const byte* function_end, Counters* counters);
V8_EXPORT_PRIVATE WasmInitExpr DecodeWasmInitExprForTesting(const byte* start,
const byte* end);
V8_EXPORT_PRIVATE WasmInitExpr DecodeWasmInitExprForTesting(
const WasmFeatures& enabled, const byte* start, const byte* end);
struct CustomSectionOffset {
WireBytesRef section;
@ -111,7 +114,7 @@ class ModuleDecoderImpl;
class ModuleDecoder {
public:
ModuleDecoder();
explicit ModuleDecoder(const WasmFeatures& enabled);
~ModuleDecoder();
void StartDecoding(Counters* counters, AccountingAllocator* allocator,
@ -145,6 +148,7 @@ class ModuleDecoder {
static SectionCode IdentifyUnknownSection(Decoder& decoder, const byte* end);
private:
const WasmFeatures enabled_features_;
std::unique_ptr<ModuleDecoderImpl> impl_;
};

View File

@ -298,12 +298,13 @@ WasmCode::~WasmCode() {
}
}
NativeModule::NativeModule(Isolate* isolate, bool can_request_more,
VirtualMemory* code_space,
NativeModule::NativeModule(Isolate* isolate, const WasmFeatures& enabled,
bool can_request_more, VirtualMemory* code_space,
WasmCodeManager* code_manager,
std::shared_ptr<const WasmModule> module,
const ModuleEnv& env)
: module_(std::move(module)),
: enabled_features_(enabled),
module_(std::move(module)),
compilation_state_(NewCompilationState(isolate, env)),
free_code_space_({code_space->address(), code_space->end()}),
wasm_code_manager_(code_manager),
@ -853,8 +854,9 @@ bool WasmCodeManager::ShouldForceCriticalMemoryPressureNotification() {
}
std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
Isolate* isolate, size_t memory_estimate, bool can_request_more,
std::shared_ptr<const WasmModule> module, const ModuleEnv& env) {
Isolate* isolate, const WasmFeatures& enabled, size_t memory_estimate,
bool can_request_more, std::shared_ptr<const WasmModule> module,
const ModuleEnv& env) {
if (ShouldForceCriticalMemoryPressureNotification()) {
(reinterpret_cast<v8::Isolate*>(isolate))
->MemoryPressureNotification(MemoryPressureLevel::kCritical);
@ -868,8 +870,9 @@ std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
Address start = mem.address();
size_t size = mem.size();
Address end = mem.end();
std::unique_ptr<NativeModule> ret(new NativeModule(
isolate, can_request_more, &mem, this, std::move(module), env));
std::unique_ptr<NativeModule> ret(
new NativeModule(isolate, enabled, can_request_more, &mem, this,
std::move(module), env));
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", this, start,
size);
base::LockGuard<base::Mutex> lock(&native_modules_mutex_);

View File

@ -16,6 +16,7 @@
#include "src/trap-handler/trap-handler.h"
#include "src/vector.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-features.h"
namespace v8 {
namespace internal {
@ -345,13 +346,16 @@ class V8_EXPORT_PRIVATE NativeModule final {
~NativeModule();
const WasmFeatures& enabled_features() const { return enabled_features_; }
private:
friend class WasmCode;
friend class WasmCodeManager;
friend class NativeModuleModificationScope;
NativeModule(Isolate* isolate, bool can_request_more,
VirtualMemory* code_space, WasmCodeManager* code_manager,
NativeModule(Isolate* isolate, const WasmFeatures& enabled_features,
bool can_request_more, VirtualMemory* code_space,
WasmCodeManager* code_manager,
std::shared_ptr<const WasmModule> module, const ModuleEnv& env);
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;
}
// 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
// AsyncCompileJob).
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.
// TODO(titzer): isolate is only required here for CompilationState.
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);
NativeModule* LookupNativeModule(Address pc) const;

View File

@ -25,11 +25,12 @@ WasmEngine::~WasmEngine() {
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.
if (bytes.start() == nullptr || bytes.length() == 0) return false;
ModuleResult result =
DecodeWasmModule(bytes.start(), bytes.end(), true, kWasmOrigin,
DecodeWasmModule(enabled, bytes.start(), bytes.end(), true, kWasmOrigin,
isolate->counters(), allocator());
return result.ok();
}
@ -39,20 +40,22 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompileTranslatedAsmJs(
Handle<Script> asm_js_script,
Vector<const byte> asm_js_offset_table_bytes) {
ModuleResult result =
DecodeWasmModule(bytes.start(), bytes.end(), false, kAsmJsOrigin,
isolate->counters(), allocator());
DecodeWasmModule(kAsmjsWasmFeatures, bytes.start(), bytes.end(), false,
kAsmJsOrigin, isolate->counters(), allocator());
CHECK(!result.failed());
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
// in {CompileToModuleObject}.
return CompileToModuleObject(isolate, thrower, std::move(result.val), bytes,
asm_js_script, asm_js_offset_table_bytes);
return CompileToModuleObject(isolate, kAsmjsWasmFeatures, thrower,
std::move(result.val), bytes, asm_js_script,
asm_js_offset_table_bytes);
}
MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) {
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
const ModuleWireBytes& bytes) {
ModuleResult result =
DecodeWasmModule(bytes.start(), bytes.end(), false, kWasmOrigin,
DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
isolate->counters(), allocator());
if (result.failed()) {
thrower->CompileFailed("Wasm decoding failed", result);
@ -61,8 +64,8 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
// in {CompileToModuleObject}.
return CompileToModuleObject(isolate, thrower, std::move(result.val), bytes,
Handle<Script>(), Vector<const byte>());
return CompileToModuleObject(isolate, enabled, thrower, std::move(result.val),
bytes, Handle<Script>(), Vector<const byte>());
}
MaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate(
@ -109,7 +112,8 @@ void WasmEngine::AsyncInstantiate(
}
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) {
if (!FLAG_wasm_async_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()]);
memcpy(copy.get(), bytes.start(), 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 {
// 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()) {
resolver->OnCompilationFailed(thrower.Reify());
@ -136,8 +140,9 @@ void WasmEngine::AsyncCompile(
if (FLAG_wasm_test_streaming) {
std::shared_ptr<StreamingDecoder> streaming_decoder =
isolate->wasm_engine()->StartStreamingCompilation(
isolate, handle(isolate->context(), isolate), std::move(resolver));
StartStreamingCompilation(isolate, enabled,
handle(isolate->context(), isolate),
std::move(resolver));
streaming_decoder->OnBytesReceived(bytes.module_bytes());
streaming_decoder->Finish();
return;
@ -148,17 +153,17 @@ void WasmEngine::AsyncCompile(
memcpy(copy.get(), bytes.start(), bytes.length());
AsyncCompileJob* job = CreateAsyncCompileJob(
isolate, std::move(copy), bytes.length(),
isolate, enabled, std::move(copy), bytes.length(),
handle(isolate->context(), isolate), std::move(resolver));
job->Start();
}
std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
Isolate* isolate, Handle<Context> context,
Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
std::unique_ptr<CompilationResultResolver> resolver) {
AsyncCompileJob* job =
CreateAsyncCompileJob(isolate, std::unique_ptr<byte[]>(nullptr), 0,
context, std::move(resolver));
CreateAsyncCompileJob(isolate, enabled, std::unique_ptr<byte[]>(nullptr),
0, context, std::move(resolver));
return job->CreateStreamingDecoder();
}
@ -207,11 +212,12 @@ CodeTracer* WasmEngine::GetCodeTracer() {
}
AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
Handle<Context> context,
Isolate* isolate, const WasmFeatures& enabled,
std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
std::unique_ptr<CompilationResultResolver> resolver) {
AsyncCompileJob* job = new AsyncCompileJob(
isolate, std::move(bytes_copy), length, context, std::move(resolver));
AsyncCompileJob* job =
new AsyncCompileJob(isolate, enabled, std::move(bytes_copy), length,
context, std::move(resolver));
// Pass ownership to the unique_ptr in {jobs_}.
base::LockGuard<base::Mutex> guard(&mutex_);
jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);

View File

@ -22,6 +22,7 @@ class WasmInstanceObject;
namespace wasm {
class ErrorThrower;
struct WasmFeatures;
struct ModuleWireBytes;
class V8_EXPORT_PRIVATE CompilationResultResolver {
@ -47,7 +48,8 @@ class V8_EXPORT_PRIVATE WasmEngine {
// Synchronously validates the given bytes that represent an encoded WASM
// 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
// asm.js module.
@ -59,6 +61,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
// Synchronously compiles the given bytes that represent an encoded WASM
// module.
MaybeHandle<WasmModuleObject> SyncCompile(Isolate* isolate,
const WasmFeatures& enabled,
ErrorThrower* thrower,
const ModuleWireBytes& bytes);
@ -74,7 +77,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
// encoded WASM module.
// The {is_shared} flag indicates if the bytes backing the module could
// 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,
const ModuleWireBytes& bytes, bool is_shared);
@ -85,7 +88,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
MaybeHandle<JSReceiver> imports);
std::shared_ptr<StreamingDecoder> StartStreamingCompilation(
Isolate* isolate, Handle<Context> context,
Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
std::unique_ptr<CompilationResultResolver> resolver);
// Exports the sharable parts of the given module object so that they can be
@ -140,7 +143,8 @@ class V8_EXPORT_PRIVATE WasmEngine {
private:
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,
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 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) {
imm.sig = module->signatures[imm.sig_index];
}
@ -801,7 +802,8 @@ class SideTable : public ZoneObject {
break;
}
case kExprIf: {
BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
i.pc());
if (imm.type == kWasmVar) {
imm.sig = module->signatures[imm.sig_index];
}
@ -1664,7 +1666,6 @@ class ThreadImpl {
byte* GetGlobalPtr(const WasmGlobal* global) {
if (global->mutability && global->imported) {
DCHECK(FLAG_experimental_wasm_mut_global);
return reinterpret_cast<byte*>(
instance_object_->imported_mutable_globals()[global->index]);
} else {
@ -2133,17 +2134,20 @@ class ThreadImpl {
case kExprNop:
break;
case kExprBlock: {
BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
&decoder, code->at(pc));
len = 1 + imm.length;
break;
}
case kExprLoop: {
BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
&decoder, code->at(pc));
len = 1 + imm.length;
break;
}
case kExprIf: {
BlockTypeImmediate<Decoder::kNoValidate> imm(&decoder, code->at(pc));
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures,
&decoder, code->at(pc));
WasmValue cond = Pop();
bool is_true = cond.to<uint32_t>() != 0;
if (is_true) {

View File

@ -400,8 +400,9 @@ void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
// Asynchronous compilation handles copying wire bytes if necessary.
i_isolate->wasm_engine()->AsyncCompile(i_isolate, std::move(resolver), bytes,
is_shared);
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
std::move(resolver), bytes, is_shared);
}
// WebAssembly.validate(bytes) -> bool
@ -422,6 +423,7 @@ void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
bool validated = false;
if (is_shared) {
// 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());
i::wasm::ModuleWireBytes bytes_copy(copy.get(),
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 {
// 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));
@ -462,6 +466,7 @@ void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (thrower.error()) {
return;
}
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
i::MaybeHandle<i::Object> module_obj;
if (is_shared) {
// 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());
i::wasm::ModuleWireBytes bytes_copy(copy.get(),
copy.get() + bytes.length());
module_obj =
i_isolate->wasm_engine()->SyncCompile(i_isolate, &thrower, bytes_copy);
module_obj = i_isolate->wasm_engine()->SyncCompile(
i_isolate, enabled_features, &thrower, bytes_copy);
} else {
// The wire bytes are not shared, OK to use them directly.
module_obj =
i_isolate->wasm_engine()->SyncCompile(i_isolate, &thrower, bytes);
module_obj = i_isolate->wasm_engine()->SyncCompile(
i_isolate, enabled_features, &thrower, bytes);
}
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.
i_isolate->wasm_engine()->AsyncCompile(
i_isolate, std::move(compilation_resolver), bytes, is_shared);
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
i_isolate->wasm_engine()->AsyncCompile(i_isolate, enabled_features,
std::move(compilation_resolver), bytes,
is_shared);
}
bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
@ -855,7 +862,8 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
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
Local<String> shared_key = v8_str(isolate, "shared");
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);
// 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 =
InstallFunc(isolate, webassembly, "Global", WebAssemblyGlobal, 1);
context->set_wasm_global_constructor(*global_constructor);

View File

@ -240,7 +240,6 @@ Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store,
SharedFlag shared) {
Handle<JSArrayBuffer> buffer =
isolate->factory()->NewJSArrayBuffer(shared, TENURED);
if (shared == SharedFlag::kShared) DCHECK(FLAG_experimental_wasm_threads);
constexpr bool is_wasm_memory = true;
JSArrayBuffer::Setup(buffer, isolate, is_external, backing_store, size,
shared, is_wasm_memory);

View File

@ -178,9 +178,10 @@ enum DispatchTableElements : int {
// static
Handle<WasmModuleObject> WasmModuleObject::New(
Isolate* isolate, std::shared_ptr<const wasm::WasmModule> shared_module,
wasm::ModuleEnv& env, OwnedVector<const uint8_t> wire_bytes,
Handle<Script> script, Handle<ByteArray> asm_js_offset_table) {
Isolate* isolate, const wasm::WasmFeatures& enabled,
std::shared_ptr<const wasm::WasmModule> shared_module, wasm::ModuleEnv& env,
OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
Handle<ByteArray> asm_js_offset_table) {
DCHECK_EQ(shared_module.get(), env.module);
// Create a new {NativeModule} first.
@ -188,7 +189,7 @@ Handle<WasmModuleObject> WasmModuleObject::New(
isolate->wasm_engine()->code_manager()->EstimateNativeModuleSize(
env.module);
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),
env);
native_module->set_wire_bytes(std::move(wire_bytes));

View File

@ -30,6 +30,7 @@ class SignatureMap;
class WireBytesRef;
class WasmInterpreter;
using FunctionSig = Signature<ValueType>;
struct WasmFeatures;
} // namespace wasm
class BreakPoint;
@ -133,9 +134,10 @@ class WasmModuleObject : public JSObject {
// Creates a new {WasmModuleObject} with a new {NativeModule} underneath.
static Handle<WasmModuleObject> New(
Isolate* isolate, std::shared_ptr<const wasm::WasmModule> module,
wasm::ModuleEnv& env, OwnedVector<const uint8_t> wire_bytes,
Handle<Script> script, Handle<ByteArray> asm_js_offset_table);
Isolate* isolate, const wasm::WasmFeatures& enabled,
std::shared_ptr<const wasm::WasmModule> module, wasm::ModuleEnv& env,
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
// reference counted and might be shared between multiple Isolates.

View File

@ -545,9 +545,11 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
if (!IsSupportedVersion(isolate, data)) {
return {};
}
// TODO(titzer): module features should be part of the serialization format.
WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
ModuleResult decode_result = DecodeWasmModule(
wire_bytes.start(), wire_bytes.end(), false, i::wasm::kWasmOrigin,
isolate->counters(), isolate->allocator());
enabled_features, wire_bytes.start(), wire_bytes.end(), false,
i::wasm::kWasmOrigin, isolate->counters(), isolate->allocator());
if (!decode_result.ok()) return {};
CHECK_NOT_NULL(decode_result.val);
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);
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
isolate, std::move(decode_result.val), env, std::move(wire_bytes_copy),
script, Handle<ByteArray>::null());
isolate, enabled_features, std::move(decode_result.val), env,
std::move(wire_bytes_copy), script, Handle<ByteArray>::null());
NativeModule* native_module = module_object->native_module();
if (FLAG_wasm_lazy_compilation) {

View File

@ -100,7 +100,8 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
case kExprIf:
case kExprBlock:
case kExprTry: {
BlockTypeImmediate<Decoder::kNoValidate> imm(&i, i.pc());
BlockTypeImmediate<Decoder::kNoValidate> imm(kAllWasmFeatures, &i,
i.pc());
os << WasmOpcodes::OpcodeName(opcode);
if (imm.type == kWasmVar) {
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
// within a code object.
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) {

View File

@ -886,9 +886,11 @@ TEST(AtomicOpDisassembly) {
testing::SetupIsolateForWasmModule(isolate);
ErrorThrower thrower(isolate, "Test");
auto enabled_features = WasmFeaturesFromIsolate(isolate);
MaybeHandle<WasmModuleObject> module_object =
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);
}

View File

@ -113,7 +113,7 @@ class StreamTester {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
stream_ = i_isolate->wasm_engine()->StartStreamingCompilation(
i_isolate, v8::Utils::OpenHandle(*context),
i_isolate, kAllWasmFeatures, v8::Utils::OpenHandle(*context),
base::make_unique<TestResolver>(&state_));
}
@ -212,9 +212,9 @@ STREAM_TEST(TestAllBytesArriveAOTCompilerFinishesFirst) {
size_t GetFunctionOffset(i::Isolate* isolate, const uint8_t* buffer,
size_t size, size_t index) {
ModuleResult result =
DecodeWasmModule(buffer, buffer + size, false, ModuleOrigin::kWasmOrigin,
isolate->counters(), isolate->allocator());
ModuleResult result = DecodeWasmModule(
kAllWasmFeatures, buffer, buffer + size, false, ModuleOrigin::kWasmOrigin,
isolate->counters(), isolate->allocator());
CHECK(result.ok());
const WasmFunction* func = &result.val->functions[1];
return func->code.offset();

View File

@ -147,9 +147,10 @@ class WasmSerializationTest {
HandleScope scope(serialization_isolate);
testing::SetupIsolateForWasmModule(serialization_isolate);
auto enabled_features = WasmFeaturesFromIsolate(serialization_isolate);
MaybeHandle<WasmModuleObject> maybe_module_object =
serialization_isolate->wasm_engine()->SyncCompile(
serialization_isolate, &thrower,
serialization_isolate, enabled_features, &thrower,
ModuleWireBytes(buffer.begin(), buffer.end()));
Handle<WasmModuleObject> module_object =
maybe_module_object.ToHandleChecked();
@ -291,9 +292,10 @@ void TestTransferrableWasmModules(bool should_share) {
Isolate* from_i_isolate = reinterpret_cast<Isolate*>(from_isolate);
testing::SetupIsolateForWasmModule(from_i_isolate);
ErrorThrower thrower(from_i_isolate, "TestTransferrableWasmModules");
auto enabled_features = WasmFeaturesFromIsolate(from_i_isolate);
MaybeHandle<WasmModuleObject> maybe_module_object =
from_i_isolate->wasm_engine()->SyncCompile(
from_i_isolate, &thrower,
from_i_isolate, enabled_features, &thrower,
ModuleWireBytes(buffer.begin(), buffer.end()));
Handle<WasmModuleObject> module_object =
maybe_module_object.ToHandleChecked();

View File

@ -187,8 +187,9 @@ void PumpMessageLoop(SharedEngineIsolate& isolate) {
Handle<WasmInstanceObject> CompileAndInstantiateAsync(
SharedEngineIsolate& isolate, ZoneBuffer* buffer) {
Handle<Object> maybe_instance = handle(Smi::kZero, isolate.isolate());
auto enabled_features = WasmFeaturesFromIsolate(isolate.isolate());
isolate.isolate()->wasm_engine()->AsyncCompile(
isolate.isolate(),
isolate.isolate(), enabled_features,
base::make_unique<MockCompilationResolver>(isolate, &maybe_instance),
ModuleWireBytes(buffer->begin(), buffer->end()), true);
while (!maybe_instance->IsWasmInstanceObject()) PumpMessageLoop(isolate);

View File

@ -20,6 +20,7 @@ TestingModuleBuilder::TestingModuleBuilder(
: test_module_(std::make_shared<WasmModule>()),
test_module_ptr_(test_module_.get()),
isolate_(CcTest::InitIsolateOnce()),
enabled_features_(WasmFeaturesFromIsolate(isolate_)),
execution_mode_(mode),
runtime_exception_support_(exception_support),
lower_simd_(lower_simd) {
@ -213,8 +214,9 @@ Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
script->set_type(Script::TYPE_WASM);
ModuleEnv env = CreateModuleEnv();
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
isolate_, test_module_, env, {}, script, Handle<ByteArray>::null());
Handle<WasmModuleObject> module_object =
WasmModuleObject::New(isolate_, enabled_features_, test_module_, env, {},
script, Handle<ByteArray>::null());
// 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
// interpreter when we get a memory. We do have globals, though.
@ -229,14 +231,18 @@ Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
void TestBuildingGraphWithBuilder(compiler::WasmGraphBuilder* builder,
Zone* zone, FunctionSig* sig,
const byte* start, const byte* end) {
WasmFeatures unused_detected_features;
FunctionBody body(sig, 0, start, end);
DecodeResult result =
BuildTFGraph(zone->allocator(), builder, sig, start, end);
BuildTFGraph(zone->allocator(), kAllWasmFeatures, nullptr, builder,
&unused_detected_features, body, nullptr);
if (result.failed()) {
#ifdef DEBUG
if (!FLAG_trace_wasm_decoder) {
// Retry the compilation with the tracing flag on, to help in debugging.
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

View File

@ -225,6 +225,7 @@ class TestingModuleBuilder {
std::shared_ptr<WasmModule> test_module_;
WasmModule* test_module_ptr_;
Isolate* isolate_;
WasmFeatures enabled_features_;
uint32_t global_offset = 0;
byte* mem_start_ = nullptr;
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_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_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 SIZEOF_SIG_ENTRY_x 4
#define SIZEOF_SIG_ENTRY_x_x 5
#define SIZEOF_SIG_ENTRY_x_xx 6
#define SIZEOF_SIG_ENTRY_xx_xx 7
#define SIZEOF_SIG_ENTRY_x_xxx 7
#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(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes) {
MaybeHandle<WasmModuleObject> module =
isolate->wasm_engine()->SyncCompile(isolate, thrower, bytes);
auto enabled_features = WasmFeaturesFromIsolate(isolate);
MaybeHandle<WasmModuleObject> module = isolate->wasm_engine()->SyncCompile(
isolate, enabled_features, thrower, bytes);
DCHECK_EQ(thrower->error(), module.is_null());
if (module.is_null()) return {};
@ -42,9 +43,10 @@ std::shared_ptr<WasmModule> DecodeWasmModuleForTesting(
const byte* module_end, ModuleOrigin origin, bool verify_functions) {
// Decode the module, but don't verify function bodies, since we'll
// be compiling them anyway.
ModuleResult decoding_result =
DecodeWasmModule(module_start, module_end, verify_functions, origin,
isolate->counters(), isolate->allocator());
auto enabled_features = WasmFeaturesFromIsolate(isolate);
ModuleResult decoding_result = DecodeWasmModule(
enabled_features, module_start, module_end, verify_functions, origin,
isolate->counters(), isolate->allocator());
if (decoding_result.failed()) {
// Module verification failed. throw.

View File

@ -19,6 +19,7 @@
#include "src/optimized-compilation-info.h"
#include "src/simulator.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-features.h"
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-objects-inl.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
// within a code object.
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) {

View File

@ -68,8 +68,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
testing::SetupIsolateForWasmModule(i_isolate);
bool done = false;
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
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);
// 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,
bool compiles) {
constexpr bool kVerifyFunctions = false;
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
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());
CHECK(module_res.ok());
WasmModule* module = module_res.val.get();
@ -181,7 +182,7 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
os << ", undefined";
}
os << ", " << (module->mem_export ? "true" : "false");
if (FLAG_experimental_wasm_threads && module->has_shared_memory) {
if (module->has_shared_memory) {
os << ", shared";
}
os << ");\n";
@ -208,7 +209,8 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
// Add locals.
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()) {
os << " ";
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());
// Compile with Turbofan here. Liftoff will be tested later.
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
MaybeHandle<WasmModuleObject> compiled_module;
{
// 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<int> tier_mask_scope(&FLAG_wasm_tier_mask_for_testing, tier_mask);
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();
@ -300,8 +303,8 @@ int WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
GenerateTestCase(i_isolate, wire_bytes, compiles);
}
bool validates =
i_isolate->wasm_engine()->SyncValidate(i_isolate, wire_bytes);
bool validates = i_isolate->wasm_engine()->SyncValidate(
i_isolate, enabled_features, wire_bytes);
CHECK_EQ(compiles, 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::wasm::ErrorThrower thrower(i_isolate, "wasm fuzzer");
i::Handle<i::WasmModuleObject> module_object;
bool compiles = i_isolate->wasm_engine()
->SyncCompile(i_isolate, &thrower, wire_bytes)
.ToHandle(&module_object);
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
bool compiles =
i_isolate->wasm_engine()
->SyncCompile(i_isolate, enabled_features, &thrower, wire_bytes)
.ToHandle(&module_object);
if (i::FLAG_wasm_fuzzer_gen_test) {
i::wasm::fuzzer::GenerateTestCase(i_isolate, wire_bytes, compiles);

View File

@ -92,6 +92,9 @@ static const WasmOpcode kInt32BinopOpcodes[] = {
class FunctionBodyDecoderTest : public TestWithZone {
public:
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()) {}
@ -133,8 +136,11 @@ class FunctionBodyDecoderTest : public TestWithZone {
PrepareBytecode(&start, &end, append_end);
// Verify the code.
FunctionBody body(sig, 0, start, end);
WasmFeatures unused_detected_features;
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();
std::ostringstream str;
@ -198,6 +204,17 @@ class FunctionBodyDecoderTest : public TestWithZone {
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;
// A helper for tests that require a module environment for functions,
@ -263,7 +280,7 @@ TEST_F(FunctionBodyDecoderTest, Int32Const1) {
}
TEST_F(FunctionBodyDecoderTest, RefNull) {
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
WASM_FEATURE_SCOPE(anyref);
byte code[] = {kExprRefNull};
EXPECT_VERIFIES_C(r_v, code);
}
@ -1236,8 +1253,8 @@ TEST_F(FunctionBodyDecoderTest, MacrosInt64) {
}
TEST_F(FunctionBodyDecoderTest, AllSimpleExpressions) {
EXPERIMENTAL_FLAG_SCOPE(se);
EXPERIMENTAL_FLAG_SCOPE(anyref);
WASM_FEATURE_SCOPE(se);
WASM_FEATURE_SCOPE(anyref);
// Test all simple expressions which are described by a signature.
#define DECODE_TEST(name, opcode, sig) \
{ \
@ -1476,7 +1493,7 @@ TEST_F(FunctionBodyDecoderTest, CallsWithMismatchedSigs3) {
}
TEST_F(FunctionBodyDecoderTest, MultiReturn) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
ValueType storage[] = {kWasmI32, kWasmI32};
FunctionSig sig_ii_v(2, 0, storage);
FunctionSig sig_v_ii(0, 2, storage);
@ -1492,7 +1509,7 @@ TEST_F(FunctionBodyDecoderTest, MultiReturn) {
}
TEST_F(FunctionBodyDecoderTest, MultiReturnType) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
for (size_t a = 0; a < arraysize(kValueTypes); a++) {
for (size_t b = 0; b < arraysize(kValueTypes); b++) {
for (size_t c = 0; c < arraysize(kValueTypes); c++) {
@ -1612,7 +1629,7 @@ TEST_F(FunctionBodyDecoderTest, IncompleteStore) {
}
TEST_F(FunctionBodyDecoderTest, IncompleteS8x16Shuffle) {
EXPERIMENTAL_FLAG_SCOPE(simd);
WASM_FEATURE_SCOPE(simd);
FunctionSig* sig = sigs.i_i();
TestModuleBuilder builder;
builder.InitializeMemory();
@ -2383,7 +2400,7 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) {
}
TEST_F(FunctionBodyDecoderTest, Throw) {
EXPERIMENTAL_FLAG_SCOPE(eh);
WASM_FEATURE_SCOPE(eh);
TestModuleBuilder builder;
module = builder.module();
@ -2403,7 +2420,7 @@ TEST_F(FunctionBodyDecoderTest, Throw) {
TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
// TODO(titzer): unreachable code after throw should validate.
EXPERIMENTAL_FLAG_SCOPE(eh);
WASM_FEATURE_SCOPE(eh);
TestModuleBuilder builder;
module = builder.module();
@ -2420,7 +2437,7 @@ TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
#define WASM_CATCH(index) kExprCatch, static_cast<byte>(index)
TEST_F(FunctionBodyDecoderTest, TryCatch) {
EXPERIMENTAL_FLAG_SCOPE(eh);
WASM_FEATURE_SCOPE(eh);
TestModuleBuilder builder;
module = builder.module();
@ -2445,7 +2462,7 @@ TEST_F(FunctionBodyDecoderTest, TryCatch) {
#undef WASM_CATCH
TEST_F(FunctionBodyDecoderTest, MultiValBlock1) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f0 = builder.AddSignature(sigs.ii_v());
@ -2461,7 +2478,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValBlock1) {
}
TEST_F(FunctionBodyDecoderTest, MultiValBlock2) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f0 = builder.AddSignature(sigs.ii_v());
@ -2479,7 +2496,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValBlock2) {
}
TEST_F(FunctionBodyDecoderTest, MultiValBlockBr) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f0 = builder.AddSignature(sigs.ii_v());
@ -2491,7 +2508,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValBlockBr) {
}
TEST_F(FunctionBodyDecoderTest, MultiValLoop1) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f0 = builder.AddSignature(sigs.ii_v());
@ -2507,7 +2524,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValLoop1) {
}
TEST_F(FunctionBodyDecoderTest, MultiValIf) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f0 = builder.AddSignature(sigs.ii_v());
@ -2570,7 +2587,7 @@ TEST_F(FunctionBodyDecoderTest, MultiValIf) {
}
TEST_F(FunctionBodyDecoderTest, BlockParam) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f1 = builder.AddSignature(sigs.i_i());
@ -2596,7 +2613,7 @@ TEST_F(FunctionBodyDecoderTest, BlockParam) {
}
TEST_F(FunctionBodyDecoderTest, LoopParam) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f1 = builder.AddSignature(sigs.i_i());
@ -2622,7 +2639,7 @@ TEST_F(FunctionBodyDecoderTest, LoopParam) {
}
TEST_F(FunctionBodyDecoderTest, LoopParamBr) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f1 = builder.AddSignature(sigs.i_i());
@ -2644,7 +2661,7 @@ TEST_F(FunctionBodyDecoderTest, LoopParamBr) {
}
TEST_F(FunctionBodyDecoderTest, IfParam) {
EXPERIMENTAL_FLAG_SCOPE(mv);
WASM_FEATURE_SCOPE(mv);
TestModuleBuilder builder;
module = builder.module();
byte f1 = builder.AddSignature(sigs.i_i());
@ -2678,8 +2695,11 @@ TEST_F(FunctionBodyDecoderTest, Regression709741) {
PrepareBytecode(&start, &end, kAppendEnd);
for (const byte* i = start; i < end; i++) {
FunctionBody body(sigs.v_v(), 0, start, i);
WasmFeatures unused_detected_features;
DecodeResult result =
VerifyWasmCode(zone()->allocator(), nullptr, sigs.v_v(), start, i);
VerifyWasmCode(zone()->allocator(), kAllWasmFeatures, nullptr,
&unused_detected_features, body);
if (result.ok()) {
std::ostringstream str;
str << "Expected verification to fail";
@ -2999,6 +3019,7 @@ typedef ZoneVector<ValueType> TypesOfLocals;
class LocalDeclDecoderTest : public TestWithZone {
public:
v8::internal::AccountingAllocator allocator;
WasmFeatures enabled_features_;
size_t ExpectRun(TypesOfLocals map, size_t pos, ValueType expected,
size_t count) {
@ -3007,6 +3028,11 @@ class LocalDeclDecoderTest : public TestWithZone {
}
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) {
@ -3024,7 +3050,7 @@ TEST_F(LocalDeclDecoderTest, NoLocals) {
}
TEST_F(LocalDeclDecoderTest, OneLocal) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WASM_FEATURE_SCOPE(anyref);
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueType type = kValueTypes[i];
const byte data[] = {1, 1,
@ -3040,7 +3066,7 @@ TEST_F(LocalDeclDecoderTest, OneLocal) {
}
TEST_F(LocalDeclDecoderTest, FiveLocals) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WASM_FEATURE_SCOPE(anyref);
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueType type = kValueTypes[i];
const byte data[] = {1, 5,
@ -3180,6 +3206,7 @@ TEST_F(BytecodeIteratorTest, WithLocalDecls) {
EXPECT_FALSE(iter.has_next());
}
#undef WASM_FEATURE_SCOPE
#undef B1
#undef B2
#undef B3

View File

@ -7,6 +7,7 @@
#include "src/handles.h"
#include "src/objects-inl.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-features.h"
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-opcodes.h"
#include "test/common/wasm/flag-utils.h"
@ -146,6 +147,8 @@ struct ValueTypePair {
class WasmModuleVerifyTest : public TestWithIsolateAndZone {
public:
WasmFeatures enabled_features_;
ModuleResult DecodeModule(const byte* module_start, const byte* module_end) {
// Add the wasm magic and version number automatically.
size_t size = static_cast<size_t>(module_end - module_start);
@ -154,19 +157,39 @@ class WasmModuleVerifyTest : public TestWithIsolateAndZone {
auto temp = new byte[total];
memcpy(temp, header, sizeof(header));
memcpy(temp + sizeof(header), module_start, size);
ModuleResult result =
DecodeWasmModule(temp, temp + total, false, kWasmOrigin,
isolate()->counters(), isolate()->allocator());
ModuleResult result = DecodeWasmModule(
enabled_features_, temp, temp + total, false, kWasmOrigin,
isolate()->counters(), isolate()->allocator());
delete[] temp;
return result;
}
ModuleResult DecodeModuleNoHeader(const byte* module_start,
const byte* module_end) {
return DecodeWasmModule(module_start, module_end, false, kWasmOrigin,
isolate()->counters(), isolate()->allocator());
return DecodeWasmModule(enabled_features_, module_start, module_end, false,
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) {
for (uint32_t x = 1; x; x <<= 1) {
const byte data[] = {U32_LE(kWasmMagic ^ x), U32_LE(kWasmVersion)};
@ -218,7 +241,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobal) {
}
TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
SECTION(Global, 5), // --
1,
@ -244,7 +267,7 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) {
}
TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
SECTION(Import, 8), // section header
1, // number of imports
@ -314,6 +337,7 @@ TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
}
TEST_F(WasmModuleVerifyTest, ExportMutableGlobal) {
WASM_FEATURE_SCOPE(mut_global);
{
static const byte data[] = {
SECTION(Global, 6), // --
@ -445,7 +469,7 @@ TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
EXPERIMENTAL_FLAG_SCOPE(eh);
WASM_FEATURE_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
@ -459,7 +483,7 @@ TEST_F(WasmModuleVerifyTest, OneI32Exception) {
};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
EXPERIMENTAL_FLAG_SCOPE(eh);
WASM_FEATURE_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(1u, result.val->exceptions.size());
@ -477,7 +501,7 @@ TEST_F(WasmModuleVerifyTest, TwoExceptions) {
1, kLocalI32};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
EXPERIMENTAL_FLAG_SCOPE(eh);
WASM_FEATURE_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(2u, result.val->exceptions.size());
@ -496,7 +520,7 @@ TEST_F(WasmModuleVerifyTest, Exception_invalid_type) {
FAIL_IF_NO_EXPERIMENTAL_EH(data);
// Should fail decoding exception section.
EXPERIMENTAL_FLAG_SCOPE(eh);
WASM_FEATURE_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_FALSE(result.ok());
}
@ -940,7 +964,7 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
// Test that if we have multiple tables, in 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[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
@ -970,7 +994,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) {
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
// Test that if we have multiple tables, both imported and module-defined, in
// 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[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
@ -1027,7 +1051,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) {
TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
// Test that the order in which tables are targeted in the element secion
// can be arbitrary.
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
@ -1061,7 +1085,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) {
TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
// 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.
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
@ -1118,7 +1142,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) {
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
// Test that tables of type 'AnyRef' cannot be initialized by the element
// section.
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
@ -1148,7 +1172,7 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) {
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) {
// Test that imported tables of type AnyRef cannot be initialized in the
// elements section.
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
// sig#0 ---------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
@ -1232,7 +1256,7 @@ TEST_F(WasmModuleVerifyTest, MultipleTablesWithoutFlag) {
}
TEST_F(WasmModuleVerifyTest, MultipleTablesWithFlag) {
FlagScope<bool> flag_scope(&FLAG_experimental_wasm_anyref, true);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
SECTION(Table, 7), // table section
ENTRY_COUNT(2), // 2 tables
@ -1258,22 +1282,18 @@ TEST_F(WasmModuleVerifyTest, MultipleTablesWithFlag) {
class WasmSignatureDecodeTest : public TestWithZone {
public:
WasmSignatureDecodeTest()
// 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) {}
WasmFeatures enabled_features_;
private:
FlagScope<bool> flag_scope;
FunctionSig* DecodeSig(const byte* start, const byte* end) {
return DecodeWasmSignatureForTesting(enabled_features_, zone(), start, end);
}
};
TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
static const byte data[] = {SIG_ENTRY_v_v};
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
FunctionSig* sig =
DecodeWasmSignatureForTesting(&zone, data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_TRUE(sig != nullptr);
EXPECT_EQ(0u, sig->parameter_count());
@ -1281,11 +1301,11 @@ TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
}
TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
WASM_FEATURE_SCOPE(anyref);
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueTypePair ret_type = kValueTypes[i];
const byte data[] = {SIG_ENTRY_x(ret_type.code)};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_TRUE(sig != nullptr);
EXPECT_EQ(0u, sig->parameter_count());
@ -1295,11 +1315,11 @@ TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
}
TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
WASM_FEATURE_SCOPE(anyref);
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueTypePair param_type = kValueTypes[i];
const byte data[] = {SIG_ENTRY_v_x(param_type.code)};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_TRUE(sig != nullptr);
EXPECT_EQ(1u, sig->parameter_count());
@ -1309,13 +1329,13 @@ TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
}
TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
WASM_FEATURE_SCOPE(anyref);
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueTypePair ret_type = kValueTypes[i];
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
ValueTypePair param_type = kValueTypes[j];
const byte data[] = {SIG_ENTRY_x_x(ret_type.code, param_type.code)};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_TRUE(sig != nullptr);
EXPECT_EQ(1u, sig->parameter_count());
@ -1327,14 +1347,15 @@ TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
}
TEST_F(WasmSignatureDecodeTest, Ok_i_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_x_xx(kLocalI32, p0_type.code, p1_type.code)};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_TRUE(sig != nullptr);
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) {
static const byte data[] = {kWasmFunctionTypeCode,
WASM_I32V_3(kV8MaxWasmFunctionParams + 1),
kLocalI32, 0};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_FALSE(sig != nullptr);
}
TEST_F(WasmSignatureDecodeTest, TooManyReturns) {
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>(
FLAG_experimental_wasm_mv ? kV8MaxWasmFunctionMultiReturns
: kV8MaxWasmFunctionReturns);
enable_mv ? kV8MaxWasmFunctionMultiReturns : kV8MaxWasmFunctionReturns);
byte data[] = {kWasmFunctionTypeCode, 0, WASM_I32V_3(max_return_count + 1),
kLocalI32};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_EQ(nullptr, sig);
}
}
@ -1376,7 +1417,7 @@ TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
for (int i = 0; i < p + 1; i++) {
// 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);
}
}
@ -1384,14 +1425,13 @@ TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
TEST_F(WasmSignatureDecodeTest, Fail_anyref_without_flag) {
// 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};
for (byte invalid_type : ref_types) {
for (size_t i = 0; i < SIZEOF_SIG_ENTRY_x_xx; i++) {
byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)};
data[i] = invalid_type;
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
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++) {
byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)};
data[i] = kInvalidType;
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_EQ(nullptr, sig);
}
}
TEST_F(WasmSignatureDecodeTest, Fail_invalid_ret_type1) {
static const byte data[] = {SIG_ENTRY_x_x(kLocalVoid, kLocalI32)};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_EQ(nullptr, sig);
}
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type1) {
static const byte data[] = {SIG_ENTRY_x_x(kLocalI32, kLocalVoid)};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_EQ(nullptr, sig);
}
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type2) {
static const byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalVoid)};
FunctionSig* sig =
DecodeWasmSignatureForTesting(zone(), data, data + sizeof(data));
FunctionSig* sig = DecodeSig(data, data + sizeof(data));
EXPECT_EQ(nullptr, sig);
}
class WasmFunctionVerifyTest : public TestWithIsolateAndZone {
public:
WasmFunctionVerifyTest() {}
virtual ~WasmFunctionVerifyTest() {}
WasmFeatures enabled_features_;
WasmModule module;
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) {
@ -1454,8 +1496,8 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
kExprEnd // body
};
FunctionResult result = DecodeWasmFunctionForTesting(
zone(), bytes, &module, data, data + sizeof(data), isolate()->counters());
FunctionResult result =
DecodeWasmFunction(bytes, &module, data, data + sizeof(data));
EXPECT_OK(result);
if (result.val && result.ok()) {
@ -1584,6 +1626,7 @@ TEST_F(WasmModuleVerifyTest, ImportTable_nosigs1) {
}
TEST_F(WasmModuleVerifyTest, ImportTable_mutable_global) {
WASM_FEATURE_SCOPE(mut_global);
{
static const byte data[] = {
SECTION(Import, 8), // section header
@ -1615,6 +1658,7 @@ TEST_F(WasmModuleVerifyTest, ImportTable_mutable_global) {
}
TEST_F(WasmModuleVerifyTest, ImportTable_mutability_malformed) {
WASM_FEATURE_SCOPE(mut_global);
static const byte data[] = {
SECTION(Import, 8),
1, // --
@ -2022,61 +2066,68 @@ TEST_F(WasmModuleVerifyTest, Regression684855) {
EXPECT_VERIFIES(data);
}
#define EXPECT_INIT_EXPR(Type, type, value, ...) \
{ \
static const byte data[] = {__VA_ARGS__, kExprEnd}; \
WasmInitExpr expr = \
DecodeWasmInitExprForTesting(data, data + sizeof(data)); \
EXPECT_EQ(WasmInitExpr::k##Type##Const, expr.kind); \
EXPECT_EQ(value, expr.val.type##_const); \
class WasmInitExprDecodeTest : public TestWithZone {
public:
WasmInitExprDecodeTest() {}
WasmFeatures enabled_features_;
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, -21, WASM_I32V_1(-21));
EXPECT_INIT_EXPR(I32, i32, 437, WASM_I32V_2(437));
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>(-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>(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, -21, WASM_I64V_2(-21));
EXPECT_INIT_EXPR(I64, i64, 437, WASM_I64V_5(437));
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, -771.3, WASM_F64(-771.3));
EXPECT_INIT_EXPR(F64, f64, 43703.0, WASM_F64(43703.0));
EXPECT_INIT_EXPR(F64, f64, 77999.1, WASM_F64(77999.1));
}
TEST_F(WasmModuleVerifyTest, InitExpr_AnyRef) {
EXPERIMENTAL_FLAG_SCOPE(anyref);
TEST_F(WasmInitExprDecodeTest, InitExpr_AnyRef) {
WASM_FEATURE_SCOPE(anyref);
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);
}
#undef EXPECT_INIT_EXPR
#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) {
TEST_F(WasmInitExprDecodeTest, InitExpr_illegal) {
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_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));
}
#undef EXPECT_INIT_EXPR_FAIL
TEST_F(WasmModuleVerifyTest, Multiple_Named_Sections) {
static const byte data[] = {
SECTION(Unknown, 4), 1, 'X', 17, 18, // --
@ -2174,6 +2223,10 @@ TEST_F(WasmModuleCustomSectionTest, TwoKnownTwoUnknownSections) {
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_2
#undef WASM_INIT_EXPR_I32V_3

View File

@ -168,8 +168,8 @@ class WasmCodeManagerTest : public TestWithContext,
bool can_request_more = style == Growable;
ModuleEnv env(module.get(), UseTrapHandler::kNoTrapHandler,
RuntimeExceptionSupport::kNoRuntimeExceptionSupport);
return manager->NewNativeModule(i_isolate(), size, can_request_more,
std::move(module), env);
return manager->NewNativeModule(i_isolate(), kAllWasmFeatures, size,
can_request_more, std::move(module), env);
}
WasmCode* AddCode(NativeModule* native_module, uint32_t index, size_t size) {