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