Commit d2187182 authored by ssanfilippo's avatar ssanfilippo Committed by Commit bot

[Interpreter] generate-bytecode-expectations improvements.

A few options and features have been added to the tool:

* an output file might be specified using --output=file.name
* a shortcut when the output file is also the input, which is handy
   when fixing golden files, --rebaseline.
* the input snippet might be optionally not wrapped in a top function,
   or not executed after compilation (--no-wrap and --no-execute).
* the name of the wrapper can be configured using --wrapper-name=foo

The same options can be configured via setters on the usual
BytecodeExpectationsPrinter.

The output file now includes all the relevant flags to reproduce it
when running again through the tool (usually with --rebaseline).

In particular, when running in --rebaseline mode, options from the
file header will override options specified in the command line.

A couple of other fixes and improvements:

* description of the handlers is now emitted (closing the TODO).
* the snippet is now correctly unquoted when double quotes are used.
* special registers (closure, context etc.) are now emitted as such,
   instead of displaying their numeric value.
* the tool can now process top level code as well.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#34152}
parent a33abf0b
......@@ -5,6 +5,7 @@
#include "test/cctest/interpreter/bytecode-expectations-printer.h"
#include <iostream>
#include <vector>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
......@@ -22,6 +23,10 @@ namespace v8 {
namespace internal {
namespace interpreter {
// static
const char* const BytecodeExpectationsPrinter::kDefaultTopFunctionName =
"__genbckexp_wrapper__";
v8::Local<v8::String> BytecodeExpectationsPrinter::V8StringFromUTF8(
const char* data) const {
return v8::String::NewFromUtf8(isolate_, data, v8::NewStringType::kNormal)
......@@ -38,17 +43,15 @@ std::string BytecodeExpectationsPrinter::WrapCodeInFunction(
return program_stream.str();
}
v8::Local<v8::Value> BytecodeExpectationsPrinter::CompileAndRun(
v8::Local<v8::Script> BytecodeExpectationsPrinter::Compile(
const char* program) const {
v8::Local<v8::String> source = V8StringFromUTF8(program);
v8::Local<v8::Script> script =
v8::Script::Compile(isolate_->GetCurrentContext(), source)
.ToLocalChecked();
v8::Local<v8::Value> result;
CHECK(script->Run(isolate_->GetCurrentContext()).ToLocal(&result));
return v8::Script::Compile(isolate_->GetCurrentContext(), source)
.ToLocalChecked();
}
return result;
void BytecodeExpectationsPrinter::Run(v8::Local<v8::Script> script) const {
(void)script->Run(isolate_->GetCurrentContext());
}
i::Handle<v8::internal::BytecodeArray>
......@@ -67,6 +70,13 @@ BytecodeExpectationsPrinter::GetBytecodeArrayForGlobal(
return bytecodes;
}
i::Handle<i::BytecodeArray>
BytecodeExpectationsPrinter::GetBytecodeArrayForScript(
v8::Local<v8::Script> script) const {
i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*script);
return i::handle(js_function->shared()->bytecode_array(), i_isolate());
}
void BytecodeExpectationsPrinter::PrintEscapedString(
std::ostream& stream, const std::string& string) const {
for (char c : string) {
......@@ -86,7 +96,7 @@ void BytecodeExpectationsPrinter::PrintEscapedString(
void BytecodeExpectationsPrinter::PrintBytecodeOperand(
std::ostream& stream, const BytecodeArrayIterator& bytecode_iter,
const Bytecode& bytecode, int op_index) const {
const Bytecode& bytecode, int op_index, int parameter_count) const {
OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index);
OperandSize op_size = Bytecodes::GetOperandSize(bytecode, op_index);
......@@ -107,7 +117,22 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand(
Register register_value = bytecode_iter.GetRegisterOperand(op_index);
stream << 'R';
if (op_size != OperandSize::kByte) stream << size_tag;
stream << '(' << register_value.index() << ')';
if (register_value.is_new_target()) {
stream << "(new_target)";
} else if (register_value.is_current_context()) {
stream << "(context)";
} else if (register_value.is_function_closure()) {
stream << "(closure)";
} else if (register_value.is_parameter()) {
int parameter_index = register_value.ToParameterIndex(parameter_count);
if (parameter_index == 0) {
stream << "(this)";
} else {
stream << "(arg" << (parameter_index - 1) << ')';
}
} else {
stream << '(' << register_value.index() << ')';
}
} else {
stream << 'U' << size_tag << '(';
......@@ -127,7 +152,8 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand(
}
void BytecodeExpectationsPrinter::PrintBytecode(
std::ostream& stream, const BytecodeArrayIterator& bytecode_iter) const {
std::ostream& stream, const BytecodeArrayIterator& bytecode_iter,
int parameter_count) const {
Bytecode bytecode = bytecode_iter.current_bytecode();
stream << "B(" << Bytecodes::ToString(bytecode) << ')';
......@@ -135,7 +161,8 @@ void BytecodeExpectationsPrinter::PrintBytecode(
int operands_count = Bytecodes::NumberOfOperands(bytecode);
for (int op_index = 0; op_index < operands_count; ++op_index) {
stream << ", ";
PrintBytecodeOperand(stream, bytecode_iter, bytecode, op_index);
PrintBytecodeOperand(stream, bytecode_iter, bytecode, op_index,
parameter_count);
}
}
......@@ -155,7 +182,7 @@ void BytecodeExpectationsPrinter::PrintConstant(
CHECK(constant->IsString());
PrintV8String(stream, i::String::cast(*constant));
break;
case ConstantPoolType::kInteger:
case ConstantPoolType::kNumber:
if (constant->IsSmi()) {
i::Smi::cast(*constant)->SmiPrint(stream);
} else if (constant->IsHeapNumber()) {
......@@ -164,9 +191,6 @@ void BytecodeExpectationsPrinter::PrintConstant(
UNREACHABLE();
}
break;
case ConstantPoolType::kDouble:
i::HeapNumber::cast(*constant)->HeapNumberPrint(stream);
break;
case ConstantPoolType::kMixed:
if (constant->IsSmi()) {
stream << "kInstanceTypeDontCare";
......@@ -199,7 +223,7 @@ void BytecodeExpectationsPrinter::PrintBytecodeSequence(
BytecodeArrayIterator bytecode_iter(bytecode_array);
for (; !bytecode_iter.done(); bytecode_iter.Advance()) {
stream << " ";
PrintBytecode(stream, bytecode_iter);
PrintBytecode(stream, bytecode_iter, bytecode_array->parameter_count());
stream << ",\n";
}
stream << "]\n";
......@@ -232,32 +256,43 @@ void BytecodeExpectationsPrinter::PrintCodeSnippet(
stream << "\"\n";
}
void BytecodeExpectationsPrinter::PrintHandlers(
std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
stream << "handlers: [\n";
HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table());
for (int i = 0, num_entries = table->NumberOfRangeEntries(); i < num_entries;
++i) {
stream << " [" << table->GetRangeStart(i) << ", " << table->GetRangeEnd(i)
<< ", " << table->GetRangeHandler(i) << "],\n";
}
stream << "]\n";
}
void BytecodeExpectationsPrinter::PrintBytecodeArray(
std::ostream& stream, const std::string& body,
i::Handle<i::BytecodeArray> bytecode_array) const {
stream << "---\n";
PrintCodeSnippet(stream, body);
std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const {
PrintFrameSize(stream, bytecode_array);
PrintBytecodeSequence(stream, bytecode_array);
PrintConstantPool(stream, bytecode_array->constant_pool());
// TODO(ssanfilippo) print handlers.
i::HandlerTable* handlers =
i::HandlerTable::cast(bytecode_array->handler_table());
CHECK_EQ(handlers->NumberOfRangeEntries(), 0);
PrintHandlers(stream, bytecode_array);
}
void BytecodeExpectationsPrinter::PrintExpectation(
std::ostream& stream, const std::string& snippet) const {
const char* wrapper_function_name = "__genbckexp_wrapper__";
std::string source_code =
wrap_ ? WrapCodeInFunction(test_function_name_.c_str(), snippet)
: snippet;
std::string source_code = WrapCodeInFunction(wrapper_function_name, snippet);
CompileAndRun(source_code.c_str());
v8::Local<v8::Script> script = Compile(source_code.c_str());
if (execute_) Run(script);
i::Handle<i::BytecodeArray> bytecode_array =
GetBytecodeArrayForGlobal(wrapper_function_name);
top_level_ ? GetBytecodeArrayForScript(script)
: GetBytecodeArrayForGlobal(test_function_name_.c_str());
PrintBytecodeArray(stream, snippet, bytecode_array);
stream << "---\n";
PrintCodeSnippet(stream, snippet);
PrintBytecodeArray(stream, bytecode_array);
stream << '\n';
}
......
......@@ -7,6 +7,7 @@
#include <iostream>
#include <string>
#include <vector>
#include "src/interpreter/bytecodes.h"
#include "src/objects.h"
......@@ -25,29 +26,50 @@ class BytecodeExpectationsPrinter final {
enum class ConstantPoolType {
kUnknown,
kString,
kInteger,
kDouble,
kNumber,
kMixed,
};
BytecodeExpectationsPrinter(v8::Isolate* i,
ConstantPoolType t = ConstantPoolType::kMixed)
: isolate_(i), const_pool_type_(t) {}
: isolate_(i),
const_pool_type_(t),
execute_(true),
wrap_(true),
test_function_name_(kDefaultTopFunctionName) {}
void PrintExpectation(std::ostream& stream, // NOLINT
const std::string& snippet) const;
void set_constant_pool_type(ConstantPoolType t) { const_pool_type_ = t; }
ConstantPoolType constant_pool_type() const { return const_pool_type_; }
void set_constant_pool_type(ConstantPoolType const_pool_type) {
const_pool_type_ = const_pool_type;
}
ConstantPoolType const_pool_type() const { return const_pool_type_; }
void set_execute(bool execute) { execute_ = execute; }
bool execute() const { return execute_; }
void set_wrap(bool wrap) { wrap_ = wrap; }
bool wrap() const { return wrap_; }
void set_top_level(bool top_level) { top_level_ = top_level; }
bool top_level() const { return top_level_; }
void set_test_function_name(const std::string& test_function_name) {
test_function_name_ = test_function_name;
}
std::string test_function_name() const { return test_function_name_; }
private:
void PrintEscapedString(std::ostream& stream, // NOLINT
const std::string& string) const;
void PrintBytecodeOperand(std::ostream& stream, // NOLINT
const BytecodeArrayIterator& bytecode_iter,
const Bytecode& bytecode, int op_index) const;
const Bytecode& bytecode, int op_index,
int parameter_count) const;
void PrintBytecode(std::ostream& stream, // NOLINT
const BytecodeArrayIterator& bytecode_iter) const;
const BytecodeArrayIterator& bytecode_iter,
int parameter_count) const;
void PrintV8String(std::ostream& stream, // NOLINT
i::String* string) const;
void PrintConstant(std::ostream& stream, // NOLINT
......@@ -61,16 +83,20 @@ class BytecodeExpectationsPrinter final {
void PrintCodeSnippet(std::ostream& stream, // NOLINT
const std::string& body) const;
void PrintBytecodeArray(std::ostream& stream, // NOLINT
const std::string& body,
i::Handle<i::BytecodeArray> bytecode_array) const;
void PrintHandlers(std::ostream& stream, // NOLINT
i::Handle<i::BytecodeArray> bytecode_array) const;
v8::Local<v8::String> V8StringFromUTF8(const char* data) const;
std::string WrapCodeInFunction(const char* function_name,
const std::string& function_body) const;
v8::Local<v8::Value> CompileAndRun(const char* program) const;
v8::Local<v8::Script> Compile(const char* program) const;
void Run(v8::Local<v8::Script> script) const;
i::Handle<i::BytecodeArray> GetBytecodeArrayForGlobal(
const char* global_name) const;
i::Handle<v8::internal::BytecodeArray> GetBytecodeArrayForScript(
v8::Local<v8::Script> script) const;
i::Isolate* i_isolate() const {
return reinterpret_cast<i::Isolate*>(isolate_);
......@@ -78,6 +104,12 @@ class BytecodeExpectationsPrinter final {
v8::Isolate* isolate_;
ConstantPoolType const_pool_type_;
bool execute_;
bool wrap_;
bool top_level_;
std::string test_function_name_;
static const char* const kDefaultTopFunctionName;
};
} // namespace interpreter
......
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