[wasm] Add WasmFeatures to enable/detect features
This CL introduces a set of configuration options implemented as a struct of booleans that together comprise the set of enabled or detected features. The configuration options replace command-line flags that were checked deep in the implementation. As such, it is necessary to plumb them through multiple levels of abstraction. R=ahaas@chromium.org CC=mstarzinger@chromium.org BUG=chromium:868844 Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng Change-Id: I1b82f5826e4fd263f68e8cafcd923bac5818a637 Reviewed-on: https://chromium-review.googlesource.com/1163670 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#55018}
This commit is contained in:
parent
3b2b858f11
commit
6aa2a25313
3
BUILD.gn
3
BUILD.gn
@ -2508,6 +2508,9 @@ v8_source_set("v8_base") {
|
||||
"src/wasm/wasm-engine.h",
|
||||
"src/wasm/wasm-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",
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
|
@ -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: "
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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>();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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++) {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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>());
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
26
src/wasm/wasm-feature-flags.h
Normal file
26
src/wasm/wasm-feature-flags.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_WASM_WASM_FEATURE_FLAGS_H_
|
||||
#define V8_WASM_WASM_FEATURE_FLAGS_H_
|
||||
|
||||
// The SEPARATOR argument allows generating proper comma-separated lists.
|
||||
#define FOREACH_WASM_FEATURE_FLAG(V, SEPARATOR) \
|
||||
V(mv, "multi-value support", false) \
|
||||
SEPARATOR \
|
||||
V(eh, "exception handling opcodes", false) \
|
||||
SEPARATOR \
|
||||
V(se, "sign extension opcodes", true) \
|
||||
SEPARATOR \
|
||||
V(sat_f2i_conversions, "saturating float conversion opcodes", false) \
|
||||
SEPARATOR \
|
||||
V(threads, "thread opcodes", false) \
|
||||
SEPARATOR \
|
||||
V(simd, "SIMD opcodes", false) \
|
||||
SEPARATOR \
|
||||
V(anyref, "anyref opcodes", false) \
|
||||
SEPARATOR \
|
||||
V(mut_global, "import/export mutable global support", true)
|
||||
|
||||
#endif // V8_WASM_WASM_FEATURE_FLAGS_H_
|
38
src/wasm/wasm-features.cc
Normal file
38
src/wasm/wasm-features.cc
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/wasm/wasm-features.h"
|
||||
#include "src/flags.h"
|
||||
#include "src/isolate.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
#define COMMA ,
|
||||
#define SPACE
|
||||
#define DO_UNION(feat, desc, val) dst->feat |= src->feat;
|
||||
#define FLAG_REF(feat, desc, val) FLAG_experimental_wasm_##feat
|
||||
|
||||
void UnionFeaturesInto(WasmFeatures* dst, WasmFeatures* src) {
|
||||
FOREACH_WASM_FEATURE(DO_UNION, SPACE)
|
||||
}
|
||||
|
||||
namespace {
|
||||
inline WasmFeatures WasmFeaturesFromFlags() {
|
||||
return WasmFeatures{FOREACH_WASM_FEATURE(FLAG_REF, COMMA)};
|
||||
}
|
||||
}; // namespace
|
||||
|
||||
WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate) {
|
||||
return WasmFeaturesFromFlags();
|
||||
}
|
||||
|
||||
#undef DO_UNION
|
||||
#undef FLAG_REF
|
||||
#undef SPACE
|
||||
#undef COMMA
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
61
src/wasm/wasm-features.h
Normal file
61
src/wasm/wasm-features.h
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_WASM_WASM_FEATURES_H_
|
||||
#define V8_WASM_WASM_FEATURES_H_
|
||||
|
||||
// The feature flags are declared in their own header.
|
||||
#include "src/base/macros.h"
|
||||
#include "src/wasm/wasm-feature-flags.h"
|
||||
|
||||
// All features, including features that do not have flags.
|
||||
#define FOREACH_WASM_FEATURE FOREACH_WASM_FEATURE_FLAG
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
class Isolate;
|
||||
namespace wasm {
|
||||
|
||||
#define COMMA ,
|
||||
#define SPACE
|
||||
#define DECL_FIELD(feat, desc, val) bool feat = false;
|
||||
#define JUST_TRUE(feat, desc, val) true
|
||||
#define JUST_FALSE(feat, desc, val) false
|
||||
#define DECL_PARAM(feat, desc, val) bool p##feat
|
||||
#define DO_INIT(feat, desc, val) feat(p##feat)
|
||||
|
||||
// Enabled or detected features.
|
||||
struct WasmFeatures {
|
||||
FOREACH_WASM_FEATURE(DECL_FIELD, SPACE)
|
||||
|
||||
constexpr WasmFeatures() = default;
|
||||
|
||||
explicit constexpr WasmFeatures(FOREACH_WASM_FEATURE(DECL_PARAM, COMMA))
|
||||
: FOREACH_WASM_FEATURE(DO_INIT, COMMA) {}
|
||||
};
|
||||
|
||||
static constexpr WasmFeatures kAllWasmFeatures{
|
||||
FOREACH_WASM_FEATURE(JUST_TRUE, COMMA)};
|
||||
|
||||
static constexpr WasmFeatures kNoWasmFeatures{
|
||||
FOREACH_WASM_FEATURE(JUST_FALSE, COMMA)};
|
||||
|
||||
#undef JUST_TRUE
|
||||
#undef JUST_FALSE
|
||||
#undef DECL_FIELD
|
||||
#undef DECL_PARAM
|
||||
#undef DO_INIT
|
||||
#undef COMMA
|
||||
#undef SPACE
|
||||
|
||||
static constexpr WasmFeatures kAsmjsWasmFeatures = kNoWasmFeatures;
|
||||
|
||||
V8_EXPORT_PRIVATE WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate);
|
||||
V8_EXPORT_PRIVATE void UnionFeaturesInto(WasmFeatures* dst, WasmFeatures* src);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_WASM_WASM_FEATURES_H_
|
@ -786,7 +786,8 @@ class SideTable : public ZoneObject {
|
||||
case kExprBlock:
|
||||
case 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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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 << ")";
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user