Revert of [wasm] Initial signal handler (patchset #60 id:1170001 of https://codereview.chromium.org/2371833007/ )

Reason for revert:
ASAN breakage, such as https://build.chromium.org/p/client.v8/builders/V8%20Linux64%20ASAN/builds/19111/steps/Check/logs/grow-memory

Original issue's description:
> [wasm] Initial signal handler
>
> This is basically the minimum viable signal handler for Wasm bounds checks.
> It includes the TLS check and the fine grained instructions checks. These
> two checks provide most of the safety for the signal handler. Future CLs will
> add code range and data range checks for more robustness.
>
> The trap handling code and data structures are all in src/trap-handler, with
> the code that actually runs in the signal handler confined to
> src/trap-handler/signal-handler.cc.
>
> This changes adds a new V8 API that the embedder should call from a signal
> handler that will give V8 the chance to handle the fault first. For hosts that
> do not want to implement their own signal handler, we include the option to
> install a simple one. This simple handler is also used for the tests.
>
> When a Wasm module is instantiated, information about each function is passed
> to the trap handler, which is used to classify faults. These are removed during
> the instance finalizer.
>
> Several future enhancements are planned before turning this on by default.
> Obviously, the additional checks will be added to MaybeHandleFault. We are
> also planning to add a two-level CodeObjectData table that is grouped by
> isolates to make cleanup easier and also reduce potential for contending on
> a single data structure.
>
> BUG= https://bugs.chromium.org/p/v8/issues/detail?id=5277
>
> Review-Url: https://codereview.chromium.org/2371833007
> Cr-Original-Commit-Position: refs/heads/master@{#43523}
> Committed: a5af7fe9ee
> Review-Url: https://codereview.chromium.org/2371833007
> Cr-Commit-Position: refs/heads/master@{#43755}
> Committed: 338622d7ca

TBR=ahaas@chromium.org,bradnelson@google.com,hpayer@chromium.org,jochen@chromium.org,mark@chromium.org,mseaborn@chromium.org,titzer@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG= https://bugs.chromium.org/p/v8/issues/detail?id=5277

Review-Url: https://codereview.chromium.org/2744383002
Cr-Commit-Position: refs/heads/master@{#43757}
This commit is contained in:
eholk 2017-03-13 13:03:25 -07:00 committed by Commit bot
parent d3f236fa05
commit aba151b92f
27 changed files with 57 additions and 800 deletions

View File

@ -1819,9 +1819,6 @@ v8_source_set("v8_base") {
"src/transitions-inl.h",
"src/transitions.cc",
"src/transitions.h",
"src/trap-handler/handler-outside.cc",
"src/trap-handler/handler-shared.cc",
"src/trap-handler/trap-handler-internal.h",
"src/trap-handler/trap-handler.h",
"src/type-hints.cc",
"src/type-hints.h",
@ -1978,9 +1975,6 @@ v8_source_set("v8_base") {
"src/x64/simulator-x64.h",
"src/x64/sse-instr.h",
]
if (is_linux) {
sources += [ "src/trap-handler/handler-inside.cc" ]
}
} else if (v8_current_cpu == "arm") {
sources += [ ### gcmole(arch:arm) ###
"src/arm/assembler-arm-inl.h",

View File

@ -7633,35 +7633,6 @@ class V8_EXPORT V8 {
*/
static void ShutdownPlatform();
#if V8_OS_LINUX && V8_TARGET_ARCH_X64
/**
* Give the V8 signal handler a chance to handle a fault.
*
* This function determines whether a memory access violation can be recovered
* by V8. If so, it will return true and modify context to return to a code
* fragment that can recover from the fault. Otherwise, TryHandleSignal will
* return false.
*
* The parameters to this function correspond to those passed to a Linux
* signal handler.
*
* \param signal_number The signal number.
*
* \param info A pointer to the siginfo_t structure provided to the signal
* handler.
*
* \param context The third argument passed to the Linux signal handler, which
* points to a ucontext_t structure.
*/
static bool TryHandleSignal(int signal_number, void* info, void* context);
#endif // V8_OS_LINUX
/**
* Enable the default signal handler rather than using one provided by the
* embedder.
*/
static bool RegisterDefaultSignalHandler();
private:
V8();

View File

@ -18,8 +18,6 @@ include_rules = [
"+src/interpreter/bytecode-register.h",
"+src/interpreter/bytecodes.h",
"+src/interpreter/interpreter.h",
"-src/trap-handler",
"+src/trap-handler/trap-handler.h",
"+testing/gtest/include/gtest/gtest_prod.h",
"-src/libplatform",
"-include/libplatform"

View File

@ -69,7 +69,6 @@
#include "src/snapshot/snapshot.h"
#include "src/startup-data-util.h"
#include "src/tracing/trace-event.h"
#include "src/trap-handler/trap-handler.h"
#include "src/unicode-inl.h"
#include "src/v8.h"
#include "src/v8threads.h"
@ -6155,16 +6154,6 @@ bool v8::V8::Initialize() {
return true;
}
#if V8_OS_LINUX && V8_TARGET_ARCH_X64
bool V8::TryHandleSignal(int signum, void* info, void* context) {
return v8::internal::trap_handler::TryHandleSignal(
signum, static_cast<siginfo_t*>(info), static_cast<ucontext_t*>(context));
}
#endif // V8_OS_LINUX
bool V8::RegisterDefaultSignalHandler() {
return v8::internal::trap_handler::RegisterDefaultSignalHandler();
}
void v8::V8::SetEntropySource(EntropySource entropy_source) {
base::RandomNumberGenerator::SetEntropySource(entropy_source);

View File

@ -111,6 +111,13 @@ Node* BuildCallToRuntime(Runtime::FunctionId f, JSGraph* jsgraph,
} // namespace
// TODO(eholk): Support trap handlers on other platforms.
#if V8_TARGET_ARCH_X64 && V8_OS_LINUX
const bool kTrapHandlerSupported = true;
#else
const bool kTrapHandlerSupported = false;
#endif
// A helper that handles building graph fragments for trapping.
// To avoid generating a ton of redundant code that just calls the runtime
// to trap, we generate a per-trap-reason block of code that all trap sites
@ -2800,15 +2807,6 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
args[pos++] = wasm_param;
}
// Set the ThreadInWasm flag before we do the actual call.
if (trap_handler::UseTrapHandler()) {
// TODO(eholk): Set the flag directly without a runtime call. We should be
// able to store directly to a location in the isolate (later TLS) that sets
// the g_thread_in_wasm_code flag.
BuildCallToRuntime(Runtime::kSetThreadInWasm, jsgraph(), nullptr, 0,
effect_, *control_);
}
args[pos++] = *effect_;
args[pos++] = *control_;
@ -2818,16 +2816,6 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args);
*effect_ = call;
// Clear the ThreadInWasmFlag
if (trap_handler::UseTrapHandler()) {
// TODO(eholk): Set the flag directly without a runtime call. We should be
// able to store directly to a location in the isolate (later TLS) that sets
// the g_thread_in_wasm_code flag.
BuildCallToRuntime(Runtime::kClearThreadInWasm, jsgraph(), nullptr, 0,
effect_, *control_);
}
Node* retval = call;
Node* jsval = ToJS(
retval, sig->return_count() == 0 ? wasm::kWasmStmt : sig->GetReturn());
@ -2874,11 +2862,6 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target,
Node* call;
bool direct_call = false;
if (trap_handler::UseTrapHandler()) {
BuildCallToRuntime(Runtime::kClearThreadInWasm, jsgraph(), nullptr, 0,
effect_, *control_);
}
if (target->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction>::cast(target);
if (function->shared()->internal_formal_parameter_count() == wasm_count) {
@ -2943,11 +2926,6 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target,
*effect_ = call;
SetSourcePosition(call, 0);
if (trap_handler::UseTrapHandler()) {
BuildCallToRuntime(Runtime::kSetThreadInWasm, jsgraph(), nullptr, 0,
effect_, *control_);
}
// Convert the return value back.
Node* i32_zero = jsgraph()->Int32Constant(0);
Node* val = sig->return_count() == 0
@ -3217,7 +3195,7 @@ Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype,
Node* load;
// WASM semantics throw on OOB. Introduce explicit bounds check.
if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) {
if (!FLAG_wasm_trap_handler || !kTrapHandlerSupported) {
BoundsCheckMem(memtype, index, offset, position);
}
bool aligned = static_cast<int>(alignment) >=
@ -3225,7 +3203,7 @@ Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype,
if (aligned ||
jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) {
if (FLAG_wasm_trap_handler && V8_TRAP_HANDLER_SUPPORTED) {
if (FLAG_wasm_trap_handler && kTrapHandlerSupported) {
DCHECK(FLAG_wasm_guard_pages);
Node* position_node = jsgraph()->Int32Constant(position);
load = graph()->NewNode(jsgraph()->machine()->ProtectedLoad(memtype),
@ -3237,7 +3215,7 @@ Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype,
}
} else {
// TODO(eholk): Support unaligned loads with trap handlers.
DCHECK(!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED);
DCHECK(!FLAG_wasm_trap_handler || !kTrapHandlerSupported);
load = graph()->NewNode(jsgraph()->machine()->UnalignedLoad(memtype),
MemBuffer(offset), index, *effect_, *control_);
}
@ -3271,7 +3249,7 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
Node* store;
// WASM semantics throw on OOB. Introduce explicit bounds check.
if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) {
if (!FLAG_wasm_trap_handler || !kTrapHandlerSupported) {
BoundsCheckMem(memtype, index, offset, position);
}
StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
@ -3285,7 +3263,7 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
if (aligned ||
jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) {
if (FLAG_wasm_trap_handler && V8_TRAP_HANDLER_SUPPORTED) {
if (FLAG_wasm_trap_handler && kTrapHandlerSupported) {
Node* position_node = jsgraph()->Int32Constant(position);
store = graph()->NewNode(
jsgraph()->machine()->ProtectedStore(memtype.representation()),
@ -3298,7 +3276,7 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
}
} else {
// TODO(eholk): Support unaligned stores with trap handlers.
DCHECK(!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED);
DCHECK(!FLAG_wasm_trap_handler || !kTrapHandlerSupported);
UnalignedStoreRepresentation rep(memtype.representation());
store =
graph()->NewNode(jsgraph()->machine()->UnalignedStore(rep),

View File

@ -270,12 +270,13 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
class WasmOutOfLineTrap final : public OutOfLineCode {
public:
WasmOutOfLineTrap(CodeGenerator* gen, int pc, bool frame_elided,
int32_t position)
int32_t position, Instruction* instr)
: OutOfLineCode(gen),
gen_(gen),
pc_(pc),
frame_elided_(frame_elided),
position_(position) {}
position_(position),
instr_(instr) {}
// TODO(eholk): Refactor this method to take the code generator as a
// parameter.
@ -289,17 +290,14 @@ class WasmOutOfLineTrap final : public OutOfLineCode {
wasm::TrapReason trap_id = wasm::kTrapMemOutOfBounds;
int trap_reason = wasm::WasmOpcodes::TrapReasonToMessageId(trap_id);
__ Push(Smi::FromInt(trap_reason));
// TODO(eholk): use AssembleSourcePosition instead of passing in position_
// as a parameter. See AssembleArchTrap as an example. Consider sharing code
// with AssembleArchTrap.
__ Push(Smi::FromInt(position_));
__ Move(rsi, Smi::kZero);
__ Move(rsi, gen_->isolate()->native_context());
__ CallRuntime(Runtime::kThrowWasmError);
ReferenceMap* reference_map =
new (gen_->code()->zone()) ReferenceMap(gen_->code()->zone());
gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
if (instr_->reference_map() != nullptr) {
gen_->RecordSafepoint(instr_->reference_map(), Safepoint::kSimple, 0,
Safepoint::kNoLazyDeopt);
}
}
private:
@ -307,17 +305,18 @@ class WasmOutOfLineTrap final : public OutOfLineCode {
int pc_;
bool frame_elided_;
int32_t position_;
Instruction* instr_;
};
void EmitOOLTrapIfNeeded(Zone* zone, CodeGenerator* codegen,
InstructionCode opcode, size_t input_count,
X64OperandConverter& i, int pc) {
X64OperandConverter& i, int pc, Instruction* instr) {
const X64MemoryProtection protection =
static_cast<X64MemoryProtection>(MiscField::decode(opcode));
if (protection == X64MemoryProtection::kProtected) {
const bool frame_elided = !codegen->frame_access_state()->has_frame();
const int32_t position = i.InputInt32(input_count - 1);
new (zone) WasmOutOfLineTrap(codegen, pc, frame_elided, position);
new (zone) WasmOutOfLineTrap(codegen, pc, frame_elided, position, instr);
}
}
} // namespace
@ -1860,30 +1859,30 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
case kX64Movsxbl:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movsxbl);
__ AssertZeroExtended(i.OutputRegister());
break;
case kX64Movzxbl:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movzxbl);
__ AssertZeroExtended(i.OutputRegister());
break;
case kX64Movsxbq:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movsxbq);
break;
case kX64Movzxbq:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movzxbq);
__ AssertZeroExtended(i.OutputRegister());
break;
case kX64Movb: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
size_t index = 0;
Operand operand = i.MemoryOperand(&index);
if (HasImmediateInput(instr, index)) {
@ -1895,30 +1894,30 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64Movsxwl:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movsxwl);
__ AssertZeroExtended(i.OutputRegister());
break;
case kX64Movzxwl:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movzxwl);
__ AssertZeroExtended(i.OutputRegister());
break;
case kX64Movsxwq:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movsxwq);
break;
case kX64Movzxwq:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movzxwq);
__ AssertZeroExtended(i.OutputRegister());
break;
case kX64Movw: {
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
size_t index = 0;
Operand operand = i.MemoryOperand(&index);
if (HasImmediateInput(instr, index)) {
@ -1930,7 +1929,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64Movl:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
if (instr->HasOutput()) {
if (instr->addressing_mode() == kMode_None) {
if (instr->InputAt(0)->IsRegister()) {
@ -1954,12 +1953,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
case kX64Movsxlq:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
ASSEMBLE_MOVX(movsxlq);
break;
case kX64Movq:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
if (instr->HasOutput()) {
__ movq(i.OutputRegister(), i.MemoryOperand());
} else {
@ -1974,7 +1973,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
case kX64Movss:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
if (instr->HasOutput()) {
__ movss(i.OutputDoubleRegister(), i.MemoryOperand());
} else {
@ -1985,7 +1984,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
case kX64Movsd:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr->InputCount(), i,
__ pc_offset());
__ pc_offset(), instr);
if (instr->HasOutput()) {
__ Movsd(i.OutputDoubleRegister(), i.MemoryOperand());
} else {

View File

@ -36,7 +36,6 @@
#include "src/msan.h"
#include "src/objects-inl.h"
#include "src/snapshot/natives.h"
#include "src/trap-handler/trap-handler.h"
#include "src/utils.h"
#include "src/v8.h"
@ -2954,13 +2953,6 @@ int Shell::Main(int argc, char* argv[]) {
create_params.add_histogram_sample_callback = AddHistogramSample;
}
if (i::trap_handler::UseTrapHandler()) {
if (!v8::V8::RegisterDefaultSignalHandler()) {
fprintf(stderr, "Could not register signal handler");
exit(1);
}
}
Isolate* isolate = Isolate::New(create_params);
{
Isolate::Scope scope(isolate);

View File

@ -1700,7 +1700,6 @@ Handle<Code> Factory::NewCode(const CodeDesc& desc,
code->set_prologue_offset(prologue_offset);
code->set_constant_pool_offset(desc.instr_size - desc.constant_pool_size);
code->set_builtin_index(-1);
code->set_trap_handler_index(Smi::FromInt(-1));
if (code->kind() == Code::OPTIMIZED_FUNCTION) {
code->set_marked_for_deoptimization(false);

View File

@ -1202,10 +1202,6 @@ Object* Isolate::UnwindAndFindHandler() {
for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
StackFrame* frame = iter.frame();
if (frame->is_wasm() && trap_handler::IsThreadInWasm()) {
trap_handler::ClearThreadInWasm();
}
// For JSEntryStub frames we always have a handler.
if (frame->is_entry() || frame->is_entry_construct()) {
StackHandler* handler = frame->top_handler();
@ -1237,11 +1233,6 @@ Object* Isolate::UnwindAndFindHandler() {
handler_sp = return_sp;
handler_fp = frame->fp();
// This is going to be handled by Wasm, so we need to set the TLS flag
// again.
trap_handler::SetThreadInWasm();
break;
}
}

View File

@ -6652,7 +6652,6 @@ CODE_ACCESSORS(relocation_info, ByteArray, kRelocationInfoOffset)
CODE_ACCESSORS(handler_table, FixedArray, kHandlerTableOffset)
CODE_ACCESSORS(deoptimization_data, FixedArray, kDeoptimizationDataOffset)
CODE_ACCESSORS(source_position_table, ByteArray, kSourcePositionTableOffset)
CODE_ACCESSORS(trap_handler_index, Smi, kTrapHandlerIndex)
CODE_ACCESSORS(raw_type_feedback_info, Object, kTypeFeedbackInfoOffset)
CODE_ACCESSORS(next_code_link, Object, kNextCodeLinkOffset)
#undef CODE_ACCESSORS

View File

@ -13829,12 +13829,6 @@ void Code::InvalidateEmbeddedObjects() {
void Code::Relocate(intptr_t delta) {
if (trap_handler::UseTrapHandler() && is_wasm_code()) {
const int index = trap_handler_index()->value();
if (index >= 0) {
trap_handler::UpdateHandlerDataCodePointer(index, instruction_start());
}
}
for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
it.rinfo()->apply(delta);
}

View File

@ -4915,10 +4915,6 @@ class Code: public HeapObject {
// [source_position_table]: ByteArray for the source positions table.
DECL_ACCESSORS(source_position_table, ByteArray)
// [trap_handler_index]: An index into the trap handler's master list of code
// objects.
DECL_ACCESSORS(trap_handler_index, Smi)
// [raw_type_feedback_info]: This field stores various things, depending on
// the kind of the code object.
// FUNCTION => type feedback information.
@ -5307,8 +5303,7 @@ class Code: public HeapObject {
static const int kConstantPoolOffset = kPrologueOffset + kIntSize;
static const int kBuiltinIndexOffset =
kConstantPoolOffset + kConstantPoolSize;
static const int kTrapHandlerIndex = kBuiltinIndexOffset + kIntSize;
static const int kHeaderPaddingStart = kTrapHandlerIndex + kPointerSize;
static const int kHeaderPaddingStart = kBuiltinIndexOffset + kIntSize;
enum TrapFields { kTrapCodeOffset, kTrapLandingOffset, kTrapDataSize };

View File

@ -12,7 +12,6 @@
#include "src/factory.h"
#include "src/frames-inl.h"
#include "src/objects-inl.h"
#include "src/trap-handler/trap-handler.h"
#include "src/v8memory.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects.h"
@ -169,16 +168,6 @@ RUNTIME_FUNCTION(Runtime_WasmGetCaughtExceptionValue) {
return exception;
}
RUNTIME_FUNCTION(Runtime_SetThreadInWasm) {
trap_handler::SetThreadInWasm();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_ClearThreadInWasm) {
trap_handler::ClearThreadInWasm();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_WasmRunInterpreter) {
DCHECK_EQ(3, args.length());
HandleScope scope(isolate);

View File

@ -642,9 +642,7 @@ namespace internal {
F(WasmThrow, 2, 1) \
F(WasmGetCaughtExceptionValue, 1, 1) \
F(WasmRunInterpreter, 3, 1) \
F(WasmStackGuard, 0, 1) \
F(SetThreadInWasm, 0, 1) \
F(ClearThreadInWasm, 0, 1)
F(WasmStackGuard, 0, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
F(LoadLookupSlotForCall, 1, 2)

View File

@ -1,17 +0,0 @@
# In order to make it easier to audit the signal handler code, we use very
# restrictive include rules to limit the amount of code that the signal handler
# can depend on.
include_rules = [
"-src",
"-include",
"+src/trap-handler",
]
specific_include_rules = {
"trap-handler.h": [
"+src/base/build_config.h",
"+src/globals.h",
"+src/flags.h",
]
}

View File

@ -1,10 +0,0 @@
set noparent
jochen@chromium.org
bradnelson@chromium.org
# Changes to this directory should also be reviewed by:
#
# eholk@chromium.org
# mseaborn@chromium.org
# mark@chromium.org

View File

@ -1,170 +0,0 @@
// Copyright 2017 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.
// PLEASE READ BEFORE CHANGING THIS FILE!
//
// This file implements the out of bounds signal handler for
// WebAssembly. Signal handlers are notoriously difficult to get
// right, and getting it wrong can lead to security
// vulnerabilities. In order to minimize this risk, here are some
// rules to follow.
//
// 1. Do not introduce any new external dependencies. This file needs
// to be self contained so it is easy to audit everything that a
// signal handler might do.
//
// 2. Any changes must be reviewed by someone from the crash reporting
// or security team. See OWNERS for suggested reviewers.
//
// For more information, see https://goo.gl/yMeyUY.
//
// This file contains most of the code that actually runs in a signal handler
// context. Some additional code is used both inside and outside the signal
// handler. This code can be found in handler-shared.cc.
#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
#include "src/trap-handler/trap-handler-internal.h"
#include "src/trap-handler/trap-handler.h"
namespace v8 {
namespace internal {
namespace trap_handler {
namespace {
bool IsKernelGeneratedSignal(siginfo_t* info) {
return info->si_code > 0 && info->si_code != SI_USER &&
info->si_code != SI_QUEUE && info->si_code != SI_TIMER &&
info->si_code != SI_ASYNCIO && info->si_code != SI_MESGQ;
}
#if V8_TRAP_HANDLER_SUPPORTED
class SigUnmaskStack {
public:
explicit SigUnmaskStack(sigset_t sigs) {
// TODO(eholk): consider using linux-syscall-support for calling this
// syscall.
pthread_sigmask(SIG_UNBLOCK, &sigs, &old_mask_);
}
~SigUnmaskStack() { pthread_sigmask(SIG_SETMASK, &old_mask_, nullptr); }
private:
sigset_t old_mask_;
// We'd normally use DISALLOW_COPY_AND_ASSIGN, but we're avoiding a dependency
// on base/macros.h
SigUnmaskStack(const SigUnmaskStack&) = delete;
void operator=(const SigUnmaskStack&) = delete;
};
#endif
} // namespace
#if V8_TRAP_HANDLER_SUPPORTED && V8_OS_LINUX
bool TryHandleSignal(int signum, siginfo_t* info, ucontext_t* context) {
// Bail out early in case we got called for the wrong kind of signal.
if (signum != SIGSEGV) {
return false;
}
// Make sure the signal was generated by the kernel and not some other source.
if (!IsKernelGeneratedSignal(info)) {
return false;
}
// Ensure the faulting thread was actually running Wasm code.
if (!IsThreadInWasm()) {
return false;
}
// Clear g_thread_in_wasm_code, primarily to protect against nested faults.
g_thread_in_wasm_code = false;
// Begin signal mask scope. We need to be sure to restore the signal mask
// before we restore the g_thread_in_wasm_code flag.
{
// Unmask the signal so that if this signal handler crashes, the crash will
// be handled by the crash reporter. Otherwise, the process might be killed
// with the crash going unreported.
sigset_t sigs;
// Fortunately, sigemptyset and sigaddset are async-signal-safe according to
// the POSIX standard.
sigemptyset(&sigs);
sigaddset(&sigs, SIGSEGV);
SigUnmaskStack unmask(sigs);
uintptr_t fault_addr = context->uc_mcontext.gregs[REG_RIP];
// TODO(eholk): broad code range check
// Taking locks in a signal handler is risky because a fault in the signal
// handler could lead to a deadlock when attempting to acquire the lock
// again. We guard against this case with g_thread_in_wasm_code. The lock
// may only be taken when not executing Wasm code (an assert in
// MetadataLock's constructor ensures this). This signal handler will bail
// out before trying to take the lock if g_thread_in_wasm_code is not set.
MetadataLock lock_holder;
for (size_t i = 0; i < gNumCodeObjects; ++i) {
const CodeProtectionInfo* data = gCodeObjects[i].code_info;
if (data == nullptr) {
continue;
}
const uintptr_t base = reinterpret_cast<uintptr_t>(data->base);
if (fault_addr >= base && fault_addr < base + data->size) {
// Hurray, we found the code object. Check for protected addresses.
const ptrdiff_t offset = fault_addr - base;
for (unsigned i = 0; i < data->num_protected_instructions; ++i) {
if (data->instructions[i].instr_offset == offset) {
// Hurray again, we found the actual instruction. Tell the caller to
// return to the landing pad.
context->uc_mcontext.gregs[REG_RIP] =
data->instructions[i].landing_offset + base;
return true;
}
}
}
}
} // end signal mask scope
// If we get here, it's not a recoverable wasm fault, so we go to the next
// handler.
g_thread_in_wasm_code = true;
return false;
}
#endif // V8_TRAP_HANDLER_SUPPORTED && V8_OS_LINUX
#if V8_TRAP_HANDLER_SUPPORTED
void HandleSignal(int signum, siginfo_t* info, void* context) {
ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
if (!TryHandleSignal(signum, info, uc)) {
// Since V8 didn't handle this signal, we want to re-raise the same signal.
// For kernel-generated SEGV signals, we do this by restoring the default
// SEGV handler and then returning. The fault will happen again and the
// usual SEGV handling will happen.
//
// We handle user-generated signals by calling raise() instead. This is for
// completeness. We should never actually see one of these, but just in
// case, we do the right thing.
struct sigaction action;
action.sa_handler = SIG_DFL;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(signum, &action, nullptr);
if (!IsKernelGeneratedSignal(info)) {
raise(signum);
}
}
// TryHandleSignal modifies context to change where we return to.
}
#endif
} // namespace trap_handler
} // namespace internal
} // namespace v8

View File

@ -1,191 +0,0 @@
// Copyright 2017 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.
// PLEASE READ BEFORE CHANGING THIS FILE!
//
// This file implements the support code for the out of bounds signal handler.
// Nothing in here actually runs in the signal handler, but the code here
// manipulates data structures used by the signal handler so we still need to be
// careful. In order to minimize this risk, here are some rules to follow.
//
// 1. Avoid introducing new external dependencies. The files in src/trap-handler
// should be as self-contained as possible to make it easy to audit the code.
//
// 2. Any changes must be reviewed by someone from the crash reporting
// or security team. Se OWNERS for suggested reviewers.
//
// For more information, see https://goo.gl/yMeyUY.
//
// For the code that runs in the signal handler itself, see handler-inside.cc.
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atomic>
#include <limits>
#include "src/trap-handler/trap-handler-internal.h"
#include "src/trap-handler/trap-handler.h"
namespace {
size_t gNextCodeObject = 0;
}
namespace v8 {
namespace internal {
namespace trap_handler {
const size_t kInitialCodeObjectSize = 1024;
const size_t kCodeObjectGrowthFactor = 2;
constexpr size_t HandlerDataSize(size_t num_protected_instructions) {
return offsetof(CodeProtectionInfo, instructions) +
num_protected_instructions * sizeof(ProtectedInstructionData);
}
CodeProtectionInfo* CreateHandlerData(
void* base, size_t size, size_t num_protected_instructions,
ProtectedInstructionData* protected_instructions) {
const size_t alloc_size = HandlerDataSize(num_protected_instructions);
CodeProtectionInfo* data =
reinterpret_cast<CodeProtectionInfo*>(malloc(alloc_size));
if (data == nullptr) {
return nullptr;
}
data->base = base;
data->size = size;
data->num_protected_instructions = num_protected_instructions;
memcpy(data->instructions, protected_instructions,
num_protected_instructions * sizeof(ProtectedInstructionData));
return data;
}
void UpdateHandlerDataCodePointer(int index, void* base) {
MetadataLock lock;
if (static_cast<size_t>(index) >= gNumCodeObjects) {
abort();
}
CodeProtectionInfo* data = gCodeObjects[index].code_info;
data->base = base;
}
int RegisterHandlerData(void* base, size_t size,
size_t num_protected_instructions,
ProtectedInstructionData* protected_instructions) {
// TODO(eholk): in debug builds, make sure this data isn't already registered.
CodeProtectionInfo* data = CreateHandlerData(
base, size, num_protected_instructions, protected_instructions);
if (data == nullptr) {
abort();
}
MetadataLock lock;
size_t i = gNextCodeObject;
// Explicitly convert std::numeric_limits<int>::max() to unsigned to avoid
// compiler warnings about signed/unsigned comparisons. We aren't worried
// about sign extension because we know std::numeric_limits<int>::max() is
// positive.
const size_t int_max = std::numeric_limits<int>::max();
// We didn't find an opening in the available space, so grow.
if (i == gNumCodeObjects) {
size_t new_size = gNumCodeObjects > 0
? gNumCodeObjects * kCodeObjectGrowthFactor
: kInitialCodeObjectSize;
// Because we must return an int, there is no point in allocating space for
// more objects than can fit in an int.
if (new_size > int_max) {
new_size = int_max;
}
if (new_size == gNumCodeObjects) {
return -1;
}
// Now that we know our new size is valid, we can go ahead and realloc the
// array.
gCodeObjects = static_cast<CodeProtectionInfoListEntry*>(
realloc(gCodeObjects, sizeof(*gCodeObjects) * new_size));
if (gCodeObjects == nullptr) {
abort();
}
memset(gCodeObjects + gNumCodeObjects, 0,
sizeof(*gCodeObjects) * (new_size - gNumCodeObjects));
gNumCodeObjects = new_size;
}
DCHECK(gCodeObjects[i].code_info == nullptr);
// Find out where the next entry should go.
if (gCodeObjects[i].next_free == 0) {
// if this is a fresh entry, use the next one.
gNextCodeObject = i + 1;
DCHECK(gNextCodeObject == gNumCodeObjects ||
(gCodeObjects[gNextCodeObject].code_info == nullptr &&
gCodeObjects[gNextCodeObject].next_free == 0));
} else {
gNextCodeObject = gCodeObjects[i].next_free - 1;
}
if (i <= int_max) {
gCodeObjects[i].code_info = data;
return static_cast<int>(i);
} else {
return -1;
}
}
void ReleaseHandlerData(int index) {
// Remove the data from the global list if it's there.
CodeProtectionInfo* data = nullptr;
{
MetadataLock lock;
data = gCodeObjects[index].code_info;
gCodeObjects[index].code_info = nullptr;
// +1 because we reserve {next_entry == 0} to indicate a fresh list entry.
gCodeObjects[index].next_free = gNextCodeObject + 1;
gNextCodeObject = index;
}
// TODO(eholk): on debug builds, ensure there are no more copies in
// the list.
free(data);
}
bool RegisterDefaultSignalHandler() {
#if V8_TRAP_HANDLER_SUPPORTED
struct sigaction action;
action.sa_sigaction = HandleSignal;
action.sa_flags = SA_SIGINFO;
sigemptyset(&action.sa_mask);
// {sigaction} installs a new custom segfault handler. On success, it returns
// 0. If we get a nonzero value, we report an error to the caller by returning
// false.
if (sigaction(SIGSEGV, &action, nullptr) != 0) {
return false;
}
return true;
#else
return false;
#endif
}
} // namespace trap_handler
} // namespace internal
} // namespace v8

View File

@ -1,52 +0,0 @@
// Copyright 2017 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.
// PLEASE READ BEFORE CHANGING THIS FILE!
//
// This file contains code that is used both inside and outside the out of
// bounds signal handler. Because this code runs in a signal handler context,
// use extra care when modifying this file. Here are some rules to follow.
//
// 1. Do not introduce any new external dependencies. This file needs
// to be self contained so it is easy to audit everything that a
// signal handler might do.
//
// 2. Any changes must be reviewed by someone from the crash reporting
// or security team. See OWNERS for suggested reviewers.
//
// For more information, see https://goo.gl/yMeyUY.
#include "src/trap-handler/trap-handler-internal.h"
namespace v8 {
namespace internal {
namespace trap_handler {
THREAD_LOCAL bool g_thread_in_wasm_code = false;
size_t gNumCodeObjects = 0;
CodeProtectionInfoListEntry* gCodeObjects = nullptr;
std::atomic_flag MetadataLock::spinlock_ = ATOMIC_FLAG_INIT;
MetadataLock::MetadataLock() {
if (g_thread_in_wasm_code) {
abort();
}
while (spinlock_.test_and_set(std::memory_order::memory_order_acquire)) {
}
}
MetadataLock::~MetadataLock() {
if (g_thread_in_wasm_code) {
abort();
}
spinlock_.clear(std::memory_order::memory_order_release);
}
} // namespace trap_handler
} // namespace internal
} // namespace v8

View File

@ -1,67 +0,0 @@
// Copyright 2016 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 TRAP_HANDLER_INTERNAL_H_
#define TRAP_HANDLER_INTERNAL_H_
// This file should not be included (even transitively) by files outside of
// src/trap-handler.
#include "src/trap-handler/trap-handler.h"
#include <atomic>
namespace v8 {
namespace internal {
namespace trap_handler {
// This describes a chunk of code that the signal handler will be able to handle
// faults in. {base} points to the beginning of the chunk, and {size} is the
// number of bytes in the code chunk. The remainder of the struct is a list of
// protected memory access instructions and an offset to a landing pad to handle
// faults on that instruction.
struct CodeProtectionInfo {
void* base;
size_t size;
size_t num_protected_instructions;
ProtectedInstructionData instructions[1];
};
class MetadataLock {
static std::atomic_flag spinlock_;
public:
MetadataLock();
~MetadataLock();
// We'd normally use DISALLOW_COPY_AND_ASSIGN, but we're avoiding a dependency
// on base/macros.h
MetadataLock(const MetadataLock&) = delete;
void operator=(const MetadataLock&) = delete;
};
#if V8_TRAP_HANDLER_SUPPORTED
void HandleSignal(int signum, siginfo_t* info, void* context);
#endif
// To enable constant time registration of handler data, we keep a free list of
// entries in the gCodeObjects table. Each entry contains a {next_free} field,
// which can be used to figure out where the next entry should be inserted.
// In order to avoid having to initialize all the links to start with, we use
// 0 to indicate that this is a fresh, never-used list entry and that therefore
// the next entry is known to be free. If {next_entry} is greater than zero,
// then {next_entry - 1} is the index that we should insert into next.
struct CodeProtectionInfoListEntry {
CodeProtectionInfo* code_info;
size_t next_free;
};
extern size_t gNumCodeObjects;
extern CodeProtectionInfoListEntry* gCodeObjects;
} // namespace trap_handler
} // namespace internal
} // namespace v8
#endif // TRAP_HANDLER_INTERNAL_H_

View File

@ -5,29 +5,10 @@
#ifndef V8_TRAP_HANDLER_H_
#define V8_TRAP_HANDLER_H_
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include "src/base/build_config.h"
#include "src/flags.h"
#include "src/globals.h"
#if V8_OS_LINUX
#include <ucontext.h>
#endif
namespace v8 {
namespace internal {
namespace trap_handler {
// TODO(eholk): Support trap handlers on other platforms.
#if V8_TARGET_ARCH_X64 && V8_OS_LINUX
#define V8_TRAP_HANDLER_SUPPORTED 1
#else
#define V8_TRAP_HANDLER_SUPPORTED 0
#endif
struct ProtectedInstructionData {
// The offset of this instruction from the start of its code object.
intptr_t instr_offset;
@ -38,56 +19,6 @@ struct ProtectedInstructionData {
intptr_t landing_offset;
};
/// Adjusts the base code pointer.
void UpdateHandlerDataCodePointer(int index, void* base);
/// Adds the handler data to the place where the signal handler will find it.
///
/// This returns a number that can be used to identify the handler data to
/// UpdateHandlerDataCodePointer and ReleaseHandlerData, or -1 on failure.
int RegisterHandlerData(void* base, size_t size,
size_t num_protected_instructions,
ProtectedInstructionData* protected_instructions);
/// Removes the data from the master list and frees any memory, if necessary.
void ReleaseHandlerData(int index);
#if V8_OS_WIN
#define THREAD_LOCAL __declspec(thread)
#elif V8_OS_ANDROID
// TODO(eholk): fix this before enabling for trap handlers for Android.
#define THREAD_LOCAL
#else
#define THREAD_LOCAL __thread
#endif
inline bool UseTrapHandler() {
return FLAG_wasm_trap_handler && V8_TRAP_HANDLER_SUPPORTED;
}
extern THREAD_LOCAL bool g_thread_in_wasm_code;
inline bool IsThreadInWasm() { return g_thread_in_wasm_code; }
inline void SetThreadInWasm() {
if (UseTrapHandler()) {
DCHECK(!IsThreadInWasm());
g_thread_in_wasm_code = true;
}
}
inline void ClearThreadInWasm() {
if (UseTrapHandler()) {
DCHECK(IsThreadInWasm());
g_thread_in_wasm_code = false;
}
}
bool RegisterDefaultSignalHandler();
#if V8_OS_LINUX
bool TryHandleSignal(int signum, siginfo_t* info, ucontext_t* context);
#endif // V8_OS_LINUX
} // namespace trap_handler
} // namespace internal
} // namespace v8

View File

@ -1279,10 +1279,7 @@
'transitions-inl.h',
'transitions.cc',
'transitions.h',
'trap-handler/handler-outside.cc',
'trap-handler/handler-shared.cc',
'trap-handler/trap-handler.h',
'trap-handler/trap-handler-internal.h',
'type-hints.cc',
'type-hints.h',
'type-info.cc',
@ -1675,9 +1672,6 @@
'third_party/valgrind/valgrind.h',
],
}],
['v8_target_arch=="x64" and OS=="linux"', {
'sources': ['trap-handler/handler-inside.cc']
}],
['v8_target_arch=="ppc" or v8_target_arch=="ppc64"', {
'sources': [ ### gcmole(arch:ppc) ###
'builtins/ppc/builtins-ppc.cc',

View File

@ -14,7 +14,6 @@
#include "src/property-descriptor.h"
#include "src/simulator.h"
#include "src/snapshot/snapshot.h"
#include "src/trap-handler/trap-handler.h"
#include "src/v8.h"
#include "src/asmjs/asm-wasm-builder.h"
@ -672,18 +671,6 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
DCHECK(compiled_module->has_weak_wasm_module());
WeakCell* weak_wasm_module = compiled_module->ptr_to_weak_wasm_module();
if (trap_handler::UseTrapHandler()) {
Handle<FixedArray> code_table = compiled_module->code_table();
for (int i = 0; i < code_table->length(); ++i) {
Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
int index = code->trap_handler_index()->value();
if (index >= 0) {
trap_handler::ReleaseHandlerData(index);
code->set_trap_handler_index(Smi::FromInt(-1));
}
}
}
// weak_wasm_module may have been cleared, meaning the module object
// was GC-ed. In that case, there won't be any new instances created,
// and we don't need to maintain the links between instances.
@ -1243,7 +1230,7 @@ class InstantiationHelper {
//--------------------------------------------------------------------------
// Unpack and notify signal handler of protected instructions.
//--------------------------------------------------------------------------
if (trap_handler::UseTrapHandler()) {
if (FLAG_wasm_trap_handler) {
for (int i = 0; i < code_table->length(); ++i) {
Handle<Code> code = code_table->GetValueChecked<Code>(isolate_, i);
@ -1264,15 +1251,8 @@ class InstantiationHelper {
reinterpret_cast<intptr_t>(it.rinfo()->pc()) - base;
unpacked.emplace_back(data);
}
if (unpacked.size() > 0) {
int size = code->CodeSize();
const int index =
RegisterHandlerData(reinterpret_cast<void*>(base), size,
unpacked.size(), &unpacked[0]);
// TODO(eholk): if index is negative, fail.
DCHECK(index >= 0);
code->set_trap_handler_index(Smi::FromInt(index));
}
// TODO(eholk): Register the protected instruction information once the
// trap handler is in place.
}
}

View File

@ -31,7 +31,6 @@
#include "include/libplatform/libplatform.h"
#include "src/debug/debug.h"
#include "src/objects-inl.h"
#include "src/trap-handler/trap-handler.h"
#include "test/cctest/print-extension.h"
#include "test/cctest/profiler-extension.h"
#include "test/cctest/trace-extension.h"
@ -269,10 +268,6 @@ int main(int argc, char* argv[]) {
v8::V8::Initialize();
v8::V8::InitializeExternalStartupData(argv[0]);
if (i::trap_handler::UseTrapHandler()) {
v8::V8::RegisterDefaultSignalHandler();
}
CcTestArrayBufferAllocator array_buffer_allocator;
CcTest::set_array_buffer_allocator(&array_buffer_allocator);

View File

@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "src/assembler-inl.h"
#include "src/trap-handler/trap-handler.h"
#include "src/wasm/wasm-macro-gen.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/value-helper.h"
@ -99,14 +98,6 @@ TEST(Unreachable) {
// Trigger a trap for loading from out-of-bounds.
TEST(IllegalLoad) {
if (trap_handler::UseTrapHandler()) {
// r.module().AddMemory() does not allocate guard pages, so we skip this
// test for now when using trap handlers. The simple out of bounds access
// case is covered by mjsunit tests, so we are still getting test coverage.
//
// TODO(eholk): make this test work with trap handlers.
return;
}
WasmRunner<void> r(kExecuteCompiled);
TestSignatures sigs;
// Set the execution context, such that a runtime error can be thrown.

View File

@ -23,7 +23,6 @@
#include "src/compiler/pipeline.h"
#include "src/compiler/wasm-compiler.h"
#include "src/compiler/zone-stats.h"
#include "src/trap-handler/trap-handler.h"
#include "src/wasm/function-body-decoder.h"
#include "src/wasm/wasm-external-refs.h"
#include "src/wasm/wasm-interpreter.h"
@ -825,29 +824,17 @@ bool WasmRunnerBase::trap_happened;
TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \
void RunWasm_##name(WasmExecutionMode execution_mode)
#define WASM_EXEC_TEST_WITH_TRAP(name) \
void RunWasm_##name(WasmExecutionMode execution_mode); \
TEST(RunWasmCompiled_##name) { \
if (trap_handler::UseTrapHandler()) { \
return; \
} \
RunWasm_##name(kExecuteCompiled); \
} \
TEST(RunWasmCompiledWithoutTrapIf_##name) { \
if (trap_handler::UseTrapHandler()) { \
return; \
} \
bool trap_if = FLAG_wasm_trap_if; \
FLAG_wasm_trap_if = true; \
RunWasm_##name(kExecuteCompiled); \
FLAG_wasm_trap_if = trap_if; \
} \
TEST(RunWasmInterpreted_##name) { \
if (trap_handler::UseTrapHandler()) { \
return; \
} \
RunWasm_##name(kExecuteInterpreted); \
} \
#define WASM_EXEC_TEST_WITH_TRAP(name) \
void RunWasm_##name(WasmExecutionMode execution_mode); \
TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \
void RunWasm_##name(WasmExecutionMode execution_mode); \
TEST(RunWasmCompiledWithoutTrapIf_##name) { \
bool trap_if = FLAG_wasm_trap_if; \
FLAG_wasm_trap_if = false; \
RunWasm_##name(kExecuteCompiled); \
FLAG_wasm_trap_if = trap_if; \
} \
TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \
void RunWasm_##name(WasmExecutionMode execution_mode)
#define WASM_EXEC_COMPILED_TEST(name) \

View File

@ -14,7 +14,7 @@ ALL_VARIANT_FLAGS = {
"ignition": [["--ignition"]],
"ignition_turbofan": [["--ignition-staging", "--turbo"]],
"asm_wasm": [["--validate-asm"]],
"wasm_traps": [["--wasm_guard_pages", "--wasm_trap_handler", "--invoke-weak-callbacks"]],
"wasm_traps": [["--wasm_guard_pages", "--invoke-weak-callbacks"]],
}
# FAST_VARIANTS implies no --always-opt.
@ -28,7 +28,7 @@ FAST_VARIANT_FLAGS = {
"ignition": [["--ignition"]],
"ignition_turbofan": [["--ignition-staging", "--turbo"]],
"asm_wasm": [["--validate-asm"]],
"wasm_traps": [["--wasm_guard_pages", "--wasm_trap_handler", "--invoke-weak-callbacks"]],
"wasm_traps": [["--wasm_guard_pages", "--invoke-weak-callbacks"]],
}
ALL_VARIANTS = set(["default", "stress", "turbofan", "turbofan_opt",