#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-and-tokens.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_UNOPTIMIZED
namespace {
void AdvanceToOffsetForTracing(
interpreter::BytecodeArrayIterator& bytecode_iterator, 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 PrintRegisterRange(UnoptimizedFrame* frame, std::ostream& os,
interpreter::BytecodeArrayIterator& bytecode_iterator,
const int& reg_field_width, const char* arrow_direction,
interpreter::Register first_reg, int range) {
for (int reg_index = first_reg.index(); reg_index < first_reg.index() + range;
reg_index++) {
Tagged<Object> reg_object = frame->ReadInterpreterRegister(reg_index);
os << " [ " << std::setw(reg_field_width)
<< interpreter::Register(reg_index).ToString() << arrow_direction;
ShortPrint(reg_object, os);
os << " ]" << std::endl;
}
}
void PrintRegisters(UnoptimizedFrame* frame, std::ostream& os, bool is_input,
interpreter::BytecodeArrayIterator& bytecode_iterator,
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 (v8_flags.log_colour) {
os << (is_input ? kInputColourCode : kOutputColourCode);
}
interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
if ((is_input && interpreter::Bytecodes::ReadsAccumulator(bytecode)) ||
(!is_input &&
interpreter::Bytecodes::WritesOrClobbersAccumulator(bytecode))) {
os << " [ " << kAccumulator << kArrowDirection;
ShortPrint(*accumulator, os);
os << " ]" << std::endl;
}
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);
PrintRegisterRange(frame, os, bytecode_iterator, kRegFieldWidth,
kArrowDirection, first_reg, range);
}
}
if (!is_input && interpreter::Bytecodes::IsShortStar(bytecode)) {
PrintRegisterRange(frame, os, bytecode_iterator, kRegFieldWidth,
kArrowDirection,
interpreter::Register::FromShortStar(bytecode), 1);
}
if (v8_flags.log_colour) {
os << kNormalColourCode;
}
}
}
RUNTIME_FUNCTION(Runtime_TraceUnoptimizedBytecodeEntry) {
if (!v8_flags.trace_ignition && !v8_flags.trace_baseline_exec) {
return ReadOnlyRoots(isolate).undefined_value();
}
JavaScriptStackFrameIterator frame_iterator(isolate);
UnoptimizedFrame* frame =
reinterpret_cast<UnoptimizedFrame*>(frame_iterator.frame());
if (frame->is_interpreted() && !v8_flags.trace_ignition) {
return ReadOnlyRoots(isolate).undefined_value();
}
if (frame->is_baseline() && !v8_flags.trace_baseline_exec) {
return ReadOnlyRoots(isolate).undefined_value();
}
SealHandleScope shs(isolate);
DCHECK_EQ(3, args.length());
Handle<BytecodeArray> bytecode_array = args.at<BytecodeArray>(0);
int bytecode_offset = args.smi_value_at(1);
Handle<Object> accumulator = args.at(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;
const uint8_t* base_address = reinterpret_cast<const uint8_t*>(
bytecode_array->GetFirstBytecodeAddress());
const uint8_t* bytecode_address = base_address + offset;
if (frame->is_baseline()) {
os << "B-> ";
} else {
os << " -> ";
}
os << static_cast<const void*>(bytecode_address) << " @ " << std::setw(4)
<< offset << " : ";
interpreter::BytecodeDecoder::Decode(os, bytecode_address);
os << std::endl;
PrintRegisters(frame, os, true, bytecode_iterator, accumulator);
os << std::flush;
}
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_TraceUnoptimizedBytecodeExit) {
if (!v8_flags.trace_ignition && !v8_flags.trace_baseline_exec) {
return ReadOnlyRoots(isolate).undefined_value();
}
JavaScriptStackFrameIterator frame_iterator(isolate);
UnoptimizedFrame* frame =
reinterpret_cast<UnoptimizedFrame*>(frame_iterator.frame());
if (frame->is_interpreted() && !v8_flags.trace_ignition) {
return ReadOnlyRoots(isolate).undefined_value();
}
if (frame->is_baseline() && !v8_flags.trace_baseline_exec) {
return ReadOnlyRoots(isolate).undefined_value();
}
SealHandleScope shs(isolate);
DCHECK_EQ(3, args.length());
Handle<BytecodeArray> bytecode_array = args.at<BytecodeArray>(0);
int bytecode_offset = args.smi_value_at(1);
Handle<Object> accumulator = args.at(2);
int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
AdvanceToOffsetForTracing(bytecode_iterator, offset);
if (bytecode_iterator.current_operand_scale() ==
interpreter::OperandScale::kSingle ||
offset > bytecode_iterator.current_offset()) {
StdoutStream os;
PrintRegisters(frame, os, false, bytecode_iterator, accumulator);
os << std::flush;
}
return ReadOnlyRoots(isolate).undefined_value();
}
#endif
#ifdef V8_TRACE_FEEDBACK_UPDATES
RUNTIME_FUNCTION(Runtime_TraceUpdateFeedback) {
if (!v8_flags.trace_feedback_updates) {
return ReadOnlyRoots(isolate).undefined_value();
}
SealHandleScope shs(isolate);
DCHECK_EQ(3, args.length());
Handle<FeedbackVector> vector = args.at<FeedbackVector>(0);
int slot = args.smi_value_at(1);
auto reason = Cast<String>(args[2]);
FeedbackVector::TraceFeedbackChange(isolate, *vector, FeedbackSlot(slot),
reason->ToCString().get());
return ReadOnlyRoots(isolate).undefined_value();
}
#endif
}
}