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_UNOPTIMIZED
25
26 namespace {
27
AdvanceToOffsetForTracing(interpreter::BytecodeArrayIterator & bytecode_iterator,int offset)28 void AdvanceToOffsetForTracing(
29 interpreter::BytecodeArrayIterator& bytecode_iterator, int offset) {
30 while (bytecode_iterator.current_offset() +
31 bytecode_iterator.current_bytecode_size() <=
32 offset) {
33 bytecode_iterator.Advance();
34 }
35 DCHECK(bytecode_iterator.current_offset() == offset ||
36 ((bytecode_iterator.current_offset() + 1) == offset &&
37 bytecode_iterator.current_operand_scale() >
38 interpreter::OperandScale::kSingle));
39 }
40
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)41 void PrintRegisterRange(UnoptimizedFrame* frame, std::ostream& os,
42 interpreter::BytecodeArrayIterator& bytecode_iterator,
43 const int& reg_field_width, const char* arrow_direction,
44 interpreter::Register first_reg, int range) {
45 for (int reg_index = first_reg.index(); reg_index < first_reg.index() + range;
46 reg_index++) {
47 Object reg_object = frame->ReadInterpreterRegister(reg_index);
48 os << " [ " << std::setw(reg_field_width)
49 << interpreter::Register(reg_index).ToString() << arrow_direction;
50 reg_object.ShortPrint(os);
51 os << " ]" << std::endl;
52 }
53 }
54
PrintRegisters(UnoptimizedFrame * frame,std::ostream & os,bool is_input,interpreter::BytecodeArrayIterator & bytecode_iterator,Handle<Object> accumulator)55 void PrintRegisters(UnoptimizedFrame* frame, std::ostream& os, bool is_input,
56 interpreter::BytecodeArrayIterator& bytecode_iterator,
57 Handle<Object> accumulator) {
58 static const char kAccumulator[] = "accumulator";
59 static const int kRegFieldWidth = static_cast<int>(sizeof(kAccumulator) - 1);
60 static const char* kInputColourCode = "\033[0;36m";
61 static const char* kOutputColourCode = "\033[0;35m";
62 static const char* kNormalColourCode = "\033[0;m";
63 const char* kArrowDirection = is_input ? " -> " : " <- ";
64 if (FLAG_log_colour) {
65 os << (is_input ? kInputColourCode : kOutputColourCode);
66 }
67
68 interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
69
70 // Print accumulator.
71 if ((is_input && interpreter::Bytecodes::ReadsAccumulator(bytecode)) ||
72 (!is_input && interpreter::Bytecodes::WritesAccumulator(bytecode))) {
73 os << " [ " << kAccumulator << kArrowDirection;
74 accumulator->ShortPrint(os);
75 os << " ]" << std::endl;
76 }
77
78 // Print the registers.
79 int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode);
80 for (int operand_index = 0; operand_index < operand_count; operand_index++) {
81 interpreter::OperandType operand_type =
82 interpreter::Bytecodes::GetOperandType(bytecode, operand_index);
83 bool should_print =
84 is_input
85 ? interpreter::Bytecodes::IsRegisterInputOperandType(operand_type)
86 : interpreter::Bytecodes::IsRegisterOutputOperandType(operand_type);
87 if (should_print) {
88 interpreter::Register first_reg =
89 bytecode_iterator.GetRegisterOperand(operand_index);
90 int range = bytecode_iterator.GetRegisterOperandRange(operand_index);
91 PrintRegisterRange(frame, os, bytecode_iterator, kRegFieldWidth,
92 kArrowDirection, first_reg, range);
93 }
94 }
95 if (!is_input && interpreter::Bytecodes::IsShortStar(bytecode)) {
96 PrintRegisterRange(frame, os, bytecode_iterator, kRegFieldWidth,
97 kArrowDirection,
98 interpreter::Register::FromShortStar(bytecode), 1);
99 }
100 if (FLAG_log_colour) {
101 os << kNormalColourCode;
102 }
103 }
104
105 } // namespace
106
RUNTIME_FUNCTION(Runtime_TraceUnoptimizedBytecodeEntry)107 RUNTIME_FUNCTION(Runtime_TraceUnoptimizedBytecodeEntry) {
108 if (!FLAG_trace_ignition && !FLAG_trace_baseline_exec) {
109 return ReadOnlyRoots(isolate).undefined_value();
110 }
111
112 JavaScriptFrameIterator frame_iterator(isolate);
113 UnoptimizedFrame* frame =
114 reinterpret_cast<UnoptimizedFrame*>(frame_iterator.frame());
115
116 if (frame->is_interpreted() && !FLAG_trace_ignition) {
117 return ReadOnlyRoots(isolate).undefined_value();
118 }
119 if (frame->is_baseline() && !FLAG_trace_baseline_exec) {
120 return ReadOnlyRoots(isolate).undefined_value();
121 }
122
123 SealHandleScope shs(isolate);
124 DCHECK_EQ(3, args.length());
125 Handle<BytecodeArray> bytecode_array = args.at<BytecodeArray>(0);
126 int bytecode_offset = args.smi_value_at(1);
127 Handle<Object> accumulator = args.at(2);
128
129 int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
130 interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
131 AdvanceToOffsetForTracing(bytecode_iterator, offset);
132 if (offset == bytecode_iterator.current_offset()) {
133 StdoutStream os;
134
135 // Print bytecode.
136 const uint8_t* base_address = reinterpret_cast<const uint8_t*>(
137 bytecode_array->GetFirstBytecodeAddress());
138 const uint8_t* bytecode_address = base_address + offset;
139
140 if (frame->is_baseline()) {
141 os << "B-> ";
142 } else {
143 os << " -> ";
144 }
145 os << static_cast<const void*>(bytecode_address) << " @ " << std::setw(4)
146 << offset << " : ";
147 interpreter::BytecodeDecoder::Decode(os, bytecode_address);
148 os << std::endl;
149 // Print all input registers and accumulator.
150 PrintRegisters(frame, os, true, bytecode_iterator, accumulator);
151
152 os << std::flush;
153 }
154 return ReadOnlyRoots(isolate).undefined_value();
155 }
156
RUNTIME_FUNCTION(Runtime_TraceUnoptimizedBytecodeExit)157 RUNTIME_FUNCTION(Runtime_TraceUnoptimizedBytecodeExit) {
158 if (!FLAG_trace_ignition && !FLAG_trace_baseline_exec) {
159 return ReadOnlyRoots(isolate).undefined_value();
160 }
161
162 JavaScriptFrameIterator frame_iterator(isolate);
163 UnoptimizedFrame* frame =
164 reinterpret_cast<UnoptimizedFrame*>(frame_iterator.frame());
165
166 if (frame->is_interpreted() && !FLAG_trace_ignition) {
167 return ReadOnlyRoots(isolate).undefined_value();
168 }
169 if (frame->is_baseline() && !FLAG_trace_baseline_exec) {
170 return ReadOnlyRoots(isolate).undefined_value();
171 }
172
173 SealHandleScope shs(isolate);
174 DCHECK_EQ(3, args.length());
175 Handle<BytecodeArray> bytecode_array = args.at<BytecodeArray>(0);
176 int bytecode_offset = args.smi_value_at(1);
177 Handle<Object> accumulator = args.at(2);
178
179 int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
180 interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
181 AdvanceToOffsetForTracing(bytecode_iterator, offset);
182 // The offset comparison here ensures registers only printed when the
183 // (potentially) widened bytecode has completed. The iterator reports
184 // the offset as the offset of the prefix bytecode.
185 if (bytecode_iterator.current_operand_scale() ==
186 interpreter::OperandScale::kSingle ||
187 offset > bytecode_iterator.current_offset()) {
188 StdoutStream os;
189
190 // Print all output registers and accumulator.
191 PrintRegisters(frame, os, false, bytecode_iterator, accumulator);
192 os << std::flush;
193 }
194 return ReadOnlyRoots(isolate).undefined_value();
195 }
196
197 #endif
198
199 #ifdef V8_TRACE_FEEDBACK_UPDATES
200
RUNTIME_FUNCTION(Runtime_TraceUpdateFeedback)201 RUNTIME_FUNCTION(Runtime_TraceUpdateFeedback) {
202 if (!FLAG_trace_feedback_updates) {
203 return ReadOnlyRoots(isolate).undefined_value();
204 }
205
206 SealHandleScope shs(isolate);
207 DCHECK_EQ(3, args.length());
208 Handle<JSFunction> function = args.at<JSFunction>(0);
209 int slot = args.smi_value_at(1);
210 auto reason = String::cast(args[2]);
211
212 int slot_count = function->feedback_vector().metadata().slot_count();
213
214 StdoutStream os;
215 os << "[Feedback slot " << slot << "/" << slot_count << " in ";
216 function->shared().ShortPrint(os);
217 os << " updated to ";
218 function->feedback_vector().FeedbackSlotPrint(os, FeedbackSlot(slot));
219 os << " - ";
220
221 StringCharacterStream stream(reason);
222 while (stream.HasMore()) {
223 uint16_t character = stream.GetNext();
224 PrintF("%c", character);
225 }
226
227 os << "]" << std::endl;
228
229 return ReadOnlyRoots(isolate).undefined_value();
230 }
231
232 #endif
233
234 } // namespace internal
235 } // namespace v8
236