• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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