1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <iomanip>
6
7 #include "src/execution/arguments-inl.h"
8 #include "src/execution/frames-inl.h"
9 #include "src/execution/isolate-inl.h"
10 #include "src/interpreter/bytecode-array-iterator.h"
11 #include "src/interpreter/bytecode-decoder.h"
12 #include "src/interpreter/bytecode-flags.h"
13 #include "src/interpreter/bytecode-register.h"
14 #include "src/interpreter/bytecodes.h"
15 #include "src/interpreter/interpreter.h"
16 #include "src/logging/counters.h"
17 #include "src/runtime/runtime-utils.h"
18 #include "src/snapshot/snapshot.h"
19 #include "src/utils/ostreams.h"
20
21 namespace v8 {
22 namespace internal {
23
24 #ifdef V8_TRACE_IGNITION
25
26 namespace {
27
AdvanceToOffsetForTracing(interpreter::BytecodeArrayIterator & bytecode_iterator,int offset)28 void AdvanceToOffsetForTracing(
29 interpreter::BytecodeArrayIterator&
30 bytecode_iterator, // NOLINT(runtime/references)
31 int offset) {
32 while (bytecode_iterator.current_offset() +
33 bytecode_iterator.current_bytecode_size() <=
34 offset) {
35 bytecode_iterator.Advance();
36 }
37 DCHECK(bytecode_iterator.current_offset() == offset ||
38 ((bytecode_iterator.current_offset() + 1) == offset &&
39 bytecode_iterator.current_operand_scale() >
40 interpreter::OperandScale::kSingle));
41 }
42
PrintRegisters(Isolate * isolate,std::ostream & os,bool is_input,interpreter::BytecodeArrayIterator & bytecode_iterator,Handle<Object> accumulator)43 void PrintRegisters(Isolate* isolate, std::ostream& os, bool is_input,
44 interpreter::BytecodeArrayIterator&
45 bytecode_iterator, // NOLINT(runtime/references)
46 Handle<Object> accumulator) {
47 static const char kAccumulator[] = "accumulator";
48 static const int kRegFieldWidth = static_cast<int>(sizeof(kAccumulator) - 1);
49 static const char* kInputColourCode = "\033[0;36m";
50 static const char* kOutputColourCode = "\033[0;35m";
51 static const char* kNormalColourCode = "\033[0;m";
52 const char* kArrowDirection = is_input ? " -> " : " <- ";
53 if (FLAG_log_colour) {
54 os << (is_input ? kInputColourCode : kOutputColourCode);
55 }
56
57 interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
58
59 // Print accumulator.
60 if ((is_input && interpreter::Bytecodes::ReadsAccumulator(bytecode)) ||
61 (!is_input && interpreter::Bytecodes::WritesAccumulator(bytecode))) {
62 os << " [ " << kAccumulator << kArrowDirection;
63 accumulator->ShortPrint();
64 os << " ]" << std::endl;
65 }
66
67 // Print the registers.
68 JavaScriptFrameIterator frame_iterator(isolate);
69 InterpretedFrame* frame =
70 reinterpret_cast<InterpretedFrame*>(frame_iterator.frame());
71 int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode);
72 for (int operand_index = 0; operand_index < operand_count; operand_index++) {
73 interpreter::OperandType operand_type =
74 interpreter::Bytecodes::GetOperandType(bytecode, operand_index);
75 bool should_print =
76 is_input
77 ? interpreter::Bytecodes::IsRegisterInputOperandType(operand_type)
78 : interpreter::Bytecodes::IsRegisterOutputOperandType(operand_type);
79 if (should_print) {
80 interpreter::Register first_reg =
81 bytecode_iterator.GetRegisterOperand(operand_index);
82 int range = bytecode_iterator.GetRegisterOperandRange(operand_index);
83 for (int reg_index = first_reg.index();
84 reg_index < first_reg.index() + range; reg_index++) {
85 Object reg_object = frame->ReadInterpreterRegister(reg_index);
86 os << " [ " << std::setw(kRegFieldWidth)
87 << interpreter::Register(reg_index).ToString(
88 bytecode_iterator.bytecode_array()->parameter_count())
89 << kArrowDirection;
90 reg_object.ShortPrint(os);
91 os << " ]" << std::endl;
92 }
93 }
94 }
95 if (FLAG_log_colour) {
96 os << kNormalColourCode;
97 }
98 }
99
100 } // namespace
101
RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry)102 RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) {
103 if (!FLAG_trace_ignition) {
104 return ReadOnlyRoots(isolate).undefined_value();
105 }
106
107 SealHandleScope shs(isolate);
108 DCHECK_EQ(3, args.length());
109 CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0);
110 CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1);
111 CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2);
112
113 int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
114 interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
115 AdvanceToOffsetForTracing(bytecode_iterator, offset);
116 if (offset == bytecode_iterator.current_offset()) {
117 StdoutStream os;
118
119 // Print bytecode.
120 const uint8_t* base_address = reinterpret_cast<const uint8_t*>(
121 bytecode_array->GetFirstBytecodeAddress());
122 const uint8_t* bytecode_address = base_address + offset;
123 os << " -> " << static_cast<const void*>(bytecode_address) << " @ "
124 << std::setw(4) << offset << " : ";
125 interpreter::BytecodeDecoder::Decode(os, bytecode_address,
126 bytecode_array->parameter_count());
127 os << std::endl;
128 // Print all input registers and accumulator.
129 PrintRegisters(isolate, os, true, bytecode_iterator, accumulator);
130
131 os << std::flush;
132 }
133 return ReadOnlyRoots(isolate).undefined_value();
134 }
135
RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit)136 RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit) {
137 if (!FLAG_trace_ignition) {
138 return ReadOnlyRoots(isolate).undefined_value();
139 }
140
141 SealHandleScope shs(isolate);
142 DCHECK_EQ(3, args.length());
143 CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0);
144 CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1);
145 CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2);
146
147 int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
148 interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
149 AdvanceToOffsetForTracing(bytecode_iterator, offset);
150 // The offset comparison here ensures registers only printed when the
151 // (potentially) widened bytecode has completed. The iterator reports
152 // the offset as the offset of the prefix bytecode.
153 if (bytecode_iterator.current_operand_scale() ==
154 interpreter::OperandScale::kSingle ||
155 offset > bytecode_iterator.current_offset()) {
156 StdoutStream os;
157 // Print all output registers and accumulator.
158 PrintRegisters(isolate, os, false, bytecode_iterator, accumulator);
159 os << std::flush;
160 }
161 return ReadOnlyRoots(isolate).undefined_value();
162 }
163
164 #endif
165
166 #ifdef V8_TRACE_FEEDBACK_UPDATES
167
RUNTIME_FUNCTION(Runtime_InterpreterTraceUpdateFeedback)168 RUNTIME_FUNCTION(Runtime_InterpreterTraceUpdateFeedback) {
169 if (!FLAG_trace_feedback_updates) {
170 return ReadOnlyRoots(isolate).undefined_value();
171 }
172
173 SealHandleScope shs(isolate);
174 DCHECK_EQ(3, args.length());
175 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
176 CONVERT_SMI_ARG_CHECKED(slot, 1);
177 CONVERT_ARG_CHECKED(String, reason, 2);
178
179 int slot_count = function->feedback_vector().metadata().slot_count();
180
181 StdoutStream os;
182 os << "[Feedback slot " << slot << "/" << slot_count << " in ";
183 function->shared().ShortPrint(os);
184 os << " updated to ";
185 function->feedback_vector().FeedbackSlotPrint(os, FeedbackSlot(slot));
186 os << " - ";
187
188 StringCharacterStream stream(reason);
189 while (stream.HasMore()) {
190 uint16_t character = stream.GetNext();
191 PrintF("%c", character);
192 }
193
194 os << "]" << std::endl;
195
196 return ReadOnlyRoots(isolate).undefined_value();
197 }
198
199 #endif
200
201 } // namespace internal
202 } // namespace v8
203