Commit 6399fce5 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add option to trace bytecode execution.

Adds --trace-ignition flag which allows tracing of bytecodes as they
execute. As well as printing out the bytecode, this also prints out the
input and output registers to each operation. The generated output looks
as follows:

 -> 0x350cb46d5264 (139) : 49 fc fb 03 07    Call r4, r5, #3, [7]
      [ accumulator -> 0x177fba00bc99 <JS Array[2]> ]
      [          r4 -> 0x350cb46ce099 <JS Function InstallFunctions (SharedFunctionInfo 0x350cb46470c1)> ]
      [          r5 -> 0x350cb46cddc1 <an Object with map 0x35fdf590a3a9> ]
      [          r6 -> 0x350cb46d3f11 <JS Function Proxy (SharedFunctionInfo 0x350cb46d3e61)> ]
      [          r7 -> 2 ]
      [ accumulator <- 0x350cb4604189 <undefined> ]
 -> 0x350cb46d5978 (47) : 4b f8 00 00 00    CallRuntime [248], r0, #0
      [ accumulator -> 0x350cb4604189 <undefined> ]
      [ accumulator <- 0x350cb4604189 <undefined> ]
 -> 0x350cb46d597d (52) : 23 09             Ldar a0
      [ accumulator -> 0x350cb4604189 <undefined> ]
      [          a0 -> 0x350cb46d3f11 <JS Function Proxy (SharedFunctionInfo 0x350cb46d3e61)> ]
      [ accumulator <- 0x350cb46d3f11 <JS Function Proxy (SharedFunctionInfo 0x350cb46d3e61)> ]
 -> 0x350cb46d597f (54) : 24 fd             Star r3
      [ accumulator -> 0x350cb46d3f11 <JS Function Proxy (SharedFunctionInfo 0x350cb46d3e61)> ]
      [ accumulator <- 0x350cb46d3f11 <JS Function Proxy (SharedFunctionInfo 0x350cb46d3e61)> ]
      [          r3 <- 0x350cb46d3f11 <JS Function Proxy (SharedFunctionInfo 0x350cb46d3e61)> ]

Also adds support for --print_source and --print-ast to the interpreter.

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1640213002

Cr-Commit-Position: refs/heads/master@{#33594}
parent 87b6e880
......@@ -24,7 +24,6 @@ namespace v8 {
namespace internal {
namespace compiler {
InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
interpreter::Bytecode bytecode)
: bytecode_(bytecode),
......@@ -35,12 +34,13 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
InstructionSelector::SupportedMachineOperatorFlags())),
accumulator_(
raw_assembler_->Parameter(Linkage::kInterpreterAccumulatorParameter)),
bytecode_offset_(raw_assembler_->Parameter(
Linkage::kInterpreterBytecodeOffsetParameter)),
context_(
raw_assembler_->Parameter(Linkage::kInterpreterContextParameter)),
code_generated_(false) {}
code_generated_(false) {
if (FLAG_trace_ignition) {
TraceBytecode(Runtime::kInterpreterTraceBytecodeEntry);
}
}
InterpreterAssembler::~InterpreterAssembler() {}
......@@ -85,9 +85,10 @@ void InterpreterAssembler::SetContext(Node* value) {
context_ = value;
}
Node* InterpreterAssembler::BytecodeOffset() { return bytecode_offset_; }
Node* InterpreterAssembler::BytecodeOffset() {
return raw_assembler_->Parameter(
Linkage::kInterpreterBytecodeOffsetParameter);
}
Node* InterpreterAssembler::RegisterFileRawPointer() {
return raw_assembler_->Parameter(Linkage::kInterpreterRegisterFileParameter);
......@@ -464,18 +465,11 @@ Node* InterpreterAssembler::CallConstruct(Node* new_target, Node* constructor,
void InterpreterAssembler::CallPrologue() {
StoreRegister(SmiTag(bytecode_offset_),
StoreRegister(SmiTag(BytecodeOffset()),
InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer);
}
void InterpreterAssembler::CallEpilogue() {
// Restore the bytecode offset from the stack frame.
bytecode_offset_ = SmiUntag(LoadRegister(
InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
}
Node* InterpreterAssembler::CallN(CallDescriptor* descriptor, Node* code_target,
Node** args) {
CallPrologue();
......@@ -491,7 +485,6 @@ Node* InterpreterAssembler::CallN(CallDescriptor* descriptor, Node* code_target,
kUnexpectedStackPointer);
}
CallEpilogue();
return return_val;
}
......@@ -594,7 +587,6 @@ Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
CallPrologue();
Node* return_val =
raw_assembler_->CallRuntime1(function_id, arg1, GetContext());
CallEpilogue();
return return_val;
}
......@@ -604,10 +596,16 @@ Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
CallPrologue();
Node* return_val =
raw_assembler_->CallRuntime2(function_id, arg1, arg2, GetContext());
CallEpilogue();
return return_val;
}
Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
Node* arg1, Node* arg2, Node* arg3) {
CallPrologue();
Node* return_val =
raw_assembler_->CallRuntime3(function_id, arg1, arg2, arg3, GetContext());
return return_val;
}
Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
Node* arg1, Node* arg2, Node* arg3,
......@@ -615,12 +613,15 @@ Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
CallPrologue();
Node* return_val = raw_assembler_->CallRuntime4(function_id, arg1, arg2, arg3,
arg4, GetContext());
CallEpilogue();
return return_val;
}
void InterpreterAssembler::Return() {
if (FLAG_trace_ignition) {
TraceBytecode(Runtime::kInterpreterTraceBytecodeExit);
}
Node* exit_trampoline_code_object =
HeapConstant(isolate()->builtins()->InterpreterExitTrampoline());
// If the order of the parameters you need to change the call signature below.
......@@ -650,10 +651,8 @@ Node* InterpreterAssembler::Advance(Node* delta) {
return raw_assembler_->IntPtrAdd(BytecodeOffset(), delta);
}
void InterpreterAssembler::Jump(Node* delta) { DispatchTo(Advance(delta)); }
void InterpreterAssembler::JumpIfWordEqual(Node* lhs, Node* rhs, Node* delta) {
RawMachineLabel match, no_match;
Node* condition = raw_assembler_->WordEqual(lhs, rhs);
......@@ -671,6 +670,9 @@ void InterpreterAssembler::Dispatch() {
void InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) {
if (FLAG_trace_ignition) {
TraceBytecode(Runtime::kInterpreterTraceBytecodeExit);
}
Node* target_bytecode = raw_assembler_->Load(
MachineType::Uint8(), BytecodeArrayTaggedPointer(), new_bytecode_offset);
......@@ -716,6 +718,10 @@ void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs,
raw_assembler_->Bind(&match);
}
void InterpreterAssembler::TraceBytecode(Runtime::FunctionId function_id) {
CallRuntime(function_id, BytecodeArrayTaggedPointer(),
SmiTag(BytecodeOffset()), GetAccumulator());
}
// static
bool InterpreterAssembler::TargetSupportsUnalignedAccess() {
......
......@@ -137,6 +137,8 @@ class InterpreterAssembler {
int return_size = 1);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1, Node* arg2);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1, Node* arg2,
Node* arg3);
Node* CallRuntime(Runtime::FunctionId function_id, Node* arg1, Node* arg2,
Node* arg3, Node* arg4);
......@@ -176,7 +178,9 @@ class InterpreterAssembler {
// Saves and restores interpreter bytecode offset to the interpreter stack
// frame when performing a call.
void CallPrologue();
void CallEpilogue();
// Traces the current bytecode by calling |function_id|.
void TraceBytecode(Runtime::FunctionId function_id);
// Returns the offset of register |index| relative to RegisterFilePointer().
Node* RegisterFrameOffset(Node* index);
......@@ -209,7 +213,6 @@ class InterpreterAssembler {
base::SmartPointer<RawMachineAssembler> raw_assembler_;
Node* accumulator_;
Node* bytecode_offset_;
Node* context_;
bool code_generated_;
......
......@@ -183,6 +183,21 @@ Node* RawMachineAssembler::CallRuntime2(Runtime::FunctionId function,
context);
}
Node* RawMachineAssembler::CallRuntime3(Runtime::FunctionId function,
Node* arg1, Node* arg2, Node* arg3,
Node* context) {
CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
zone(), function, 3, Operator::kNoProperties, CallDescriptor::kNoFlags);
int return_count = static_cast<int>(descriptor->ReturnCount());
Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
Node* ref = AddNode(
common()->ExternalConstant(ExternalReference(function, isolate())));
Node* arity = Int32Constant(3);
return AddNode(common()->Call(descriptor), centry, arg1, arg2, arg3, ref,
arity, context);
}
Node* RawMachineAssembler::CallRuntime4(Runtime::FunctionId function,
Node* arg1, Node* arg2, Node* arg3,
......
......@@ -569,6 +569,9 @@ class RawMachineAssembler {
// Call to a runtime function with two arguments.
Node* CallRuntime2(Runtime::FunctionId function, Node* arg1, Node* arg2,
Node* context);
// Call to a runtime function with three arguments.
Node* CallRuntime3(Runtime::FunctionId function, Node* arg1, Node* arg2,
Node* arg3, Node* context);
// Call to a runtime function with four arguments.
Node* CallRuntime4(Runtime::FunctionId function, Node* arg1, Node* arg2,
Node* arg3, Node* arg4, Node* context);
......
......@@ -144,6 +144,11 @@ struct MaybeBoolFlag {
#else
# define ENABLE_NEON_DEFAULT false
#endif
#ifdef V8_OS_WIN
# define ENABLE_LOG_COLOUR false
#else
# define ENABLE_LOG_COLOUR true
#endif
#define DEFINE_BOOL(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
#define DEFINE_BOOL_READONLY(nam, def, cmt) \
......@@ -302,6 +307,8 @@ DEFINE_BOOL(ignition, false, "use ignition interpreter")
DEFINE_STRING(ignition_filter, "*", "filter for ignition interpreter")
DEFINE_BOOL(print_bytecode, false,
"print bytecode generated by ignition interpreter")
DEFINE_BOOL(trace_ignition, false,
"trace the bytecodes executed by the ignition interpreter")
DEFINE_BOOL(trace_ignition_codegen, false,
"trace the codegen of ignition interpreter bytecode handlers")
......@@ -788,7 +795,8 @@ DEFINE_INT(sim_stack_size, 2 * MB / KB,
"in kBytes (default is 2 MB)")
DEFINE_BOOL(log_regs_modified, true,
"When logging register values, only print modified registers.")
DEFINE_BOOL(log_colour, true, "When logging, try to use coloured output.")
DEFINE_BOOL(log_colour, ENABLE_LOG_COLOUR,
"When logging, try to use coloured output.")
DEFINE_BOOL(ignore_asm_unimplemented_break, false,
"Don't break for ASM_UNIMPLEMENTED_BREAK macros.")
DEFINE_BOOL(trace_sim_messages, false,
......
......@@ -100,6 +100,36 @@ Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
return Register();
}
int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const {
interpreter::OperandType operand_type =
Bytecodes::GetOperandType(current_bytecode(), operand_index);
DCHECK(Bytecodes::IsRegisterOperandType(operand_type));
switch (operand_type) {
case OperandType::kRegPair8:
case OperandType::kRegPair16:
case OperandType::kRegOutPair8:
case OperandType::kRegOutPair16:
return 2;
case OperandType::kRegOutTriple8:
case OperandType::kRegOutTriple16:
return 3;
default: {
if (operand_index + 1 !=
Bytecodes::NumberOfOperands(current_bytecode())) {
// TODO(oth): Ensure all bytecodes specify the full range of registers
// with kRegCount (currently Call/CallJSRuntime are off by one due to
// reciever.
OperandType next_operand_type =
Bytecodes::GetOperandType(current_bytecode(), operand_index + 1);
if (next_operand_type == OperandType::kRegCount8 ||
next_operand_type == OperandType::kRegCount16) {
return GetCountOperand(operand_index + 1);
}
}
return 1;
}
}
}
Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
int operand_index) const {
......
......@@ -21,6 +21,7 @@ class BytecodeArrayIterator {
bool done() const;
Bytecode current_bytecode() const;
int current_bytecode_size() const;
void set_current_offset(int offset) { bytecode_offset_ = offset; }
int current_offset() const { return bytecode_offset_; }
const Handle<BytecodeArray>& bytecode_array() const {
return bytecode_array_;
......@@ -30,6 +31,7 @@ class BytecodeArrayIterator {
int GetIndexOperand(int operand_index) const;
int GetCountOperand(int operand_index) const;
Register GetRegisterOperand(int operand_index) const;
int GetRegisterOperandRange(int operand_index) const;
Handle<Object> GetConstantForIndexOperand(int operand_index) const;
// Get the raw byte for the given operand. Note: you should prefer using the
......
......@@ -380,22 +380,7 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
case interpreter::OperandType::kRegOut8:
case interpreter::OperandType::kRegOut16: {
Register reg = DecodeRegister(operand_start, op_type);
if (reg.is_current_context()) {
os << "<context>";
} else if (reg.is_function_closure()) {
os << "<closure>";
} else if (reg.is_new_target()) {
os << "<new.target>";
} else if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count);
if (parameter_index == 0) {
os << "<this>";
} else {
os << "a" << parameter_index - 1;
}
} else {
os << "r" << reg.index();
}
os << reg.ToString(parameter_count);
break;
}
case interpreter::OperandType::kRegOutTriple8:
......@@ -406,14 +391,10 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
case interpreter::OperandType::kRegPair8:
case interpreter::OperandType::kRegPair16: {
range += 1;
Register reg = DecodeRegister(operand_start, op_type);
if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count);
DCHECK_GT(parameter_index, 0);
os << "a" << parameter_index - range << "-" << parameter_index;
} else {
os << "r" << reg.index() << "-" << reg.index() + range;
}
Register first_reg = DecodeRegister(operand_start, op_type);
Register last_reg = Register(first_reg.index() + range);
os << first_reg.ToString(parameter_count) << "-"
<< last_reg.ToString(parameter_count);
break;
}
case interpreter::OperandType::kNone:
......@@ -427,7 +408,6 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
return os;
}
std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
return os << Bytecodes::ToString(bytecode);
}
......@@ -442,7 +422,6 @@ std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) {
return os << Bytecodes::OperandSizeToString(operand_size);
}
static const int kLastParamRegisterIndex =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
static const int kFunctionClosureRegisterIndex =
......@@ -569,6 +548,29 @@ bool Register::AreContiguous(Register reg1, Register reg2, Register reg3,
return true;
}
std::string Register::ToString(int parameter_count) {
if (is_current_context()) {
return std::string("<context>");
} else if (is_function_closure()) {
return std::string("<closure>");
} else if (is_new_target()) {
return std::string("<new.target>");
} else if (is_parameter()) {
int parameter_index = ToParameterIndex(parameter_count);
if (parameter_index == 0) {
return std::string("<this>");
} else {
std::ostringstream s;
s << "a" << parameter_index - 1;
return s.str();
}
} else {
std::ostringstream s;
s << "r" << index();
return s.str();
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -344,6 +344,8 @@ class Register {
Register reg4 = Register(),
Register reg5 = Register());
std::string ToString(int parameter_count);
bool operator==(const Register& other) const {
return index() == other.index();
}
......
......@@ -4,6 +4,7 @@
#include "src/interpreter/interpreter.h"
#include "src/ast/prettyprinter.h"
#include "src/code-factory.h"
#include "src/compiler.h"
#include "src/compiler/interpreter-assembler.h"
......@@ -60,6 +61,31 @@ void Interpreter::Initialize() {
bool Interpreter::MakeBytecode(CompilationInfo* info) {
if (FLAG_print_bytecode || FLAG_print_source || FLAG_print_ast) {
OFStream os(stdout);
base::SmartArrayPointer<char> name = info->GetDebugName();
os << "[generating bytecode for function: " << info->GetDebugName().get()
<< "]" << std::endl
<< std::flush;
}
#ifdef DEBUG
if (info->parse_info() && FLAG_print_source) {
OFStream os(stdout);
os << "--- Source from AST ---" << std::endl
<< PrettyPrinter(info->isolate()).PrintProgram(info->literal())
<< std::endl
<< std::flush;
}
if (info->parse_info() && FLAG_print_ast) {
OFStream os(stdout);
os << "--- AST ---" << std::endl
<< AstPrinter(info->isolate()).PrintProgram(info->literal()) << std::endl
<< std::flush;
}
#endif // DEBUG
BytecodeGenerator generator(info->isolate(), info->zone());
info->EnsureFeedbackVector();
Handle<BytecodeArray> bytecodes = generator.MakeBytecode(info);
......@@ -78,11 +104,14 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) {
bool Interpreter::IsInterpreterTableInitialized(
Handle<FixedArray> handler_table) {
if (FLAG_trace_ignition) {
// Regenerate table to add bytecode tracing operations.
return false;
}
DCHECK(handler_table->length() == static_cast<int>(Bytecode::kLast) + 1);
return handler_table->get(0) != isolate_->heap()->undefined_value();
}
// LdaZero
//
// Load literal '0' into the accumulator.
......
......@@ -4448,8 +4448,6 @@ class BytecodeArray : public FixedArrayBase {
kHandlerTableOffset + kPointerSize;
static const int kHeaderSize = kSourcePositionTableOffset + kPointerSize;
static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
// Maximal memory consumption for a single BytecodeArray.
static const int kMaxSize = 512 * MB;
// Maximal length of a single BytecodeArray.
......
......@@ -4,7 +4,12 @@
#include "src/runtime/runtime-utils.h"
#include <iomanip>
#include "src/arguments.h"
#include "src/frames-inl.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecodes.h"
#include "src/isolate-inl.h"
namespace v8 {
......@@ -147,5 +152,106 @@ RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) {
shared, context, static_cast<PretenureFlag>(pretenured_flag));
}
namespace {
void PrintRegisters(std::ostream& os, bool is_input,
Handle<BytecodeArray> bytecode_array, int bytecode_offset,
Handle<Object> accumulator) {
static const int kRegFieldWidth = static_cast<int>(strlen("accumulator"));
static const char* kInputColourCode = "\033[0;36m";
static const char* kOutputColourCode = "\033[0;35m";
static const char* kNormalColourCode = "\033[0;m";
const char* kArrowDirection = is_input ? " -> " : " <- ";
if (FLAG_log_colour) {
os << (is_input ? kInputColourCode : kOutputColourCode);
}
// Print accumulator.
os << " [ accumulator" << kArrowDirection;
accumulator->ShortPrint();
os << " ]" << std::endl;
// Find the location of the register file.
JavaScriptFrameIterator frame_iterator(bytecode_array->GetIsolate());
JavaScriptFrame* frame = frame_iterator.frame();
Address register_file =
frame->fp() + InterpreterFrameConstants::kRegisterFilePointerFromFp;
// Print the registers.
interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
bytecode_iterator.set_current_offset(
bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag);
interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode);
for (int operand_index = 0; operand_index < operand_count; operand_index++) {
interpreter::OperandType operand_type =
interpreter::Bytecodes::GetOperandType(bytecode, operand_index);
bool should_print =
is_input
? interpreter::Bytecodes::IsRegisterInputOperandType(operand_type)
: interpreter::Bytecodes::IsRegisterOutputOperandType(operand_type);
if (should_print) {
interpreter::Register first_reg =
bytecode_iterator.GetRegisterOperand(operand_index);
int range = bytecode_iterator.GetRegisterOperandRange(operand_index);
for (int reg_index = first_reg.index();
reg_index < first_reg.index() + range; reg_index++) {
Address reg_location = register_file - reg_index * kPointerSize;
Object* reg_object = Memory::Object_at(reg_location);
os << " [ " << std::setw(kRegFieldWidth)
<< interpreter::Register(reg_index).ToString(
bytecode_array->parameter_count())
<< kArrowDirection;
reg_object->ShortPrint(os);
os << " ]" << std::endl;
}
}
}
if (FLAG_log_colour) {
os << kNormalColourCode;
}
}
} // namespace
RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) {
SealHandleScope shs(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0);
CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2);
OFStream os(stdout);
// Print bytecode.
const uint8_t* bytecode_address =
reinterpret_cast<const uint8_t*>(*bytecode_array) + bytecode_offset;
Vector<char> buf = Vector<char>::New(50);
SNPrintF(buf, "%p", bytecode_address);
os << " -> " << buf.start() << " (" << bytecode_offset << ") : ";
interpreter::Bytecodes::Decode(os, bytecode_address,
bytecode_array->parameter_count());
os << std::endl;
// Print all input registers and accumulator.
PrintRegisters(os, true, bytecode_array, bytecode_offset, accumulator);
os << std::flush;
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit) {
SealHandleScope shs(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0);
CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2);
OFStream os(stdout);
// Print all output registers and accumulator.
PrintRegisters(os, false, bytecode_array, bytecode_offset, accumulator);
os << std::flush;
return isolate->heap()->undefined_value();
}
} // namespace internal
} // namespace v8
......@@ -209,7 +209,6 @@ namespace internal {
F(ForInNext, 4, 1) \
F(ForInStep, 1, 1)
#define FOR_EACH_INTRINSIC_INTERPRETER(F) \
F(InterpreterEquals, 2, 1) \
F(InterpreterNotEquals, 2, 1) \
......@@ -222,8 +221,9 @@ namespace internal {
F(InterpreterToBoolean, 1, 1) \
F(InterpreterLogicalNot, 1, 1) \
F(InterpreterTypeOf, 1, 1) \
F(InterpreterNewClosure, 2, 1)
F(InterpreterNewClosure, 2, 1) \
F(InterpreterTraceBytecodeEntry, 3, 1) \
F(InterpreterTraceBytecodeExit, 3, 1)
#define FOR_EACH_INTRINSIC_FUNCTION(F) \
F(FunctionGetName, 1, 1) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment