"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",
#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"
}
+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());
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.
// 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")
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.
--- /dev/null
+// 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
--- /dev/null
+// 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_
#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"
}
+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);
// 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, ...) \
}
+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
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);
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;
}
'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',
--- /dev/null
+// 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
'../../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',