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 "src/runtime/runtime-utils.h"
6 
7 #include <iomanip>
8 
9 #include "src/arguments.h"
10 #include "src/frames-inl.h"
11 #include "src/interpreter/bytecode-array-iterator.h"
12 #include "src/interpreter/bytecode-decoder.h"
13 #include "src/interpreter/bytecode-flags.h"
14 #include "src/interpreter/bytecode-register.h"
15 #include "src/interpreter/bytecodes.h"
16 #include "src/isolate-inl.h"
17 #include "src/ostreams.h"
18 
19 namespace v8 {
20 namespace internal {
21 
RUNTIME_FUNCTION(Runtime_InterpreterNewClosure)22 RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) {
23   HandleScope scope(isolate);
24   DCHECK_EQ(2, args.length());
25   CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
26   CONVERT_SMI_ARG_CHECKED(pretenured_flag, 1);
27   Handle<Context> context(isolate->context(), isolate);
28   return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
29       shared, context, static_cast<PretenureFlag>(pretenured_flag));
30 }
31 
32 namespace {
33 
AdvanceToOffsetForTracing(interpreter::BytecodeArrayIterator & bytecode_iterator,int offset)34 void AdvanceToOffsetForTracing(
35     interpreter::BytecodeArrayIterator& bytecode_iterator, int offset) {
36   while (bytecode_iterator.current_offset() +
37              bytecode_iterator.current_bytecode_size() <=
38          offset) {
39     bytecode_iterator.Advance();
40   }
41   DCHECK(bytecode_iterator.current_offset() == offset ||
42          ((bytecode_iterator.current_offset() + 1) == offset &&
43           bytecode_iterator.current_operand_scale() >
44               interpreter::OperandScale::kSingle));
45 }
46 
PrintRegisters(std::ostream & os,bool is_input,interpreter::BytecodeArrayIterator & bytecode_iterator,Handle<Object> accumulator)47 void PrintRegisters(std::ostream& os, bool is_input,
48                     interpreter::BytecodeArrayIterator& bytecode_iterator,
49                     Handle<Object> accumulator) {
50   static const char kAccumulator[] = "accumulator";
51   static const int kRegFieldWidth = static_cast<int>(sizeof(kAccumulator) - 1);
52   static const char* kInputColourCode = "\033[0;36m";
53   static const char* kOutputColourCode = "\033[0;35m";
54   static const char* kNormalColourCode = "\033[0;m";
55   const char* kArrowDirection = is_input ? " -> " : " <- ";
56   if (FLAG_log_colour) {
57     os << (is_input ? kInputColourCode : kOutputColourCode);
58   }
59 
60   interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
61 
62   // Print accumulator.
63   if ((is_input && interpreter::Bytecodes::ReadsAccumulator(bytecode)) ||
64       (!is_input && interpreter::Bytecodes::WritesAccumulator(bytecode))) {
65     os << "      [ " << kAccumulator << kArrowDirection;
66     accumulator->ShortPrint();
67     os << " ]" << std::endl;
68   }
69 
70   // Print the registers.
71   JavaScriptFrameIterator frame_iterator(
72       bytecode_iterator.bytecode_array()->GetIsolate());
73   InterpretedFrame* frame =
74       reinterpret_cast<InterpretedFrame*>(frame_iterator.frame());
75   int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode);
76   for (int operand_index = 0; operand_index < operand_count; operand_index++) {
77     interpreter::OperandType operand_type =
78         interpreter::Bytecodes::GetOperandType(bytecode, operand_index);
79     bool should_print =
80         is_input
81             ? interpreter::Bytecodes::IsRegisterInputOperandType(operand_type)
82             : interpreter::Bytecodes::IsRegisterOutputOperandType(operand_type);
83     if (should_print) {
84       interpreter::Register first_reg =
85           bytecode_iterator.GetRegisterOperand(operand_index);
86       int range = bytecode_iterator.GetRegisterOperandRange(operand_index);
87       for (int reg_index = first_reg.index();
88            reg_index < first_reg.index() + range; reg_index++) {
89         Object* reg_object = frame->ReadInterpreterRegister(reg_index);
90         os << "      [ " << std::setw(kRegFieldWidth)
91            << interpreter::Register(reg_index).ToString(
92                   bytecode_iterator.bytecode_array()->parameter_count())
93            << kArrowDirection;
94         reg_object->ShortPrint(os);
95         os << " ]" << std::endl;
96       }
97     }
98   }
99   if (FLAG_log_colour) {
100     os << kNormalColourCode;
101   }
102 }
103 
104 }  // namespace
105 
RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry)106 RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) {
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   OFStream os(stdout);
113 
114   int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
115   interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
116   AdvanceToOffsetForTracing(bytecode_iterator, offset);
117   if (offset == bytecode_iterator.current_offset()) {
118     // Print bytecode.
119     const uint8_t* base_address = bytecode_array->GetFirstBytecodeAddress();
120     const uint8_t* bytecode_address = base_address + offset;
121     os << " -> " << static_cast<const void*>(bytecode_address) << " @ "
122        << std::setw(4) << offset << " : ";
123     interpreter::BytecodeDecoder::Decode(os, bytecode_address,
124                                          bytecode_array->parameter_count());
125     os << std::endl;
126     // Print all input registers and accumulator.
127     PrintRegisters(os, true, bytecode_iterator, accumulator);
128 
129     os << std::flush;
130   }
131   return isolate->heap()->undefined_value();
132 }
133 
RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit)134 RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit) {
135   SealHandleScope shs(isolate);
136   DCHECK_EQ(3, args.length());
137   CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0);
138   CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1);
139   CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2);
140 
141   int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
142   interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
143   AdvanceToOffsetForTracing(bytecode_iterator, offset);
144   // The offset comparison here ensures registers only printed when the
145   // (potentially) widened bytecode has completed. The iterator reports
146   // the offset as the offset of the prefix bytecode.
147   if (bytecode_iterator.current_operand_scale() ==
148           interpreter::OperandScale::kSingle ||
149       offset > bytecode_iterator.current_offset()) {
150     OFStream os(stdout);
151     // Print all output registers and accumulator.
152     PrintRegisters(os, false, bytecode_iterator, accumulator);
153     os << std::flush;
154   }
155   return isolate->heap()->undefined_value();
156 }
157 
RUNTIME_FUNCTION(Runtime_InterpreterClearPendingMessage)158 RUNTIME_FUNCTION(Runtime_InterpreterClearPendingMessage) {
159   SealHandleScope shs(isolate);
160   DCHECK_EQ(0, args.length());
161   Object* message = isolate->thread_local_top()->pending_message_obj_;
162   isolate->clear_pending_message();
163   return message;
164 }
165 
RUNTIME_FUNCTION(Runtime_InterpreterSetPendingMessage)166 RUNTIME_FUNCTION(Runtime_InterpreterSetPendingMessage) {
167   SealHandleScope shs(isolate);
168   DCHECK_EQ(1, args.length());
169   CONVERT_ARG_HANDLE_CHECKED(Object, message, 0);
170   isolate->thread_local_top()->pending_message_obj_ = *message;
171   return isolate->heap()->undefined_value();
172 }
173 
RUNTIME_FUNCTION(Runtime_InterpreterAdvanceBytecodeOffset)174 RUNTIME_FUNCTION(Runtime_InterpreterAdvanceBytecodeOffset) {
175   SealHandleScope shs(isolate);
176   DCHECK_EQ(2, args.length());
177   CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0);
178   CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1);
179   interpreter::BytecodeArrayIterator it(bytecode_array);
180   int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
181   while (it.current_offset() < offset) it.Advance();
182   DCHECK_EQ(offset, it.current_offset());
183   it.Advance();  // Advance by one bytecode.
184   offset = it.current_offset() + BytecodeArray::kHeaderSize - kHeapObjectTag;
185   return Smi::FromInt(offset);
186 }
187 
188 }  // namespace internal
189 }  // namespace v8
190