[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 VmovIndexLo = { 0 };
|
||||||
constexpr VmovIndex VmovIndexHi = { 1 };
|
constexpr VmovIndex VmovIndexHi = { 1 };
|
||||||
|
|
||||||
class Assembler : public AssemblerBase {
|
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||||
public:
|
public:
|
||||||
// Create an assembler. Instructions and relocation information are emitted
|
// Create an assembler. Instructions and relocation information are emitted
|
||||||
// into a buffer, with the instructions starting from the beginning and the
|
// into a buffer, with the instructions starting from the beginning and the
|
||||||
|
@ -1881,6 +1881,16 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
return;
|
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)));
|
Move(r1, Smi::FromInt(static_cast<int>(reason)));
|
||||||
|
|
||||||
// Disable stub call restrictions to always allow calls to abort.
|
// 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,
|
void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
|
||||||
int num_double_arguments) {
|
int num_double_arguments,
|
||||||
|
Register scratch) {
|
||||||
int frame_alignment = ActivationFrameAlignment();
|
int frame_alignment = ActivationFrameAlignment();
|
||||||
int stack_passed_arguments = CalculateStackPassedWords(
|
int stack_passed_arguments = CalculateStackPassedWords(
|
||||||
num_reg_arguments, num_double_arguments);
|
num_reg_arguments, num_double_arguments);
|
||||||
if (frame_alignment > kPointerSize) {
|
if (frame_alignment > kPointerSize) {
|
||||||
UseScratchRegisterScope temps(this);
|
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
|
// Make stack end at alignment and make room for num_arguments - 4 words
|
||||||
// and the original value of sp.
|
// and the original value of sp.
|
||||||
mov(scratch, sp);
|
mov(scratch, sp);
|
||||||
@ -2263,7 +2274,7 @@ void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
|
|||||||
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
|
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
|
||||||
and_(sp, sp, Operand(-frame_alignment));
|
and_(sp, sp, Operand(-frame_alignment));
|
||||||
str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
|
str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
|
||||||
} else {
|
} else if (stack_passed_arguments > 0) {
|
||||||
sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
|
sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ enum TargetAddressStorageMode {
|
|||||||
NEVER_INLINE_TARGET_ADDRESS
|
NEVER_INLINE_TARGET_ADDRESS
|
||||||
};
|
};
|
||||||
|
|
||||||
class TurboAssembler : public TurboAssemblerBase {
|
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||||
public:
|
public:
|
||||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||||
void* buffer, int buffer_size,
|
void* buffer, int buffer_size,
|
||||||
@ -259,8 +259,8 @@ class TurboAssembler : public TurboAssemblerBase {
|
|||||||
// C++ code.
|
// C++ code.
|
||||||
// Needs a scratch register to do some arithmetic. This register will be
|
// Needs a scratch register to do some arithmetic. This register will be
|
||||||
// trashed.
|
// trashed.
|
||||||
void PrepareCallCFunction(int num_reg_arguments,
|
void PrepareCallCFunction(int num_reg_arguments, int num_double_registers = 0,
|
||||||
int num_double_registers = 0);
|
Register scratch = no_reg);
|
||||||
|
|
||||||
// Removes current frame and its arguments from the stack preserving
|
// Removes current frame and its arguments from the stack preserving
|
||||||
// the arguments and a return address pushed to the stack for the next call.
|
// the arguments and a return address pushed to the stack for the next call.
|
||||||
|
@ -882,7 +882,7 @@ class ConstPool {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Assembler.
|
// Assembler.
|
||||||
|
|
||||||
class Assembler : public AssemblerBase {
|
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||||
public:
|
public:
|
||||||
// Create an assembler. Instructions and relocation information are emitted
|
// Create an assembler. Instructions and relocation information are emitted
|
||||||
// into a buffer, with the instructions starting from the beginning and the
|
// 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) {
|
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
|
// Save all kCallerSaved registers (including lr), since this can be called
|
||||||
// from anywhere.
|
// from anywhere.
|
||||||
|
@ -1429,7 +1429,7 @@ void MacroAssembler::PopCalleeSavedRegisters() {
|
|||||||
|
|
||||||
void TurboAssembler::AssertSpAligned() {
|
void TurboAssembler::AssertSpAligned() {
|
||||||
if (emit_debug_code()) {
|
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
|
// Arm64 requires the stack pointer to be 16-byte aligned prior to address
|
||||||
// calculation.
|
// calculation.
|
||||||
UseScratchRegisterScope scope(this);
|
UseScratchRegisterScope scope(this);
|
||||||
@ -2998,38 +2998,26 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
RegList old_tmp_list = TmpList()->list();
|
RegList old_tmp_list = TmpList()->list();
|
||||||
TmpList()->Combine(MacroAssembler::DefaultTmpList());
|
TmpList()->Combine(MacroAssembler::DefaultTmpList());
|
||||||
|
|
||||||
if (use_real_aborts()) {
|
if (should_abort_hard()) {
|
||||||
// Avoid infinite recursion; Push contains some assertions that use Abort.
|
// We don't care if we constructed a frame. Just pretend we did.
|
||||||
NoUseRealAbortsScope no_real_aborts(this);
|
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_) {
|
Move(x1, Smi::FromInt(static_cast<int>(reason)));
|
||||||
// We don't actually want to generate a pile of code for this, so just
|
|
||||||
// claim there is a stack frame, without generating one.
|
if (!has_frame_) {
|
||||||
FrameScope scope(this, StackFrame::NONE);
|
// We don't actually want to generate a pile of code for this, so just
|
||||||
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
// claim there is a stack frame, without generating one.
|
||||||
} else {
|
FrameScope scope(this, StackFrame::NONE);
|
||||||
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Load the string to pass to Printf.
|
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TmpList()->set_list(old_tmp_list);
|
TmpList()->set_list(old_tmp_list);
|
||||||
|
@ -177,7 +177,7 @@ enum PreShiftImmMode {
|
|||||||
kAnyShift // Allow any pre-shift.
|
kAnyShift // Allow any pre-shift.
|
||||||
};
|
};
|
||||||
|
|
||||||
class TurboAssembler : public TurboAssemblerBase {
|
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||||
public:
|
public:
|
||||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||||
void* buffer, int buffer_size,
|
void* buffer, int buffer_size,
|
||||||
@ -185,27 +185,6 @@ class TurboAssembler : public TurboAssemblerBase {
|
|||||||
: TurboAssemblerBase(isolate, options, buffer, buffer_size,
|
: TurboAssemblerBase(isolate, options, buffer, buffer_size,
|
||||||
create_code_object) {}
|
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
|
#if DEBUG
|
||||||
void set_allow_macro_instructions(bool value) {
|
void set_allow_macro_instructions(bool value) {
|
||||||
allow_macro_instructions_ = value;
|
allow_macro_instructions_ = value;
|
||||||
@ -1267,8 +1246,6 @@ class TurboAssembler : public TurboAssemblerBase {
|
|||||||
CPURegList tmp_list_ = DefaultTmpList();
|
CPURegList tmp_list_ = DefaultTmpList();
|
||||||
CPURegList fptmp_list_ = DefaultFPTmpList();
|
CPURegList fptmp_list_ = DefaultFPTmpList();
|
||||||
|
|
||||||
bool use_real_aborts_ = true;
|
|
||||||
|
|
||||||
// Helps resolve branching to labels potentially out of range.
|
// Helps resolve branching to labels potentially out of range.
|
||||||
// If the label is not bound, it registers the information necessary to later
|
// If the label is not bound, it registers the information necessary to later
|
||||||
// be able to emit a veneer for this branch if necessary.
|
// 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);
|
Isolate* isolate, bool explicitly_support_serialization = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AssemblerBase : public Malloced {
|
class V8_EXPORT_PRIVATE AssemblerBase : public Malloced {
|
||||||
public:
|
public:
|
||||||
AssemblerBase(const AssemblerOptions& options, void* buffer, int buffer_size);
|
AssemblerBase(const AssemblerOptions& options, void* buffer, int buffer_size);
|
||||||
virtual ~AssemblerBase();
|
virtual ~AssemblerBase();
|
||||||
|
@ -26,6 +26,11 @@ const char* GetAbortReason(AbortReason reason) {
|
|||||||
return error_messages_[static_cast<int>(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
|
#undef ERROR_MESSAGES_TEXTS
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -125,6 +125,7 @@ enum class AbortReason {
|
|||||||
|
|
||||||
const char* GetBailoutReason(BailoutReason reason);
|
const char* GetBailoutReason(BailoutReason reason);
|
||||||
const char* GetAbortReason(AbortReason reason);
|
const char* GetAbortReason(AbortReason reason);
|
||||||
|
bool IsValidAbortReason(int reason_id);
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -2218,7 +2218,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
|||||||
// Convert to Smi for the runtime call.
|
// Convert to Smi for the runtime call.
|
||||||
__ SmiTag(r4, r4);
|
__ 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);
|
FrameAndConstantPoolScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// 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) {
|
void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
||||||
Label negate, done;
|
Label negate, done;
|
||||||
|
|
||||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||||
UseScratchRegisterScope temps(masm);
|
UseScratchRegisterScope temps(masm);
|
||||||
Register result_reg = r7;
|
Register result_reg = r7;
|
||||||
Register double_low = GetRegisterThatIsNotOneOf(result_reg);
|
Register double_low = GetRegisterThatIsNotOneOf(result_reg);
|
||||||
|
@ -2676,7 +2676,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
|||||||
__ sxtw(x8, w8);
|
__ sxtw(x8, w8);
|
||||||
__ SmiTag(x8, x8);
|
__ 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);
|
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// 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.
|
// fall-back Abort mechanism.
|
||||||
//
|
//
|
||||||
// Note that this stub must be generated before any use of Abort.
|
// 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");
|
ASM_LOCATION("CEntry::Generate entry");
|
||||||
ProfileEntryHookStub::MaybeCallEntryHook(masm);
|
ProfileEntryHookStub::MaybeCallEntryHook(masm);
|
||||||
@ -2938,7 +2938,7 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
|
|||||||
|
|
||||||
DCHECK(result.Is64Bits());
|
DCHECK(result.Is64Bits());
|
||||||
|
|
||||||
TrapOnAbortScope trap_on_abort_scope(masm); // Avoid calls to Abort.
|
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
|
||||||
UseScratchRegisterScope temps(masm);
|
UseScratchRegisterScope temps(masm);
|
||||||
Register scratch1 = temps.AcquireX();
|
Register scratch1 = temps.AcquireX();
|
||||||
Register scratch2 = temps.AcquireX();
|
Register scratch2 = temps.AcquireX();
|
||||||
|
@ -2384,7 +2384,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
|||||||
// Convert to Smi for the runtime call.
|
// Convert to Smi for the runtime call.
|
||||||
__ SmiTag(edi);
|
__ 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);
|
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// 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.
|
// Convert to Smi for the runtime call.
|
||||||
__ SmiTag(t0);
|
__ 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);
|
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// 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
|
// Convert to Smi for the runtime call
|
||||||
__ SmiTag(t0);
|
__ 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);
|
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// 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.
|
// Convert to Smi for the runtime call.
|
||||||
__ SmiTag(r15, r15);
|
__ 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);
|
FrameAndConstantPoolScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// 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;
|
Label out_of_range, only_low, negate, done, fastpath_done;
|
||||||
Register result_reg = r3;
|
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.
|
// Immediate values for this stub fit in instructions, so it's safe to use ip.
|
||||||
Register scratch = GetRegisterThatIsNotOneOf(result_reg);
|
Register scratch = GetRegisterThatIsNotOneOf(result_reg);
|
||||||
|
@ -2305,7 +2305,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
|||||||
// Convert to Smi for the runtime call.
|
// Convert to Smi for the runtime call.
|
||||||
__ SmiTag(r7, r7);
|
__ 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);
|
FrameAndConstantPoolScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// 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;
|
Label out_of_range, only_low, negate, done, fastpath_done;
|
||||||
Register result_reg = r2;
|
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.
|
// Immediate values for this stub fit in instructions, so it's safe to use ip.
|
||||||
Register scratch = GetRegisterThatIsNotOneOf(result_reg);
|
Register scratch = GetRegisterThatIsNotOneOf(result_reg);
|
||||||
|
@ -2339,7 +2339,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
|
|||||||
// Convert to Smi for the runtime call.
|
// Convert to Smi for the runtime call.
|
||||||
__ SmiTag(r11, r11);
|
__ 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);
|
FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY);
|
||||||
|
|
||||||
// Save all parameter registers (see wasm-linkage.cc). They might be
|
// Save all parameter registers (see wasm-linkage.cc). They might be
|
||||||
|
@ -90,7 +90,7 @@ CodeGenerator::CodeGenerator(
|
|||||||
if (code_kind == Code::WASM_FUNCTION ||
|
if (code_kind == Code::WASM_FUNCTION ||
|
||||||
code_kind == Code::WASM_TO_JS_FUNCTION ||
|
code_kind == Code::WASM_TO_JS_FUNCTION ||
|
||||||
code_kind == Code::WASM_INTERPRETER_ENTRY) {
|
code_kind == Code::WASM_INTERPRETER_ENTRY) {
|
||||||
tasm_.set_trap_on_abort(true);
|
tasm_.set_abort_hard(true);
|
||||||
}
|
}
|
||||||
tasm_.set_builtin_index(builtin_index);
|
tasm_.set_builtin_index(builtin_index);
|
||||||
}
|
}
|
||||||
|
@ -459,6 +459,10 @@ ExternalReference ExternalReference::address_of_pending_message_obj(
|
|||||||
return ExternalReference(isolate->pending_message_obj_address());
|
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() {
|
ExternalReference ExternalReference::address_of_min_int() {
|
||||||
return ExternalReference(reinterpret_cast<Address>(&double_min_int_constant));
|
return ExternalReference(reinterpret_cast<Address>(&double_min_int_constant));
|
||||||
}
|
}
|
||||||
@ -951,5 +955,16 @@ std::ostream& operator<<(std::ostream& os, ExternalReference reference) {
|
|||||||
return os;
|
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 internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -71,6 +71,7 @@ class StatsCounter;
|
|||||||
EXTERNAL_REFERENCE_LIST_NON_INTERPRETED_REGEXP(V)
|
EXTERNAL_REFERENCE_LIST_NON_INTERPRETED_REGEXP(V)
|
||||||
|
|
||||||
#define EXTERNAL_REFERENCE_LIST(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_abs_constant, "double_absolute_constant") \
|
||||||
V(address_of_double_neg_constant, "double_negate_constant") \
|
V(address_of_double_neg_constant, "double_negate_constant") \
|
||||||
V(address_of_float_abs_constant, "float_absolute_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);
|
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, ExternalReference);
|
||||||
|
|
||||||
|
void abort_with_reason(int reason);
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
|
||||||
|
@ -321,7 +321,7 @@ enum ScaleFactor {
|
|||||||
times_twice_pointer_size = times_8
|
times_twice_pointer_size = times_8
|
||||||
};
|
};
|
||||||
|
|
||||||
class Operand {
|
class V8_EXPORT_PRIVATE Operand {
|
||||||
public:
|
public:
|
||||||
// reg
|
// reg
|
||||||
V8_INLINE explicit Operand(Register reg) { set_modrm(3, 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);
|
void init(Label* L, Type type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||||
class Assembler : public AssemblerBase {
|
|
||||||
private:
|
private:
|
||||||
// We check before assembling an instruction that there is sufficient
|
// We check before assembling an instruction that there is sufficient
|
||||||
// space to write an instruction and its relocation information.
|
// space to write an instruction and its relocation information.
|
||||||
|
@ -1591,6 +1591,15 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
return;
|
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)));
|
Move(edx, Smi::FromInt(static_cast<int>(reason)));
|
||||||
|
|
||||||
// Disable stub call restrictions to always allow calls to abort.
|
// 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);
|
Register reg8 = no_reg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class TurboAssembler : public TurboAssemblerBase {
|
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||||
public:
|
public:
|
||||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||||
void* buffer, int buffer_size,
|
void* buffer, int buffer_size,
|
||||||
|
@ -4695,6 +4695,15 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
return;
|
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)));
|
Move(a0, Smi::FromInt(static_cast<int>(reason)));
|
||||||
|
|
||||||
// Disable stub call restrictions to always allow calls to abort.
|
// Disable stub call restrictions to always allow calls to abort.
|
||||||
|
@ -5024,6 +5024,15 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
return;
|
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)));
|
Move(a0, Smi::FromInt(static_cast<int>(reason)));
|
||||||
|
|
||||||
// Disable stub call restrictions to always allow calls to abort.
|
// Disable stub call restrictions to always allow calls to abort.
|
||||||
|
@ -1757,7 +1757,9 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Avoid emitting call to builtin if requested.
|
// 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);
|
stop(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1688,7 +1688,9 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Avoid emitting call to builtin if requested.
|
// 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);
|
stop(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace internal {
|
|||||||
|
|
||||||
// Common base class for platform-specific TurboAssemblers containing
|
// Common base class for platform-specific TurboAssemblers containing
|
||||||
// platform-independent bits.
|
// platform-independent bits.
|
||||||
class TurboAssemblerBase : public Assembler {
|
class V8_EXPORT_PRIVATE TurboAssemblerBase : public Assembler {
|
||||||
public:
|
public:
|
||||||
Isolate* isolate() const { return isolate_; }
|
Isolate* isolate() const { return isolate_; }
|
||||||
|
|
||||||
@ -26,7 +26,9 @@ class TurboAssemblerBase : public Assembler {
|
|||||||
void set_root_array_available(bool v) { root_array_available_ = v; }
|
void set_root_array_available(bool v) { root_array_available_ = v; }
|
||||||
|
|
||||||
bool trap_on_abort() const { return trap_on_abort_; }
|
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; }
|
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.
|
// Immediately trap instead of calling {Abort} when debug code fails.
|
||||||
bool trap_on_abort_ = FLAG_trap_on_abort;
|
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.
|
// May be set while generating builtins.
|
||||||
int maybe_builtin_index_ = Builtins::kNoBuiltinId;
|
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
|
// Avoids emitting calls to the {Builtins::kAbort} builtin when emitting debug
|
||||||
// code during the lifetime of this scope object. For disabling debug code
|
// code during the lifetime of this scope object. For disabling debug code
|
||||||
// entirely use the {DontEmitDebugCodeScope} instead.
|
// entirely use the {DontEmitDebugCodeScope} instead.
|
||||||
class TrapOnAbortScope BASE_EMBEDDED {
|
class HardAbortScope BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
explicit TrapOnAbortScope(TurboAssemblerBase* assembler)
|
explicit HardAbortScope(TurboAssemblerBase* assembler)
|
||||||
: assembler_(assembler), old_value_(assembler->trap_on_abort()) {
|
: assembler_(assembler), old_value_(assembler->should_abort_hard()) {
|
||||||
assembler_->set_trap_on_abort(true);
|
assembler_->set_abort_hard(true);
|
||||||
}
|
}
|
||||||
~TrapOnAbortScope() { assembler_->set_trap_on_abort(old_value_); }
|
~HardAbortScope() { assembler_->set_abort_hard(old_value_); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TurboAssemblerBase* assembler_;
|
TurboAssemblerBase* assembler_;
|
||||||
|
@ -349,7 +349,7 @@ constexpr AssemblerOptions DefaultLiftoffOptions() {
|
|||||||
LiftoffAssembler::LiftoffAssembler()
|
LiftoffAssembler::LiftoffAssembler()
|
||||||
: TurboAssembler(nullptr, DefaultLiftoffOptions(), nullptr, 0,
|
: TurboAssembler(nullptr, DefaultLiftoffOptions(), nullptr, 0,
|
||||||
CodeObjectRequired::kNo) {
|
CodeObjectRequired::kNo) {
|
||||||
set_trap_on_abort(true); // Avoid calls to Abort.
|
set_abort_hard(true); // Avoid calls to Abort.
|
||||||
}
|
}
|
||||||
|
|
||||||
LiftoffAssembler::~LiftoffAssembler() {
|
LiftoffAssembler::~LiftoffAssembler() {
|
||||||
|
@ -1380,14 +1380,8 @@ void LiftoffAssembler::CallC(wasm::FunctionSig* sig,
|
|||||||
}
|
}
|
||||||
DCHECK_LE(arg_bytes, stack_bytes);
|
DCHECK_LE(arg_bytes, stack_bytes);
|
||||||
|
|
||||||
// Pass a pointer to the buffer with the arguments to the C function.
|
// 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}.
|
movp(arg_reg_1, rsp);
|
||||||
#ifdef _WIN64
|
|
||||||
constexpr Register kFirstArgReg = rcx;
|
|
||||||
#else
|
|
||||||
constexpr Register kFirstArgReg = rdi;
|
|
||||||
#endif
|
|
||||||
movp(kFirstArgReg, rsp);
|
|
||||||
|
|
||||||
constexpr int kNumCCallArgs = 1;
|
constexpr int kNumCCallArgs = 1;
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ static_assert(sizeof(Operand) <= 2 * kPointerSize,
|
|||||||
V(shr, 0x5) \
|
V(shr, 0x5) \
|
||||||
V(sar, 0x7)
|
V(sar, 0x7)
|
||||||
|
|
||||||
class Assembler : public AssemblerBase {
|
class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||||
private:
|
private:
|
||||||
// We check before assembling an instruction that there is sufficient
|
// We check before assembling an instruction that there is sufficient
|
||||||
// space to write an instruction and its relocation information.
|
// space to write an instruction and its relocation information.
|
||||||
|
@ -427,6 +427,16 @@ void TurboAssembler::Abort(AbortReason reason) {
|
|||||||
return;
|
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)));
|
Move(rdx, Smi::FromInt(static_cast<int>(reason)));
|
||||||
|
|
||||||
if (!has_frame()) {
|
if (!has_frame()) {
|
||||||
|
@ -125,7 +125,7 @@ class StackArgumentsAccessor BASE_EMBEDDED {
|
|||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TurboAssembler : public TurboAssemblerBase {
|
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||||
public:
|
public:
|
||||||
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
TurboAssembler(Isolate* isolate, const AssemblerOptions& options,
|
||||||
void* buffer, int buffer_size,
|
void* buffer, int buffer_size,
|
||||||
|
@ -50,9 +50,10 @@ v8_source_set("cctest_sources") {
|
|||||||
"$target_gen_dir/resources.cc",
|
"$target_gen_dir/resources.cc",
|
||||||
|
|
||||||
### gcmole(all) ###
|
### gcmole(all) ###
|
||||||
"../../test/common/wasm/flag-utils.h",
|
"../common/assembler-tester.h",
|
||||||
"../../test/common/wasm/test-signatures.h",
|
"../common/wasm/flag-utils.h",
|
||||||
"../../test/common/wasm/wasm-macro-gen.h",
|
"../common/wasm/test-signatures.h",
|
||||||
|
"../common/wasm/wasm-macro-gen.h",
|
||||||
"cctest.cc",
|
"cctest.cc",
|
||||||
"cctest.h",
|
"cctest.h",
|
||||||
"compiler/c-signature.h",
|
"compiler/c-signature.h",
|
||||||
|
@ -548,32 +548,6 @@ static inline void CheckDoubleEquals(double expected, double actual) {
|
|||||||
CHECK_GE(expected, actual - kEpsilon);
|
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 v8::debug::DebugDelegate dummy_delegate;
|
||||||
|
|
||||||
static inline void EnableDebugger(v8::Isolate* isolate) {
|
static inline void EnableDebugger(v8::Isolate* isolate) {
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "src/macro-assembler.h"
|
#include "src/macro-assembler.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
#include "test/cctest/test-utils-arm64.h"
|
#include "test/cctest/test-utils-arm64.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "src/ostreams.h"
|
#include "src/ostreams.h"
|
||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "src/v8.h"
|
#include "src/v8.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
#include "test/cctest/test-code-stubs.h"
|
#include "test/cctest/test-code-stubs.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
#include "test/cctest/test-code-stubs.h"
|
#include "test/cctest/test-code-stubs.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "src/objects-inl.h"
|
#include "src/objects-inl.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
#include "test/cctest/test-code-stubs.h"
|
#include "test/cctest/test-code-stubs.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
#include "test/cctest/test-code-stubs.h"
|
#include "test/cctest/test-code-stubs.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
#include "test/cctest/test-code-stubs.h"
|
#include "test/cctest/test-code-stubs.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "src/register-configuration.h"
|
#include "src/register-configuration.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
#include "test/cctest/test-code-stubs.h"
|
#include "test/cctest/test-code-stubs.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "src/snapshot/macros.h"
|
#include "src/snapshot/macros.h"
|
||||||
#include "src/snapshot/snapshot.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
|
// To generate the binary files for the test function, enable this section and
|
||||||
// run GenerateTestFunctionData once on each arch.
|
// run GenerateTestFunctionData once on each arch.
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "src/v8.h"
|
#include "src/v8.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "src/objects-inl.h"
|
#include "src/objects-inl.h"
|
||||||
#include "src/simulator.h"
|
#include "src/simulator.h"
|
||||||
#include "test/cctest/cctest.h"
|
#include "test/cctest/cctest.h"
|
||||||
|
#include "test/common/assembler-tester.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
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
|
testonly = true
|
||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
|
"../../test/common/assembler-tester.h",
|
||||||
"../../test/common/wasm/wasm-macro-gen.h",
|
"../../test/common/wasm/wasm-macro-gen.h",
|
||||||
"../../testing/gmock-support.h",
|
"../../testing/gmock-support.h",
|
||||||
"../../testing/gtest-support.h",
|
"../../testing/gtest-support.h",
|
||||||
@ -222,17 +223,35 @@ v8_source_set("unittests_sources") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (v8_current_cpu == "arm") {
|
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") {
|
} 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") {
|
} 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") {
|
} 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") {
|
} 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") {
|
} 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") {
|
} else if (v8_current_cpu == "ppc" || v8_current_cpu == "ppc64") {
|
||||||
sources += [ "compiler/ppc/instruction-selector-ppc-unittest.cc" ]
|
sources += [ "compiler/ppc/instruction-selector-ppc-unittest.cc" ]
|
||||||
} else if (v8_current_cpu == "s390" || v8_current_cpu == "s390x") {
|
} 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/",
|
"../../include/",
|
||||||
"../../src/",
|
"../../src/",
|
||||||
"../../test/cctest/",
|
"../../test/cctest/",
|
||||||
|
"../../test/common/",
|
||||||
"../../testing/gtest/include/gtest/gtest_prod.h",
|
"../../testing/gtest/include/gtest/gtest_prod.h",
|
||||||
"../../third_party/googletest/src/googletest/include/gtest/gtest_prod.h",
|
"../../third_party/googletest/src/googletest/include/gtest/gtest_prod.h",
|
||||||
"../../third_party/icu/source/",
|
"../../third_party/icu/source/",
|
||||||
|
Loading…
Reference in New Issue
Block a user