| // Copyright 2015 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 <iomanip> |
| |
| #include "src/execution/arguments-inl.h" |
| #include "src/execution/frames-inl.h" |
| #include "src/execution/isolate-inl.h" |
| #include "src/interpreter/bytecode-array-iterator.h" |
| #include "src/interpreter/bytecode-decoder.h" |
| #include "src/interpreter/bytecode-flags.h" |
| #include "src/interpreter/bytecode-register.h" |
| #include "src/interpreter/bytecodes.h" |
| #include "src/interpreter/interpreter.h" |
| #include "src/logging/counters.h" |
| #include "src/runtime/runtime-utils.h" |
| #include "src/snapshot/snapshot.h" |
| #include "src/utils/ostreams.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #ifdef V8_TRACE_IGNITION |
| |
| namespace { |
| |
| void AdvanceToOffsetForTracing( |
| interpreter::BytecodeArrayIterator& |
| bytecode_iterator, // NOLINT(runtime/references) |
| int offset) { |
| while (bytecode_iterator.current_offset() + |
| bytecode_iterator.current_bytecode_size() <= |
| offset) { |
| bytecode_iterator.Advance(); |
| } |
| DCHECK(bytecode_iterator.current_offset() == offset || |
| ((bytecode_iterator.current_offset() + 1) == offset && |
| bytecode_iterator.current_operand_scale() > |
| interpreter::OperandScale::kSingle)); |
| } |
| |
| void PrintRegisters(Isolate* isolate, std::ostream& os, bool is_input, |
| interpreter::BytecodeArrayIterator& |
| bytecode_iterator, // NOLINT(runtime/references) |
| Handle<Object> accumulator) { |
| static const char kAccumulator[] = "accumulator"; |
| static const int kRegFieldWidth = static_cast<int>(sizeof(kAccumulator) - 1); |
| static const char* kInputColourCode = "\033[0;36m"; |
| static const char* kOutputColourCode = "\033[0;35m"; |
| static const char* kNormalColourCode = "\033[0;m"; |
| const char* kArrowDirection = is_input ? " -> " : " <- "; |
| if (FLAG_log_colour) { |
| os << (is_input ? kInputColourCode : kOutputColourCode); |
| } |
| |
| interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode(); |
| |
| // Print accumulator. |
| if ((is_input && interpreter::Bytecodes::ReadsAccumulator(bytecode)) || |
| (!is_input && interpreter::Bytecodes::WritesAccumulator(bytecode))) { |
| os << " [ " << kAccumulator << kArrowDirection; |
| accumulator->ShortPrint(); |
| os << " ]" << std::endl; |
| } |
| |
| // Print the registers. |
| JavaScriptFrameIterator frame_iterator(isolate); |
| InterpretedFrame* frame = |
| reinterpret_cast<InterpretedFrame*>(frame_iterator.frame()); |
| int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode); |
| for (int operand_index = 0; operand_index < operand_count; operand_index++) { |
| interpreter::OperandType operand_type = |
| interpreter::Bytecodes::GetOperandType(bytecode, operand_index); |
| bool should_print = |
| is_input |
| ? interpreter::Bytecodes::IsRegisterInputOperandType(operand_type) |
| : interpreter::Bytecodes::IsRegisterOutputOperandType(operand_type); |
| if (should_print) { |
| interpreter::Register first_reg = |
| bytecode_iterator.GetRegisterOperand(operand_index); |
| int range = bytecode_iterator.GetRegisterOperandRange(operand_index); |
| for (int reg_index = first_reg.index(); |
| reg_index < first_reg.index() + range; reg_index++) { |
| Object reg_object = frame->ReadInterpreterRegister(reg_index); |
| os << " [ " << std::setw(kRegFieldWidth) |
| << interpreter::Register(reg_index).ToString( |
| bytecode_iterator.bytecode_array()->parameter_count()) |
| << kArrowDirection; |
| reg_object.ShortPrint(os); |
| os << " ]" << std::endl; |
| } |
| } |
| } |
| if (FLAG_log_colour) { |
| os << kNormalColourCode; |
| } |
| } |
| |
| } // namespace |
| |
| RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) { |
| if (!FLAG_trace_ignition) { |
| return ReadOnlyRoots(isolate).undefined_value(); |
| } |
| |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(3, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0); |
| CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2); |
| |
| int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag; |
| interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array); |
| AdvanceToOffsetForTracing(bytecode_iterator, offset); |
| if (offset == bytecode_iterator.current_offset()) { |
| StdoutStream os; |
| |
| // Print bytecode. |
| const uint8_t* base_address = reinterpret_cast<const uint8_t*>( |
| bytecode_array->GetFirstBytecodeAddress()); |
| const uint8_t* bytecode_address = base_address + offset; |
| os << " -> " << static_cast<const void*>(bytecode_address) << " @ " |
| << std::setw(4) << offset << " : "; |
| interpreter::BytecodeDecoder::Decode(os, bytecode_address, |
| bytecode_array->parameter_count()); |
| os << std::endl; |
| // Print all input registers and accumulator. |
| PrintRegisters(isolate, os, true, bytecode_iterator, accumulator); |
| |
| os << std::flush; |
| } |
| return ReadOnlyRoots(isolate).undefined_value(); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit) { |
| if (!FLAG_trace_ignition) { |
| return ReadOnlyRoots(isolate).undefined_value(); |
| } |
| |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(3, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0); |
| CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2); |
| |
| int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag; |
| interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array); |
| AdvanceToOffsetForTracing(bytecode_iterator, offset); |
| // The offset comparison here ensures registers only printed when the |
| // (potentially) widened bytecode has completed. The iterator reports |
| // the offset as the offset of the prefix bytecode. |
| if (bytecode_iterator.current_operand_scale() == |
| interpreter::OperandScale::kSingle || |
| offset > bytecode_iterator.current_offset()) { |
| StdoutStream os; |
| // Print all output registers and accumulator. |
| PrintRegisters(isolate, os, false, bytecode_iterator, accumulator); |
| os << std::flush; |
| } |
| return ReadOnlyRoots(isolate).undefined_value(); |
| } |
| |
| #endif |
| |
| #ifdef V8_TRACE_FEEDBACK_UPDATES |
| |
| RUNTIME_FUNCTION(Runtime_InterpreterTraceUpdateFeedback) { |
| if (!FLAG_trace_feedback_updates) { |
| return ReadOnlyRoots(isolate).undefined_value(); |
| } |
| |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(3, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); |
| CONVERT_SMI_ARG_CHECKED(slot, 1); |
| CONVERT_ARG_CHECKED(String, reason, 2); |
| |
| int slot_count = function->feedback_vector().metadata().slot_count(); |
| |
| StdoutStream os; |
| os << "[Feedback slot " << slot << "/" << slot_count << " in "; |
| function->shared().ShortPrint(os); |
| os << " updated to "; |
| function->feedback_vector().FeedbackSlotPrint(os, FeedbackSlot(slot)); |
| os << " - "; |
| |
| StringCharacterStream stream(reason); |
| while (stream.HasMore()) { |
| uint16_t character = stream.GetNext(); |
| PrintF("%c", character); |
| } |
| |
| os << "]" << std::endl; |
| |
| return ReadOnlyRoots(isolate).undefined_value(); |
| } |
| |
| #endif |
| |
| } // namespace internal |
| } // namespace v8 |