[turboassembler] Introduce hard-abort mode
For checks and assertions (mostly for debug code, like stack alignment or zero extension), we had two modes: Emit a call to the {Abort} runtime function (the default), and emit a debug break (used for testing, enabled via --trap-on-abort). In wasm, where we cannot just call a runtime function because code must be isolate independent, we always used the trap-on-abort behaviour. This causes problems for our fuzzers, which do not catch SIGTRAP, and hence do not detect debug code failures. This CL introduces a third mode ("hard abort"), which calls a C function via {ExternalReference}. The C function still outputs the abort reason, but does not print the stack trace. It then aborts via "OS::Abort", just like the runtime function. This will allow fuzzers to detect the crash and even find a nice error message. Even though this looks like a lot of code churn, it is actually not. Most added lines are new tests, and other changes are minimal. R=mstarzinger@chromium.org Bug: chromium:863799 Change-Id: I77c58ff72db552d49014614436259ccfb49ba87b Reviewed-on: https://chromium-review.googlesource.com/1142163 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#54592}
This commit is contained in:
parent
bced36d203
commit
a462a7854a
@ -612,7 +612,7 @@ struct VmovIndex {
|
||||
constexpr VmovIndex VmovIndexLo = { 0 };
|
||||
constexpr VmovIndex VmovIndexHi = { 1 };
|
||||
|
||||
class Assembler : public AssemblerBase {
|
||||
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||
public:
|
||||
// Create an assembler. Instructions and relocation information are emitted
|
||||
// into a buffer, with the instructions starting from the beginning and the
|
||||
|
@ -1881,6 +1881,16 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_abort_hard()) {
|
||||
// We don't care if we constructed a frame. Just pretend we did.
|
||||
FrameScope assume_frame(this, StackFrame::NONE);
|
||||
Move32BitImmediate(r0, Operand(static_cast<int>(reason)));
|
||||
PrepareCallCFunction(0, 0, r1);
|
||||
Move(r1, ExternalReference::abort_with_reason());
|
||||
Call(r1);
|
||||
return;
|
||||
}
|
||||
|
||||
Move(r1, Smi::FromInt(static_cast<int>(reason)));
|
||||
|
||||
// Disable stub call restrictions to always allow calls to abort.
|
||||
@ -2249,13 +2259,14 @@ int TurboAssembler::CalculateStackPassedWords(int num_reg_arguments,
|
||||
}
|
||||
|
||||
void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
|
||||
int num_double_arguments) {
|
||||
int num_double_arguments,
|
||||
Register scratch) {
|
||||
int frame_alignment = ActivationFrameAlignment();
|
||||
int stack_passed_arguments = CalculateStackPassedWords(
|
||||
num_reg_arguments, num_double_arguments);
|
||||
if (frame_alignment > kPointerSize) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
if (!scratch.is_valid()) scratch = temps.Acquire();
|
||||
// Make stack end at alignment and make room for num_arguments - 4 words
|
||||
// and the original value of sp.
|
||||
mov(scratch, sp);
|
||||
@ -2263,7 +2274,7 @@ void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
|
||||
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
|
||||
and_(sp, sp, Operand(-frame_alignment));
|
||||
str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
|
||||
} else {
|
||||
} else if (stack_passed_arguments > 0) {
|
||||
sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ enum TargetAddressStorageMode {
|
||||
NEVER_INLINE_TARGET_ADDRESS
|
||||
};
|
||||
|
||||
class TurboAssembler : public TurboAssemblerBase {
|
||||
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
public:
|
||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||
void* buffer, int buffer_size,
|
||||
@ -259,8 +259,8 @@ class TurboAssembler : public TurboAssemblerBase {
|
||||
// C++ code.
|
||||
// Needs a scratch register to do some arithmetic. This register will be
|
||||
// trashed.
|
||||
void PrepareCallCFunction(int num_reg_arguments,
|
||||
int num_double_registers = 0);
|
||||
void PrepareCallCFunction(int num_reg_arguments, int num_double_registers = 0,
|
||||
Register scratch = no_reg);
|
||||
|
||||
// Removes current frame and its arguments from the stack preserving
|
||||
// the arguments and a return address pushed to the stack for the next call.
|
||||
|
@ -882,7 +882,7 @@ class ConstPool {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Assembler.
|
||||
|
||||
class Assembler : public AssemblerBase {
|
||||
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||
public:
|
||||
// Create an assembler. Instructions and relocation information are emitted
|
||||
// into a buffer, with the instructions starting from the beginning and the
|
||||
|
@ -249,7 +249,7 @@ void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
|
||||
|
||||
|
||||
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
|
||||
MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
|
||||
HardAbortScope hard_aborts(masm);
|
||||
|
||||
// Save all kCallerSaved registers (including lr), since this can be called
|
||||
// from anywhere.
|
||||
|
@ -1429,7 +1429,7 @@ void MacroAssembler::PopCalleeSavedRegisters() {
|
||||
|
||||
void TurboAssembler::AssertSpAligned() {
|
||||
if (emit_debug_code()) {
|
||||
TrapOnAbortScope trap_on_abort_scope(this); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(this); // Avoid calls to Abort.
|
||||
// Arm64 requires the stack pointer to be 16-byte aligned prior to address
|
||||
// calculation.
|
||||
UseScratchRegisterScope scope(this);
|
||||
@ -2998,38 +2998,26 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
RegList old_tmp_list = TmpList()->list();
|
||||
TmpList()->Combine(MacroAssembler::DefaultTmpList());
|
||||
|
||||
if (use_real_aborts()) {
|
||||
// Avoid infinite recursion; Push contains some assertions that use Abort.
|
||||
NoUseRealAbortsScope no_real_aborts(this);
|
||||
if (should_abort_hard()) {
|
||||
// We don't care if we constructed a frame. Just pretend we did.
|
||||
FrameScope assume_frame(this, StackFrame::NONE);
|
||||
Mov(w0, static_cast<int>(reason));
|
||||
Call(ExternalReference::abort_with_reason());
|
||||
return;
|
||||
}
|
||||
|
||||
Move(x1, Smi::FromInt(static_cast<int>(reason)));
|
||||
// Avoid infinite recursion; Push contains some assertions that use Abort.
|
||||
HardAbortScope hard_aborts(this);
|
||||
|
||||
if (!has_frame_) {
|
||||
// We don't actually want to generate a pile of code for this, so just
|
||||
// claim there is a stack frame, without generating one.
|
||||
FrameScope scope(this, StackFrame::NONE);
|
||||
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
Move(x1, Smi::FromInt(static_cast<int>(reason)));
|
||||
|
||||
if (!has_frame_) {
|
||||
// We don't actually want to generate a pile of code for this, so just
|
||||
// claim there is a stack frame, without generating one.
|
||||
FrameScope scope(this, StackFrame::NONE);
|
||||
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Load the string to pass to Printf.
|
||||
Label msg_address;
|
||||
Adr(x0, &msg_address);
|
||||
|
||||
// Call Printf directly to report the error.
|
||||
CallPrintf();
|
||||
|
||||
// We need a way to stop execution on both the simulator and real hardware,
|
||||
// and Unreachable() is the best option.
|
||||
Unreachable();
|
||||
|
||||
// Emit the message string directly in the instruction stream.
|
||||
{
|
||||
BlockPoolsScope scope(this);
|
||||
Bind(&msg_address);
|
||||
EmitStringData(GetAbortReason(reason));
|
||||
}
|
||||
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
TmpList()->set_list(old_tmp_list);
|
||||
|
@ -177,7 +177,7 @@ enum PreShiftImmMode {
|
||||
kAnyShift // Allow any pre-shift.
|
||||
};
|
||||
|
||||
class TurboAssembler : public TurboAssemblerBase {
|
||||
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
public:
|
||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||
void* buffer, int buffer_size,
|
||||
@ -185,27 +185,6 @@ class TurboAssembler : public TurboAssemblerBase {
|
||||
: TurboAssemblerBase(isolate, options, buffer, buffer_size,
|
||||
create_code_object) {}
|
||||
|
||||
// The Abort method should call a V8 runtime function, but the CallRuntime
|
||||
// mechanism depends on CEntry. If use_real_aborts is false, Abort will
|
||||
// use a simpler abort mechanism that doesn't depend on CEntry.
|
||||
//
|
||||
// The purpose of this is to allow Aborts to be compiled whilst CEntry is
|
||||
// being generated.
|
||||
bool use_real_aborts() const { return use_real_aborts_; }
|
||||
|
||||
class NoUseRealAbortsScope {
|
||||
public:
|
||||
explicit NoUseRealAbortsScope(TurboAssembler* tasm)
|
||||
: saved_(tasm->use_real_aborts_), tasm_(tasm) {
|
||||
tasm_->use_real_aborts_ = false;
|
||||
}
|
||||
~NoUseRealAbortsScope() { tasm_->use_real_aborts_ = saved_; }
|
||||
|
||||
private:
|
||||
bool saved_;
|
||||
TurboAssembler* tasm_;
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
void set_allow_macro_instructions(bool value) {
|
||||
allow_macro_instructions_ = value;
|
||||
@ -1267,8 +1246,6 @@ class TurboAssembler : public TurboAssemblerBase {
|
||||
CPURegList tmp_list_ = DefaultTmpList();
|
||||
CPURegList fptmp_list_ = DefaultFPTmpList();
|
||||
|
||||
bool use_real_aborts_ = true;
|
||||
|
||||
// Helps resolve branching to labels potentially out of range.
|
||||
// If the label is not bound, it registers the information necessary to later
|
||||
// be able to emit a veneer for this branch if necessary.
|
||||
|
@ -167,7 +167,7 @@ struct V8_EXPORT_PRIVATE AssemblerOptions {
|
||||
Isolate* isolate, bool explicitly_support_serialization = false);
|
||||
};
|
||||
|
||||
class AssemblerBase : public Malloced {
|
||||
class V8_EXPORT_PRIVATE AssemblerBase : public Malloced {
|
||||
public:
|
||||
AssemblerBase(const AssemblerOptions& options, void* buffer, int buffer_size);
|
||||
virtual ~AssemblerBase();
|
||||
|
@ -26,6 +26,11 @@ const char* GetAbortReason(AbortReason reason) {
|
||||
return error_messages_[static_cast<int>(reason)];
|
||||
}
|
||||
|
||||
bool IsValidAbortReason(int reason_id) {
|
||||
return reason_id >= static_cast<int>(AbortReason::kNoReason) &&
|
||||
reason_id < static_cast<int>(AbortReason::kLastErrorMessage);
|
||||
}
|
||||
|
||||
#undef ERROR_MESSAGES_TEXTS
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -125,6 +125,7 @@ enum class AbortReason {
|
||||
|
||||
const char* GetBailoutReason(BailoutReason reason);
|
||||
const char* GetAbortReason(AbortReason reason);
|
||||
bool IsValidAbortReason(int reason_id);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -2218,7 +2218,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
// Convert to Smi for the runtime call.
|
||||
__ SmiTag(r4, r4);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
@ -2415,7 +2415,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
|
||||
void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
Label negate, done;
|
||||
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
UseScratchRegisterScope temps(masm);
|
||||
Register result_reg = r7;
|
||||
Register double_low = GetRegisterThatIsNotOneOf(result_reg);
|
||||
|
@ -2676,7 +2676,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
__ sxtw(x8, w8);
|
||||
__ SmiTag(x8, x8);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
@ -2718,7 +2718,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
|
||||
// fall-back Abort mechanism.
|
||||
//
|
||||
// Note that this stub must be generated before any use of Abort.
|
||||
MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
|
||||
HardAbortScope hard_aborts(masm);
|
||||
|
||||
ASM_LOCATION("CEntry::Generate entry");
|
||||
ProfileEntryHookStub::MaybeCallEntryHook(masm);
|
||||
@ -2938,7 +2938,7 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
|
||||
DCHECK(result.Is64Bits());
|
||||
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
UseScratchRegisterScope temps(masm);
|
||||
Register scratch1 = temps.AcquireX();
|
||||
Register scratch2 = temps.AcquireX();
|
||||
|
@ -2384,7 +2384,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
// Convert to Smi for the runtime call.
|
||||
__ SmiTag(edi);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
|
@ -2272,7 +2272,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
// Convert to Smi for the runtime call.
|
||||
__ SmiTag(t0);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
|
@ -2289,7 +2289,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
// Convert to Smi for the runtime call
|
||||
__ SmiTag(t0);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
|
@ -2300,7 +2300,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
// Convert to Smi for the runtime call.
|
||||
__ SmiTag(r15, r15);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
@ -2531,7 +2531,7 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
Label out_of_range, only_low, negate, done, fastpath_done;
|
||||
Register result_reg = r3;
|
||||
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
|
||||
// Immediate values for this stub fit in instructions, so it's safe to use ip.
|
||||
Register scratch = GetRegisterThatIsNotOneOf(result_reg);
|
||||
|
@ -2305,7 +2305,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
// Convert to Smi for the runtime call.
|
||||
__ SmiTag(r7, r7);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameAndConstantPoolScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
@ -2525,7 +2525,7 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||
Label out_of_range, only_low, negate, done, fastpath_done;
|
||||
Register result_reg = r2;
|
||||
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
|
||||
// Immediate values for this stub fit in instructions, so it's safe to use ip.
|
||||
Register scratch = GetRegisterThatIsNotOneOf(result_reg);
|
||||
|
@ -2339,7 +2339,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
||||
// Convert to Smi for the runtime call.
|
||||
__ SmiTag(r11, r11);
|
||||
{
|
||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
||||
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||
|
||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||
|
@ -90,7 +90,7 @@ CodeGenerator::CodeGenerator(
|
||||
if (code_kind == Code::WASM_FUNCTION ||
|
||||
code_kind == Code::WASM_TO_JS_FUNCTION ||
|
||||
code_kind == Code::WASM_INTERPRETER_ENTRY) {
|
||||
tasm_.set_trap_on_abort(true);
|
||||
tasm_.set_abort_hard(true);
|
||||
}
|
||||
tasm_.set_builtin_index(builtin_index);
|
||||
}
|
||||
|
@ -459,6 +459,10 @@ ExternalReference ExternalReference::address_of_pending_message_obj(
|
||||
return ExternalReference(isolate->pending_message_obj_address());
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::abort_with_reason() {
|
||||
return ExternalReference(Redirect(FUNCTION_ADDR(i::abort_with_reason)));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::address_of_min_int() {
|
||||
return ExternalReference(reinterpret_cast<Address>(&double_min_int_constant));
|
||||
}
|
||||
@ -951,5 +955,16 @@ std::ostream& operator<<(std::ostream& os, ExternalReference reference) {
|
||||
return os;
|
||||
}
|
||||
|
||||
void abort_with_reason(int reason) {
|
||||
if (IsValidAbortReason(reason)) {
|
||||
const char* message = GetAbortReason(static_cast<AbortReason>(reason));
|
||||
base::OS::PrintError("abort: %s\n", message);
|
||||
} else {
|
||||
base::OS::PrintError("abort: <unknown reason: %d>\n", reason);
|
||||
}
|
||||
base::OS::Abort();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -71,6 +71,7 @@ class StatsCounter;
|
||||
EXTERNAL_REFERENCE_LIST_NON_INTERPRETED_REGEXP(V)
|
||||
|
||||
#define EXTERNAL_REFERENCE_LIST(V) \
|
||||
V(abort_with_reason, "abort_with_reason") \
|
||||
V(address_of_double_abs_constant, "double_absolute_constant") \
|
||||
V(address_of_double_neg_constant, "double_negate_constant") \
|
||||
V(address_of_float_abs_constant, "float_absolute_constant") \
|
||||
@ -301,6 +302,8 @@ size_t hash_value(ExternalReference);
|
||||
|
||||
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, ExternalReference);
|
||||
|
||||
void abort_with_reason(int reason);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -321,7 +321,7 @@ enum ScaleFactor {
|
||||
times_twice_pointer_size = times_8
|
||||
};
|
||||
|
||||
class Operand {
|
||||
class V8_EXPORT_PRIVATE Operand {
|
||||
public:
|
||||
// reg
|
||||
V8_INLINE explicit Operand(Register reg) { set_modrm(3, reg); }
|
||||
@ -472,8 +472,7 @@ class Displacement BASE_EMBEDDED {
|
||||
void init(Label* L, Type type);
|
||||
};
|
||||
|
||||
|
||||
class Assembler : public AssemblerBase {
|
||||
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||
private:
|
||||
// We check before assembling an instruction that there is sufficient
|
||||
// space to write an instruction and its relocation information.
|
||||
|
@ -1591,6 +1591,15 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_abort_hard()) {
|
||||
// We don't care if we constructed a frame. Just pretend we did.
|
||||
FrameScope assume_frame(this, StackFrame::NONE);
|
||||
PrepareCallCFunction(1, eax);
|
||||
mov(Operand(esp, 0), Immediate(static_cast<int>(reason)));
|
||||
CallCFunction(ExternalReference::abort_with_reason(), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Move(edx, Smi::FromInt(static_cast<int>(reason)));
|
||||
|
||||
// Disable stub call restrictions to always allow calls to abort.
|
||||
|
@ -54,7 +54,7 @@ bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg,
|
||||
Register reg8 = no_reg);
|
||||
#endif
|
||||
|
||||
class TurboAssembler : public TurboAssemblerBase {
|
||||
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
public:
|
||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||
void* buffer, int buffer_size,
|
||||
|
@ -4695,6 +4695,15 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_abort_hard()) {
|
||||
// We don't care if we constructed a frame. Just pretend we did.
|
||||
FrameScope assume_frame(this, StackFrame::NONE);
|
||||
PrepareCallCFunction(0, a0);
|
||||
li(a0, Operand(static_cast<int>(reason)));
|
||||
CallCFunction(ExternalReference::abort_with_reason(), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Move(a0, Smi::FromInt(static_cast<int>(reason)));
|
||||
|
||||
// Disable stub call restrictions to always allow calls to abort.
|
||||
|
@ -5024,6 +5024,15 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_abort_hard()) {
|
||||
// We don't care if we constructed a frame. Just pretend we did.
|
||||
FrameScope assume_frame(this, StackFrame::NONE);
|
||||
PrepareCallCFunction(0, a0);
|
||||
li(a0, Operand(static_cast<int>(reason)));
|
||||
CallCFunction(ExternalReference::abort_with_reason(), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Move(a0, Smi::FromInt(static_cast<int>(reason)));
|
||||
|
||||
// Disable stub call restrictions to always allow calls to abort.
|
||||
|
@ -1757,7 +1757,9 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
#endif
|
||||
|
||||
// Avoid emitting call to builtin if requested.
|
||||
if (trap_on_abort()) {
|
||||
if (trap_on_abort() || should_abort_hard()) {
|
||||
// TODO(ppc): Call {ExternalReference::abort_with_reason} if
|
||||
// {should_abort_hard} is set.
|
||||
stop(msg);
|
||||
return;
|
||||
}
|
||||
|
@ -1688,7 +1688,9 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
#endif
|
||||
|
||||
// Avoid emitting call to builtin if requested.
|
||||
if (trap_on_abort()) {
|
||||
if (trap_on_abort() || should_abort_hard()) {
|
||||
// TODO(s390): Call {ExternalReference::abort_with_reason} if
|
||||
// {should_abort_hard} is set.
|
||||
stop(msg);
|
||||
return;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace internal {
|
||||
|
||||
// Common base class for platform-specific TurboAssemblers containing
|
||||
// platform-independent bits.
|
||||
class TurboAssemblerBase : public Assembler {
|
||||
class V8_EXPORT_PRIVATE TurboAssemblerBase : public Assembler {
|
||||
public:
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
|
||||
@ -26,7 +26,9 @@ class TurboAssemblerBase : public Assembler {
|
||||
void set_root_array_available(bool v) { root_array_available_ = v; }
|
||||
|
||||
bool trap_on_abort() const { return trap_on_abort_; }
|
||||
void set_trap_on_abort(bool v) { trap_on_abort_ = v; }
|
||||
|
||||
bool should_abort_hard() const { return hard_abort_; }
|
||||
void set_abort_hard(bool v) { hard_abort_ = v; }
|
||||
|
||||
void set_builtin_index(int i) { maybe_builtin_index_ = i; }
|
||||
|
||||
@ -78,6 +80,9 @@ class TurboAssemblerBase : public Assembler {
|
||||
// Immediately trap instead of calling {Abort} when debug code fails.
|
||||
bool trap_on_abort_ = FLAG_trap_on_abort;
|
||||
|
||||
// Emit a C call to abort instead of a runtime call.
|
||||
bool hard_abort_ = false;
|
||||
|
||||
// May be set while generating builtins.
|
||||
int maybe_builtin_index_ = Builtins::kNoBuiltinId;
|
||||
|
||||
@ -89,13 +94,13 @@ class TurboAssemblerBase : public Assembler {
|
||||
// Avoids emitting calls to the {Builtins::kAbort} builtin when emitting debug
|
||||
// code during the lifetime of this scope object. For disabling debug code
|
||||
// entirely use the {DontEmitDebugCodeScope} instead.
|
||||
class TrapOnAbortScope BASE_EMBEDDED {
|
||||
class HardAbortScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit TrapOnAbortScope(TurboAssemblerBase* assembler)
|
||||
: assembler_(assembler), old_value_(assembler->trap_on_abort()) {
|
||||
assembler_->set_trap_on_abort(true);
|
||||
explicit HardAbortScope(TurboAssemblerBase* assembler)
|
||||
: assembler_(assembler), old_value_(assembler->should_abort_hard()) {
|
||||
assembler_->set_abort_hard(true);
|
||||
}
|
||||
~TrapOnAbortScope() { assembler_->set_trap_on_abort(old_value_); }
|
||||
~HardAbortScope() { assembler_->set_abort_hard(old_value_); }
|
||||
|
||||
private:
|
||||
TurboAssemblerBase* assembler_;
|
||||
|
@ -349,7 +349,7 @@ constexpr AssemblerOptions DefaultLiftoffOptions() {
|
||||
LiftoffAssembler::LiftoffAssembler()
|
||||
: TurboAssembler(nullptr, DefaultLiftoffOptions(), nullptr, 0,
|
||||
CodeObjectRequired::kNo) {
|
||||
set_trap_on_abort(true); // Avoid calls to Abort.
|
||||
set_abort_hard(true); // Avoid calls to Abort.
|
||||
}
|
||||
|
||||
LiftoffAssembler::~LiftoffAssembler() {
|
||||
|
@ -1380,14 +1380,8 @@ void LiftoffAssembler::CallC(wasm::FunctionSig* sig,
|
||||
}
|
||||
DCHECK_LE(arg_bytes, stack_bytes);
|
||||
|
||||
// Pass a pointer to the buffer with the arguments to the C function.
|
||||
// On win64, the first argument is in {rcx}, otherwise it is {rdi}.
|
||||
#ifdef _WIN64
|
||||
constexpr Register kFirstArgReg = rcx;
|
||||
#else
|
||||
constexpr Register kFirstArgReg = rdi;
|
||||
#endif
|
||||
movp(kFirstArgReg, rsp);
|
||||
// Pass a pointer to the buffer with the arguments to the C function.
|
||||
movp(arg_reg_1, rsp);
|
||||
|
||||
constexpr int kNumCCallArgs = 1;
|
||||
|
||||
|
@ -422,7 +422,7 @@ static_assert(sizeof(Operand) <= 2 * kPointerSize,
|
||||
V(shr, 0x5) \
|
||||
V(sar, 0x7)
|
||||
|
||||
class Assembler : public AssemblerBase {
|
||||
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||
private:
|
||||
// We check before assembling an instruction that there is sufficient
|
||||
// space to write an instruction and its relocation information.
|
||||
|
@ -427,6 +427,16 @@ void TurboAssembler::Abort(AbortReason reason) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (should_abort_hard()) {
|
||||
// We don't care if we constructed a frame. Just pretend we did.
|
||||
FrameScope assume_frame(this, StackFrame::NONE);
|
||||
movl(arg_reg_1, Immediate(static_cast<int>(reason)));
|
||||
PrepareCallCFunction(1);
|
||||
LoadAddress(rax, ExternalReference::abort_with_reason());
|
||||
call(rax);
|
||||
return;
|
||||
}
|
||||
|
||||
Move(rdx, Smi::FromInt(static_cast<int>(reason)));
|
||||
|
||||
if (!has_frame()) {
|
||||
|
@ -125,7 +125,7 @@ class StackArgumentsAccessor BASE_EMBEDDED {
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
|
||||
};
|
||||
|
||||
class TurboAssembler : public TurboAssemblerBase {
|
||||
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
public:
|
||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||
void* buffer, int buffer_size,
|
||||
|
@ -50,9 +50,10 @@ v8_source_set("cctest_sources") {
|
||||
"$target_gen_dir/resources.cc",
|
||||
|
||||
### gcmole(all) ###
|
||||
"../../test/common/wasm/flag-utils.h",
|
||||
"../../test/common/wasm/test-signatures.h",
|
||||
"../../test/common/wasm/wasm-macro-gen.h",
|
||||
"../common/assembler-tester.h",
|
||||
"../common/wasm/flag-utils.h",
|
||||
"../common/wasm/test-signatures.h",
|
||||
"../common/wasm/wasm-macro-gen.h",
|
||||
"cctest.cc",
|
||||
"cctest.h",
|
||||
"compiler/c-signature.h",
|
||||
|
@ -548,32 +548,6 @@ static inline void CheckDoubleEquals(double expected, double actual) {
|
||||
CHECK_GE(expected, actual - kEpsilon);
|
||||
}
|
||||
|
||||
static inline uint8_t* AllocateAssemblerBuffer(
|
||||
size_t* allocated,
|
||||
size_t requested = v8::internal::AssemblerBase::kMinimalBufferSize) {
|
||||
size_t page_size = v8::internal::AllocatePageSize();
|
||||
size_t alloc_size = RoundUp(requested, page_size);
|
||||
void* result = v8::internal::AllocatePages(
|
||||
nullptr, alloc_size, page_size, v8::PageAllocator::kReadWriteExecute);
|
||||
CHECK(result);
|
||||
*allocated = alloc_size;
|
||||
return static_cast<uint8_t*>(result);
|
||||
}
|
||||
|
||||
static inline void MakeAssemblerBufferExecutable(uint8_t* buffer,
|
||||
size_t allocated) {
|
||||
bool result = v8::internal::SetPermissions(buffer, allocated,
|
||||
v8::PageAllocator::kReadExecute);
|
||||
CHECK(result);
|
||||
}
|
||||
|
||||
static inline void MakeAssemblerBufferWritable(uint8_t* buffer,
|
||||
size_t allocated) {
|
||||
bool result = v8::internal::SetPermissions(buffer, allocated,
|
||||
v8::PageAllocator::kReadWrite);
|
||||
CHECK(result);
|
||||
}
|
||||
|
||||
static v8::debug::DebugDelegate dummy_delegate;
|
||||
|
||||
static inline void EnableDebugger(v8::Isolate* isolate) {
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "src/macro-assembler.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-utils-arm64.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "src/ostreams.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "src/objects-inl.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "src/register-configuration.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-code-stubs.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/simulator.h"
|
||||
#include "src/snapshot/macros.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
// To generate the binary files for the test function, enable this section and
|
||||
// run GenerateTestFunctionData once on each arch.
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "src/simulator.h"
|
||||
#include "src/v8.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
42
test/common/assembler-tester.h
Normal file
42
test/common/assembler-tester.h
Normal file
@ -0,0 +1,42 @@
|
||||
// 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_TEST_COMMON_ASSEMBLER_TESTER_H_
|
||||
#define V8_TEST_COMMON_ASSEMBLER_TESTER_H_
|
||||
|
||||
#include "src/assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
static inline uint8_t* AllocateAssemblerBuffer(
|
||||
size_t* allocated,
|
||||
size_t requested = v8::internal::AssemblerBase::kMinimalBufferSize) {
|
||||
size_t page_size = v8::internal::AllocatePageSize();
|
||||
size_t alloc_size = RoundUp(requested, page_size);
|
||||
void* result = v8::internal::AllocatePages(
|
||||
nullptr, alloc_size, page_size, v8::PageAllocator::kReadWriteExecute);
|
||||
CHECK(result);
|
||||
*allocated = alloc_size;
|
||||
return static_cast<uint8_t*>(result);
|
||||
}
|
||||
|
||||
static inline void MakeAssemblerBufferExecutable(uint8_t* buffer,
|
||||
size_t allocated) {
|
||||
bool result = v8::internal::SetPermissions(buffer, allocated,
|
||||
v8::PageAllocator::kReadExecute);
|
||||
CHECK(result);
|
||||
}
|
||||
|
||||
static inline void MakeAssemblerBufferWritable(uint8_t* buffer,
|
||||
size_t allocated) {
|
||||
bool result = v8::internal::SetPermissions(buffer, allocated,
|
||||
v8::PageAllocator::kReadWrite);
|
||||
CHECK(result);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_TEST_COMMON_ASSEMBLER_TESTER_H_
|
@ -41,6 +41,7 @@ v8_source_set("unittests_sources") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"../../test/common/assembler-tester.h",
|
||||
"../../test/common/wasm/wasm-macro-gen.h",
|
||||
"../../testing/gmock-support.h",
|
||||
"../../testing/gtest-support.h",
|
||||
@ -222,17 +223,35 @@ v8_source_set("unittests_sources") {
|
||||
}
|
||||
|
||||
if (v8_current_cpu == "arm") {
|
||||
sources += [ "compiler/arm/instruction-selector-arm-unittest.cc" ]
|
||||
sources += [
|
||||
"assembler/turbo-assembler-arm-unittest.cc",
|
||||
"compiler/arm/instruction-selector-arm-unittest.cc",
|
||||
]
|
||||
} else if (v8_current_cpu == "arm64") {
|
||||
sources += [ "compiler/arm64/instruction-selector-arm64-unittest.cc" ]
|
||||
sources += [
|
||||
"assembler/turbo-assembler-arm64-unittest.cc",
|
||||
"compiler/arm64/instruction-selector-arm64-unittest.cc",
|
||||
]
|
||||
} else if (v8_current_cpu == "x86") {
|
||||
sources += [ "compiler/ia32/instruction-selector-ia32-unittest.cc" ]
|
||||
sources += [
|
||||
"assembler/turbo-assembler-ia32-unittest.cc",
|
||||
"compiler/ia32/instruction-selector-ia32-unittest.cc",
|
||||
]
|
||||
} else if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel") {
|
||||
sources += [ "compiler/mips/instruction-selector-mips-unittest.cc" ]
|
||||
sources += [
|
||||
"assembler/turbo-assembler-mips-unittest.cc",
|
||||
"compiler/mips/instruction-selector-mips-unittest.cc",
|
||||
]
|
||||
} else if (v8_current_cpu == "mips64" || v8_current_cpu == "mips64el") {
|
||||
sources += [ "compiler/mips64/instruction-selector-mips64-unittest.cc" ]
|
||||
sources += [
|
||||
"assembler/turbo-assembler-mips64-unittest.cc",
|
||||
"compiler/mips64/instruction-selector-mips64-unittest.cc",
|
||||
]
|
||||
} else if (v8_current_cpu == "x64") {
|
||||
sources += [ "compiler/x64/instruction-selector-x64-unittest.cc" ]
|
||||
sources += [
|
||||
"assembler/turbo-assembler-x64-unittest.cc",
|
||||
"compiler/x64/instruction-selector-x64-unittest.cc",
|
||||
]
|
||||
} else if (v8_current_cpu == "ppc" || v8_current_cpu == "ppc64") {
|
||||
sources += [ "compiler/ppc/instruction-selector-ppc-unittest.cc" ]
|
||||
} else if (v8_current_cpu == "s390" || v8_current_cpu == "s390x") {
|
||||
|
68
test/unittests/assembler/turbo-assembler-arm-unittest.cc
Normal file
68
test/unittests/assembler/turbo-assembler-arm-unittest.cc
Normal file
@ -0,0 +1,68 @@
|
||||
// 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/arm/assembler-arm-inl.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ tasm.
|
||||
|
||||
// Test the x64 assembler by compiling some simple functions into
|
||||
// a buffer and executing them. These tests do not initialize the
|
||||
// V8 library, create a context, or use any V8 objects.
|
||||
|
||||
class TurboAssemblerTest : public TestWithIsolate {};
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
|
||||
}
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter is 17.
|
||||
__ Move32BitImmediate(r1, Operand(17));
|
||||
__ cmp(r0, r1); // 1st parameter is in {r0}.
|
||||
__ Check(Condition::ne, AbortReason::kNoReason);
|
||||
__ Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
|
||||
|
||||
f.Call(0);
|
||||
f.Call(18);
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason");
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
68
test/unittests/assembler/turbo-assembler-arm64-unittest.cc
Normal file
68
test/unittests/assembler/turbo-assembler-arm64-unittest.cc
Normal file
@ -0,0 +1,68 @@
|
||||
// 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/arm64/macro-assembler-arm64-inl.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ tasm.
|
||||
|
||||
// Test the x64 assembler by compiling some simple functions into
|
||||
// a buffer and executing them. These tests do not initialize the
|
||||
// V8 library, create a context, or use any V8 objects.
|
||||
|
||||
class TurboAssemblerTest : public TestWithIsolate {};
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
|
||||
}
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter is 17.
|
||||
__ Mov(w1, Immediate(17));
|
||||
__ Cmp(w0, w1); // 1st parameter is in {w0}.
|
||||
__ Check(Condition::ne, AbortReason::kNoReason);
|
||||
__ Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
|
||||
|
||||
f.Call(0);
|
||||
f.Call(18);
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason");
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
62
test/unittests/assembler/turbo-assembler-ia32-unittest.cc
Normal file
62
test/unittests/assembler/turbo-assembler-ia32-unittest.cc
Normal file
@ -0,0 +1,62 @@
|
||||
// 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/macro-assembler.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ tasm.
|
||||
|
||||
// Test the x64 assembler by compiling some simple functions into
|
||||
// a buffer and executing them. These tests do not initialize the
|
||||
// V8 library, create a context, or use any V8 objects.
|
||||
|
||||
TEST(TurboAssemblerTest, TestHardAbort) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer);
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
|
||||
}
|
||||
|
||||
TEST(TurboAssemblerTest, TestCheck) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter is 17.
|
||||
__ mov(eax, 17);
|
||||
__ cmp(eax, Operand(esp, 4)); // compare with 1st parameter.
|
||||
__ Check(Condition::not_equal, AbortReason::kNoReason);
|
||||
__ ret(0);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer);
|
||||
|
||||
f.Call(0);
|
||||
f.Call(18);
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason");
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
66
test/unittests/assembler/turbo-assembler-mips-unittest.cc
Normal file
66
test/unittests/assembler/turbo-assembler-mips-unittest.cc
Normal file
@ -0,0 +1,66 @@
|
||||
// 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/macro-assembler.h"
|
||||
#include "src/mips/assembler-mips-inl.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ tasm.
|
||||
|
||||
// Test the x64 assembler by compiling some simple functions into
|
||||
// a buffer and executing them. These tests do not initialize the
|
||||
// V8 library, create a context, or use any V8 objects.
|
||||
|
||||
class TurboAssemblerTest : public TestWithIsolate {};
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
|
||||
}
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter (in {a0}) is 17.
|
||||
__ Check(Condition::ne, AbortReason::kNoReason, a0, Operand(17));
|
||||
__ Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
|
||||
|
||||
f.Call(0);
|
||||
f.Call(18);
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason");
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
66
test/unittests/assembler/turbo-assembler-mips64-unittest.cc
Normal file
66
test/unittests/assembler/turbo-assembler-mips64-unittest.cc
Normal file
@ -0,0 +1,66 @@
|
||||
// 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/macro-assembler.h"
|
||||
#include "src/mips64/assembler-mips64-inl.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ tasm.
|
||||
|
||||
// Test the x64 assembler by compiling some simple functions into
|
||||
// a buffer and executing them. These tests do not initialize the
|
||||
// V8 library, create a context, or use any V8 objects.
|
||||
|
||||
class TurboAssemblerTest : public TestWithIsolate {};
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer);
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
|
||||
}
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter (in {a0}) is 17.
|
||||
__ Check(Condition::ne, AbortReason::kNoReason, a0, Operand(17));
|
||||
__ Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer);
|
||||
|
||||
f.Call(0);
|
||||
f.Call(18);
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason");
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
62
test/unittests/assembler/turbo-assembler-x64-unittest.cc
Normal file
62
test/unittests/assembler/turbo-assembler-x64-unittest.cc
Normal file
@ -0,0 +1,62 @@
|
||||
// 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/macro-assembler.h"
|
||||
#include "src/simulator.h"
|
||||
#include "test/common/assembler-tester.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ tasm.
|
||||
|
||||
// Test the x64 assembler by compiling some simple functions into
|
||||
// a buffer and executing them. These tests do not initialize the
|
||||
// V8 library, create a context, or use any V8 objects.
|
||||
|
||||
TEST(TurboAssemblerTest, TestHardAbort) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer);
|
||||
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason");
|
||||
}
|
||||
|
||||
TEST(TurboAssemblerTest, TestCheck) {
|
||||
size_t allocated;
|
||||
byte* buffer = AllocateAssemblerBuffer(&allocated);
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer,
|
||||
static_cast<int>(allocated), CodeObjectRequired::kNo);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter is 17.
|
||||
__ movl(rax, Immediate(17));
|
||||
__ cmpl(rax, arg_reg_1);
|
||||
__ Check(Condition::not_equal, AbortReason::kNoReason);
|
||||
__ ret(0);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
MakeAssemblerBufferExecutable(buffer, allocated);
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer);
|
||||
|
||||
f.Call(0);
|
||||
f.Call(18);
|
||||
ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason");
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -20,6 +20,7 @@ group("v8_run_gcmole") {
|
||||
"../../include/",
|
||||
"../../src/",
|
||||
"../../test/cctest/",
|
||||
"../../test/common/",
|
||||
"../../testing/gtest/include/gtest/gtest_prod.h",
|
||||
"../../third_party/googletest/src/googletest/include/gtest/gtest_prod.h",
|
||||
"../../third_party/icu/source/",
|
||||
|
Loading…
Reference in New Issue
Block a user