[Interpreter] Minimal bytecode generator.
authoroth <oth@chromium.org>
Tue, 18 Aug 2015 13:46:43 +0000 (06:46 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 18 Aug 2015 13:46:57 +0000 (13:46 +0000)
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}

14 files changed:
BUILD.gn
src/compiler.cc
src/flag-definitions.h
src/interpreter/bytecode-array-builder.cc
src/interpreter/bytecode-generator.cc [new file with mode: 0644]
src/interpreter/bytecode-generator.h [new file with mode: 0644]
src/interpreter/interpreter.cc
src/interpreter/interpreter.h
src/objects-inl.h
src/objects.h
src/runtime/runtime-compiler.cc
test/cctest/cctest.gyp
test/cctest/interpreter/test-bytecode-generator.cc [new file with mode: 0644]
tools/gyp/v8.gyp

index 59314f2d5f99ff6f3f62510108aaa47a93ddcc18..903e6a53355de1c8b89730503a77a5342fe8091b 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -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",
index 7e0f0fdfbcda8ed644ddd18ceaf0c4288d52b44b..aa56ca92e72b667c4c5f9ad8d5de431abab02d0d 100644 (file)
@@ -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.
index 7a6bc879ab75d11b1774557d5d6c98afb472b960..5ab05f6417346270e2c2b522de95599a6888f479 100644 (file)
@@ -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")
 
index 8cc0772db97d4b0a98180c57d5c0ffa28d8cc726..24fec96bfa47bd0a76feaea9ce815f6b458f0282 100644 (file)
@@ -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.
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
new file mode 100644 (file)
index 0000000..e5baaae
--- /dev/null
@@ -0,0 +1,370 @@
+// 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
diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h
new file mode 100644 (file)
index 0000000..5caf3f1
--- /dev/null
@@ -0,0 +1,44 @@
+// 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_
index 4f961318085e12bbf63f5d336d006ddda14c909d..6167efe4befc7e1e60f2b2d79d563d66c86a40b8 100644 (file)
@@ -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);
index ba145faaf1429285c2c20b9fb53a86f8b9c02b07..64101de6570a7ecf831daa0f90f7d9cb50436796 100644 (file)
@@ -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, ...) \
index 0c8617aca5cc4048e0971ed989bade8dd0cb9b3e..cc1ae853c966c267d52daafa915fbba4909308b4 100644 (file)
@@ -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
index a19ac5d510f689ed73a404c5f4c76cdfe640e90c..a136a93a5c31a91e33750dc40e9c354fa62d50e4 100644 (file)
@@ -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);
index cf76fa0b5d541c3c4f0053e1f1b0b3435c39b9f6..f7819701c26c8b39936f2fb4d22b83767a5b8f60 100644 (file)
@@ -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;
 }
index b58aee953c92143ff1e6c09cc8f10a476e4a66c5..52e480d4cfdd7eb516364508b26a785dea6a5a15 100644 (file)
@@ -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',
diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc
new file mode 100644 (file)
index 0000000..deb6c97
--- /dev/null
@@ -0,0 +1,129 @@
+// 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
index 34e2c97d823e943101cfeb047a01a42dadd45dde..2a2e4955789d62535ddc93c97c6ceb03239ea8c3 100644 (file)
         '../../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',