From a462a7854a081f4f34bb4c112ee33f3d69efa309 Mon Sep 17 00:00:00 2001 From: Clemens Hammacher Date: Fri, 20 Jul 2018 16:00:30 +0200 Subject: [PATCH] [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 Reviewed-by: Michael Starzinger Cr-Commit-Position: refs/heads/master@{#54592} --- src/arm/assembler-arm.h | 2 +- src/arm/macro-assembler-arm.cc | 17 ++++- src/arm/macro-assembler-arm.h | 6 +- src/arm64/assembler-arm64.h | 2 +- src/arm64/code-stubs-arm64.cc | 2 +- src/arm64/macro-assembler-arm64.cc | 48 +++++-------- src/arm64/macro-assembler-arm64.h | 25 +------ src/assembler.h | 2 +- src/bailout-reason.cc | 5 ++ src/bailout-reason.h | 1 + src/builtins/arm/builtins-arm.cc | 4 +- src/builtins/arm64/builtins-arm64.cc | 6 +- src/builtins/ia32/builtins-ia32.cc | 2 +- src/builtins/mips/builtins-mips.cc | 2 +- src/builtins/mips64/builtins-mips64.cc | 2 +- src/builtins/ppc/builtins-ppc.cc | 4 +- src/builtins/s390/builtins-s390.cc | 4 +- src/builtins/x64/builtins-x64.cc | 2 +- src/compiler/code-generator.cc | 2 +- src/external-reference.cc | 15 ++++ src/external-reference.h | 3 + src/ia32/assembler-ia32.h | 5 +- src/ia32/macro-assembler-ia32.cc | 9 +++ src/ia32/macro-assembler-ia32.h | 2 +- src/mips/macro-assembler-mips.cc | 9 +++ src/mips64/macro-assembler-mips64.cc | 9 +++ src/ppc/macro-assembler-ppc.cc | 4 +- src/s390/macro-assembler-s390.cc | 4 +- src/turbo-assembler.h | 19 ++++-- src/wasm/baseline/liftoff-assembler.cc | 2 +- src/wasm/baseline/x64/liftoff-assembler-x64.h | 10 +-- src/x64/assembler-x64.h | 2 +- src/x64/macro-assembler-x64.cc | 10 +++ src/x64/macro-assembler-x64.h | 2 +- test/cctest/BUILD.gn | 7 +- test/cctest/cctest.h | 26 ------- test/cctest/test-assembler-arm64.cc | 1 + test/cctest/test-assembler-x64.cc | 1 + test/cctest/test-code-stubs-arm.cc | 1 + test/cctest/test-code-stubs-arm64.cc | 1 + test/cctest/test-code-stubs-ia32.cc | 1 + test/cctest/test-code-stubs-mips.cc | 1 + test/cctest/test-code-stubs-mips64.cc | 1 + test/cctest/test-code-stubs-x64.cc | 1 + .../test-isolate-independent-builtins.cc | 1 + test/cctest/test-macro-assembler-arm.cc | 1 + test/cctest/test-macro-assembler-x64.cc | 1 + test/common/assembler-tester.h | 42 ++++++++++++ test/unittests/BUILD.gn | 31 +++++++-- .../assembler/turbo-assembler-arm-unittest.cc | 68 +++++++++++++++++++ .../turbo-assembler-arm64-unittest.cc | 68 +++++++++++++++++++ .../turbo-assembler-ia32-unittest.cc | 62 +++++++++++++++++ .../turbo-assembler-mips-unittest.cc | 66 ++++++++++++++++++ .../turbo-assembler-mips64-unittest.cc | 66 ++++++++++++++++++ .../assembler/turbo-assembler-x64-unittest.cc | 62 +++++++++++++++++ tools/gcmole/BUILD.gn | 1 + 56 files changed, 616 insertions(+), 137 deletions(-) create mode 100644 test/common/assembler-tester.h create mode 100644 test/unittests/assembler/turbo-assembler-arm-unittest.cc create mode 100644 test/unittests/assembler/turbo-assembler-arm64-unittest.cc create mode 100644 test/unittests/assembler/turbo-assembler-ia32-unittest.cc create mode 100644 test/unittests/assembler/turbo-assembler-mips-unittest.cc create mode 100644 test/unittests/assembler/turbo-assembler-mips64-unittest.cc create mode 100644 test/unittests/assembler/turbo-assembler-x64-unittest.cc diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 2e71ce59e6..a45dde18e4 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -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 diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 503b2cf62d..9ade33cbd6 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -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(reason))); + PrepareCallCFunction(0, 0, r1); + Move(r1, ExternalReference::abort_with_reason()); + Call(r1); + return; + } + Move(r1, Smi::FromInt(static_cast(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)); } } diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 47a717d72a..202f70bddc 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -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. diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h index 70ee5350f8..66afe970e9 100644 --- a/src/arm64/assembler-arm64.h +++ b/src/arm64/assembler-arm64.h @@ -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 diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index 7a5f06c492..d63ce36925 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc @@ -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. diff --git a/src/arm64/macro-assembler-arm64.cc b/src/arm64/macro-assembler-arm64.cc index 3123e1bad7..6b27affb89 100644 --- a/src/arm64/macro-assembler-arm64.cc +++ b/src/arm64/macro-assembler-arm64.cc @@ -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(reason)); + Call(ExternalReference::abort_with_reason()); + return; + } - Move(x1, Smi::FromInt(static_cast(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(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); diff --git a/src/arm64/macro-assembler-arm64.h b/src/arm64/macro-assembler-arm64.h index 930212d56f..866fc455ee 100644 --- a/src/arm64/macro-assembler-arm64.h +++ b/src/arm64/macro-assembler-arm64.h @@ -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. diff --git a/src/assembler.h b/src/assembler.h index 92a6987d8d..920b0dd064 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -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(); diff --git a/src/bailout-reason.cc b/src/bailout-reason.cc index 7cf983861c..54b3dbda54 100644 --- a/src/bailout-reason.cc +++ b/src/bailout-reason.cc @@ -26,6 +26,11 @@ const char* GetAbortReason(AbortReason reason) { return error_messages_[static_cast(reason)]; } +bool IsValidAbortReason(int reason_id) { + return reason_id >= static_cast(AbortReason::kNoReason) && + reason_id < static_cast(AbortReason::kLastErrorMessage); +} + #undef ERROR_MESSAGES_TEXTS } // namespace internal } // namespace v8 diff --git a/src/bailout-reason.h b/src/bailout-reason.h index d48d696022..24ce3a1ea4 100644 --- a/src/bailout-reason.h +++ b/src/bailout-reason.h @@ -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 diff --git a/src/builtins/arm/builtins-arm.cc b/src/builtins/arm/builtins-arm.cc index 624971e325..cad7252704 100644 --- a/src/builtins/arm/builtins-arm.cc +++ b/src/builtins/arm/builtins-arm.cc @@ -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); diff --git a/src/builtins/arm64/builtins-arm64.cc b/src/builtins/arm64/builtins-arm64.cc index 0b97142491..fd272d4581 100644 --- a/src/builtins/arm64/builtins-arm64.cc +++ b/src/builtins/arm64/builtins-arm64.cc @@ -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(); diff --git a/src/builtins/ia32/builtins-ia32.cc b/src/builtins/ia32/builtins-ia32.cc index 110abcbd9f..7830381028 100644 --- a/src/builtins/ia32/builtins-ia32.cc +++ b/src/builtins/ia32/builtins-ia32.cc @@ -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 diff --git a/src/builtins/mips/builtins-mips.cc b/src/builtins/mips/builtins-mips.cc index d32c4204cc..d046d75299 100644 --- a/src/builtins/mips/builtins-mips.cc +++ b/src/builtins/mips/builtins-mips.cc @@ -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 diff --git a/src/builtins/mips64/builtins-mips64.cc b/src/builtins/mips64/builtins-mips64.cc index 6e14547bcc..d27624e202 100644 --- a/src/builtins/mips64/builtins-mips64.cc +++ b/src/builtins/mips64/builtins-mips64.cc @@ -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 diff --git a/src/builtins/ppc/builtins-ppc.cc b/src/builtins/ppc/builtins-ppc.cc index c955a325d6..38d248a1a7 100644 --- a/src/builtins/ppc/builtins-ppc.cc +++ b/src/builtins/ppc/builtins-ppc.cc @@ -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); diff --git a/src/builtins/s390/builtins-s390.cc b/src/builtins/s390/builtins-s390.cc index 7788968182..d11e13ad41 100644 --- a/src/builtins/s390/builtins-s390.cc +++ b/src/builtins/s390/builtins-s390.cc @@ -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); diff --git a/src/builtins/x64/builtins-x64.cc b/src/builtins/x64/builtins-x64.cc index f4ba9e044e..48c5f46d07 100644 --- a/src/builtins/x64/builtins-x64.cc +++ b/src/builtins/x64/builtins-x64.cc @@ -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 diff --git a/src/compiler/code-generator.cc b/src/compiler/code-generator.cc index 6a7d0985f4..0d59fb59da 100644 --- a/src/compiler/code-generator.cc +++ b/src/compiler/code-generator.cc @@ -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); } diff --git a/src/external-reference.cc b/src/external-reference.cc index e4dc132fbb..63dcd2c025 100644 --- a/src/external-reference.cc +++ b/src/external-reference.cc @@ -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
(&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(reason)); + base::OS::PrintError("abort: %s\n", message); + } else { + base::OS::PrintError("abort: \n", reason); + } + base::OS::Abort(); + UNREACHABLE(); +} + } // namespace internal } // namespace v8 diff --git a/src/external-reference.h b/src/external-reference.h index c0d9cfbeea..83745199eb 100644 --- a/src/external-reference.h +++ b/src/external-reference.h @@ -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 diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index 7da22192c6..070dde69aa 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -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. diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 72fc778966..dd52bd1235 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -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(reason))); + CallCFunction(ExternalReference::abort_with_reason(), 1); + return; + } + Move(edx, Smi::FromInt(static_cast(reason))); // Disable stub call restrictions to always allow calls to abort. diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index 5d2b9bb0af..a7f39971c6 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -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, diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index 64a80dbef8..69e4b164fa 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -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(reason))); + CallCFunction(ExternalReference::abort_with_reason(), 1); + return; + } + Move(a0, Smi::FromInt(static_cast(reason))); // Disable stub call restrictions to always allow calls to abort. diff --git a/src/mips64/macro-assembler-mips64.cc b/src/mips64/macro-assembler-mips64.cc index 6e78411673..57e28f25cb 100644 --- a/src/mips64/macro-assembler-mips64.cc +++ b/src/mips64/macro-assembler-mips64.cc @@ -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(reason))); + CallCFunction(ExternalReference::abort_with_reason(), 1); + return; + } + Move(a0, Smi::FromInt(static_cast(reason))); // Disable stub call restrictions to always allow calls to abort. diff --git a/src/ppc/macro-assembler-ppc.cc b/src/ppc/macro-assembler-ppc.cc index 05bb2621ff..83017f8940 100644 --- a/src/ppc/macro-assembler-ppc.cc +++ b/src/ppc/macro-assembler-ppc.cc @@ -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; } diff --git a/src/s390/macro-assembler-s390.cc b/src/s390/macro-assembler-s390.cc index 161a0a31ca..912af492b0 100644 --- a/src/s390/macro-assembler-s390.cc +++ b/src/s390/macro-assembler-s390.cc @@ -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; } diff --git a/src/turbo-assembler.h b/src/turbo-assembler.h index 67f895b1ca..67932fba9a 100644 --- a/src/turbo-assembler.h +++ b/src/turbo-assembler.h @@ -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_; diff --git a/src/wasm/baseline/liftoff-assembler.cc b/src/wasm/baseline/liftoff-assembler.cc index 0e913c19dc..cf12165de2 100644 --- a/src/wasm/baseline/liftoff-assembler.cc +++ b/src/wasm/baseline/liftoff-assembler.cc @@ -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() { diff --git a/src/wasm/baseline/x64/liftoff-assembler-x64.h b/src/wasm/baseline/x64/liftoff-assembler-x64.h index b8d08c56aa..5ac43a1adb 100644 --- a/src/wasm/baseline/x64/liftoff-assembler-x64.h +++ b/src/wasm/baseline/x64/liftoff-assembler-x64.h @@ -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; diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index aeff5ee06d..3ac0ee3226 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -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. diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 838b81efed..174bf9e191 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -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(reason))); + PrepareCallCFunction(1); + LoadAddress(rax, ExternalReference::abort_with_reason()); + call(rax); + return; + } + Move(rdx, Smi::FromInt(static_cast(reason))); if (!has_frame()) { diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index c4b4da78d7..d7a0f06bfa 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -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, diff --git a/test/cctest/BUILD.gn b/test/cctest/BUILD.gn index 9072d6bed7..cb0b1351ff 100644 --- a/test/cctest/BUILD.gn +++ b/test/cctest/BUILD.gn @@ -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", diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h index 8bae124ea1..6c1303f982 100644 --- a/test/cctest/cctest.h +++ b/test/cctest/cctest.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(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) { diff --git a/test/cctest/test-assembler-arm64.cc b/test/cctest/test-assembler-arm64.cc index c9a13c0b1c..7b439417b5 100644 --- a/test/cctest/test-assembler-arm64.cc +++ b/test/cctest/test-assembler-arm64.cc @@ -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 { diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc index eb172ee2aa..7ecef4429c 100644 --- a/test/cctest/test-assembler-x64.cc +++ b/test/cctest/test-assembler-x64.cc @@ -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 { diff --git a/test/cctest/test-code-stubs-arm.cc b/test/cctest/test-code-stubs-arm.cc index 8247afeb49..d54b051ef6 100644 --- a/test/cctest/test-code-stubs-arm.cc +++ b/test/cctest/test-code-stubs-arm.cc @@ -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 { diff --git a/test/cctest/test-code-stubs-arm64.cc b/test/cctest/test-code-stubs-arm64.cc index 43bea1d910..60446de2ed 100644 --- a/test/cctest/test-code-stubs-arm64.cc +++ b/test/cctest/test-code-stubs-arm64.cc @@ -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 { diff --git a/test/cctest/test-code-stubs-ia32.cc b/test/cctest/test-code-stubs-ia32.cc index 77a2254245..54f53e57c3 100644 --- a/test/cctest/test-code-stubs-ia32.cc +++ b/test/cctest/test-code-stubs-ia32.cc @@ -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 { diff --git a/test/cctest/test-code-stubs-mips.cc b/test/cctest/test-code-stubs-mips.cc index f57459ead0..53bdc8ce79 100644 --- a/test/cctest/test-code-stubs-mips.cc +++ b/test/cctest/test-code-stubs-mips.cc @@ -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 { diff --git a/test/cctest/test-code-stubs-mips64.cc b/test/cctest/test-code-stubs-mips64.cc index 6605f82422..90bc60ecba 100644 --- a/test/cctest/test-code-stubs-mips64.cc +++ b/test/cctest/test-code-stubs-mips64.cc @@ -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 { diff --git a/test/cctest/test-code-stubs-x64.cc b/test/cctest/test-code-stubs-x64.cc index 327d45d16c..c55b2e2b1e 100644 --- a/test/cctest/test-code-stubs-x64.cc +++ b/test/cctest/test-code-stubs-x64.cc @@ -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 { diff --git a/test/cctest/test-isolate-independent-builtins.cc b/test/cctest/test-isolate-independent-builtins.cc index c878484976..4b4babdb37 100644 --- a/test/cctest/test-isolate-independent-builtins.cc +++ b/test/cctest/test-isolate-independent-builtins.cc @@ -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. diff --git a/test/cctest/test-macro-assembler-arm.cc b/test/cctest/test-macro-assembler-arm.cc index d442903ea0..3f115af416 100644 --- a/test/cctest/test-macro-assembler-arm.cc +++ b/test/cctest/test-macro-assembler-arm.cc @@ -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 { diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc index 54924def87..49d57aed21 100644 --- a/test/cctest/test-macro-assembler-x64.cc +++ b/test/cctest/test-macro-assembler-x64.cc @@ -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 { diff --git a/test/common/assembler-tester.h b/test/common/assembler-tester.h new file mode 100644 index 0000000000..ad9b9b6706 --- /dev/null +++ b/test/common/assembler-tester.h @@ -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(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_ diff --git a/test/unittests/BUILD.gn b/test/unittests/BUILD.gn index a6cf82f163..06ea545542 100644 --- a/test/unittests/BUILD.gn +++ b/test/unittests/BUILD.gn @@ -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") { diff --git a/test/unittests/assembler/turbo-assembler-arm-unittest.cc b/test/unittests/assembler/turbo-assembler-arm-unittest.cc new file mode 100644 index 0000000000..551cdb0436 --- /dev/null +++ b/test/unittests/assembler/turbo-assembler-arm-unittest.cc @@ -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(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::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(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::FromBuffer(isolate(), buffer); + + f.Call(0); + f.Call(18); + ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason"); +} + +#undef __ + +} // namespace internal +} // namespace v8 diff --git a/test/unittests/assembler/turbo-assembler-arm64-unittest.cc b/test/unittests/assembler/turbo-assembler-arm64-unittest.cc new file mode 100644 index 0000000000..530465cd03 --- /dev/null +++ b/test/unittests/assembler/turbo-assembler-arm64-unittest.cc @@ -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(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::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(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::FromBuffer(isolate(), buffer); + + f.Call(0); + f.Call(18); + ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason"); +} + +#undef __ + +} // namespace internal +} // namespace v8 diff --git a/test/unittests/assembler/turbo-assembler-ia32-unittest.cc b/test/unittests/assembler/turbo-assembler-ia32-unittest.cc new file mode 100644 index 0000000000..ba3634314f --- /dev/null +++ b/test/unittests/assembler/turbo-assembler-ia32-unittest.cc @@ -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(allocated), CodeObjectRequired::kNo); + __ set_abort_hard(true); + + __ Abort(AbortReason::kNoReason); + + CodeDesc desc; + tasm.GetCode(nullptr, &desc); + MakeAssemblerBufferExecutable(buffer, allocated); + auto f = GeneratedCode::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(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::FromBuffer(nullptr, buffer); + + f.Call(0); + f.Call(18); + ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason"); +} + +#undef __ + +} // namespace internal +} // namespace v8 diff --git a/test/unittests/assembler/turbo-assembler-mips-unittest.cc b/test/unittests/assembler/turbo-assembler-mips-unittest.cc new file mode 100644 index 0000000000..abba0ff30b --- /dev/null +++ b/test/unittests/assembler/turbo-assembler-mips-unittest.cc @@ -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(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::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(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::FromBuffer(isolate(), buffer); + + f.Call(0); + f.Call(18); + ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason"); +} + +#undef __ + +} // namespace internal +} // namespace v8 diff --git a/test/unittests/assembler/turbo-assembler-mips64-unittest.cc b/test/unittests/assembler/turbo-assembler-mips64-unittest.cc new file mode 100644 index 0000000000..8d8bc0756c --- /dev/null +++ b/test/unittests/assembler/turbo-assembler-mips64-unittest.cc @@ -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(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::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(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::FromBuffer(isolate(), buffer); + + f.Call(0); + f.Call(18); + ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason"); +} + +#undef __ + +} // namespace internal +} // namespace v8 diff --git a/test/unittests/assembler/turbo-assembler-x64-unittest.cc b/test/unittests/assembler/turbo-assembler-x64-unittest.cc new file mode 100644 index 0000000000..060060c762 --- /dev/null +++ b/test/unittests/assembler/turbo-assembler-x64-unittest.cc @@ -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(allocated), CodeObjectRequired::kNo); + __ set_abort_hard(true); + + __ Abort(AbortReason::kNoReason); + + CodeDesc desc; + tasm.GetCode(nullptr, &desc); + MakeAssemblerBufferExecutable(buffer, allocated); + auto f = GeneratedCode::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(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::FromBuffer(nullptr, buffer); + + f.Call(0); + f.Call(18); + ASSERT_DEATH_IF_SUPPORTED({ f.Call(17); }, "abort: no reason"); +} + +#undef __ + +} // namespace internal +} // namespace v8 diff --git a/tools/gcmole/BUILD.gn b/tools/gcmole/BUILD.gn index 99b5c0aea7..f10667e6c2 100644 --- a/tools/gcmole/BUILD.gn +++ b/tools/gcmole/BUILD.gn @@ -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/",