Commit 238397c1 authored by oth's avatar oth Committed by Commit bot

[Interpreter] Minimal bytecode generator.

Bytecode generator for local assignment and basic binary operations.

Command-line flag for printing bytecodes.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30221}
parent c01f419e
......@@ -1008,6 +1008,10 @@ source_set("v8_base") {
"src/interface-descriptors.h",
"src/interpreter/bytecodes.cc",
"src/interpreter/bytecodes.h",
"src/interpreter/bytecode-array-builder.cc",
"src/interpreter/bytecode-array-builder.h",
"src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h",
"src/interpreter/interpreter.cc",
"src/interpreter/interpreter.h",
"src/isolate.cc",
......
......@@ -18,6 +18,7 @@
#include "src/full-codegen/full-codegen.h"
#include "src/gdb-jit.h"
#include "src/hydrogen.h"
#include "src/interpreter/interpreter.h"
#include "src/lithium.h"
#include "src/log-inl.h"
#include "src/messages.h"
......@@ -666,6 +667,18 @@ static bool CompileUnoptimizedCode(CompilationInfo* info) {
}
static bool GenerateBytecode(CompilationInfo* info) {
DCHECK(AllowCompilation::IsAllowed(info->isolate()));
if (!Compiler::Analyze(info->parse_info()) ||
!interpreter::Interpreter::MakeBytecode(info)) {
Isolate* isolate = info->isolate();
if (!isolate->has_pending_exception()) isolate->StackOverflow();
return false;
}
return true;
}
MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCodeCommon(
CompilationInfo* info) {
VMState<COMPILER> state(info->isolate());
......@@ -679,11 +692,16 @@ MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCodeCommon(
SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
MaybeDisableOptimization(shared, lit->dont_optimize_reason());
// Compile unoptimized code.
if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>();
if (FLAG_ignition && info->closure()->PassesFilter(FLAG_ignition_filter)) {
// Compile bytecode for the interpreter.
if (!GenerateBytecode(info)) return MaybeHandle<Code>();
} else {
// Compile unoptimized code.
if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>();
CHECK_EQ(Code::FUNCTION, info->code()->kind());
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
CHECK_EQ(Code::FUNCTION, info->code()->kind());
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
}
// Update the shared function info with the scope info. Allocating the
// ScopeInfo object may cause a GC.
......
......@@ -282,6 +282,8 @@ DEFINE_BOOL(string_slices, true, "use string slices")
// Flags for Ignition.
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_codegen, false,
"trace the codegen of ignition interpreter bytecode handlers")
......
......@@ -50,7 +50,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
int32_t raw_smi = smi->value();
if (raw_smi == 0) {
Output(Bytecode::kLdaZero);
} else if (raw_smi > -128 && raw_smi <= 128) {
} else if (raw_smi >= -128 && raw_smi <= 127) {
Output(Bytecode::kLdaSmi8, static_cast<uint8_t>(raw_smi));
} else {
// TODO(oth): Put Smi in constant pool.
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/interpreter/bytecode-generator.h"
#include <stack>
#include "src/compiler.h"
#include "src/objects.h"
#include "src/scopes.h"
#include "src/token.h"
namespace v8 {
namespace internal {
namespace interpreter {
BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
: builder_(isolate) {
InitializeAstVisitor(isolate, zone);
}
BytecodeGenerator::~BytecodeGenerator() {}
Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
set_scope(info->scope());
// This a temporary guard (oth).
DCHECK(scope()->is_function_scope());
builder().set_locals_count(scope()->num_stack_slots());
// Visit implicit declaration of the function name.
if (scope()->is_function_scope() && scope()->function() != NULL) {
VisitVariableDeclaration(scope()->function());
}
// Visit declarations within the function scope.
VisitDeclarations(scope()->declarations());
// Visit statements in the function body.
VisitStatements(info->function()->body());
set_scope(nullptr);
return builder_.ToBytecodeArray();
}
void BytecodeGenerator::VisitBlock(Block* node) {
if (node->scope() == NULL) {
// Visit statements in the same scope, no declarations.
VisitStatements(node->statements());
} else {
// Visit declarations and statements in a block scope.
if (node->scope()->ContextLocalCount() > 0) {
UNIMPLEMENTED();
} else {
VisitDeclarations(node->scope()->declarations());
VisitStatements(node->statements());
}
}
}
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
Variable* variable = decl->proxy()->var();
switch (variable->location()) {
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED:
UNIMPLEMENTED();
break;
case VariableLocation::PARAMETER:
UNIMPLEMENTED();
break;
case VariableLocation::LOCAL:
// Details stored in scope, i.e. variable index.
break;
case VariableLocation::CONTEXT:
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
break;
}
}
void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Visit(stmt->expression());
}
void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitIfStatement(IfStatement* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitContinueStatement(ContinueStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitBreakStatement(BreakStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* node) {
Visit(node->expression());
builder().Return();
}
void BytecodeGenerator::VisitWithStatement(WithStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitWhileStatement(WhileStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitForStatement(ForStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitForInStatement(ForInStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitForOfStatement(ForOfStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitClassLiteral(ClassLiteral* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitNativeFunctionLiteral(
NativeFunctionLiteral* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitConditional(Conditional* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitLiteral(Literal* expr) {
if (expr->IsPropertyName()) {
UNIMPLEMENTED();
}
Handle<Object> value = expr->value();
if (value->IsSmi()) {
builder().LoadLiteral(Smi::cast(*value));
} else if (value->IsUndefined()) {
builder().LoadUndefined();
} else if (value->IsTrue()) {
builder().LoadTrue();
} else if (value->IsFalse()) {
builder().LoadFalse();
} else if (value->IsNull()) {
builder().LoadNull();
} else if (value->IsTheHole()) {
builder().LoadTheHole();
} else {
UNIMPLEMENTED();
}
}
void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
Variable* variable = proxy->var();
switch (variable->location()) {
case VariableLocation::LOCAL: {
Register source(variable->index());
builder().LoadAccumulatorWithRegister(source);
break;
}
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED:
case VariableLocation::PARAMETER:
case VariableLocation::CONTEXT:
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
}
}
void BytecodeGenerator::VisitAssignment(Assignment* expr) {
DCHECK(expr->target()->IsValidReferenceExpression());
// Left-hand side can only be a property, a global or a variable slot.
Property* property = expr->target()->AsProperty();
LhsKind assign_type = Property::GetAssignType(property);
DCHECK(!expr->is_compound());
Visit(expr->value());
switch (assign_type) {
case VARIABLE: {
Variable* variable = expr->target()->AsVariableProxy()->var();
DCHECK(variable->location() == VariableLocation::LOCAL);
Register destination(variable->index());
builder().StoreAccumulatorInRegister(destination);
break;
}
case NAMED_PROPERTY:
case KEYED_PROPERTY:
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNIMPLEMENTED();
}
}
void BytecodeGenerator::VisitYield(Yield* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitThrow(Throw* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitProperty(Property* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitCall(Call* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitCallNew(CallNew* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitCallRuntime(CallRuntime* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitCountOperation(CountOperation* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
switch (binop->op()) {
case Token::COMMA:
case Token::OR:
case Token::AND:
UNIMPLEMENTED();
break;
default:
VisitArithmeticExpression(binop);
break;
}
}
void BytecodeGenerator::VisitCompareOperation(CompareOperation* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitSpread(Spread* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitThisFunction(ThisFunction* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitSuperPropertyReference(
SuperPropertyReference* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
Token::Value op = binop->op();
Expression* left = binop->left();
Expression* right = binop->right();
TemporaryRegisterScope temporary_register_scope(&builder_);
Register temporary = temporary_register_scope.NewRegister();
Visit(left);
builder().StoreAccumulatorInRegister(temporary);
Visit(right);
builder().BinaryOperation(op, temporary);
}
} // namespace interpreter
} // namespace internal
} // namespace v8
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTERPRETER_BYTECODE_GENERATOR_H_
#define V8_INTERPRETER_BYTECODE_GENERATOR_H_
#include "src/ast.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecodes.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeGenerator : public AstVisitor {
public:
BytecodeGenerator(Isolate* isolate, Zone* zone);
virtual ~BytecodeGenerator();
Handle<BytecodeArray> MakeBytecode(CompilationInfo* info);
#define DECLARE_VISIT(type) void Visit##type(type* node) override;
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
private:
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
void VisitArithmeticExpression(BinaryOperation* binop);
inline BytecodeArrayBuilder& builder() { return builder_; }
inline Scope* scope() const { return scope_; }
inline void set_scope(Scope* s) { scope_ = s; }
BytecodeArrayBuilder builder_;
Scope* scope_;
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_GENERATOR_H_
......@@ -7,6 +7,7 @@
#include "src/compiler.h"
#include "src/compiler/interpreter-assembler.h"
#include "src/factory.h"
#include "src/interpreter/bytecode-generator.h"
#include "src/interpreter/bytecodes.h"
#include "src/zone.h"
......@@ -56,6 +57,27 @@ void Interpreter::Initialize() {
}
bool Interpreter::MakeBytecode(CompilationInfo* info) {
Handle<SharedFunctionInfo> shared_info = info->shared_info();
BytecodeGenerator generator(info->isolate(), info->zone());
Handle<BytecodeArray> bytecodes = generator.MakeBytecode(info);
if (FLAG_print_bytecode) {
bytecodes->Print();
}
DCHECK(shared_info->function_data()->IsUndefined());
if (!shared_info->function_data()->IsUndefined()) {
return false;
}
shared_info->set_function_data(*bytecodes);
info->SetCode(info->isolate()->builtins()->InterpreterEntryTrampoline());
info->EnsureFeedbackVector();
return true;
}
bool Interpreter::IsInterpreterTableInitialized(
Handle<FixedArray> handler_table) {
DCHECK(handler_table->length() == static_cast<int>(Bytecode::kLast) + 1);
......
......@@ -36,6 +36,9 @@ class Interpreter {
// Initializes the interpreter.
void Initialize();
// Generate bytecode for |info|.
static bool MakeBytecode(CompilationInfo* info);
private:
// Bytecode handler generator functions.
#define DECLARE_BYTECODE_HANDLER_GENERATOR(Name, ...) \
......
......@@ -4903,6 +4903,16 @@ bool Code::IsCodeStubOrIC() {
}
bool Code::IsJavaScriptCode() {
if (kind() == FUNCTION || kind() == OPTIMIZED_FUNCTION) {
return true;
}
Handle<Code> interpreter_entry =
GetIsolate()->builtins()->InterpreterEntryTrampoline();
return interpreter_entry.location() != nullptr && *interpreter_entry == this;
}
InlineCacheState Code::ic_state() {
InlineCacheState result = ExtractICStateFromFlags(flags());
// Only allow uninitialized or debugger states for non-IC code
......
......@@ -4615,6 +4615,7 @@ class Code: public HeapObject {
inline bool embeds_maps_weakly();
inline bool IsCodeStubOrIC();
inline bool IsJavaScriptCode();
inline void set_raw_kind_specific_flags1(int value);
inline void set_raw_kind_specific_flags2(int value);
......
......@@ -35,8 +35,8 @@ RUNTIME_FUNCTION(Runtime_CompileLazy) {
Handle<Code> code;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code,
Compiler::GetLazyCode(function));
DCHECK(code->kind() == Code::FUNCTION ||
code->kind() == Code::OPTIMIZED_FUNCTION);
DCHECK(code->IsJavaScriptCode());
function->ReplaceCode(*code);
return *code;
}
......
......@@ -83,6 +83,7 @@
'compiler/test-run-variables.cc',
'compiler/test-simplified-lowering.cc',
'cctest.cc',
'interpreter/test-bytecode-generator.cc',
'interpreter/test-interpreter.cc',
'gay-fixed.cc',
'gay-precision.cc',
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#include "src/compiler.h"
#include "src/interpreter/bytecode-generator.h"
#include "src/interpreter/interpreter.h"
#include "test/cctest/cctest.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeGeneratorHelper {
public:
const char* kFunctionName = "my_function";
BytecodeGeneratorHelper() {
i::FLAG_ignition = true;
i::FLAG_ignition_filter = kFunctionName;
CcTest::i_isolate()->interpreter()->Initialize();
}
Handle<BytecodeArray> MakeBytecode(const char* script,
const char* function_name) {
CompileRun(script);
Local<Function> function =
Local<Function>::Cast(CcTest::global()->Get(v8_str(function_name)));
i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*function);
return handle(js_function->shared()->bytecode_array(), CcTest::i_isolate());
}
Handle<BytecodeArray> MakeBytecodeForFunctionBody(const char* body) {
ScopedVector<char> program(1024);
SNPrintF(program, "function %s() { %s }\n%s();", kFunctionName, body,
kFunctionName);
return MakeBytecode(program.start(), kFunctionName);
}
};
// Structure for containing expected bytecode snippets.
struct ExpectedSnippet {
const char* body;
int frame_size;
int bytecode_length;
const uint8_t bytecode[16];
};
// Helper macros for handcrafting bytecode sequences.
#define B(x) static_cast<uint8_t>(Bytecode::k##x)
#define U8(x) static_cast<uint8_t>(x & 0xff)
#define R(x) static_cast<uint8_t>(-x & 0xff)
TEST(PrimitiveReturnStatements) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
ExpectedSnippet snippets[] = {
{"return;", 0, 2, {B(LdaUndefined), B(Return)}},
{"return null;", 0, 2, {B(LdaNull), B(Return)}},
{"return true;", 0, 2, {B(LdaTrue), B(Return)}},
{"return false;", 0, 2, {B(LdaFalse), B(Return)}},
{"return 0;", 0, 2, {B(LdaZero), B(Return)}},
{"return +1;", 0, 3, {B(LdaSmi8), U8(1), B(Return)}},
{"return -1;", 0, 3, {B(LdaSmi8), U8(-1), B(Return)}},
{"return +127;", 0, 3, {B(LdaSmi8), U8(127), B(Return)}},
{"return -128;", 0, 3, {B(LdaSmi8), U8(-128), B(Return)}},
};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunctionBody(snippets[i].body);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->length(), snippets[i].bytecode_length);
CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
ba->length()));
}
}
TEST(PrimitiveExpressions) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
ExpectedSnippet snippets[] = {
{"var x = 0; return x;",
kPointerSize,
6,
{
B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Return) //
}},
{"var x = 0; return x + 3;",
2 * kPointerSize,
12,
{
B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Add), R(1), //
B(Return) //
}}};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunctionBody(snippets[i].body);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->length(), snippets[i].bytecode_length);
CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
ba->length()));
}
}
} // namespace interpreter
} // namespace internal
} // namespance v8
......@@ -799,6 +799,8 @@
'../../src/interface-descriptors.h',
'../../src/interpreter/bytecodes.cc',
'../../src/interpreter/bytecodes.h',
'../../src/interpreter/bytecode-generator.cc',
'../../src/interpreter/bytecode-generator.h',
'../../src/interpreter/bytecode-array-builder.cc',
'../../src/interpreter/bytecode-array-builder.h',
'../../src/interpreter/interpreter.cc',
......
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