[wasm] Explicit opt-out of stack checks and traps

We've been passing a context to the compiler, which turns out to be
solely used to determine if we're executing in a specific cctest configuration.

This change adds a configuration to the graph builder that we can use to
explicitly opt out of stack checks and traps. CcTests default to opting out,
except for the few that don't.

Bug: 
Change-Id: I4724e31c2a62e9b3ab4feadb788287c374b39f53
Reviewed-on: https://chromium-review.googlesource.com/585779
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Mircea Trofin <mtrofin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46943}
This commit is contained in:
Mircea Trofin 2017-07-26 13:12:27 -07:00 committed by Commit Bot
parent 44f88dcd87
commit be915fd7d1
7 changed files with 46 additions and 49 deletions

View File

@ -192,10 +192,12 @@ Node* WasmGraphBuilder::Int64Constant(int64_t value) {
void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
Node** effect, Node** control) {
if (FLAG_wasm_no_stack_checks) return;
// We do not generate stack checks for cctests.
if (!module_ || (module_->instance && module_->instance->context.is_null()))
// TODO(mtrofin): "!module_" happens when we generate a wrapper.
// We should factor wrappers separately from wasm codegen.
if (FLAG_wasm_no_stack_checks || !module_ ||
!has_runtime_exception_support_) {
return;
}
if (effect == nullptr) effect = effect_;
if (control == nullptr) control = control_;
@ -828,9 +830,8 @@ Node* WasmGraphBuilder::BranchExpectFalse(Node* cond, Node** true_node,
BranchHint::kFalse);
}
namespace {
Builtins::Name GetBuiltinIdForTrap(bool in_cctest, wasm::TrapReason reason) {
if (in_cctest) {
Builtins::Name WasmGraphBuilder::GetBuiltinIdForTrap(wasm::TrapReason reason) {
if (!has_runtime_exception_support_) {
// We use Builtins::builtin_count as a marker to tell the code generator
// to generate a call to a testing c-function instead of a runtime
// function. This code should only be called from a cctest.
@ -847,14 +848,10 @@ Builtins::Name GetBuiltinIdForTrap(bool in_cctest, wasm::TrapReason reason) {
UNREACHABLE();
}
}
} // namespace
Node* WasmGraphBuilder::TrapIfTrue(wasm::TrapReason reason, Node* cond,
wasm::WasmCodePosition position) {
// TODO(wasm): Introduce a testing flag instead of trying to infer it here.
bool in_cctest =
!module_ || (module_->instance && module_->instance->context.is_null());
int32_t trap_id = GetBuiltinIdForTrap(in_cctest, reason);
Builtins::Name trap_id = GetBuiltinIdForTrap(reason);
Node* node = graph()->NewNode(jsgraph()->common()->TrapIf(trap_id), cond,
Effect(), Control());
*control_ = node;
@ -864,10 +861,7 @@ Node* WasmGraphBuilder::TrapIfTrue(wasm::TrapReason reason, Node* cond,
Node* WasmGraphBuilder::TrapIfFalse(wasm::TrapReason reason, Node* cond,
wasm::WasmCodePosition position) {
// TODO(wasm): Introduce a testing flag instead of trying to infer it here.
bool in_cctest =
!module_ || (module_->instance && module_->instance->context.is_null());
int32_t trap_id = GetBuiltinIdForTrap(in_cctest, reason);
Builtins::Name trap_id = GetBuiltinIdForTrap(reason);
Node* node = graph()->NewNode(jsgraph()->common()->TrapUnless(trap_id), cond,
Effect(), Control());

View File

@ -280,6 +280,10 @@ class WasmGraphBuilder {
wasm::ModuleEnv* module_env() const { return module_; }
void SetRuntimeExceptionSupport(bool value) {
has_runtime_exception_support_ = value;
}
private:
static const int kDefaultBufferSize = 16;
@ -299,6 +303,10 @@ class WasmGraphBuilder {
Node* def_buffer_[kDefaultBufferSize];
bool has_simd_ = false;
bool needs_stack_check_ = false;
// If the runtime doesn't support exception propagation,
// we won't generate stack checks, and trap handling will also
// be generated differently.
bool has_runtime_exception_support_ = true;
wasm::FunctionSig* sig_;
SetOncePointer<const Operator> allocate_heap_number_operator_;
@ -440,6 +448,7 @@ class WasmGraphBuilder {
Node** parameters, int parameter_count);
Node* BuildModifyThreadInWasmFlag(bool new_value);
Builtins::Name GetBuiltinIdForTrap(wasm::TrapReason reason);
};
V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(Zone* zone,

View File

@ -330,7 +330,6 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObject(
Vector<const byte> asm_js_offset_table_bytes) {
Factory* factory = isolate_->factory();
WasmInstance temp_instance(module_.get());
temp_instance.context = isolate_->native_context();
temp_instance.mem_size = WasmModule::kPageSize * module_->min_mem_pages;
temp_instance.mem_start = nullptr;
temp_instance.globals_start = nullptr;
@ -2062,7 +2061,6 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
Factory* factory = job_->isolate_->factory();
job_->temp_instance_.reset(new WasmInstance(module_.get()));
job_->temp_instance_->context = job_->context_;
job_->temp_instance_->mem_size =
WasmModule::kPageSize * module_->min_mem_pages;
job_->temp_instance_->mem_start = nullptr;

View File

@ -229,7 +229,6 @@ struct WasmInstance {
const WasmModule* module; // static representation of the module.
// -- Heap allocated --------------------------------------------------------
Handle<Context> context; // JavaScript native context.
std::vector<Handle<FixedArray>> function_tables; // indirect function tables.
std::vector<Handle<FixedArray>>
signature_tables; // indirect signature tables.
@ -248,8 +247,6 @@ struct WasmInstance {
function_code(m->functions.size()) {}
void ReopenHandles(Isolate* isolate) {
context = handle(*context, isolate);
for (auto& table : function_tables) {
table = handle(*table, isolate);
}

View File

@ -125,9 +125,8 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) {
// Trigger a trap in wasm, stack should be JS -> wasm -> wasm.
TEST(CollectDetailedWasmStack_WasmError) {
TestSignatures sigs;
WasmRunner<int> r(kExecuteCompiled);
// Set the execution context, such that a runtime error can be thrown.
r.SetModuleContext();
// Create a WasmRunner with stack checks and traps enabled.
WasmRunner<int> r(kExecuteCompiled, "main", true);
BUILD(r, WASM_UNREACHABLE);
uint32_t wasm_index_1 = r.function()->func_index;

View File

@ -64,10 +64,9 @@ void CheckExceptionInfos(Handle<Object> exc,
// Trigger a trap for executing unreachable.
TEST(Unreachable) {
WasmRunner<void> r(kExecuteCompiled);
// Create a WasmRunner with stack checks and traps enabled.
WasmRunner<void> r(kExecuteCompiled, "main", true);
TestSignatures sigs;
// Set the execution context, such that a runtime error can be thrown.
r.SetModuleContext();
BUILD(r, WASM_UNREACHABLE);
uint32_t wasm_index = r.function()->func_index;
@ -99,10 +98,9 @@ TEST(Unreachable) {
// Trigger a trap for loading from out-of-bounds.
TEST(IllegalLoad) {
WasmRunner<void> r(kExecuteCompiled);
WasmRunner<void> r(kExecuteCompiled, "main", true);
TestSignatures sigs;
// Set the execution context, such that a runtime error can be thrown.
r.SetModuleContext();
r.module().AddMemory(0L);
BUILD(r, WASM_IF(WASM_ONE, WASM_SEQ(WASM_LOAD_MEM(MachineType::Int32(),

View File

@ -356,10 +356,13 @@ class TestingModule : public ModuleEnv {
inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
FunctionSig* sig,
SourcePositionTable* source_position_table,
const byte* start, const byte* end) {
const byte* start, const byte* end,
bool runtime_exception_support = false) {
compiler::WasmGraphBuilder builder(
module, zone, jsgraph, CEntryStub(jsgraph->isolate(), 1).GetCode(), sig,
source_position_table);
builder.SetRuntimeExceptionSupport(runtime_exception_support);
DecodeResult result =
BuildTFGraph(zone->allocator(), &builder, sig, start, end);
if (result.failed()) {
@ -550,7 +553,8 @@ class WasmFunctionCompiler : private GraphAndBuilders {
// Build the TurboFan graph.
TestBuildingGraph(zone(), &jsgraph, testing_module_, sig,
&source_position_table_, start, end);
&source_position_table_, start, end,
runtime_exception_support_);
Handle<Code> code = Compile();
testing_module_->SetFunctionCode(function_index(), code);
@ -586,7 +590,8 @@ class WasmFunctionCompiler : private GraphAndBuilders {
friend class WasmRunnerBase;
explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
TestingModule* module, const char* name)
TestingModule* module, const char* name,
bool runtime_exception_support)
: GraphAndBuilders(zone),
jsgraph(module->isolate(), this->graph(), this->common(), nullptr,
nullptr, this->machine()),
@ -595,7 +600,8 @@ class WasmFunctionCompiler : private GraphAndBuilders {
testing_module_(module),
local_decls(zone, sig),
source_position_table_(this->graph()),
interpreter_(module->interpreter()) {
interpreter_(module->interpreter()),
runtime_exception_support_(runtime_exception_support) {
// Get a new function from the testing module.
int index = module->AddFunction(sig, Handle<Code>::null(), name);
function_ = testing_module_->GetFunctionAt(index);
@ -651,16 +657,19 @@ class WasmFunctionCompiler : private GraphAndBuilders {
LocalDeclEncoder local_decls;
SourcePositionTable source_position_table_;
WasmInterpreter* interpreter_;
bool runtime_exception_support_ = false;
};
// A helper class to build a module around Wasm bytecode, generate machine
// code, and run that code.
class WasmRunnerBase : public HandleAndZoneScope {
public:
explicit WasmRunnerBase(WasmExecutionMode execution_mode, int num_params)
explicit WasmRunnerBase(WasmExecutionMode execution_mode, int num_params,
bool runtime_exception_support)
: zone_(&allocator_, ZONE_NAME),
module_(&zone_, execution_mode),
wrapper_(&zone_, num_params) {}
wrapper_(&zone_, num_params),
runtime_exception_support_(runtime_exception_support) {}
// Builds a graph from the given Wasm code and generates the machine
// code and call wrapper for that graph. This method must not be called
@ -683,8 +692,8 @@ class WasmRunnerBase : public HandleAndZoneScope {
// Returns the index of the previously built function.
WasmFunctionCompiler& NewFunction(FunctionSig* sig,
const char* name = nullptr) {
functions_.emplace_back(
new WasmFunctionCompiler(&zone_, sig, &module_, name));
functions_.emplace_back(new WasmFunctionCompiler(
&zone_, sig, &module_, name, runtime_exception_support_));
return *functions_.back();
}
@ -702,16 +711,6 @@ class WasmRunnerBase : public HandleAndZoneScope {
TestingModule& module() { return module_; }
Zone* zone() { return &zone_; }
// Set the context, such that e.g. runtime functions can be called.
void SetModuleContext() {
if (!module_.instance->context.is_null()) {
CHECK(module_.instance->context.is_identical_to(
main_isolate()->native_context()));
return;
}
module_.instance->context = main_isolate()->native_context();
}
bool interpret() { return module_.interpret(); }
private:
@ -752,6 +751,7 @@ class WasmRunnerBase : public HandleAndZoneScope {
WasmFunctionWrapper wrapper_;
bool compiled_ = false;
bool possible_nondeterminism_ = false;
bool runtime_exception_support_ = false;
public:
// This field has to be static. Otherwise, gcc complains about the use in
@ -763,8 +763,10 @@ template <typename ReturnType, typename... ParamTypes>
class WasmRunner : public WasmRunnerBase {
public:
explicit WasmRunner(WasmExecutionMode execution_mode,
const char* main_fn_name = "main")
: WasmRunnerBase(execution_mode, sizeof...(ParamTypes)) {
const char* main_fn_name = "main",
bool runtime_exception_support = false)
: WasmRunnerBase(execution_mode, sizeof...(ParamTypes),
runtime_exception_support) {
NewFunction<ReturnType, ParamTypes...>(main_fn_name);
if (!interpret()) {
wrapper_.Init<ReturnType, ParamTypes...>(functions_[0]->descriptor());