diff options
Diffstat (limited to 'deps/v8/src/diagnostics')
-rw-r--r-- | deps/v8/src/diagnostics/arm/disasm-arm.cc | 90 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/arm64/disasm-arm64.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/disassembler.cc | 16 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/eh-frame.cc | 37 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/eh-frame.h | 11 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/gdb-jit.cc | 12 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/ia32/disasm-ia32.cc | 28 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/objects-debug.cc | 328 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/objects-printer.cc | 379 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/perf-jit.cc | 83 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/perf-jit.h | 54 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/ppc/eh-frame-ppc.cc | 57 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/s390/disasm-s390.cc | 7 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/s390/eh-frame-s390.cc | 65 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/unwinder.cc | 192 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/unwinding-info-win64.cc | 194 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/unwinding-info-win64.h | 29 | ||||
-rw-r--r-- | deps/v8/src/diagnostics/x64/disasm-x64.cc | 213 |
18 files changed, 1021 insertions, 776 deletions
diff --git a/deps/v8/src/diagnostics/arm/disasm-arm.cc b/deps/v8/src/diagnostics/arm/disasm-arm.cc index 891ab0662e..e17936d8d2 100644 --- a/deps/v8/src/diagnostics/arm/disasm-arm.cc +++ b/deps/v8/src/diagnostics/arm/disasm-arm.cc @@ -1861,6 +1861,11 @@ void Decoder::DecodeSpecialCondition(Instruction* instr) { out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "vorr q%d, q%d, q%d", Vd, Vn, Vm); } + } else if (instr->Bits(21, 20) == 1 && instr->Bit(6) == 1 && + instr->Bit(4) == 1) { + // vbic Qd, Qn, Qm + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, + "vbic q%d, q%d, q%d", Vd, Vn, Vm); } else if (instr->Bits(21, 20) == 0 && instr->Bit(6) == 1 && instr->Bit(4) == 1) { // vand Qd, Qm, Qn. @@ -1991,8 +1996,27 @@ void Decoder::DecodeSpecialCondition(Instruction* instr) { break; } case 5: - if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) && - (instr->Bit(4) == 1)) { + if (instr->Bit(23) == 1 && instr->Bits(21, 19) == 0 && + instr->Bit(7) == 0 && instr->Bit(4) == 1) { + // One register and a modified immediate value, see ARM DDI 0406C.d + // A7.4.6. + byte cmode = instr->Bits(11, 8); + switch (cmode) { + case 0: { + int vd = instr->VFPDRegValue(kSimd128Precision); + int a = instr->Bit(24); + int bcd = instr->Bits(18, 16); + int efgh = instr->Bits(3, 0); + int imm64 = a << 7 | bcd << 4 | efgh; + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, + "vmov.i32 q%d, %d", vd, imm64); + break; + } + default: + Unknown(instr); + } + } else if ((instr->Bits(18, 16) == 0) && (instr->Bits(11, 6) == 0x28) && + (instr->Bit(4) == 1)) { // vmovl signed if ((instr->VdValue() & 1) != 0) Unknown(instr); int Vd = (instr->Bit(22) << 3) | (instr->VdValue() >> 1); @@ -2009,19 +2033,23 @@ void Decoder::DecodeSpecialCondition(Instruction* instr) { out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "vext.8 q%d, q%d, q%d, #%d", Vd, Vn, Vm, imm4); - } else if (instr->Bits(11, 7) == 0xA && instr->Bit(4) == 1) { + } else if (instr->Bits(11, 8) == 5 && instr->Bit(4) == 1) { // vshl.i<size> Qd, Qm, shift - int size = base::bits::RoundDownToPowerOfTwo32(instr->Bits(21, 16)); - int shift = instr->Bits(21, 16) - size; + int imm7 = instr->Bits(21, 16); + if (instr->Bit(7) != 0) imm7 += 64; + int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int shift = imm7 - size; int Vd = instr->VFPDRegValue(kSimd128Precision); int Vm = instr->VFPMRegValue(kSimd128Precision); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "vshl.i%d q%d, q%d, #%d", size, Vd, Vm, shift); - } else if (instr->Bits(11, 7) == 0 && instr->Bit(4) == 1) { + } else if (instr->Bits(11, 8) == 0 && instr->Bit(4) == 1) { // vshr.s<size> Qd, Qm, shift - int size = base::bits::RoundDownToPowerOfTwo32(instr->Bits(21, 16)); - int shift = 2 * size - instr->Bits(21, 16); + int imm7 = instr->Bits(21, 16); + if (instr->Bit(7) != 0) imm7 += 64; + int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int shift = 2 * size - imm7; int Vd = instr->VFPDRegValue(kSimd128Precision); int Vm = instr->VFPMRegValue(kSimd128Precision); out_buffer_pos_ += @@ -2070,6 +2098,16 @@ void Decoder::DecodeSpecialCondition(Instruction* instr) { out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "veor q%d, q%d, q%d", Vd, Vn, Vm); } + } else if (instr->Bit(4) == 0) { + if (instr->Bit(6) == 1) { + // vrhadd.u<size> Qd, Qm, Qn. + out_buffer_pos_ += + SNPrintF(out_buffer_ + out_buffer_pos_, + "vrhadd.u%d q%d, q%d, q%d", size, Vd, Vn, Vm); + } else { + // vrhadd.u<size> Dd, Dm, Dn. + Unknown(instr); + } } else { Unknown(instr); } @@ -2216,13 +2254,15 @@ void Decoder::DecodeSpecialCondition(Instruction* instr) { PrintDRegister(Vm); } else if (instr->Bits(17, 16) == 0x2 && instr->Bits(11, 8) == 0x2 && instr->Bits(7, 6) != 0) { - // vqmovn.<type><size> Dd, Qm. + // vqmov{u}n.<type><size> Dd, Qm. int Vd = instr->VFPDRegValue(kDoublePrecision); int Vm = instr->VFPMRegValue(kSimd128Precision); - char type = instr->Bit(6) != 0 ? 'u' : 's'; + int op = instr->Bits(7, 6); + const char* name = op == 0b01 ? "vqmovun" : "vqmovn"; + char type = op == 0b11 ? 'u' : 's'; int size = 2 * kBitsPerByte * (1 << instr->Bits(19, 18)); out_buffer_pos_ += - SNPrintF(out_buffer_ + out_buffer_pos_, "vqmovn.%c%i d%d, q%d", + SNPrintF(out_buffer_ + out_buffer_pos_, "%s.%c%i d%d, q%d", name, type, size, Vd, Vm); } else { int Vd, Vm; @@ -2322,11 +2362,13 @@ void Decoder::DecodeSpecialCondition(Instruction* instr) { Unknown(instr); } } - } else if (instr->Bits(11, 7) == 0 && instr->Bit(4) == 1 && + } else if (instr->Bits(11, 8) == 0 && instr->Bit(4) == 1 && instr->Bit(6) == 1) { // vshr.u<size> Qd, Qm, shift - int size = base::bits::RoundDownToPowerOfTwo32(instr->Bits(21, 16)); - int shift = 2 * size - instr->Bits(21, 16); + int imm7 = instr->Bits(21, 16); + if (instr->Bit(7) != 0) imm7 += 64; + int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int shift = 2 * size - imm7; int Vd = instr->VFPDRegValue(kSimd128Precision); int Vm = instr->VFPMRegValue(kSimd128Precision); out_buffer_pos_ += @@ -2353,6 +2395,26 @@ void Decoder::DecodeSpecialCondition(Instruction* instr) { out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "vs%ci.%d d%d, d%d, #%d", direction, size, Vd, Vm, shift); + } else if (instr->Bits(11, 8) == 0x8 && instr->Bit(6) == 0 && + instr->Bit(4) == 0) { + // vmlal.u<size> <Qd>, <Dn>, <Dm> + int Vd = instr->VFPDRegValue(kSimd128Precision); + int Vn = instr->VFPNRegValue(kDoublePrecision); + int Vm = instr->VFPMRegValue(kDoublePrecision); + int size = 8 << instr->Bits(21, 20); + out_buffer_pos_ += + SNPrintF(out_buffer_ + out_buffer_pos_, "vmlal.u%d q%d, d%d, d%d", + size, Vd, Vn, Vm); + } else if (instr->Bits(11, 8) == 0xC && instr->Bit(6) == 0 && + instr->Bit(4) == 0) { + // vmull.u<size> <Qd>, <Dn>, <Dm> + int Vd = instr->VFPDRegValue(kSimd128Precision); + int Vn = instr->VFPNRegValue(kDoublePrecision); + int Vm = instr->VFPMRegValue(kDoublePrecision); + int size = 8 << instr->Bits(21, 20); + out_buffer_pos_ += + SNPrintF(out_buffer_ + out_buffer_pos_, "vmull.u%d q%d, d%d, d%d", + size, Vd, Vn, Vm); } else { Unknown(instr); } diff --git a/deps/v8/src/diagnostics/arm64/disasm-arm64.cc b/deps/v8/src/diagnostics/arm64/disasm-arm64.cc index db14689ad1..5a87f73529 100644 --- a/deps/v8/src/diagnostics/arm64/disasm-arm64.cc +++ b/deps/v8/src/diagnostics/arm64/disasm-arm64.cc @@ -3563,7 +3563,7 @@ void DisassemblingDecoder::ProcessOutput(Instruction* /*instr*/) { } void DisassemblingDecoder::AppendRegisterNameToOutput(const CPURegister& reg) { - DCHECK(reg.IsValid()); + DCHECK(reg.is_valid()); char reg_char; if (reg.IsRegister()) { diff --git a/deps/v8/src/diagnostics/disassembler.cc b/deps/v8/src/diagnostics/disassembler.cc index 8307ef3ff4..785c535e0a 100644 --- a/deps/v8/src/diagnostics/disassembler.cc +++ b/deps/v8/src/diagnostics/disassembler.cc @@ -8,6 +8,7 @@ #include <unordered_map> #include <vector> +#include "src/base/memory.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/code-comments.h" #include "src/codegen/code-reference.h" @@ -291,23 +292,26 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, // First decode instruction so that we know its length. byte* prev_pc = pc; if (constants > 0) { - SNPrintF(decode_buffer, "%08x constant", - *reinterpret_cast<int32_t*>(pc)); + SNPrintF( + decode_buffer, "%08x constant", + base::ReadUnalignedValue<int32_t>(reinterpret_cast<Address>(pc))); constants--; pc += 4; } else { int num_const = d.ConstantPoolSizeAt(pc); if (num_const >= 0) { - SNPrintF(decode_buffer, - "%08x constant pool begin (num_const = %d)", - *reinterpret_cast<int32_t*>(pc), num_const); + SNPrintF( + decode_buffer, "%08x constant pool begin (num_const = %d)", + base::ReadUnalignedValue<int32_t>(reinterpret_cast<Address>(pc)), + num_const); constants = num_const; pc += 4; } else if (it != nullptr && !it->done() && it->rinfo()->pc() == reinterpret_cast<Address>(pc) && it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) { // raw pointer embedded in code stream, e.g., jump table - byte* ptr = *reinterpret_cast<byte**>(pc); + byte* ptr = + base::ReadUnalignedValue<byte*>(reinterpret_cast<Address>(pc)); SNPrintF(decode_buffer, "%08" V8PRIxPTR " jump table entry %4zu", reinterpret_cast<intptr_t>(ptr), static_cast<size_t>(ptr - begin)); diff --git a/deps/v8/src/diagnostics/eh-frame.cc b/deps/v8/src/diagnostics/eh-frame.cc index 45d693a476..35cb529f09 100644 --- a/deps/v8/src/diagnostics/eh-frame.cc +++ b/deps/v8/src/diagnostics/eh-frame.cc @@ -9,8 +9,9 @@ #include "src/codegen/code-desc.h" -#if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM) && \ - !defined(V8_TARGET_ARCH_ARM64) +#if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM) && \ + !defined(V8_TARGET_ARCH_ARM64) && !defined(V8_TARGET_ARCH_S390X) && \ + !defined(V8_TARGET_ARCH_PPC64) // Placeholders for unsupported architectures. @@ -303,36 +304,48 @@ void EhFrameWriter::SetBaseAddressRegisterAndOffset(Register base_register, base_register_ = base_register; } -void EhFrameWriter::RecordRegisterSavedToStack(int register_code, int offset) { +void EhFrameWriter::RecordRegisterSavedToStack(int dwarf_register_code, + int offset) { DCHECK_EQ(writer_state_, InternalState::kInitialized); DCHECK_EQ(offset % EhFrameConstants::kDataAlignmentFactor, 0); int factored_offset = offset / EhFrameConstants::kDataAlignmentFactor; if (factored_offset >= 0) { - DCHECK_LE(register_code, EhFrameConstants::kSavedRegisterMask); + DCHECK_LE(dwarf_register_code, EhFrameConstants::kSavedRegisterMask); WriteByte((EhFrameConstants::kSavedRegisterTag << EhFrameConstants::kSavedRegisterMaskSize) | - (register_code & EhFrameConstants::kSavedRegisterMask)); + (dwarf_register_code & EhFrameConstants::kSavedRegisterMask)); WriteULeb128(factored_offset); } else { WriteOpcode(EhFrameConstants::DwarfOpcodes::kOffsetExtendedSf); - WriteULeb128(register_code); + WriteULeb128(dwarf_register_code); WriteSLeb128(factored_offset); } } void EhFrameWriter::RecordRegisterNotModified(Register name) { + RecordRegisterNotModified(RegisterToDwarfCode(name)); +} + +void EhFrameWriter::RecordRegisterNotModified(int dwarf_register_code) { DCHECK_EQ(writer_state_, InternalState::kInitialized); WriteOpcode(EhFrameConstants::DwarfOpcodes::kSameValue); - WriteULeb128(RegisterToDwarfCode(name)); + WriteULeb128(dwarf_register_code); } void EhFrameWriter::RecordRegisterFollowsInitialRule(Register name) { + RecordRegisterFollowsInitialRule(RegisterToDwarfCode(name)); +} + +void EhFrameWriter::RecordRegisterFollowsInitialRule(int dwarf_register_code) { DCHECK_EQ(writer_state_, InternalState::kInitialized); - int code = RegisterToDwarfCode(name); - DCHECK_LE(code, EhFrameConstants::kFollowInitialRuleMask); - WriteByte((EhFrameConstants::kFollowInitialRuleTag - << EhFrameConstants::kFollowInitialRuleMaskSize) | - (code & EhFrameConstants::kFollowInitialRuleMask)); + if (dwarf_register_code <= EhFrameConstants::kFollowInitialRuleMask) { + WriteByte((EhFrameConstants::kFollowInitialRuleTag + << EhFrameConstants::kFollowInitialRuleMaskSize) | + (dwarf_register_code & EhFrameConstants::kFollowInitialRuleMask)); + } else { + WriteOpcode(EhFrameConstants::DwarfOpcodes::kRestoreExtended); + WriteULeb128(dwarf_register_code); + } } void EhFrameWriter::Finish(int code_size) { diff --git a/deps/v8/src/diagnostics/eh-frame.h b/deps/v8/src/diagnostics/eh-frame.h index a9d76a2743..17ef8c0ad5 100644 --- a/deps/v8/src/diagnostics/eh-frame.h +++ b/deps/v8/src/diagnostics/eh-frame.h @@ -24,6 +24,7 @@ class V8_EXPORT_PRIVATE EhFrameConstants final kAdvanceLoc1 = 0x02, kAdvanceLoc2 = 0x03, kAdvanceLoc4 = 0x04, + kRestoreExtended = 0x06, kSameValue = 0x08, kDefCfa = 0x0c, kDefCfaRegister = 0x0d, @@ -102,11 +103,17 @@ class V8_EXPORT_PRIVATE EhFrameWriter { RecordRegisterSavedToStack(RegisterToDwarfCode(name), offset); } + // Directly accepts a DWARF register code, needed for + // handling pseudo-registers on some platforms. + void RecordRegisterSavedToStack(int dwarf_register_code, int offset); + // The register has not been modified from the previous frame. void RecordRegisterNotModified(Register name); + void RecordRegisterNotModified(int dwarf_register_code); // The register follows the rule defined in the CIE. void RecordRegisterFollowsInitialRule(Register name); + void RecordRegisterFollowsInitialRule(int dwarf_register_code); void Finish(int code_size); @@ -169,10 +176,6 @@ class V8_EXPORT_PRIVATE EhFrameWriter { // Write nops until the size reaches a multiple of 8 bytes. void WritePaddingToAlignedSize(int unpadded_size); - // Internal version that directly accepts a DWARF register code, needed for - // handling pseudo-registers on some platforms. - void RecordRegisterSavedToStack(int register_code, int offset); - int GetProcedureAddressOffset() const { return fde_offset() + EhFrameConstants::kProcedureAddressOffsetInFde; } diff --git a/deps/v8/src/diagnostics/gdb-jit.cc b/deps/v8/src/diagnostics/gdb-jit.cc index e1290bae4e..5f36437302 100644 --- a/deps/v8/src/diagnostics/gdb-jit.cc +++ b/deps/v8/src/diagnostics/gdb-jit.cc @@ -16,7 +16,6 @@ #include "src/handles/global-handles.h" #include "src/init/bootstrapper.h" #include "src/objects/objects.h" -#include "src/snapshot/natives.h" #include "src/utils/ostreams.h" #include "src/utils/vector.h" #include "src/zone/zone-chunk-list.h" @@ -220,7 +219,7 @@ class MachOSection : public DebugSectionBase<MachOSectionHeader> { : name_(name), segment_(segment), align_(align), flags_(flags) { if (align_ != 0) { DCHECK(base::bits::IsPowerOfTwo(align)); - align_ = WhichPowerOf2(align_); + align_ = base::bits::WhichPowerOfTwo(align_); } } @@ -1105,25 +1104,22 @@ class DebugInfoSection : public DebugSection { Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); uintptr_t block_start = w->position(); w->Write<uint8_t>(DW_OP_fbreg); - w->WriteSLEB128(JavaScriptFrameConstants::kLastParameterOffset + + w->WriteSLEB128(StandardFrameConstants::kFixedFrameSizeAboveFp + kSystemPointerSize * (params - param - 1)); block_size.set(static_cast<uint32_t>(w->position() - block_start)); } // See contexts.h for more information. - DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, 4); + DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, 3); DCHECK_EQ(Context::SCOPE_INFO_INDEX, 0); DCHECK_EQ(Context::PREVIOUS_INDEX, 1); DCHECK_EQ(Context::EXTENSION_INDEX, 2); - DCHECK_EQ(Context::NATIVE_CONTEXT_INDEX, 3); w->WriteULEB128(current_abbreviation++); w->WriteString(".scope_info"); w->WriteULEB128(current_abbreviation++); w->WriteString(".previous"); w->WriteULEB128(current_abbreviation++); w->WriteString(".extension"); - w->WriteULEB128(current_abbreviation++); - w->WriteString(".native_context"); for (int context_slot = 0; context_slot < context_slots; ++context_slot) { w->WriteULEB128(current_abbreviation++); @@ -1139,7 +1135,7 @@ class DebugInfoSection : public DebugSection { Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); uintptr_t block_start = w->position(); w->Write<uint8_t>(DW_OP_fbreg); - w->WriteSLEB128(JavaScriptFrameConstants::kFunctionOffset); + w->WriteSLEB128(StandardFrameConstants::kFunctionOffset); block_size.set(static_cast<uint32_t>(w->position() - block_start)); } diff --git a/deps/v8/src/diagnostics/ia32/disasm-ia32.cc b/deps/v8/src/diagnostics/ia32/disasm-ia32.cc index ead0a5a709..0cb36d1228 100644 --- a/deps/v8/src/diagnostics/ia32/disasm-ia32.cc +++ b/deps/v8/src/diagnostics/ia32/disasm-ia32.cc @@ -692,6 +692,10 @@ int DisassemblerIA32::AVXInstruction(byte* data) { int mod, regop, rm, vvvv = vex_vreg(); get_modrm(*current, &mod, ®op, &rm); switch (opcode) { + case 0x18: + AppendToBuffer("vbroadcastss %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + break; case 0x99: AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(), NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -846,6 +850,10 @@ int DisassemblerIA32::AVXInstruction(byte* data) { int mod, regop, rm, vvvv = vex_vreg(); get_modrm(*current, &mod, ®op, &rm); switch (opcode) { + case 0x12: + AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + break; case 0x51: AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -2259,13 +2267,6 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, } else if (*data == 0x90) { data++; AppendToBuffer("nop"); // 2 byte nop. - } else if (*data == 0xF3) { - data++; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - AppendToBuffer("psllq %s,%s", NameOfXMMRegister(regop), - NameOfXMMRegister(rm)); - data++; } else if (*data == 0x71) { data++; int mod, regop, rm; @@ -2291,13 +2292,6 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2], NameOfXMMRegister(rm), static_cast<int>(imm8)); data += 2; - } else if (*data == 0xD3) { - data++; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - AppendToBuffer("psrlq %s,%s", NameOfXMMRegister(regop), - NameOfXMMRegister(rm)); - data++; } else if (*data == 0x7F) { AppendToBuffer("movdqa "); data++; @@ -2444,6 +2438,12 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, get_modrm(*data, &mod, ®op, &rm); AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); data += PrintRightXMMOperand(data); + } else if (b2 == 0x12) { + data += 3; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + AppendToBuffer("movddup %s,", NameOfXMMRegister(regop)); + data += PrintRightXMMOperand(data); } else if (b2 == 0x5A) { data += 3; int mod, regop, rm; diff --git a/deps/v8/src/diagnostics/objects-debug.cc b/deps/v8/src/diagnostics/objects-debug.cc index 9c4b176dc6..d087a6d21d 100644 --- a/deps/v8/src/diagnostics/objects-debug.cc +++ b/deps/v8/src/diagnostics/objects-debug.cc @@ -10,6 +10,7 @@ #include "src/diagnostics/disassembler.h" #include "src/heap/combined-heap.h" #include "src/heap/heap-write-barrier-inl.h" +#include "src/heap/read-only-heap.h" #include "src/ic/handler-configuration-inl.h" #include "src/init/bootstrapper.h" #include "src/logging/counters.h" @@ -38,6 +39,7 @@ #include "src/objects/js-collection-inl.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-date-time-format-inl.h" +#include "src/objects/js-display-names-inl.h" #endif // V8_INTL_SUPPORT #include "src/objects/js-generator-inl.h" #ifdef V8_INTL_SUPPORT @@ -60,6 +62,7 @@ #include "src/objects/module-inl.h" #include "src/objects/oddball-inl.h" #include "src/objects/promise-inl.h" +#include "src/objects/property-descriptor-object-inl.h" #include "src/objects/stack-frame-info-inl.h" #include "src/objects/struct-inl.h" #include "src/objects/template-objects-inl.h" @@ -156,28 +159,10 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) { String::cast(*this).StringVerify(isolate); } break; - case SYMBOL_TYPE: - Symbol::cast(*this).SymbolVerify(isolate); - break; - case MAP_TYPE: - Map::cast(*this).MapVerify(isolate); - break; - case HEAP_NUMBER_TYPE: - CHECK(IsHeapNumber()); - break; - case BIGINT_TYPE: - BigInt::cast(*this).BigIntVerify(isolate); - break; - case CALL_HANDLER_INFO_TYPE: - CallHandlerInfo::cast(*this).CallHandlerInfoVerify(isolate); - break; case OBJECT_BOILERPLATE_DESCRIPTION_TYPE: ObjectBoilerplateDescription::cast(*this) .ObjectBoilerplateDescriptionVerify(isolate); break; - case EMBEDDER_DATA_ARRAY_TYPE: - EmbedderDataArray::cast(*this).EmbedderDataArrayVerify(isolate); - break; // FixedArray types case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE: case HASH_TABLE_TYPE: @@ -212,46 +197,16 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) { case WEAK_FIXED_ARRAY_TYPE: WeakFixedArray::cast(*this).WeakFixedArrayVerify(isolate); break; - case WEAK_ARRAY_LIST_TYPE: - WeakArrayList::cast(*this).WeakArrayListVerify(isolate); - break; - case FIXED_DOUBLE_ARRAY_TYPE: - FixedDoubleArray::cast(*this).FixedDoubleArrayVerify(isolate); - break; case FEEDBACK_METADATA_TYPE: FeedbackMetadata::cast(*this).FeedbackMetadataVerify(isolate); break; - case BYTE_ARRAY_TYPE: - ByteArray::cast(*this).ByteArrayVerify(isolate); - break; - case BYTECODE_ARRAY_TYPE: - BytecodeArray::cast(*this).BytecodeArrayVerify(isolate); - break; - case DESCRIPTOR_ARRAY_TYPE: - DescriptorArray::cast(*this).DescriptorArrayVerify(isolate); - break; case TRANSITION_ARRAY_TYPE: TransitionArray::cast(*this).TransitionArrayVerify(isolate); break; - case PROPERTY_ARRAY_TYPE: - PropertyArray::cast(*this).PropertyArrayVerify(isolate); - break; - case FREE_SPACE_TYPE: - FreeSpace::cast(*this).FreeSpaceVerify(isolate); - break; - case FEEDBACK_CELL_TYPE: - FeedbackCell::cast(*this).FeedbackCellVerify(isolate); - break; - case FEEDBACK_VECTOR_TYPE: - FeedbackVector::cast(*this).FeedbackVectorVerify(isolate); - break; case CODE_TYPE: Code::cast(*this).CodeVerify(isolate); break; - case ODDBALL_TYPE: - Oddball::cast(*this).OddballVerify(isolate); - break; case JS_OBJECT_TYPE: case JS_ERROR_TYPE: case JS_API_OBJECT_TYPE: @@ -259,72 +214,12 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) { case JS_CONTEXT_EXTENSION_OBJECT_TYPE: JSObject::cast(*this).JSObjectVerify(isolate); break; - case WASM_MODULE_OBJECT_TYPE: - WasmModuleObject::cast(*this).WasmModuleObjectVerify(isolate); - break; - case WASM_TABLE_OBJECT_TYPE: - WasmTableObject::cast(*this).WasmTableObjectVerify(isolate); - break; - case WASM_MEMORY_OBJECT_TYPE: - WasmMemoryObject::cast(*this).WasmMemoryObjectVerify(isolate); - break; - case WASM_GLOBAL_OBJECT_TYPE: - WasmGlobalObject::cast(*this).WasmGlobalObjectVerify(isolate); - break; - case WASM_EXCEPTION_OBJECT_TYPE: - WasmExceptionObject::cast(*this).WasmExceptionObjectVerify(isolate); - break; case WASM_INSTANCE_OBJECT_TYPE: WasmInstanceObject::cast(*this).WasmInstanceObjectVerify(isolate); break; - case JS_ARGUMENTS_OBJECT_TYPE: - JSArgumentsObject::cast(*this).JSArgumentsObjectVerify(isolate); - break; case JS_GENERATOR_OBJECT_TYPE: JSGeneratorObject::cast(*this).JSGeneratorObjectVerify(isolate); break; - case JS_ASYNC_FUNCTION_OBJECT_TYPE: - JSAsyncFunctionObject::cast(*this).JSAsyncFunctionObjectVerify(isolate); - break; - case JS_ASYNC_GENERATOR_OBJECT_TYPE: - JSAsyncGeneratorObject::cast(*this).JSAsyncGeneratorObjectVerify(isolate); - break; - case JS_PRIMITIVE_WRAPPER_TYPE: - JSPrimitiveWrapper::cast(*this).JSPrimitiveWrapperVerify(isolate); - break; - case JS_DATE_TYPE: - JSDate::cast(*this).JSDateVerify(isolate); - break; - case JS_BOUND_FUNCTION_TYPE: - JSBoundFunction::cast(*this).JSBoundFunctionVerify(isolate); - break; - case JS_FUNCTION_TYPE: - JSFunction::cast(*this).JSFunctionVerify(isolate); - break; - case JS_GLOBAL_PROXY_TYPE: - JSGlobalProxy::cast(*this).JSGlobalProxyVerify(isolate); - break; - case JS_GLOBAL_OBJECT_TYPE: - JSGlobalObject::cast(*this).JSGlobalObjectVerify(isolate); - break; - case CELL_TYPE: - Cell::cast(*this).CellVerify(isolate); - break; - case PROPERTY_CELL_TYPE: - PropertyCell::cast(*this).PropertyCellVerify(isolate); - break; - case JS_ARRAY_TYPE: - JSArray::cast(*this).JSArrayVerify(isolate); - break; - case JS_MODULE_NAMESPACE_TYPE: - JSModuleNamespace::cast(*this).JSModuleNamespaceVerify(isolate); - break; - case JS_SET_TYPE: - JSSet::cast(*this).JSSetVerify(isolate); - break; - case JS_MAP_TYPE: - JSMap::cast(*this).JSMapVerify(isolate); - break; case JS_SET_KEY_VALUE_ITERATOR_TYPE: case JS_SET_VALUE_ITERATOR_TYPE: JSSetIterator::cast(*this).JSSetIteratorVerify(isolate); @@ -334,136 +229,20 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) { case JS_MAP_VALUE_ITERATOR_TYPE: JSMapIterator::cast(*this).JSMapIteratorVerify(isolate); break; - case JS_ARRAY_ITERATOR_TYPE: - JSArrayIterator::cast(*this).JSArrayIteratorVerify(isolate); - break; - case JS_STRING_ITERATOR_TYPE: - JSStringIterator::cast(*this).JSStringIteratorVerify(isolate); - break; - case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: - JSAsyncFromSyncIterator::cast(*this).JSAsyncFromSyncIteratorVerify( - isolate); - break; - case WEAK_CELL_TYPE: - WeakCell::cast(*this).WeakCellVerify(isolate); - break; - case JS_WEAK_REF_TYPE: - JSWeakRef::cast(*this).JSWeakRefVerify(isolate); - break; - case JS_FINALIZATION_GROUP_TYPE: - JSFinalizationGroup::cast(*this).JSFinalizationGroupVerify(isolate); - break; - case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE: - JSFinalizationGroupCleanupIterator::cast(*this) - .JSFinalizationGroupCleanupIteratorVerify(isolate); - break; - case JS_WEAK_MAP_TYPE: - JSWeakMap::cast(*this).JSWeakMapVerify(isolate); - break; - case JS_WEAK_SET_TYPE: - JSWeakSet::cast(*this).JSWeakSetVerify(isolate); - break; - case JS_PROMISE_TYPE: - JSPromise::cast(*this).JSPromiseVerify(isolate); - break; - case JS_REG_EXP_TYPE: - JSRegExp::cast(*this).JSRegExpVerify(isolate); - break; - case JS_REG_EXP_STRING_ITERATOR_TYPE: - JSRegExpStringIterator::cast(*this).JSRegExpStringIteratorVerify(isolate); - break; case FILLER_TYPE: break; - case JS_PROXY_TYPE: - JSProxy::cast(*this).JSProxyVerify(isolate); - break; - case FOREIGN_TYPE: - Foreign::cast(*this).ForeignVerify(isolate); - break; - case PREPARSE_DATA_TYPE: - PreparseData::cast(*this).PreparseDataVerify(isolate); - break; - case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: - UncompiledDataWithoutPreparseData::cast(*this) - .UncompiledDataWithoutPreparseDataVerify(isolate); - break; - case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: - UncompiledDataWithPreparseData::cast(*this) - .UncompiledDataWithPreparseDataVerify(isolate); - break; - case SHARED_FUNCTION_INFO_TYPE: - SharedFunctionInfo::cast(*this).SharedFunctionInfoVerify(isolate); - break; - case JS_MESSAGE_OBJECT_TYPE: - JSMessageObject::cast(*this).JSMessageObjectVerify(isolate); - break; - case JS_ARRAY_BUFFER_TYPE: - JSArrayBuffer::cast(*this).JSArrayBufferVerify(isolate); - break; - case JS_TYPED_ARRAY_TYPE: - JSTypedArray::cast(*this).JSTypedArrayVerify(isolate); - break; - case JS_DATA_VIEW_TYPE: - JSDataView::cast(*this).JSDataViewVerify(isolate); - break; - case SMALL_ORDERED_HASH_SET_TYPE: - SmallOrderedHashSet::cast(*this).SmallOrderedHashSetVerify(isolate); - break; - case SMALL_ORDERED_HASH_MAP_TYPE: - SmallOrderedHashMap::cast(*this).SmallOrderedHashMapVerify(isolate); - break; - case SMALL_ORDERED_NAME_DICTIONARY_TYPE: - SmallOrderedNameDictionary::cast(*this).SmallOrderedNameDictionaryVerify( - isolate); - break; - case SOURCE_TEXT_MODULE_TYPE: - SourceTextModule::cast(*this).SourceTextModuleVerify(isolate); - break; - case SYNTHETIC_MODULE_TYPE: - SyntheticModule::cast(*this).SyntheticModuleVerify(isolate); - break; case CODE_DATA_CONTAINER_TYPE: CodeDataContainer::cast(*this).CodeDataContainerVerify(isolate); break; -#ifdef V8_INTL_SUPPORT - case JS_V8_BREAK_ITERATOR_TYPE: - JSV8BreakIterator::cast(*this).JSV8BreakIteratorVerify(isolate); - break; - case JS_COLLATOR_TYPE: - JSCollator::cast(*this).JSCollatorVerify(isolate); - break; - case JS_DATE_TIME_FORMAT_TYPE: - JSDateTimeFormat::cast(*this).JSDateTimeFormatVerify(isolate); - break; - case JS_LIST_FORMAT_TYPE: - JSListFormat::cast(*this).JSListFormatVerify(isolate); - break; - case JS_LOCALE_TYPE: - JSLocale::cast(*this).JSLocaleVerify(isolate); - break; - case JS_NUMBER_FORMAT_TYPE: - JSNumberFormat::cast(*this).JSNumberFormatVerify(isolate); - break; - case JS_PLURAL_RULES_TYPE: - JSPluralRules::cast(*this).JSPluralRulesVerify(isolate); - break; - case JS_RELATIVE_TIME_FORMAT_TYPE: - JSRelativeTimeFormat::cast(*this).JSRelativeTimeFormatVerify(isolate); - break; - case JS_SEGMENT_ITERATOR_TYPE: - JSSegmentIterator::cast(*this).JSSegmentIteratorVerify(isolate); - break; - case JS_SEGMENTER_TYPE: - JSSegmenter::cast(*this).JSSegmenterVerify(isolate); - break; -#endif // V8_INTL_SUPPORT -#define MAKE_STRUCT_CASE(TYPE, Name, name) \ +#define MAKE_TORQUE_CASE(Name, TYPE) \ case TYPE: \ Name::cast(*this).Name##Verify(isolate); \ break; - STRUCT_LIST(MAKE_STRUCT_CASE) -#undef MAKE_STRUCT_CASE + // Every class that has its fields defined in a .tq file and corresponds + // to exactly one InstanceType value is included in the following list. + TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE) +#undef MAKE_TORQUE_CASE case ALLOCATION_SITE_TYPE: AllocationSite::cast(*this).AllocationSiteVerify(isolate); @@ -489,8 +268,9 @@ void Symbol::SymbolVerify(Isolate* isolate) { TorqueGeneratedClassVerifiers::SymbolVerify(*this, isolate); CHECK(HasHashCode()); CHECK_GT(Hash(), 0); - CHECK(name().IsUndefined(isolate) || name().IsString()); + CHECK(description().IsUndefined(isolate) || description().IsString()); CHECK_IMPLIES(IsPrivateName(), IsPrivate()); + CHECK_IMPLIES(IsPrivateBrand(), IsPrivateName()); } USE_TORQUE_VERIFIER(ByteArray) @@ -506,23 +286,19 @@ void BytecodeArray::BytecodeArrayVerify(Isolate* isolate) { VerifyHeapPointer(isolate, constant_pool()); CHECK(source_position_table().IsUndefined() || source_position_table().IsException() || - source_position_table().IsByteArray() || - source_position_table().IsSourcePositionTableWithFrameCache()); + source_position_table().IsByteArray()); CHECK(handler_table().IsByteArray()); } USE_TORQUE_VERIFIER(FreeSpace) -void FeedbackVector::FeedbackVectorVerify(Isolate* isolate) { - TorqueGeneratedClassVerifiers::FeedbackVectorVerify(*this, isolate); - MaybeObject code = optimized_code_weak_or_smi(); - MaybeObject::VerifyMaybeObjectPointer(isolate, code); - CHECK(code->IsSmi() || code->IsWeakOrCleared()); -} +USE_TORQUE_VERIFIER(HeapNumber) + +USE_TORQUE_VERIFIER(FeedbackVector) USE_TORQUE_VERIFIER(JSReceiver) -bool JSObject::ElementsAreSafeToExamine(Isolate* isolate) const { +bool JSObject::ElementsAreSafeToExamine(const Isolate* isolate) const { // If a GC was caused while constructing this object, the elements // pointer may point to a one pointer filler map. return elements(isolate) != @@ -652,8 +428,37 @@ void Map::MapVerify(Isolate* isolate) { CHECK(instance_size() == kVariableSizeSentinel || (kTaggedSize <= instance_size() && static_cast<size_t>(instance_size()) < heap->Capacity())); - CHECK(GetBackPointer().IsUndefined(isolate) || - !Map::cast(GetBackPointer()).is_stable()); + if (IsContextMap()) { + CHECK(native_context().IsNativeContext()); + } else { + if (GetBackPointer().IsUndefined(isolate)) { + // Root maps must not have descriptors in the descriptor array that do not + // belong to the map. + CHECK_EQ(NumberOfOwnDescriptors(), + instance_descriptors().number_of_descriptors()); + } else { + // If there is a parent map it must be non-stable. + Map parent = Map::cast(GetBackPointer()); + CHECK(!parent.is_stable()); + DescriptorArray descriptors = instance_descriptors(); + if (descriptors == parent.instance_descriptors()) { + if (NumberOfOwnDescriptors() == parent.NumberOfOwnDescriptors() + 1) { + // Descriptors sharing through property transitions takes over + // ownership from the parent map. + CHECK(!parent.owns_descriptors()); + } else { + CHECK_EQ(NumberOfOwnDescriptors(), parent.NumberOfOwnDescriptors()); + // Descriptors sharing through special transitions properly takes over + // ownership from the parent map unless it uses the canonical empty + // descriptor array. + if (descriptors != ReadOnlyRoots(isolate).empty_descriptor_array()) { + CHECK_IMPLIES(owns_descriptors(), !parent.owns_descriptors()); + CHECK_IMPLIES(parent.owns_descriptors(), !owns_descriptors()); + } + } + } + } + } SLOW_DCHECK(instance_descriptors().IsSortedNoDuplicates()); DisallowHeapAllocation no_gc; SLOW_DCHECK( @@ -662,6 +467,9 @@ void Map::MapVerify(Isolate* isolate) { .IsConsistentWithBackPointers()); SLOW_DCHECK(!FLAG_unbox_double_fields || layout_descriptor().IsConsistentWithMap(*this)); + // Only JSFunction maps have has_prototype_slot() bit set and constructible + // JSFunction objects must have prototype slot. + CHECK_IMPLIES(has_prototype_slot(), instance_type() == JS_FUNCTION_TYPE); if (!may_have_interesting_symbols()) { CHECK(!has_named_interceptor()); CHECK(!is_dictionary_map()); @@ -680,7 +488,7 @@ void Map::MapVerify(Isolate* isolate) { IsAnyHoleyNonextensibleElementsKind(elements_kind())); CHECK_IMPLIES(is_deprecated(), !is_stable()); if (is_prototype_map()) { - DCHECK(prototype_info() == Smi::kZero || + DCHECK(prototype_info() == Smi::zero() || prototype_info().IsPrototypeInfo()); } } @@ -716,13 +524,7 @@ void WeakFixedArray::WeakFixedArrayVerify(Isolate* isolate) { } } -void WeakArrayList::WeakArrayListVerify(Isolate* isolate) { - VerifySmiField(kCapacityOffset); - VerifySmiField(kLengthOffset); - for (int i = 0; i < length(); i++) { - MaybeObject::VerifyMaybeObjectPointer(isolate, Get(i)); - } -} +USE_TORQUE_VERIFIER(WeakArrayList) void PropertyArray::PropertyArrayVerify(Isolate* isolate) { TorqueGeneratedClassVerifiers::PropertyArrayVerify(*this, isolate); @@ -783,13 +585,6 @@ void FeedbackMetadata::FeedbackMetadataVerify(Isolate* isolate) { void DescriptorArray::DescriptorArrayVerify(Isolate* isolate) { TorqueGeneratedClassVerifiers::DescriptorArrayVerify(*this, isolate); - for (int i = 0; i < number_of_all_descriptors(); i++) { - MaybeObjectSlot slot(GetDescriptorSlot(i)); - MaybeObject::VerifyMaybeObjectPointer(isolate, *(slot + kEntryKeyIndex)); - MaybeObject::VerifyMaybeObjectPointer(isolate, - *(slot + kEntryDetailsIndex)); - MaybeObject::VerifyMaybeObjectPointer(isolate, *(slot + kEntryValueIndex)); - } if (number_of_all_descriptors() == 0) { CHECK_EQ(ReadOnlyRoots(isolate).empty_descriptor_array(), *this); CHECK_EQ(0, number_of_all_descriptors()); @@ -1148,7 +943,13 @@ void Code::CodeVerify(Isolate* isolate) { CHECK_LE(handler_table_offset(), constant_pool_offset()); CHECK_LE(constant_pool_offset(), code_comments_offset()); CHECK_LE(code_comments_offset(), InstructionSize()); - CHECK(IsAligned(raw_instruction_start(), kCodeAlignment)); + CHECK_IMPLIES(!ReadOnlyHeap::Contains(*this), + IsAligned(raw_instruction_start(), kCodeAlignment)); + // TODO(delphick): Refactor Factory::CodeBuilder::BuildInternal, so that the + // following CHECK works builtin trampolines. It currently fails because + // CodeVerify is called halfway through constructing the trampoline and so not + // everything is set up. + // CHECK_EQ(ReadOnlyHeap::Contains(*this), !IsExecutable()); relocation_info().ObjectVerify(isolate); CHECK(Code::SizeFor(body_size()) <= kMaxRegularHeapObjectSize || isolate->heap()->InSpace(*this, CODE_LO_SPACE)); @@ -1247,9 +1048,9 @@ void WeakCell::WeakCellVerify(Isolate* isolate) { CHECK_EQ(WeakCell::cast(next()).prev(), *this); } - CHECK_IMPLIES(key().IsUndefined(isolate), + CHECK_IMPLIES(unregister_token().IsUndefined(isolate), key_list_prev().IsUndefined(isolate)); - CHECK_IMPLIES(key().IsUndefined(isolate), + CHECK_IMPLIES(unregister_token().IsUndefined(isolate), key_list_next().IsUndefined(isolate)); CHECK(key_list_prev().IsWeakCell() || key_list_prev().IsUndefined(isolate)); @@ -1449,6 +1250,7 @@ void JSRegExp::JSRegExpVerify(Isolate* isolate) { CHECK(arr.get(JSRegExp::kIrregexpCaptureCountIndex).IsSmi()); CHECK(arr.get(JSRegExp::kIrregexpMaxRegisterCountIndex).IsSmi()); CHECK(arr.get(JSRegExp::kIrregexpTicksUntilTierUpIndex).IsSmi()); + CHECK(arr.get(JSRegExp::kIrregexpBacktrackLimit).IsSmi()); break; } default: @@ -1509,8 +1311,8 @@ void AsyncGeneratorRequest::AsyncGeneratorRequestVerify(Isolate* isolate) { next().ObjectVerify(isolate); } -void BigInt::BigIntVerify(Isolate* isolate) { - CHECK(IsBigInt()); +void BigIntBase::BigIntBaseVerify(Isolate* isolate) { + TorqueGeneratedClassVerifiers::BigIntBaseVerify(*this, isolate); CHECK_GE(length(), 0); CHECK_IMPLIES(is_zero(), !sign()); // There is no -0n. } @@ -1706,7 +1508,7 @@ void AllocationSite::AllocationSiteVerify(Isolate* isolate) { CHECK(dependent_code().IsDependentCode()); CHECK(transition_info_or_boilerplate().IsSmi() || transition_info_or_boilerplate().IsJSObject()); - CHECK(nested_site().IsAllocationSite() || nested_site() == Smi::kZero); + CHECK(nested_site().IsAllocationSite() || nested_site() == Smi::zero()); } USE_TORQUE_VERIFIER(AllocationMemento) @@ -1762,6 +1564,8 @@ USE_TORQUE_VERIFIER(JSCollator) USE_TORQUE_VERIFIER(JSDateTimeFormat) +USE_TORQUE_VERIFIER(JSDisplayNames) + USE_TORQUE_VERIFIER(JSListFormat) USE_TORQUE_VERIFIER(JSLocale) diff --git a/deps/v8/src/diagnostics/objects-printer.cc b/deps/v8/src/diagnostics/objects-printer.cc index 20afb9e520..9dae2881b9 100644 --- a/deps/v8/src/diagnostics/objects-printer.cc +++ b/deps/v8/src/diagnostics/objects-printer.cc @@ -35,6 +35,7 @@ #include "src/objects/js-collection-inl.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-date-time-format-inl.h" +#include "src/objects/js-display-names-inl.h" #endif // V8_INTL_SUPPORT #include "src/objects/js-generator-inl.h" #ifdef V8_INTL_SUPPORT @@ -57,6 +58,7 @@ #include "src/objects/module-inl.h" #include "src/objects/oddball-inl.h" #include "src/objects/promise-inl.h" +#include "src/objects/property-descriptor-object-inl.h" #include "src/objects/stack-frame-info-inl.h" #include "src/objects/struct-inl.h" #include "src/objects/template-objects-inl.h" @@ -120,26 +122,6 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT } switch (instance_type) { - case SYMBOL_TYPE: - Symbol::cast(*this).SymbolPrint(os); - break; - case MAP_TYPE: - Map::cast(*this).MapPrint(os); - break; - case HEAP_NUMBER_TYPE: - HeapNumber::cast(*this).HeapNumberPrint(os); - os << "\n"; - break; - case BIGINT_TYPE: - BigInt::cast(*this).BigIntPrint(os); - os << "\n"; - break; - case EMBEDDER_DATA_ARRAY_TYPE: - EmbedderDataArray::cast(*this).EmbedderDataArrayPrint(os); - break; - case FIXED_DOUBLE_ARRAY_TYPE: - FixedDoubleArray::cast(*this).FixedDoubleArrayPrint(os); - break; case FIXED_ARRAY_TYPE: FixedArray::cast(*this).FixedArrayPrint(os); break; @@ -180,33 +162,12 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT ObjectBoilerplateDescription::cast(*this) .ObjectBoilerplateDescriptionPrint(os); break; - case PROPERTY_ARRAY_TYPE: - PropertyArray::cast(*this).PropertyArrayPrint(os); - break; - case BYTE_ARRAY_TYPE: - ByteArray::cast(*this).ByteArrayPrint(os); - break; - case BYTECODE_ARRAY_TYPE: - BytecodeArray::cast(*this).BytecodeArrayPrint(os); - break; - case DESCRIPTOR_ARRAY_TYPE: - DescriptorArray::cast(*this).DescriptorArrayPrint(os); - break; case TRANSITION_ARRAY_TYPE: TransitionArray::cast(*this).TransitionArrayPrint(os); break; - case FEEDBACK_CELL_TYPE: - FeedbackCell::cast(*this).FeedbackCellPrint(os); - break; case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE: ClosureFeedbackCellArray::cast(*this).ClosureFeedbackCellArrayPrint(os); break; - case FEEDBACK_VECTOR_TYPE: - FeedbackVector::cast(*this).FeedbackVectorPrint(os); - break; - case FREE_SPACE_TYPE: - FreeSpace::cast(*this).FreeSpacePrint(os); - break; case FILLER_TYPE: os << "filler"; @@ -215,80 +176,21 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT case JS_API_OBJECT_TYPE: case JS_SPECIAL_API_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE: - case JS_ARGUMENTS_OBJECT_TYPE: case JS_ERROR_TYPE: - // TODO(titzer): debug printing for more wasm objects - case WASM_EXCEPTION_OBJECT_TYPE: JSObject::cast(*this).JSObjectPrint(os); break; - case WASM_MODULE_OBJECT_TYPE: - WasmModuleObject::cast(*this).WasmModuleObjectPrint(os); - break; - case WASM_MEMORY_OBJECT_TYPE: - WasmMemoryObject::cast(*this).WasmMemoryObjectPrint(os); - break; - case WASM_TABLE_OBJECT_TYPE: - WasmTableObject::cast(*this).WasmTableObjectPrint(os); - break; - case WASM_GLOBAL_OBJECT_TYPE: - WasmGlobalObject::cast(*this).WasmGlobalObjectPrint(os); - break; case WASM_INSTANCE_OBJECT_TYPE: WasmInstanceObject::cast(*this).WasmInstanceObjectPrint(os); break; - case JS_ASYNC_FUNCTION_OBJECT_TYPE: - case JS_ASYNC_GENERATOR_OBJECT_TYPE: case JS_GENERATOR_OBJECT_TYPE: JSGeneratorObject::cast(*this).JSGeneratorObjectPrint(os); break; - case JS_PROMISE_TYPE: - JSPromise::cast(*this).JSPromisePrint(os); - break; - case JS_ARRAY_TYPE: - JSArray::cast(*this).JSArrayPrint(os); - break; - case JS_REG_EXP_TYPE: - JSRegExp::cast(*this).JSRegExpPrint(os); - break; - case JS_REG_EXP_STRING_ITERATOR_TYPE: - JSRegExpStringIterator::cast(*this).JSRegExpStringIteratorPrint(os); - break; - case ODDBALL_TYPE: - Oddball::cast(*this).to_string().Print(os); - break; - case JS_BOUND_FUNCTION_TYPE: - JSBoundFunction::cast(*this).JSBoundFunctionPrint(os); - break; - case JS_FUNCTION_TYPE: - JSFunction::cast(*this).JSFunctionPrint(os); - break; - case JS_GLOBAL_PROXY_TYPE: - JSGlobalProxy::cast(*this).JSGlobalProxyPrint(os); - break; - case JS_GLOBAL_OBJECT_TYPE: - JSGlobalObject::cast(*this).JSGlobalObjectPrint(os); - break; - case JS_PRIMITIVE_WRAPPER_TYPE: - JSPrimitiveWrapper::cast(*this).JSPrimitiveWrapperPrint(os); - break; - case JS_DATE_TYPE: - JSDate::cast(*this).JSDatePrint(os); - break; case CODE_TYPE: Code::cast(*this).CodePrint(os); break; case CODE_DATA_CONTAINER_TYPE: CodeDataContainer::cast(*this).CodeDataContainerPrint(os); break; - case JS_PROXY_TYPE: - JSProxy::cast(*this).JSProxyPrint(os); - break; - case JS_SET_TYPE: - JSSet::cast(*this).JSSetPrint(os); - break; - case JS_MAP_TYPE: - JSMap::cast(*this).JSMapPrint(os); - break; case JS_SET_KEY_VALUE_ITERATOR_TYPE: case JS_SET_VALUE_ITERATOR_TYPE: JSSetIterator::cast(*this).JSSetIteratorPrint(os); @@ -298,107 +200,14 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT case JS_MAP_VALUE_ITERATOR_TYPE: JSMapIterator::cast(*this).JSMapIteratorPrint(os); break; - case WEAK_CELL_TYPE: - WeakCell::cast(*this).WeakCellPrint(os); - break; - case JS_WEAK_REF_TYPE: - JSWeakRef::cast(*this).JSWeakRefPrint(os); - break; - case JS_FINALIZATION_GROUP_TYPE: - JSFinalizationGroup::cast(*this).JSFinalizationGroupPrint(os); - break; - case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE: - JSFinalizationGroupCleanupIterator::cast(*this) - .JSFinalizationGroupCleanupIteratorPrint(os); - break; - case JS_WEAK_MAP_TYPE: - JSWeakMap::cast(*this).JSWeakMapPrint(os); - break; - case JS_WEAK_SET_TYPE: - JSWeakSet::cast(*this).JSWeakSetPrint(os); - break; - case JS_MODULE_NAMESPACE_TYPE: - JSModuleNamespace::cast(*this).JSModuleNamespacePrint(os); - break; - case FOREIGN_TYPE: - Foreign::cast(*this).ForeignPrint(os); - break; - case CALL_HANDLER_INFO_TYPE: - CallHandlerInfo::cast(*this).CallHandlerInfoPrint(os); - break; - case PREPARSE_DATA_TYPE: - PreparseData::cast(*this).PreparseDataPrint(os); - break; - case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: - UncompiledDataWithoutPreparseData::cast(*this) - .UncompiledDataWithoutPreparseDataPrint(os); - break; - case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: - UncompiledDataWithPreparseData::cast(*this) - .UncompiledDataWithPreparseDataPrint(os); - break; - case SHARED_FUNCTION_INFO_TYPE: - SharedFunctionInfo::cast(*this).SharedFunctionInfoPrint(os); - break; - case JS_MESSAGE_OBJECT_TYPE: - JSMessageObject::cast(*this).JSMessageObjectPrint(os); - break; - case CELL_TYPE: - Cell::cast(*this).CellPrint(os); - break; - case PROPERTY_CELL_TYPE: - PropertyCell::cast(*this).PropertyCellPrint(os); - break; - case JS_ARRAY_BUFFER_TYPE: - JSArrayBuffer::cast(*this).JSArrayBufferPrint(os); - break; - case JS_ARRAY_ITERATOR_TYPE: - JSArrayIterator::cast(*this).JSArrayIteratorPrint(os); - break; - case JS_TYPED_ARRAY_TYPE: - JSTypedArray::cast(*this).JSTypedArrayPrint(os); - break; - case JS_DATA_VIEW_TYPE: - JSDataView::cast(*this).JSDataViewPrint(os); - break; -#ifdef V8_INTL_SUPPORT - case JS_V8_BREAK_ITERATOR_TYPE: - JSV8BreakIterator::cast(*this).JSV8BreakIteratorPrint(os); - break; - case JS_COLLATOR_TYPE: - JSCollator::cast(*this).JSCollatorPrint(os); - break; - case JS_DATE_TIME_FORMAT_TYPE: - JSDateTimeFormat::cast(*this).JSDateTimeFormatPrint(os); - break; - case JS_LIST_FORMAT_TYPE: - JSListFormat::cast(*this).JSListFormatPrint(os); - break; - case JS_LOCALE_TYPE: - JSLocale::cast(*this).JSLocalePrint(os); - break; - case JS_NUMBER_FORMAT_TYPE: - JSNumberFormat::cast(*this).JSNumberFormatPrint(os); - break; - case JS_PLURAL_RULES_TYPE: - JSPluralRules::cast(*this).JSPluralRulesPrint(os); - break; - case JS_RELATIVE_TIME_FORMAT_TYPE: - JSRelativeTimeFormat::cast(*this).JSRelativeTimeFormatPrint(os); - break; - case JS_SEGMENT_ITERATOR_TYPE: - JSSegmentIterator::cast(*this).JSSegmentIteratorPrint(os); - break; - case JS_SEGMENTER_TYPE: - JSSegmenter::cast(*this).JSSegmenterPrint(os); - break; -#endif // V8_INTL_SUPPORT -#define MAKE_STRUCT_CASE(TYPE, Name, name) \ - case TYPE: \ - Name::cast(*this).Name##Print(os); \ +#define MAKE_TORQUE_CASE(Name, TYPE) \ + case TYPE: \ + Name::cast(*this).Name##Print(os); \ break; - STRUCT_LIST(MAKE_STRUCT_CASE) -#undef MAKE_STRUCT_CASE + // Every class that has its fields defined in a .tq file and corresponds + // to exactly one InstanceType value is included in the following list. + TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE) +#undef MAKE_TORQUE_CASE case ALLOCATION_SITE_TYPE: AllocationSite::cast(*this).AllocationSitePrint(os); @@ -412,21 +221,12 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT case SCOPE_INFO_TYPE: ScopeInfo::cast(*this).ScopeInfoPrint(os); break; - case SOURCE_TEXT_MODULE_TYPE: - SourceTextModule::cast(*this).SourceTextModulePrint(os); - break; - case SYNTHETIC_MODULE_TYPE: - SyntheticModule::cast(*this).SyntheticModulePrint(os); - break; case FEEDBACK_METADATA_TYPE: FeedbackMetadata::cast(*this).FeedbackMetadataPrint(os); break; case WEAK_FIXED_ARRAY_TYPE: WeakFixedArray::cast(*this).WeakFixedArrayPrint(os); break; - case WEAK_ARRAY_LIST_TYPE: - WeakArrayList::cast(*this).WeakArrayListPrint(os); - break; case INTERNALIZED_STRING_TYPE: case EXTERNAL_INTERNALIZED_STRING_TYPE: case ONE_BYTE_INTERNALIZED_STRING_TYPE: @@ -445,11 +245,6 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT case THIN_ONE_BYTE_STRING_TYPE: case UNCACHED_EXTERNAL_STRING_TYPE: case UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE: - case SMALL_ORDERED_HASH_MAP_TYPE: - case SMALL_ORDERED_HASH_SET_TYPE: - case SMALL_ORDERED_NAME_DICTIONARY_TYPE: - case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: - case JS_STRING_ITERATOR_TYPE: // TODO(all): Handle these types too. os << "UNKNOWN TYPE " << map().instance_type(); UNREACHABLE(); @@ -477,8 +272,7 @@ bool JSObject::PrintProperties(std::ostream& os) { // NOLINT if (HasFastProperties()) { DescriptorArray descs = map().instance_descriptors(); int nof_inobject_properties = map().GetInObjectProperties(); - for (InternalIndex i : - InternalIndex::Range(map().NumberOfOwnDescriptors())) { + for (InternalIndex i : map().IterateOwnDescriptors()) { os << "\n "; descs.GetKey(i).NamePrint(os); os << ": "; @@ -570,9 +364,15 @@ void DoPrintElements(std::ostream& os, Object object, int length) { // NOLINT template <typename ElementType> void PrintTypedArrayElements(std::ostream& os, const ElementType* data_ptr, - size_t length) { + size_t length, bool is_on_heap) { if (length == 0) return; size_t previous_index = 0; + if (i::FLAG_mock_arraybuffer_allocator && !is_on_heap) { + // Don't try to print data that's not actually allocated. + os << "\n 0-" << length << ": <mocked array buffer bytes>"; + return; + } + ElementType previous_value = data_ptr[0]; ElementType value = 0; for (size_t i = 1; i <= length; i++) { @@ -586,7 +386,7 @@ void PrintTypedArrayElements(std::ostream& os, const ElementType* data_ptr, if (previous_index != i - 1) { ss << '-' << (i - 1); } - os << std::setw(12) << ss.str() << ": " << previous_value; + os << std::setw(12) << ss.str() << ": " << +previous_value; previous_index = i; previous_value = value; } @@ -696,9 +496,10 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT #define PRINT_ELEMENTS(Type, type, TYPE, elementType) \ case TYPE##_ELEMENTS: { \ size_t length = JSTypedArray::cast(*this).length(); \ + bool is_on_heap = JSTypedArray::cast(*this).is_on_heap(); \ const elementType* data_ptr = \ static_cast<const elementType*>(JSTypedArray::cast(*this).DataPtr()); \ - PrintTypedArrayElements<elementType>(os, data_ptr, length); \ + PrintTypedArrayElements<elementType>(os, data_ptr, length, is_on_heap); \ break; \ } TYPED_ARRAYS(PRINT_ELEMENTS) @@ -852,6 +653,7 @@ void JSPromise::JSPromisePrint(std::ostream& os) { // NOLINT os << "\n - result: " << Brief(result()); } os << "\n - has_handler: " << has_handler(); + os << "\n - handled_hint: " << handled_hint(); JSObjectPrintBody(os, *this); } @@ -876,8 +678,8 @@ void JSRegExpStringIterator::JSRegExpStringIteratorPrint( void Symbol::SymbolPrint(std::ostream& os) { // NOLINT PrintHeader(os, "Symbol"); os << "\n - hash: " << Hash(); - os << "\n - name: " << Brief(name()); - if (name().IsUndefined()) { + os << "\n - description: " << Brief(description()); + if (description().IsUndefined()) { os << " (" << PrivateSymbolToName() << ")"; } os << "\n - private: " << is_private(); @@ -926,9 +728,9 @@ void PrintHashTableWithHeader(std::ostream& os, T table, const char* type) { os << "\n - capacity: " << table.Capacity(); os << "\n - elements: {"; - for (int i = 0; i < table.Capacity(); i++) { + for (InternalIndex i : table.IterateEntries()) { os << '\n' - << std::setw(12) << i << ": " << Brief(table.KeyAt(i)) << " -> " + << std::setw(12) << i.as_int() << ": " << Brief(table.KeyAt(i)) << " -> " << Brief(table.ValueAt(i)); } os << "\n }\n"; @@ -984,7 +786,6 @@ void PrintContextWithHeader(std::ostream& os, Context context, os << "\n - length: " << context.length(); os << "\n - scope_info: " << Brief(context.scope_info()); os << "\n - previous: " << Brief(context.unchecked_previous()); - os << "\n - extension: " << Brief(context.extension()); os << "\n - native_context: " << Brief(context.native_context()); PrintFixedArrayElements(os, context); os << "\n"; @@ -1197,6 +998,39 @@ void FeedbackNexus::Print(std::ostream& os) { // NOLINT } } +void Oddball::OddballPrint(std::ostream& os) { // NOLINT + to_string().Print(os); +} + +void JSAsyncFunctionObject::JSAsyncFunctionObjectPrint( + std::ostream& os) { // NOLINT + JSGeneratorObjectPrint(os); +} + +void JSAsyncGeneratorObject::JSAsyncGeneratorObjectPrint( + std::ostream& os) { // NOLINT + JSGeneratorObjectPrint(os); +} + +void JSArgumentsObject::JSArgumentsObjectPrint(std::ostream& os) { // NOLINT + JSObjectPrint(os); +} + +void JSStringIterator::JSStringIteratorPrint(std::ostream& os) { // NOLINT + JSObjectPrintHeader(os, *this, "JSStringIterator"); + os << "\n - string: " << Brief(string()); + os << "\n - index: " << index(); + JSObjectPrintBody(os, *this); +} + +void JSAsyncFromSyncIterator::JSAsyncFromSyncIteratorPrint( + std::ostream& os) { // NOLINT + JSObjectPrintHeader(os, *this, "JSAsyncFromSyncIterator"); + os << "\n - sync_iterator: " << Brief(sync_iterator()); + os << "\n - next: " << Brief(next()); + JSObjectPrintBody(os, *this); +} + void JSPrimitiveWrapper::JSPrimitiveWrapperPrint(std::ostream& os) { // NOLINT JSObjectPrintHeader(os, *this, "JSPrimitiveWrapper"); os << "\n - value: " << Brief(value()); @@ -1321,7 +1155,7 @@ void WeakCell::WeakCellPrint(std::ostream& os) { os << "\n - holdings: " << Brief(holdings()); os << "\n - prev: " << Brief(prev()); os << "\n - next: " << Brief(next()); - os << "\n - key: " << Brief(key()); + os << "\n - unregister_token: " << Brief(unregister_token()); os << "\n - key_list_prev: " << Brief(key_list_prev()); os << "\n - key_list_next: " << Brief(key_list_next()); } @@ -1503,6 +1337,22 @@ void SharedFunctionInfo::PrintSourceCode(std::ostream& os) { } } +void SmallOrderedHashSet::SmallOrderedHashSetPrint(std::ostream& os) { + PrintHeader(os, "SmallOrderedHashSet"); + // TODO(tebbi): Print all fields. +} + +void SmallOrderedHashMap::SmallOrderedHashMapPrint(std::ostream& os) { + PrintHeader(os, "SmallOrderedHashMap"); + // TODO(tebbi): Print all fields. +} + +void SmallOrderedNameDictionary::SmallOrderedNameDictionaryPrint( + std::ostream& os) { + PrintHeader(os, "SmallOrderedNameDictionary"); + // TODO(tebbi): Print all fields. +} + void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT PrintHeader(os, "SharedFunctionInfo"); os << "\n - name: "; @@ -1529,9 +1379,8 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT os << "\n - data: " << Brief(function_data()); os << "\n - code (from data): " << Brief(GetCode()); PrintSourceCode(os); - // Script files are often large, hard to read. - // os << "\n - script ="; - // script()->Print(os); + // Script files are often large, thus only print their {Brief} representation. + os << "\n - script: " << Brief(script()); os << "\n - function token position: " << function_token_position(); os << "\n - start position: " << StartPosition(); os << "\n - end position: " << EndPosition(); @@ -1824,7 +1673,6 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) { // NOLINT PrintHeader(os, "AsmWasmData"); os << "\n - native module: " << Brief(managed_native_module()); os << "\n - export_wrappers: " << Brief(export_wrappers()); - os << "\n - offset table: " << Brief(asm_js_offset_table()); os << "\n - uses bitset: " << uses_bitset().value(); os << "\n"; } @@ -1913,9 +1761,6 @@ void WasmModuleObject::WasmModuleObjectPrint(std::ostream& os) { // NOLINT os << "\n - native module: " << native_module(); os << "\n - export wrappers: " << Brief(export_wrappers()); os << "\n - script: " << Brief(script()); - if (has_asm_js_offset_table()) { - os << "\n - asm_js_offset_table: " << Brief(asm_js_offset_table()); - } os << "\n"; } @@ -2179,6 +2024,7 @@ void JSCollator::JSCollatorPrint(std::ostream& os) { // NOLINT void JSDateTimeFormat::JSDateTimeFormatPrint(std::ostream& os) { // NOLINT JSObjectPrintHeader(os, *this, "JSDateTimeFormat"); + os << "\n - locale: " << Brief(locale()); os << "\n - icu locale: " << Brief(icu_locale()); os << "\n - icu simple date format: " << Brief(icu_simple_date_format()); os << "\n - icu date interval format: " << Brief(icu_date_interval_format()); @@ -2187,6 +2033,14 @@ void JSDateTimeFormat::JSDateTimeFormatPrint(std::ostream& os) { // NOLINT JSObjectPrintBody(os, *this); } +void JSDisplayNames::JSDisplayNamesPrint(std::ostream& os) { // NOLINT + JSObjectPrintHeader(os, *this, "JSDisplayNames"); + os << "\n - internal: " << Brief(internal()); + os << "\n - style: " << StyleAsString(); + os << "\n - fallback: " << FallbackAsString(); + JSObjectPrintBody(os, *this); +} + void JSListFormat::JSListFormatPrint(std::ostream& os) { // NOLINT JSObjectPrintHeader(os, *this, "JSListFormat"); os << "\n - locale: " << Brief(locale()); @@ -2205,6 +2059,7 @@ void JSLocale::JSLocalePrint(std::ostream& os) { // NOLINT void JSNumberFormat::JSNumberFormatPrint(std::ostream& os) { // NOLINT JSObjectPrintHeader(os, *this, "JSNumberFormat"); os << "\n - locale: " << Brief(locale()); + os << "\n - numberingSystem: " << Brief(numberingSystem()); os << "\n - icu_number_formatter: " << Brief(icu_number_formatter()); os << "\n - bound_format: " << Brief(bound_format()); JSObjectPrintBody(os, *this); @@ -2223,6 +2078,7 @@ void JSRelativeTimeFormat::JSRelativeTimeFormatPrint( std::ostream& os) { // NOLINT JSObjectPrintHeader(os, *this, "JSRelativeTimeFormat"); os << "\n - locale: " << Brief(locale()); + os << "\n - numberingSystem: " << Brief(numberingSystem()); os << "\n - style: " << StyleAsString(); os << "\n - numeric: " << NumericAsString(); os << "\n - icu formatter: " << Brief(icu_formatter()); @@ -2282,14 +2138,13 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT os << "\n - language mode: " << language_mode(); if (is_declaration_scope()) os << "\n - declaration scope"; if (HasReceiver()) { - os << "\n - receiver: " << ReceiverVariableField::decode(flags); + os << "\n - receiver: " << ReceiverVariableBits::decode(flags); } if (HasClassBrand()) os << "\n - has class brand"; if (HasSavedClassVariableIndex()) os << "\n - has saved class variable index"; if (HasNewTarget()) os << "\n - needs new target"; if (HasFunctionName()) { - os << "\n - function name(" << FunctionVariableField::decode(flags) - << "): "; + os << "\n - function name(" << FunctionVariableBits::decode(flags) << "): "; FunctionName().ShortPrint(os); } if (IsAsmModule()) os << "\n - asm module"; @@ -2298,12 +2153,18 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT if (HasOuterScopeInfo()) { os << "\n - outer scope info: " << Brief(OuterScopeInfo()); } + if (HasLocalsBlackList()) { + os << "\n - locals blacklist: " << Brief(LocalsBlackList()); + } if (HasFunctionName()) { os << "\n - function name: " << Brief(FunctionName()); } if (HasInferredFunctionName()) { os << "\n - inferred function name: " << Brief(InferredFunctionName()); } + if (HasContextExtensionSlot()) { + os << "\n - has context extension slot"; + } if (HasPositionInfo()) { os << "\n - start position: " << StartPosition(); @@ -2460,9 +2321,31 @@ void TaggedImpl<kRefType, StorageType>::Print(std::ostream& os) { } } +void HeapNumber::HeapNumberPrint(std::ostream& os) { + HeapNumberShortPrint(os); + os << "\n"; +} + #endif // OBJECT_PRINT -void HeapNumber::HeapNumberPrint(std::ostream& os) { os << value(); } +void HeapNumber::HeapNumberShortPrint(std::ostream& os) { + static constexpr uint64_t kUint64AllBitsSet = + static_cast<uint64_t>(int64_t{-1}); + // Min/max integer values representable by 52 bits of mantissa and 1 sign bit. + static constexpr int64_t kMinSafeInteger = + static_cast<int64_t>(kUint64AllBitsSet << 53); + static constexpr int64_t kMaxSafeInteger = -(kMinSafeInteger + 1); + + double val = value(); + if (val == DoubleToInteger(val) && + val >= static_cast<double>(kMinSafeInteger) && + val <= static_cast<double>(kMaxSafeInteger)) { + int64_t i = static_cast<int64_t>(val); + os << i << ".0"; + } else { + os << val; + } +} // TODO(cbruni): remove once the new maptracer is in place. void Name::NameShortPrint() { @@ -2471,10 +2354,10 @@ void Name::NameShortPrint() { } else { DCHECK(this->IsSymbol()); Symbol s = Symbol::cast(*this); - if (s.name().IsUndefined()) { + if (s.description().IsUndefined()) { PrintF("#<%s>", s.PrivateSymbolToName()); } else { - PrintF("<%s>", String::cast(s.name()).ToCString().get()); + PrintF("<%s>", String::cast(s.description()).ToCString().get()); } } } @@ -2486,10 +2369,11 @@ int Name::NameShortPrint(Vector<char> str) { } else { DCHECK(this->IsSymbol()); Symbol s = Symbol::cast(*this); - if (s.name().IsUndefined()) { + if (s.description().IsUndefined()) { return SNPrintF(str, "#<%s>", s.PrivateSymbolToName()); } else { - return SNPrintF(str, "<%s>", String::cast(s.name()).ToCString().get()); + return SNPrintF(str, "<%s>", + String::cast(s.description()).ToCString().get()); } } } @@ -2540,7 +2424,9 @@ void Map::MapPrint(std::ostream& os) { // NOLINT } if (is_access_check_needed()) os << "\n - access_check_needed"; if (!is_extensible()) os << "\n - non-extensible"; - if (is_prototype_map()) { + if (IsContextMap()) { + os << "\n - native context: " << Brief(native_context()); + } else if (is_prototype_map()) { os << "\n - prototype_map"; os << "\n - prototype info: " << Brief(prototype_info()); } else { @@ -2577,7 +2463,9 @@ void Map::MapPrint(std::ostream& os) { // NOLINT } } os << "\n - prototype: " << Brief(prototype()); - os << "\n - constructor: " << Brief(GetConstructor()); + if (!IsContextMap()) { + os << "\n - constructor: " << Brief(GetConstructor()); + } os << "\n - dependent code: " << Brief(dependent_code()); os << "\n - construction counter: " << construction_counter(); os << "\n"; @@ -2808,10 +2696,11 @@ V8_EXPORT_PRIVATE extern void _v8_internal_Print_Code(void* object) { if (!isolate->heap()->InSpaceSlow(address, i::CODE_SPACE) && !isolate->heap()->InSpaceSlow(address, i::LO_SPACE) && - !i::InstructionStream::PcIsOffHeap(isolate, address)) { + !i::InstructionStream::PcIsOffHeap(isolate, address) && + !i::ReadOnlyHeap::Contains(address)) { i::PrintF( - "%p is not within the current isolate's large object, code or embedded " - "spaces\n", + "%p is not within the current isolate's large object, code, read_only " + "or embedded spaces\n", object); return; } diff --git a/deps/v8/src/diagnostics/perf-jit.cc b/deps/v8/src/diagnostics/perf-jit.cc index d84c2e4f53..9b42d68037 100644 --- a/deps/v8/src/diagnostics/perf-jit.cc +++ b/deps/v8/src/diagnostics/perf-jit.cc @@ -27,29 +27,26 @@ #include "src/diagnostics/perf-jit.h" +// Only compile the {PerfJitLogger} on Linux. +#if V8_OS_LINUX + +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> #include <memory> #include "src/codegen/assembler.h" #include "src/codegen/source-position-table.h" #include "src/diagnostics/eh-frame.h" #include "src/objects/objects-inl.h" +#include "src/objects/shared-function-info.h" #include "src/snapshot/embedded/embedded-data.h" #include "src/utils/ostreams.h" #include "src/wasm/wasm-code-manager.h" -#if V8_OS_LINUX -#include <fcntl.h> -#include <sys/mman.h> -// jumbo: conflicts with v8::internal::InstanceType::MAP_TYPE -#undef MAP_TYPE // NOLINT -#include <unistd.h> -#endif // V8_OS_LINUX - namespace v8 { namespace internal { -#if V8_OS_LINUX - struct PerfJitHeader { uint32_t magic_; uint32_t version_; @@ -132,6 +129,11 @@ void PerfJitLogger::OpenJitDumpFile() { int fd = open(perf_dump_name.begin(), O_CREAT | O_TRUNC | O_RDWR, 0666); if (fd == -1) return; + // If --perf-prof-delete-file is given, unlink the file right after opening + // it. This keeps the file handle to the file valid. This only works on Linux, + // which is the only platform supported for --perf-prof anyway. + if (FLAG_perf_prof_delete_file) CHECK_EQ(0, unlink(perf_dump_name.begin())); + marker_address_ = OpenMarkerFile(fd); if (marker_address_ == nullptr) return; @@ -197,12 +199,13 @@ uint64_t PerfJitLogger::GetTimestamp() { return (ts.tv_sec * kNsecPerSec) + ts.tv_nsec; } -void PerfJitLogger::LogRecordedBuffer(AbstractCode abstract_code, - SharedFunctionInfo shared, - const char* name, int length) { +void PerfJitLogger::LogRecordedBuffer( + Handle<AbstractCode> abstract_code, + MaybeHandle<SharedFunctionInfo> maybe_shared, const char* name, + int length) { if (FLAG_perf_basic_prof_only_functions && - (abstract_code.kind() != AbstractCode::INTERPRETED_FUNCTION && - abstract_code.kind() != AbstractCode::OPTIMIZED_FUNCTION)) { + (abstract_code->kind() != AbstractCode::INTERPRETED_FUNCTION && + abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION)) { return; } @@ -211,28 +214,29 @@ void PerfJitLogger::LogRecordedBuffer(AbstractCode abstract_code, if (perf_output_handle_ == nullptr) return; // We only support non-interpreted functions. - if (!abstract_code.IsCode()) return; - Code code = abstract_code.GetCode(); - DCHECK(code.raw_instruction_start() == code.address() + Code::kHeaderSize); + if (!abstract_code->IsCode()) return; + Handle<Code> code = Handle<Code>::cast(abstract_code); + DCHECK(code->raw_instruction_start() == code->address() + Code::kHeaderSize); // Debug info has to be emitted first. - if (FLAG_perf_prof && !shared.is_null()) { + Handle<SharedFunctionInfo> shared; + if (FLAG_perf_prof && !maybe_shared.ToHandle(&shared)) { // TODO(herhut): This currently breaks for js2wasm/wasm2js functions. - if (code.kind() != Code::JS_TO_WASM_FUNCTION && - code.kind() != Code::WASM_TO_JS_FUNCTION) { + if (code->kind() != Code::JS_TO_WASM_FUNCTION && + code->kind() != Code::WASM_TO_JS_FUNCTION) { LogWriteDebugInfo(code, shared); } } const char* code_name = name; - uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code.InstructionStart()); + uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->InstructionStart()); // Code generated by Turbofan will have the safepoint table directly after // instructions. There is no need to record the safepoint table itself. - uint32_t code_size = code.ExecutableInstructionSize(); + uint32_t code_size = code->ExecutableInstructionSize(); // Unwinding info comes right after debug info. - if (FLAG_perf_prof_unwinding_info) LogWriteUnwindingInfo(code); + if (FLAG_perf_prof_unwinding_info) LogWriteUnwindingInfo(*code); WriteJitCodeLoadEntry(code_pointer, code_size, code_name, length); } @@ -328,24 +332,24 @@ SourcePositionInfo GetSourcePositionInfo(Handle<Code> code, } // namespace -void PerfJitLogger::LogWriteDebugInfo(Code code, SharedFunctionInfo shared) { +void PerfJitLogger::LogWriteDebugInfo(Handle<Code> code, + Handle<SharedFunctionInfo> shared) { // Compute the entry count and get the name of the script. uint32_t entry_count = 0; - for (SourcePositionTableIterator iterator(code.SourcePositionTable()); + for (SourcePositionTableIterator iterator(code->SourcePositionTable()); !iterator.done(); iterator.Advance()) { entry_count++; } if (entry_count == 0) return; // The WasmToJS wrapper stubs have source position entries. - if (!shared.HasSourceCode()) return; - Isolate* isolate = shared.GetIsolate(); - Handle<Script> script(Script::cast(shared.script()), isolate); + if (!shared->HasSourceCode()) return; + Handle<Script> script(Script::cast(shared->script()), isolate_); PerfJitCodeDebugInfo debug_info; debug_info.event_ = PerfJitCodeLoad::kDebugInfo; debug_info.time_stamp_ = GetTimestamp(); - debug_info.address_ = code.InstructionStart(); + debug_info.address_ = code->InstructionStart(); debug_info.entry_count_ = entry_count; uint32_t size = sizeof(debug_info); @@ -353,12 +357,10 @@ void PerfJitLogger::LogWriteDebugInfo(Code code, SharedFunctionInfo shared) { size += entry_count * sizeof(PerfJitDebugEntry); // Add the size of the name after each entry. - Handle<Code> code_handle(code, isolate); - Handle<SharedFunctionInfo> function_handle(shared, isolate); - for (SourcePositionTableIterator iterator(code.SourcePositionTable()); + for (SourcePositionTableIterator iterator(code->SourcePositionTable()); !iterator.done(); iterator.Advance()) { - SourcePositionInfo info(GetSourcePositionInfo(code_handle, function_handle, - iterator.source_position())); + SourcePositionInfo info( + GetSourcePositionInfo(code, shared, iterator.source_position())); size += GetScriptNameLength(info) + 1; } @@ -366,12 +368,12 @@ void PerfJitLogger::LogWriteDebugInfo(Code code, SharedFunctionInfo shared) { debug_info.size_ = size + padding; LogWriteBytes(reinterpret_cast<const char*>(&debug_info), sizeof(debug_info)); - Address code_start = code.InstructionStart(); + Address code_start = code->InstructionStart(); - for (SourcePositionTableIterator iterator(code.SourcePositionTable()); + for (SourcePositionTableIterator iterator(code->SourcePositionTable()); !iterator.done(); iterator.Advance()) { - SourcePositionInfo info(GetSourcePositionInfo(code_handle, function_handle, - iterator.source_position())); + SourcePositionInfo info( + GetSourcePositionInfo(code, shared, iterator.source_position())); PerfJitDebugEntry entry; // The entry point of the function will be placed straight after the ELF // header when processed by "perf inject". Adjust the position addresses @@ -523,6 +525,7 @@ void PerfJitLogger::LogWriteHeader() { LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); } -#endif // V8_OS_LINUX } // namespace internal } // namespace v8 + +#endif // V8_OS_LINUX diff --git a/deps/v8/src/diagnostics/perf-jit.h b/deps/v8/src/diagnostics/perf-jit.h index 36ab844110..2192063508 100644 --- a/deps/v8/src/diagnostics/perf-jit.h +++ b/deps/v8/src/diagnostics/perf-jit.h @@ -28,22 +28,25 @@ #ifndef V8_DIAGNOSTICS_PERF_JIT_H_ #define V8_DIAGNOSTICS_PERF_JIT_H_ +#include "include/v8config.h" + +// {PerfJitLogger} is only implemented on Linux. +#if V8_OS_LINUX + #include "src/logging/log.h" namespace v8 { namespace internal { -#if V8_OS_LINUX - -// Linux perf tool logging support +// Linux perf tool logging support. class PerfJitLogger : public CodeEventLogger { public: explicit PerfJitLogger(Isolate* isolate); ~PerfJitLogger() override; void CodeMoveEvent(AbstractCode from, AbstractCode to) override; - void CodeDisableOptEvent(AbstractCode code, - SharedFunctionInfo shared) override {} + void CodeDisableOptEvent(Handle<AbstractCode> code, + Handle<SharedFunctionInfo> shared) override {} private: void OpenJitDumpFile(); @@ -52,7 +55,8 @@ class PerfJitLogger : public CodeEventLogger { void CloseMarkerFile(void* marker_address); uint64_t GetTimestamp(); - void LogRecordedBuffer(AbstractCode code, SharedFunctionInfo shared, + void LogRecordedBuffer(Handle<AbstractCode> code, + MaybeHandle<SharedFunctionInfo> maybe_shared, const char* name, int length) override; void LogRecordedBuffer(const wasm::WasmCode* code, const char* name, int length) override; @@ -70,7 +74,7 @@ class PerfJitLogger : public CodeEventLogger { void LogWriteBytes(const char* bytes, int size); void LogWriteHeader(); - void LogWriteDebugInfo(Code code, SharedFunctionInfo shared); + void LogWriteDebugInfo(Handle<Code> code, Handle<SharedFunctionInfo> shared); void LogWriteDebugInfo(const wasm::WasmCode* code); void LogWriteUnwindingInfo(Code code); @@ -79,6 +83,8 @@ class PerfJitLogger : public CodeEventLogger { static const uint32_t kElfMachARM = 40; static const uint32_t kElfMachMIPS = 10; static const uint32_t kElfMachARM64 = 183; + static const uint32_t kElfMachS390x = 22; + static const uint32_t kElfMachPPC64 = 21; uint32_t GetElfMach() { #if V8_TARGET_ARCH_IA32 @@ -91,6 +97,10 @@ class PerfJitLogger : public CodeEventLogger { return kElfMachMIPS; #elif V8_TARGET_ARCH_ARM64 return kElfMachARM64; +#elif V8_TARGET_ARCH_S390X + return kElfMachS390x; +#elif V8_TARGET_ARCH_PPC64 + return kElfMachPPC64; #else UNIMPLEMENTED(); return 0; @@ -114,35 +124,9 @@ class PerfJitLogger : public CodeEventLogger { static uint64_t code_index_; }; -#else - -// PerfJitLogger is only implemented on Linux -class PerfJitLogger : public CodeEventLogger { - public: - explicit PerfJitLogger(Isolate* isolate) : CodeEventLogger(isolate) {} - - void CodeMoveEvent(AbstractCode from, AbstractCode to) override { - UNIMPLEMENTED(); - } - - void CodeDisableOptEvent(AbstractCode code, - SharedFunctionInfo shared) override { - UNIMPLEMENTED(); - } - - void LogRecordedBuffer(AbstractCode code, SharedFunctionInfo shared, - const char* name, int length) override { - UNIMPLEMENTED(); - } - - void LogRecordedBuffer(const wasm::WasmCode* code, const char* name, - int length) override { - UNIMPLEMENTED(); - } -}; - -#endif // V8_OS_LINUX } // namespace internal } // namespace v8 +#endif // V8_OS_LINUX + #endif // V8_DIAGNOSTICS_PERF_JIT_H_ diff --git a/deps/v8/src/diagnostics/ppc/eh-frame-ppc.cc b/deps/v8/src/diagnostics/ppc/eh-frame-ppc.cc new file mode 100644 index 0000000000..148d01116d --- /dev/null +++ b/deps/v8/src/diagnostics/ppc/eh-frame-ppc.cc @@ -0,0 +1,57 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/codegen/ppc/constants-ppc.h" +#include "src/diagnostics/eh-frame.h" + +namespace v8 { +namespace internal { + +const int EhFrameConstants::kCodeAlignmentFactor = 4; +// all PPC are 4 bytes instruction +const int EhFrameConstants::kDataAlignmentFactor = -8; // 64-bit always -8 + +void EhFrameWriter::WriteReturnAddressRegisterCode() { + WriteULeb128(kLrDwarfCode); +} + +void EhFrameWriter::WriteInitialStateInCie() { + SetBaseAddressRegisterAndOffset(fp, 0); + RecordRegisterNotModified(kLrDwarfCode); +} + +// static +int EhFrameWriter::RegisterToDwarfCode(Register name) { + switch (name.code()) { + case kRegCode_fp: + return kFpDwarfCode; + case kRegCode_sp: + return kSpDwarfCode; + case kRegCode_r0: + return kR0DwarfCode; + default: + UNIMPLEMENTED(); + return -1; + } +} + +#ifdef ENABLE_DISASSEMBLER + +// static +const char* EhFrameDisassembler::DwarfRegisterCodeToString(int code) { + switch (code) { + case kFpDwarfCode: + return "fp"; + case kSpDwarfCode: + return "sp"; + default: + UNIMPLEMENTED(); + return nullptr; + } +} + +#endif + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/diagnostics/s390/disasm-s390.cc b/deps/v8/src/diagnostics/s390/disasm-s390.cc index 9b10e236ce..5bb771fc37 100644 --- a/deps/v8/src/diagnostics/s390/disasm-s390.cc +++ b/deps/v8/src/diagnostics/s390/disasm-s390.cc @@ -827,6 +827,13 @@ bool Decoder::DecodeGeneric(Instruction* instr) { S390_VRR_E_OPCODE_LIST(DECODE_VRR_E_INSTRUCTIONS) #undef DECODE_VRR_E_INSTRUCTIONS +#define DECODE_VRR_F_INSTRUCTIONS(name, opcode_name, opcode_value) \ + case opcode_name: \ + Format(instr, #name "\t'f1,'r1,'r2"); \ + break; + S390_VRR_F_OPCODE_LIST(DECODE_VRR_F_INSTRUCTIONS) +#undef DECODE_VRR_F_INSTRUCTIONS + #define DECODE_VRX_INSTRUCTIONS(name, opcode_name, opcode_value) \ case opcode_name: \ Format(instr, #name "\t'f1,'d1('r2d,'r3),'m4"); \ diff --git a/deps/v8/src/diagnostics/s390/eh-frame-s390.cc b/deps/v8/src/diagnostics/s390/eh-frame-s390.cc new file mode 100644 index 0000000000..4f5994c8da --- /dev/null +++ b/deps/v8/src/diagnostics/s390/eh-frame-s390.cc @@ -0,0 +1,65 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/codegen/s390/assembler-s390-inl.h" +#include "src/diagnostics/eh-frame.h" + +namespace v8 { +namespace internal { + +static const int kR0DwarfCode = 0; +static const int kFpDwarfCode = 11; // frame-pointer +static const int kR14DwarfCode = 14; // return-address(lr) +static const int kSpDwarfCode = 15; // stack-pointer + +const int EhFrameConstants::kCodeAlignmentFactor = 2; // 1 or 2 in s390 +const int EhFrameConstants::kDataAlignmentFactor = -8; + +void EhFrameWriter::WriteReturnAddressRegisterCode() { + WriteULeb128(kR14DwarfCode); +} + +void EhFrameWriter::WriteInitialStateInCie() { + SetBaseAddressRegisterAndOffset(fp, 0); + RecordRegisterNotModified(r14); +} + +// static +int EhFrameWriter::RegisterToDwarfCode(Register name) { + switch (name.code()) { + case kRegCode_fp: + return kFpDwarfCode; + case kRegCode_r14: + return kR14DwarfCode; + case kRegCode_sp: + return kSpDwarfCode; + case kRegCode_r0: + return kR0DwarfCode; + default: + UNIMPLEMENTED(); + return -1; + } +} + +#ifdef ENABLE_DISASSEMBLER + +// static +const char* EhFrameDisassembler::DwarfRegisterCodeToString(int code) { + switch (code) { + case kFpDwarfCode: + return "fp"; + case kR14DwarfCode: + return "lr"; + case kSpDwarfCode: + return "sp"; + default: + UNIMPLEMENTED(); + return nullptr; + } +} + +#endif + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/diagnostics/unwinder.cc b/deps/v8/src/diagnostics/unwinder.cc index 84097c288f..64adf17b82 100644 --- a/deps/v8/src/diagnostics/unwinder.cc +++ b/deps/v8/src/diagnostics/unwinder.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> + #include "include/v8.h" #include "src/common/globals.h" #include "src/execution/frame-constants.h" @@ -10,17 +12,62 @@ namespace v8 { namespace { -bool PCIsInCodeRange(const v8::MemoryRange& code_range, void* pc) { +const i::byte* CalculateEnd(const void* start, size_t length_in_bytes) { // Given that the length of the memory range is in bytes and it is not // necessarily aligned, we need to do the pointer arithmetic in byte* here. - const i::byte* pc_as_byte = reinterpret_cast<i::byte*>(pc); - const i::byte* start = reinterpret_cast<const i::byte*>(code_range.start); - const i::byte* end = start + code_range.length_in_bytes; - return pc_as_byte >= start && pc_as_byte < end; + const i::byte* start_as_byte = reinterpret_cast<const i::byte*>(start); + return start_as_byte + length_in_bytes; +} + +bool PCIsInCodeRange(const v8::MemoryRange& code_range, void* pc) { + return pc >= code_range.start && + pc < CalculateEnd(code_range.start, code_range.length_in_bytes); +} + +// This relies on the fact that the code pages are ordered, and that they don't +// overlap. +bool PCIsInCodePages(size_t code_pages_length, const MemoryRange* code_pages, + void* pc) { + DCHECK(std::is_sorted(code_pages, code_pages + code_pages_length, + [](const MemoryRange& a, const MemoryRange& b) { + return a.start < b.start; + })); + + MemoryRange fake_range{pc, 1}; + auto it = + std::upper_bound(code_pages, code_pages + code_pages_length, fake_range, + [](const MemoryRange& a, const MemoryRange& b) { + return a.start < b.start; + }); + DCHECK_IMPLIES(it != code_pages + code_pages_length, pc < it->start); + if (it == code_pages) return false; + --it; + return it->start <= pc && pc < CalculateEnd(it->start, it->length_in_bytes); +} + +bool IsInJSEntryRange(const UnwindState& unwind_state, void* pc) { + return PCIsInCodeRange(unwind_state.js_entry_stub.code, pc) || + PCIsInCodeRange(unwind_state.js_construct_entry_stub.code, pc) || + PCIsInCodeRange(unwind_state.js_run_microtasks_entry_stub.code, pc); } -bool IsInUnsafeJSEntryRange(const v8::JSEntryStub& js_entry_stub, void* pc) { - return PCIsInCodeRange(js_entry_stub.code, pc); +bool IsInUnsafeJSEntryRange(const UnwindState& unwind_state, void* pc) { + return IsInJSEntryRange(unwind_state, pc); + + // TODO(petermarshall): We can be more precise by checking whether we are + // in JSEntry but after frame setup and before frame teardown, in which case + // we are safe to unwind the stack. For now, we bail out if the PC is anywhere + // within JSEntry. +} + +bool IsInJSEntryRange(const JSEntryStubs& entry_stubs, void* pc) { + return PCIsInCodeRange(entry_stubs.js_entry_stub.code, pc) || + PCIsInCodeRange(entry_stubs.js_construct_entry_stub.code, pc) || + PCIsInCodeRange(entry_stubs.js_run_microtasks_entry_stub.code, pc); +} + +bool IsInUnsafeJSEntryRange(const JSEntryStubs& entry_stubs, void* pc) { + return IsInJSEntryRange(entry_stubs, pc); // TODO(petermarshall): We can be more precise by checking whether we are // in JSEntry but after frame setup and before frame teardown, in which case @@ -32,21 +79,74 @@ i::Address Load(i::Address address) { return *reinterpret_cast<i::Address*>(address); } -void* GetReturnAddressFromFP(void* fp) { +void* GetReturnAddressFromFP(void* fp, void* pc, + const v8::UnwindState& unwind_state) { + int caller_pc_offset = i::CommonFrameConstants::kCallerPCOffset; +#ifdef V8_TARGET_ARCH_ARM64 + if (IsInJSEntryRange(unwind_state, pc)) { + caller_pc_offset = i::EntryFrameConstants::kDirectCallerPCOffset; + } +#endif + return reinterpret_cast<void*>( + Load(reinterpret_cast<i::Address>(fp) + caller_pc_offset)); +} + +void* GetReturnAddressFromFP(void* fp, void* pc, + const JSEntryStubs& entry_stubs) { + int caller_pc_offset = i::CommonFrameConstants::kCallerPCOffset; +#ifdef V8_TARGET_ARCH_ARM64 + if (IsInJSEntryRange(entry_stubs, pc)) { + caller_pc_offset = i::EntryFrameConstants::kDirectCallerPCOffset; + } +#endif + return reinterpret_cast<void*>( + Load(reinterpret_cast<i::Address>(fp) + caller_pc_offset)); +} + +void* GetCallerFPFromFP(void* fp, void* pc, + const v8::UnwindState& unwind_state) { + int caller_fp_offset = i::CommonFrameConstants::kCallerFPOffset; +#ifdef V8_TARGET_ARCH_ARM64 + if (IsInJSEntryRange(unwind_state, pc)) { + caller_fp_offset = i::EntryFrameConstants::kDirectCallerFPOffset; + } +#endif return reinterpret_cast<void*>( - Load(reinterpret_cast<i::Address>(fp) + - i::CommonFrameConstants::kCallerPCOffset)); + Load(reinterpret_cast<i::Address>(fp) + caller_fp_offset)); } -void* GetCallerFPFromFP(void* fp) { +void* GetCallerFPFromFP(void* fp, void* pc, const JSEntryStubs& entry_stubs) { + int caller_fp_offset = i::CommonFrameConstants::kCallerFPOffset; +#ifdef V8_TARGET_ARCH_ARM64 + if (IsInJSEntryRange(entry_stubs, pc)) { + caller_fp_offset = i::EntryFrameConstants::kDirectCallerFPOffset; + } +#endif return reinterpret_cast<void*>( - Load(reinterpret_cast<i::Address>(fp) + - i::CommonFrameConstants::kCallerFPOffset)); + Load(reinterpret_cast<i::Address>(fp) + caller_fp_offset)); +} + +void* GetCallerSPFromFP(void* fp, void* pc, + const v8::UnwindState& unwind_state) { + int caller_sp_offset = i::CommonFrameConstants::kCallerSPOffset; +#ifdef V8_TARGET_ARCH_ARM64 + if (IsInJSEntryRange(unwind_state, pc)) { + caller_sp_offset = i::EntryFrameConstants::kDirectCallerSPOffset; + } +#endif + return reinterpret_cast<void*>(reinterpret_cast<i::Address>(fp) + + caller_sp_offset); } -void* GetCallerSPFromFP(void* fp) { +void* GetCallerSPFromFP(void* fp, void* pc, const JSEntryStubs& entry_stubs) { + int caller_sp_offset = i::CommonFrameConstants::kCallerSPOffset; +#ifdef V8_TARGET_ARCH_ARM64 + if (IsInJSEntryRange(entry_stubs, pc)) { + caller_sp_offset = i::EntryFrameConstants::kDirectCallerSPOffset; + } +#endif return reinterpret_cast<void*>(reinterpret_cast<i::Address>(fp) + - i::CommonFrameConstants::kCallerSPOffset); + caller_sp_offset); } bool AddressIsInStack(const void* address, const void* stack_base, @@ -62,21 +162,21 @@ bool Unwinder::TryUnwindV8Frames(const UnwindState& unwind_state, const void* stack_top = register_state->sp; void* pc = register_state->pc; - if (PCIsInV8(unwind_state, pc) && - !IsInUnsafeJSEntryRange(unwind_state.js_entry_stub, pc)) { + if (PCIsInV8(unwind_state, pc) && !IsInUnsafeJSEntryRange(unwind_state, pc)) { void* current_fp = register_state->fp; if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false; // Peek at the return address that the caller pushed. If it's in V8, then we // assume the caller frame is a JS frame and continue to unwind. - void* next_pc = GetReturnAddressFromFP(current_fp); + void* next_pc = GetReturnAddressFromFP(current_fp, pc, unwind_state); while (PCIsInV8(unwind_state, next_pc)) { - current_fp = GetCallerFPFromFP(current_fp); + current_fp = GetCallerFPFromFP(current_fp, pc, unwind_state); if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false; - next_pc = GetReturnAddressFromFP(current_fp); + pc = next_pc; + next_pc = GetReturnAddressFromFP(current_fp, pc, unwind_state); } - void* final_sp = GetCallerSPFromFP(current_fp); + void* final_sp = GetCallerSPFromFP(current_fp, pc, unwind_state); if (!AddressIsInStack(final_sp, stack_base, stack_top)) return false; register_state->sp = final_sp; @@ -84,7 +184,50 @@ bool Unwinder::TryUnwindV8Frames(const UnwindState& unwind_state, // this is just the rbp value that JSEntryStub pushed. On platforms like // Win64 this is not used as a dedicated FP register, and could contain // anything. - void* final_fp = GetCallerFPFromFP(current_fp); + void* final_fp = GetCallerFPFromFP(current_fp, pc, unwind_state); + register_state->fp = final_fp; + + register_state->pc = next_pc; + + // Link register no longer valid after unwinding. + register_state->lr = nullptr; + return true; + } + return false; +} + +bool Unwinder::TryUnwindV8Frames(const JSEntryStubs& entry_stubs, + size_t code_pages_length, + const MemoryRange* code_pages, + RegisterState* register_state, + const void* stack_base) { + const void* stack_top = register_state->sp; + + void* pc = register_state->pc; + if (PCIsInV8(code_pages_length, code_pages, pc) && + !IsInUnsafeJSEntryRange(entry_stubs, pc)) { + void* current_fp = register_state->fp; + if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false; + + // Peek at the return address that the caller pushed. If it's in V8, then we + // assume the caller frame is a JS frame and continue to unwind. + void* next_pc = GetReturnAddressFromFP(current_fp, pc, entry_stubs); + while (PCIsInV8(code_pages_length, code_pages, next_pc)) { + current_fp = GetCallerFPFromFP(current_fp, pc, entry_stubs); + if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false; + pc = next_pc; + next_pc = GetReturnAddressFromFP(current_fp, pc, entry_stubs); + } + + void* final_sp = GetCallerSPFromFP(current_fp, pc, entry_stubs); + if (!AddressIsInStack(final_sp, stack_base, stack_top)) return false; + register_state->sp = final_sp; + + // We don't check that the final FP value is within the stack bounds because + // this is just the rbp value that JSEntryStub pushed. On platforms like + // Win64 this is not used as a dedicated FP register, and could contain + // anything. + void* final_fp = GetCallerFPFromFP(current_fp, pc, entry_stubs); register_state->fp = final_fp; register_state->pc = next_pc; @@ -101,4 +244,9 @@ bool Unwinder::PCIsInV8(const UnwindState& unwind_state, void* pc) { PCIsInCodeRange(unwind_state.embedded_code_range, pc)); } +bool Unwinder::PCIsInV8(size_t code_pages_length, const MemoryRange* code_pages, + void* pc) { + return pc && PCIsInCodePages(code_pages_length, code_pages, pc); +} + } // namespace v8 diff --git a/deps/v8/src/diagnostics/unwinding-info-win64.cc b/deps/v8/src/diagnostics/unwinding-info-win64.cc index 5a2fc73631..19b03af522 100644 --- a/deps/v8/src/diagnostics/unwinding-info-win64.cc +++ b/deps/v8/src/diagnostics/unwinding-info-win64.cc @@ -16,37 +16,6 @@ #error "Unsupported OS" #endif // V8_OS_WIN_X64 -// Forward declaration to keep this independent of Win8 -NTSYSAPI -DWORD -NTAPI -RtlAddGrowableFunctionTable( - _Out_ PVOID* DynamicTable, - _In_reads_(MaximumEntryCount) PRUNTIME_FUNCTION FunctionTable, - _In_ DWORD EntryCount, - _In_ DWORD MaximumEntryCount, - _In_ ULONG_PTR RangeBase, - _In_ ULONG_PTR RangeEnd - ); - - -NTSYSAPI -void -NTAPI -RtlGrowFunctionTable( - _Inout_ PVOID DynamicTable, - _In_ DWORD NewEntryCount - ); - - -NTSYSAPI -void -NTAPI -RtlDeleteGrowableFunctionTable( - _In_ PVOID DynamicTable - ); - - namespace v8 { namespace internal { namespace win64_unwindinfo { @@ -213,15 +182,17 @@ void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) { // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes enum UnwindOp8Bit { OpNop = 0xE3, + OpAllocS = 0x00, OpSaveFpLr = 0x40, OpSaveFpLrX = 0x80, OpSetFp = 0xE1, + OpAddFp = 0xE2, OpEnd = 0xE4, }; typedef uint32_t UNWIND_CODE; -constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0, +constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0 = OpNop, uint8_t code1 = OpNop, uint8_t code2 = OpNop, uint8_t code3 = OpNop) { @@ -242,39 +213,97 @@ struct UNWIND_INFO { uint32_t CodeWords : 5; }; -static constexpr int kNumberOfUnwindCodes = 1; +static constexpr int kDefaultNumberOfUnwindCodeWords = 1; static constexpr int kMaxExceptionThunkSize = 16; static constexpr int kFunctionLengthShiftSize = 2; static constexpr int kFunctionLengthMask = (1 << kFunctionLengthShiftSize) - 1; -static constexpr int kFramePointerAdjustmentShiftSize = 3; -static constexpr int kFramePointerAdjustmentShiftMask = - (1 << kFramePointerAdjustmentShiftSize) - 1; +static constexpr int kAllocStackShiftSize = 4; +static constexpr int kAllocStackShiftMask = (1 << kAllocStackShiftSize) - 1; +// Generate an unwind code for "stp fp, lr, [sp, #pre_index_offset]!". +uint8_t MakeOpSaveFpLrX(int pre_index_offset) { + // See unwind code save_fplr_x in + // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes + DCHECK_LE(pre_index_offset, -8); + DCHECK_GE(pre_index_offset, -512); + constexpr int kShiftSize = 3; + constexpr int kShiftMask = (1 << kShiftSize) - 1; + DCHECK_EQ(pre_index_offset & kShiftMask, 0); + USE(kShiftMask); + // Solve for Z where -(Z+1)*8 = pre_index_offset. + int encoded_value = (-pre_index_offset >> kShiftSize) - 1; + return OpSaveFpLrX | encoded_value; +} + +// Generate an unwind code for "sub sp, sp, #stack_space". +uint8_t MakeOpAllocS(int stack_space) { + // See unwind code alloc_s in + // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes + DCHECK_GE(stack_space, 0); + DCHECK_LT(stack_space, 512); + DCHECK_EQ(stack_space & kAllocStackShiftMask, 0); + return OpAllocS | (stack_space >> kAllocStackShiftSize); +} + +// Generate the second byte of the unwind code for "add fp, sp, #offset". +uint8_t MakeOpAddFpArgument(int offset) { + // See unwind code add_fp in + // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes + DCHECK_GE(offset, 0); + constexpr int kShiftSize = 3; + constexpr int kShiftMask = (1 << kShiftSize) - 1; + DCHECK_EQ(offset & kShiftMask, 0); + USE(kShiftMask); + int encoded_value = offset >> kShiftSize; + // Encoded value must fit in 8 bits. + DCHECK_LE(encoded_value, 0xff); + return encoded_value; +} + +template <int kNumberOfUnwindCodeWords = kDefaultNumberOfUnwindCodeWords> struct V8UnwindData { UNWIND_INFO unwind_info; - UNWIND_CODE unwind_codes[kNumberOfUnwindCodes]; + UNWIND_CODE unwind_codes[kNumberOfUnwindCodeWords]; V8UnwindData() { memset(&unwind_info, 0, sizeof(UNWIND_INFO)); unwind_info.X = 1; // has exception handler after unwind-codes. - unwind_info.CodeWords = 1; - - // stp fp, lr, [sp, #offset]! - unwind_codes[0] = Combine8BitUnwindCodes(OpSetFp, OpSaveFpLrX, OpEnd); + unwind_info.CodeWords = kNumberOfUnwindCodeWords; + + // Generate unwind codes for the following prolog: + // + // stp fp, lr, [sp, #-kCallerSPOffset]! + // mov fp, sp + // + // This is a very rough approximation of the actual function prologs used in + // V8. In particular, we often push other data before the (fp, lr) pair, + // meaning the stack pointer computed for the caller frame is wrong. That + // error is acceptable when the unwinding info for the caller frame also + // depends on fp rather than sp, as is the case for V8 builtins and runtime- + // generated code. + STATIC_ASSERT(kNumberOfUnwindCodeWords >= 1); + unwind_codes[0] = Combine8BitUnwindCodes( + OpSetFp, MakeOpSaveFpLrX(-CommonFrameConstants::kCallerSPOffset), + OpEnd); + + // Fill the rest with nops. + for (int i = 1; i < kNumberOfUnwindCodeWords; ++i) { + unwind_codes[i] = Combine8BitUnwindCodes(); + } } }; struct CodeRangeUnwindingRecord { void* dynamic_table; uint32_t runtime_function_count; - V8UnwindData unwind_info; + V8UnwindData<> unwind_info; uint32_t exception_handler; // For Windows ARM64 unwinding, register 2 unwind_info for each code range, // unwind_info for all full size ranges (1MB - 4 bytes) and unwind_info1 for // the remaining non full size range. There is at most 1 range which is less // than full size. - V8UnwindData unwind_info1; + V8UnwindData<> unwind_info1; uint32_t exception_handler1; uint8_t exception_thunk[kMaxExceptionThunkSize]; @@ -286,33 +315,66 @@ struct CodeRangeUnwindingRecord { #pragma pack(pop) -std::vector<uint8_t> GetUnwindInfoForBuiltinFunction(uint32_t func_len, - int32_t fp_adjustment) { +FrameOffsets::FrameOffsets() + : fp_to_saved_caller_fp(CommonFrameConstants::kCallerFPOffset), + fp_to_caller_sp(CommonFrameConstants::kCallerSPOffset) {} +bool FrameOffsets::IsDefault() const { + FrameOffsets other; + return fp_to_saved_caller_fp == other.fp_to_saved_caller_fp && + fp_to_caller_sp == other.fp_to_caller_sp; +} + +std::vector<uint8_t> GetUnwindInfoForBuiltinFunction( + uint32_t func_len, FrameOffsets fp_adjustment) { DCHECK_LE(func_len, kMaxFunctionLength); DCHECK_EQ((func_len & kFunctionLengthMask), 0); USE(kFunctionLengthMask); - // Unwind code save_fplr requires the offset to be within range [0, 504]. - // This range is defined in below doc for unwind code save_fplr. - // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes - DCHECK_GE(fp_adjustment, 0); - DCHECK_LE(fp_adjustment, 504); - DCHECK_EQ((fp_adjustment & kFramePointerAdjustmentShiftMask), 0); - USE(kFramePointerAdjustmentShiftMask); + // The largest size of unwind data required for all options below. + constexpr int kMaxNumberOfUnwindCodeWords = 2; - V8UnwindData xdata; + V8UnwindData<kMaxNumberOfUnwindCodeWords> xdata; // FunctionLength is ensured to be aligned at instruction size and Windows // ARM64 doesn't encoding its 2 LSB. xdata.unwind_info.FunctionLength = func_len >> kFunctionLengthShiftSize; - xdata.unwind_info.CodeWords = 1; - xdata.unwind_codes[0] = Combine8BitUnwindCodes( - OpSetFp, - (OpSaveFpLr | (fp_adjustment >> kFramePointerAdjustmentShiftSize)), - OpEnd); + + if (fp_adjustment.IsDefault()) { + // One code word is plenty. + STATIC_ASSERT(kDefaultNumberOfUnwindCodeWords < + kMaxNumberOfUnwindCodeWords); + xdata.unwind_info.CodeWords = kDefaultNumberOfUnwindCodeWords; + } else { + // We want to convey the following facts: + // 1. The caller's fp is found at [fp + fp_to_saved_caller_fp]. + // 2. The caller's pc is found at [fp + fp_to_saved_caller_fp + 8]. + // 3. The caller's sp is equal to fp + fp_to_caller_sp. + // + // An imaginary prolog that would establish those relationships might look + // like the following, with appropriate values for the various constants: + // + // stp fp, lr, [sp, #pre_index_amount]! + // sub sp, sp, #stack_space + // add fp, sp, offset_from_stack_top + // + // Why do we need offset_from_stack_top? The unwinding encoding for + // allocating stack space has 16-byte granularity, and the frame pointer has + // only 8-byte alignment. + int pre_index_amount = + fp_adjustment.fp_to_saved_caller_fp - fp_adjustment.fp_to_caller_sp; + int stack_space = fp_adjustment.fp_to_saved_caller_fp; + int offset_from_stack_top = stack_space & kAllocStackShiftMask; + stack_space += offset_from_stack_top; + + xdata.unwind_codes[0] = Combine8BitUnwindCodes( + OpAddFp, MakeOpAddFpArgument(offset_from_stack_top), + MakeOpAllocS(stack_space), MakeOpSaveFpLrX(pre_index_amount)); + xdata.unwind_codes[1] = Combine8BitUnwindCodes(OpEnd); + } return std::vector<uint8_t>( reinterpret_cast<uint8_t*>(&xdata), - reinterpret_cast<uint8_t*>(&xdata) + sizeof(xdata)); + reinterpret_cast<uint8_t*>( + &xdata.unwind_codes[xdata.unwind_info.CodeWords])); } template <typename Record> @@ -542,17 +604,13 @@ void XdataEncoder::onSaveFpLr() { current_frame_code_offset_ = assembler_.pc_offset() - 4; fp_offsets_.push_back(current_frame_code_offset_); fp_adjustments_.push_back(current_frame_adjustment_); - if (current_frame_adjustment_ != 0) { - current_frame_adjustment_ = 0; - } + current_frame_adjustment_ = FrameOffsets(); } -void XdataEncoder::onFramePointerAdjustment(int bytes) { - // According to below doc, offset for save_fplr is aligned to pointer size. - // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes - DCHECK_EQ((bytes & kPointerAlignmentMask), 0); - - current_frame_adjustment_ = bytes; +void XdataEncoder::onFramePointerAdjustment(int fp_to_saved_caller_fp, + int fp_to_caller_sp) { + current_frame_adjustment_.fp_to_saved_caller_fp = fp_to_saved_caller_fp; + current_frame_adjustment_.fp_to_caller_sp = fp_to_caller_sp; } #endif // V8_OS_WIN_X64 diff --git a/deps/v8/src/diagnostics/unwinding-info-win64.h b/deps/v8/src/diagnostics/unwinding-info-win64.h index 8f8c9469eb..102df15590 100644 --- a/deps/v8/src/diagnostics/unwinding-info-win64.h +++ b/deps/v8/src/diagnostics/unwinding-info-win64.h @@ -114,6 +114,13 @@ class XdataEncoder { */ static const int kMaxFunctionLength = ((1 << 18) - 1) << 2; +struct FrameOffsets { + FrameOffsets(); + bool IsDefault() const; + int fp_to_saved_caller_fp; + int fp_to_caller_sp; +}; + /** * Returns a vector of bytes that contains the Win ARM64 unwind data used for * all V8 builtin functions. @@ -123,18 +130,20 @@ static const int kMaxFunctionLength = ((1 << 18) - 1) << 2; * this is necessary to encode unwind data for Windows stack * unwinder to find correct caller's fp. */ -std::vector<uint8_t> GetUnwindInfoForBuiltinFunction(uint32_t func_len, - int32_t fp_adjustment); +std::vector<uint8_t> GetUnwindInfoForBuiltinFunction( + uint32_t func_len, FrameOffsets fp_adjustment); class BuiltinUnwindInfo { public: BuiltinUnwindInfo() : is_leaf_function_(true) {} explicit BuiltinUnwindInfo(const std::vector<int>& fp_offsets, - const std::vector<int>& fp_adjustments) + const std::vector<FrameOffsets>& fp_adjustments) : is_leaf_function_(false), fp_offsets_(fp_offsets), fp_adjustments_(fp_adjustments) {} - const std::vector<int>& fp_adjustments() const { return fp_adjustments_; } + const std::vector<FrameOffsets>& fp_adjustments() const { + return fp_adjustments_; + } bool is_leaf_function() const { return is_leaf_function_; } const std::vector<int>& fp_offsets() const { return fp_offsets_; } @@ -142,18 +151,16 @@ class BuiltinUnwindInfo { private: bool is_leaf_function_; std::vector<int> fp_offsets_; - std::vector<int> fp_adjustments_; + std::vector<FrameOffsets> fp_adjustments_; }; class XdataEncoder { public: explicit XdataEncoder(const Assembler& assembler) - : assembler_(assembler), - current_frame_code_offset_(-1), - current_frame_adjustment_(0) {} + : assembler_(assembler), current_frame_code_offset_(-1) {} void onSaveFpLr(); - void onFramePointerAdjustment(int bytes); + void onFramePointerAdjustment(int fp_to_saved_caller_fp, int fp_to_caller_sp); BuiltinUnwindInfo unwinding_info() const { return BuiltinUnwindInfo(fp_offsets_, fp_adjustments_); @@ -163,8 +170,8 @@ class XdataEncoder { const Assembler& assembler_; std::vector<int> fp_offsets_; int current_frame_code_offset_; - int current_frame_adjustment_; - std::vector<int> fp_adjustments_; + FrameOffsets current_frame_adjustment_; + std::vector<FrameOffsets> fp_adjustments_; }; #endif diff --git a/deps/v8/src/diagnostics/x64/disasm-x64.cc b/deps/v8/src/diagnostics/x64/disasm-x64.cc index 2195556af7..a1331784a3 100644 --- a/deps/v8/src/diagnostics/x64/disasm-x64.cc +++ b/deps/v8/src/diagnostics/x64/disasm-x64.cc @@ -11,6 +11,7 @@ #include "src/base/compiler-specific.h" #include "src/base/lazy-instance.h" +#include "src/base/memory.h" #include "src/base/v8-fallthrough.h" #include "src/codegen/x64/register-x64.h" #include "src/codegen/x64/sse-instr.h" @@ -245,19 +246,24 @@ uint8_t Imm8_U(const uint8_t* data) { return *reinterpret_cast<const uint8_t*>(data); } int16_t Imm16(const uint8_t* data) { - return *reinterpret_cast<const int16_t*>(data); + return v8::base::ReadUnalignedValue<int16_t>( + reinterpret_cast<v8::internal::Address>(data)); } uint16_t Imm16_U(const uint8_t* data) { - return *reinterpret_cast<const uint16_t*>(data); + return v8::base::ReadUnalignedValue<uint16_t>( + reinterpret_cast<v8::internal::Address>(data)); } int32_t Imm32(const uint8_t* data) { - return *reinterpret_cast<const int32_t*>(data); + return v8::base::ReadUnalignedValue<int32_t>( + reinterpret_cast<v8::internal::Address>(data)); } uint32_t Imm32_U(const uint8_t* data) { - return *reinterpret_cast<const uint32_t*>(data); + return v8::base::ReadUnalignedValue<uint32_t>( + reinterpret_cast<v8::internal::Address>(data)); } int64_t Imm64(const uint8_t* data) { - return *reinterpret_cast<const int64_t*>(data); + return v8::base::ReadUnalignedValue<int64_t>( + reinterpret_cast<v8::internal::Address>(data)); } } // namespace @@ -673,7 +679,7 @@ int DisassemblerX64::F6F7Instruction(byte* data) { byte modrm = *(data + 1); int mod, regop, rm; get_modrm(modrm, &mod, ®op, &rm); - if (mod == 3 && regop != 0) { + if (regop != 0) { const char* mnem = nullptr; switch (regop) { case 2: @@ -697,8 +703,18 @@ int DisassemblerX64::F6F7Instruction(byte* data) { default: UnimplementedInstruction(); } - AppendToBuffer("%s%c %s", mnem, operand_size_code(), NameOfCPURegister(rm)); - return 2; + if (mod == 3) { + AppendToBuffer("%s%c %s", mnem, operand_size_code(), + NameOfCPURegister(rm)); + return 2; + } else if (mod == 1) { + AppendToBuffer("%s%c ", mnem, operand_size_code()); + int count = PrintRightOperand(data + 1); // Use name of 64-bit register. + return 1 + count; + } else { + UnimplementedInstruction(); + return 2; + } } else if (regop == 0) { AppendToBuffer("test%c ", operand_size_code()); int count = PrintRightOperand(data + 1); // Use name of 64-bit register. @@ -819,6 +835,10 @@ int DisassemblerX64::AVXInstruction(byte* data) { int mod, regop, rm, vvvv = vex_vreg(); get_modrm(*current, &mod, ®op, &rm); switch (opcode) { + case 0x18: + AppendToBuffer("vbroadcastss %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + break; case 0x99: AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(), NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -829,6 +849,11 @@ int DisassemblerX64::AVXInstruction(byte* data) { NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); current += PrintRightXMMOperand(current); break; + case 0xB8: + AppendToBuffer("vfmadd231p%c %s,%s,", float_size_code(), + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; case 0xB9: AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(), NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -849,6 +874,11 @@ int DisassemblerX64::AVXInstruction(byte* data) { NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); current += PrintRightXMMOperand(current); break; + case 0xBC: + AppendToBuffer("vfnmadd231p%c %s,%s,", float_size_code(), + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; case 0x9D: AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(), NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -896,7 +926,19 @@ int DisassemblerX64::AVXInstruction(byte* data) { SSSE3_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE) SSE4_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE) + SSE4_2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE) #undef DECLARE_SSE_AVX_DIS_CASE + +#define DECLARE_SSE_PMOV_AVX_DIS_CASE(instruction, notUsed1, notUsed2, \ + notUsed3, opcode) \ + case 0x##opcode: { \ + AppendToBuffer("v" #instruction " %s,", NameOfXMMRegister(regop)); \ + current += PrintRightXMMOperand(current); \ + break; \ + } + SSE4_PMOV_INSTRUCTION_LIST(DECLARE_SSE_PMOV_AVX_DIS_CASE) +#undef DECLARE_SSE_PMOV_AVX_DIS_CASE + default: UnimplementedInstruction(); } @@ -916,6 +958,18 @@ int DisassemblerX64::AVXInstruction(byte* data) { current += PrintRightXMMOperand(current); AppendToBuffer(",0x%x", *current++); break; + case 0x0E: + AppendToBuffer("vpblendw %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + AppendToBuffer(",0x%x", *current++); + break; + case 0x0F: + AppendToBuffer("vpalignr %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + AppendToBuffer(",0x%x", *current++); + break; case 0x14: AppendToBuffer("vpextrb "); current += PrintRightByteOperand(current); @@ -927,7 +981,12 @@ int DisassemblerX64::AVXInstruction(byte* data) { AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++); break; case 0x16: - AppendToBuffer("vpextrd "); + AppendToBuffer("vpextr%c ", rex_w() ? 'q' : 'd'); + current += PrintRightOperand(current); + AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++); + break; + case 0x17: + AppendToBuffer("vextractps "); current += PrintRightOperand(current); AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++); break; @@ -937,12 +996,25 @@ int DisassemblerX64::AVXInstruction(byte* data) { current += PrintRightByteOperand(current); AppendToBuffer(",0x%x", *current++); break; - case 0x22: - AppendToBuffer("vpinsrd %s,%s,", NameOfXMMRegister(regop), + case 0x21: + AppendToBuffer("vinsertps %s,%s,", NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + AppendToBuffer(",0x%x", *current++); + break; + case 0x22: + AppendToBuffer("vpinsr%c %s,%s,", rex_w() ? 'q' : 'd', + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); current += PrintRightOperand(current); AppendToBuffer(",0x%x", *current++); break; + case 0x4B: { + AppendToBuffer("vblendvpd %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + AppendToBuffer(",%s", NameOfXMMRegister((*current++) >> 4)); + break; + } default: UnimplementedInstruction(); } @@ -1015,6 +1087,15 @@ int DisassemblerX64::AVXInstruction(byte* data) { NameOfXMMRegister(vvvv)); current += PrintRightXMMOperand(current); break; + case 0x6F: + AppendToBuffer("vmovdqu %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + break; + case 0x7F: + AppendToBuffer("vmovdqu "); + current += PrintRightXMMOperand(current); + AppendToBuffer(",%s", NameOfXMMRegister(regop)); + break; default: UnimplementedInstruction(); } @@ -1037,6 +1118,10 @@ int DisassemblerX64::AVXInstruction(byte* data) { } AppendToBuffer(",%s", NameOfXMMRegister(regop)); break; + case 0x12: + AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + break; case 0x2A: AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2sd" : "vcvtlsi2sd", NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -1096,6 +1181,11 @@ int DisassemblerX64::AVXInstruction(byte* data) { AppendToBuffer("vlddqu %s,", NameOfXMMRegister(regop)); current += PrintRightXMMOperand(current); break; + case 0x70: + AppendToBuffer("vpshuflw %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + AppendToBuffer(",0x%x", *current++); + break; case 0x7C: AppendToBuffer("vhaddps %s,%s,", NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -1225,6 +1315,11 @@ int DisassemblerX64::AVXInstruction(byte* data) { current += PrintRightXMMOperand(current); AppendToBuffer(",%s", NameOfXMMRegister(regop)); break; + case 0x16: + AppendToBuffer("vmovlhps %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; case 0x28: AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop)); current += PrintRightXMMOperand(current); @@ -1242,21 +1337,45 @@ int DisassemblerX64::AVXInstruction(byte* data) { AppendToBuffer("vmovmskps %s,", NameOfCPURegister(regop)); current += PrintRightXMMOperand(current); break; - case 0x54: - AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop), - NameOfXMMRegister(vvvv)); + case 0x51: + case 0x52: + case 0x53: { + const char* const pseudo_op[] = {"vsqrtps", "vrsqrtps", "vrcpps"}; + + AppendToBuffer("%s %s,", pseudo_op[opcode - 0x51], + NameOfXMMRegister(regop)); current += PrintRightXMMOperand(current); break; - case 0x55: - AppendToBuffer("vandnps %s,%s,", NameOfXMMRegister(regop), - NameOfXMMRegister(vvvv)); + } + case 0x5A: + case 0x5B: { + const char* const pseudo_op[] = {"vcvtps2pd", "vcvtdq2ps"}; + + AppendToBuffer("%s %s,", pseudo_op[opcode - 0x5A], + NameOfXMMRegister(regop)); current += PrintRightXMMOperand(current); break; + } + case 0x54: + case 0x55: + case 0x56: case 0x57: - AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop), - NameOfXMMRegister(vvvv)); + case 0x58: + case 0x59: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: { + const char* const pseudo_op[] = { + "vandps", "vandnps", "vorps", "vxorps", "vaddps", "vmulps", + "", "", "vsubps", "vminps", "vdivps", "vmaxps", + }; + + AppendToBuffer("%s %s,%s,", pseudo_op[opcode - 0x54], + NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); current += PrintRightXMMOperand(current); break; + } case 0xC2: { AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); @@ -1267,6 +1386,13 @@ int DisassemblerX64::AVXInstruction(byte* data) { current += 1; break; } + case 0xC6: { + AppendToBuffer("vshufps %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + AppendToBuffer(",0x%x", *current++); + break; + } default: UnimplementedInstruction(); } @@ -1675,6 +1801,12 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { current = data + 3; get_modrm(*current, &mod, ®op, &rm); switch (third_byte) { + case 0x15: { + AppendToBuffer("blendvpd %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + AppendToBuffer(",<xmm0>"); + break; + } #define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \ case 0x##opcode: { \ AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \ @@ -1684,6 +1816,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE) SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE) + SSE4_PMOV_INSTRUCTION_LIST(SSE34_DIS_CASE) SSE4_2_INSTRUCTION_LIST(SSE34_DIS_CASE) #undef SSE34_DIS_CASE default: @@ -1714,14 +1847,14 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { } else if (third_byte == 0x0E) { get_modrm(*current, &mod, ®op, &rm); AppendToBuffer("pblendw %s,", NameOfXMMRegister(regop)); - current += PrintRightXMMOperand(data); - AppendToBuffer(",0x%x", (*current) & 3); + current += PrintRightXMMOperand(current); + AppendToBuffer(",0x%x", *current); current += 1; } else if (third_byte == 0x0F) { - get_modrm(*data, &mod, ®op, &rm); + get_modrm(*current, &mod, ®op, &rm); AppendToBuffer("palignr %s,", NameOfXMMRegister(regop)); - current += PrintRightXMMOperand(data); - AppendToBuffer(",0x%x", (*current) & 3); + current += PrintRightXMMOperand(current); + AppendToBuffer(",0x%x", (*current)); current += 1; } else if (third_byte == 0x14) { get_modrm(*current, &mod, ®op, &rm); @@ -1754,7 +1887,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { // insertps xmm, xmm/m32, imm8 AppendToBuffer("insertps %s,", NameOfXMMRegister(regop)); current += PrintRightXMMOperand(current); - AppendToBuffer(",0x%x", (*current) & 3); + AppendToBuffer(",0x%x", (*current)); current += 1; } else if (third_byte == 0x22) { get_modrm(*current, &mod, ®op, &rm); @@ -1767,6 +1900,8 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { } else { UnimplementedInstruction(); } + } else if (opcode == 0xC1) { + current += PrintOperands("xadd", OPER_REG_OP_ORDER, current); } else { get_modrm(*current, &mod, ®op, &rm); if (opcode == 0x1F) { @@ -1907,6 +2042,8 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { mnemonic = "pcmpeqw"; } else if (opcode == 0x76) { mnemonic = "pcmpeqd"; + } else if (opcode == 0xC2) { + mnemonic = "cmppd"; } else if (opcode == 0xD1) { mnemonic = "psrlw"; } else if (opcode == 0xD2) { @@ -1933,10 +2070,14 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { mnemonic = "paddusw"; } else if (opcode == 0xDE) { mnemonic = "pmaxub"; + } else if (opcode == 0xE0) { + mnemonic = "pavgb"; } else if (opcode == 0xE1) { mnemonic = "psraw"; } else if (opcode == 0xE2) { mnemonic = "psrad"; + } else if (opcode == 0xE3) { + mnemonic = "pavgw"; } else if (opcode == 0xE8) { mnemonic = "psubsb"; } else if (opcode == 0xE9) { @@ -1975,8 +2116,6 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { mnemonic = "paddw"; } else if (opcode == 0xFE) { mnemonic = "paddd"; - } else if (opcode == 0xC2) { - mnemonic = "cmppd"; } else { UnimplementedInstruction(); } @@ -2176,6 +2315,12 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { AppendToBuffer("%s,", NameOfXMMRegister(regop)); current += PrintRightXMMOperand(current); } + } else if (opcode == 0x16) { + // movlhps xmm1, xmm2 + int mod, regop, rm; + get_modrm(*current, &mod, ®op, &rm); + AppendToBuffer("movlhps %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); } else if (opcode == 0x1F) { // NOP int mod, regop, rm; @@ -2233,6 +2378,11 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { NameOfXMMRegister(regop)); current += PrintRightXMMOperand(current); + } else if (opcode == 0xC0) { + byte_size_operand_ = true; + current += PrintOperands("xadd", OPER_REG_OP_ORDER, current); + } else if (opcode == 0xC1) { + current += PrintOperands("xadd", OPER_REG_OP_ORDER, current); } else if (opcode == 0xC2) { // cmpps xmm, xmm/m128, imm8 int mod, regop, rm; @@ -2261,13 +2411,6 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { get_modrm(*current, &mod, ®op, &rm); AppendToBuffer("movmskps %s,", NameOfCPURegister(regop)); current += PrintRightXMMOperand(current); - } else if (opcode == 0x70) { - int mod, regop, rm; - get_modrm(*current, &mod, ®op, &rm); - AppendToBuffer("pshufw %s, ", NameOfXMMRegister(regop)); - current += PrintRightXMMOperand(current); - AppendToBuffer(", %d", (*current) & 3); - current += 1; } else if ((opcode & 0xF0) == 0x80) { // Jcc: Conditional jump (branch). current = data + JumpConditional(data); @@ -2345,6 +2488,8 @@ const char* DisassemblerX64::TwoByteMnemonic(byte opcode) { return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss"; case 0x5A: // F2/F3 prefix. return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd"; + case 0x5B: // F2/F3 prefix. + return "cvttps2dq"; case 0x5D: // F2/F3 prefix. return (group_1_prefix_ == 0xF2) ? "minsd" : "minss"; case 0x5C: // F2/F3 prefix. |