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