blob: 609debf6eb192d2357304fc28523e88716d9b4dd [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#include "platform/assert.h"
#include "vm/globals.h"
#include "vm/ast.h"
#include "vm/assembler.h"
#include "vm/class_finalizer.h"
#include "vm/code_generator.h"
#include "vm/compiler.h"
#include "vm/dart_entry.h"
#include "vm/native_entry.h"
#include "vm/native_entry_test.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
#include "vm/virtual_memory.h"
namespace dart {
static const TokenPosition kPos = TokenPosition::kMinSource;
CODEGEN_TEST_GENERATE(SimpleReturnCodegen, test) {
test->node_sequence()->Add(new ReturnNode(kPos));
}
CODEGEN_TEST_RUN(SimpleReturnCodegen, Instance::null())
CODEGEN_TEST_GENERATE(SmiReturnCodegen, test) {
LiteralNode* l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
test->node_sequence()->Add(new ReturnNode(kPos, l));
}
CODEGEN_TEST_RUN(SmiReturnCodegen, Smi::New(3))
CODEGEN_TEST2_GENERATE(SimpleStaticCallCodegen, function, test) {
// Wrap the SmiReturnCodegen test above as a static function and call it.
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
test->node_sequence()->Add(
new ReturnNode(kPos, new StaticCallNode(kPos, function, no_arguments)));
}
CODEGEN_TEST2_RUN(SimpleStaticCallCodegen, SmiReturnCodegen, Smi::New(3))
// Helper to allocate and return a LocalVariable.
static LocalVariable* NewTestLocalVariable(const char* name) {
const String& variable_name =
String::ZoneHandle(Symbols::New(Thread::Current(), name));
const Type& variable_type = Type::ZoneHandle(Type::DynamicType());
return new LocalVariable(kPos, kPos, variable_name, variable_type);
}
CODEGEN_TEST_GENERATE(ReturnParameterCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
const int num_params = 1;
LocalVariable* parameter = NewTestLocalVariable("parameter");
LocalScope* local_scope = node_seq->scope();
local_scope->InsertParameterAt(0, parameter);
ASSERT(local_scope->num_variables() == num_params);
const Function& function = test->function();
function.set_num_fixed_parameters(num_params);
ASSERT(!function.HasOptionalParameters());
node_seq->Add(new ReturnNode(kPos, new LoadLocalNode(kPos, parameter)));
}
CODEGEN_TEST2_GENERATE(StaticCallReturnParameterCodegen, function, test) {
// Wrap and call the ReturnParameterCodegen test above as a static function.
SequenceNode* node_seq = test->node_sequence();
ArgumentListNode* arguments = new ArgumentListNode(kPos);
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
node_seq->Add(
new ReturnNode(kPos, new StaticCallNode(kPos, function, arguments)));
}
CODEGEN_TEST2_RUN(StaticCallReturnParameterCodegen,
ReturnParameterCodegen,
Smi::New(3))
CODEGEN_TEST_GENERATE(SmiParamSumCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
const int num_params = 2;
LocalVariable* param1 = NewTestLocalVariable("param1");
LocalVariable* param2 = NewTestLocalVariable("param2");
const int num_locals = 1;
LocalVariable* sum = NewTestLocalVariable("sum");
LocalScope* local_scope = node_seq->scope();
local_scope->InsertParameterAt(0, param1);
local_scope->InsertParameterAt(1, param2);
local_scope->AddVariable(sum);
ASSERT(local_scope->num_variables() == num_params + num_locals);
const Function& function = test->function();
function.set_num_fixed_parameters(num_params);
ASSERT(!function.HasOptionalParameters());
BinaryOpNode* add =
new BinaryOpNode(kPos, Token::kADD, new LoadLocalNode(kPos, param1),
new LoadLocalNode(kPos, param2));
node_seq->Add(new StoreLocalNode(kPos, sum, add));
node_seq->Add(new ReturnNode(kPos, new LoadLocalNode(kPos, sum)));
}
CODEGEN_TEST2_GENERATE(StaticCallSmiParamSumCodegen, function, test) {
// Wrap and call the SmiParamSumCodegen test above as a static function.
SequenceNode* node_seq = test->node_sequence();
ArgumentListNode* arguments = new ArgumentListNode(kPos);
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2))));
node_seq->Add(
new ReturnNode(kPos, new StaticCallNode(kPos, function, arguments)));
}
CODEGEN_TEST2_RUN(StaticCallSmiParamSumCodegen, SmiParamSumCodegen, Smi::New(5))
CODEGEN_TEST_GENERATE(SmiAddCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
BinaryOpNode* add_node = new BinaryOpNode(kPos, Token::kADD, a, b);
node_seq->Add(new ReturnNode(kPos, add_node));
}
CODEGEN_TEST_RUN(SmiAddCodegen, Smi::New(5))
CODEGEN_TEST_GENERATE(GenericAddCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(12.2, Heap::kOld)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
BinaryOpNode* add_node_1 = new BinaryOpNode(kPos, Token::kADD, a, b);
LiteralNode* c =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(0.8, Heap::kOld)));
BinaryOpNode* add_node_2 = new BinaryOpNode(kPos, Token::kADD, add_node_1, c);
node_seq->Add(new ReturnNode(kPos, add_node_2));
}
CODEGEN_TEST_RUN(GenericAddCodegen, Double::New(15.0))
CODEGEN_TEST_GENERATE(SmiBinaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(4)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
LiteralNode* c = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)));
BinaryOpNode* sub_node =
new BinaryOpNode(kPos, Token::kSUB, a, b); // 4 - 2 -> 2.
BinaryOpNode* mul_node =
new BinaryOpNode(kPos, Token::kMUL, sub_node, c); // 2 * 3 -> 6.
BinaryOpNode* div_node =
new BinaryOpNode(kPos, Token::kTRUNCDIV, mul_node, b); // 6 ~/ 2 -> 3.
node_seq->Add(new ReturnNode(kPos, div_node));
}
CODEGEN_TEST_RUN(SmiBinaryOpCodegen, Smi::New(3))
CODEGEN_TEST_GENERATE(BoolNotCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* b = new LiteralNode(kPos, Bool::False());
UnaryOpNode* not_node = new UnaryOpNode(kPos, Token::kNOT, b);
node_seq->Add(new ReturnNode(kPos, not_node));
}
CODEGEN_TEST_RUN(BoolNotCodegen, Bool::True().raw())
CODEGEN_TEST_GENERATE(BoolAndCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Bool::True());
LiteralNode* b = new LiteralNode(kPos, Bool::False());
BinaryOpNode* and_node = new BinaryOpNode(kPos, Token::kAND, a, b);
node_seq->Add(new ReturnNode(kPos, and_node));
}
CODEGEN_TEST_RUN(BoolAndCodegen, Bool::False().raw())
CODEGEN_TEST_GENERATE(BinaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(12, Heap::kOld)));
LiteralNode* b = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)));
LiteralNode* c =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(0.5, Heap::kOld)));
BinaryOpNode* sub_node = new BinaryOpNode(kPos, Token::kSUB, a, b);
BinaryOpNode* mul_node = new BinaryOpNode(kPos, Token::kMUL, sub_node, c);
BinaryOpNode* div_node = new BinaryOpNode(kPos, Token::kDIV, mul_node, b);
node_seq->Add(new ReturnNode(kPos, div_node));
}
CODEGEN_TEST_RUN(BinaryOpCodegen, Double::New(2.5));
CODEGEN_TEST_GENERATE(SmiUnaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(12)));
UnaryOpNode* neg_node = new UnaryOpNode(kPos, Token::kNEGATE, a);
node_seq->Add(new ReturnNode(kPos, neg_node));
}
CODEGEN_TEST_RUN(SmiUnaryOpCodegen, Smi::New(-12))
CODEGEN_TEST_GENERATE(DoubleUnaryOpCodegen, test) {
SequenceNode* node_seq = test->node_sequence();
LiteralNode* a =
new LiteralNode(kPos, Double::ZoneHandle(Double::New(12.0, Heap::kOld)));
UnaryOpNode* neg_node = new UnaryOpNode(kPos, Token::kNEGATE, a);
node_seq->Add(new ReturnNode(kPos, neg_node));
}
CODEGEN_TEST_RUN(DoubleUnaryOpCodegen, Double::New(-12.0))
static Library& MakeTestLibrary(const char* url) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const String& lib_url = String::ZoneHandle(zone, Symbols::New(thread, url));
Library& lib = Library::ZoneHandle(zone, Library::New(lib_url));
lib.Register(thread);
Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
ASSERT(!core_lib.IsNull());
const Namespace& core_ns = Namespace::Handle(
zone, Namespace::New(core_lib, Array::Handle(zone), Array::Handle(zone)));
lib.AddImport(core_ns);
return lib;
}
static RawClass* LookupClass(const Library& lib, const char* name) {
const String& cls_name =
String::ZoneHandle(Symbols::New(Thread::Current(), name));
return lib.LookupClass(cls_name);
}
CODEGEN_TEST_GENERATE(StaticCallCodegen, test) {
const char* kScriptChars =
"class A {\n"
" static bar() { return 42; }\n"
" static fly() { return 5; }\n"
"}\n";
String& url = String::Handle(String::New("dart-test:CompileScript"));
String& source = String::Handle(String::New(kScriptChars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::ProcessPendingClasses());
Class& cls = Class::Handle(LookupClass(lib, "A"));
EXPECT(!cls.IsNull());
// 'bar' will not be compiled.
String& function_bar_name = String::Handle(String::New("bar"));
Function& function_bar =
Function::ZoneHandle(cls.LookupStaticFunction(function_bar_name));
EXPECT(!function_bar.IsNull());
EXPECT(!function_bar.HasCode());
// 'fly' will be compiled.
String& function_fly_name = String::Handle(String::New("fly"));
Function& function_fly =
Function::ZoneHandle(cls.LookupStaticFunction(function_fly_name));
EXPECT(!function_fly.IsNull());
EXPECT(CompilerTest::TestCompileFunction(function_fly));
EXPECT(function_fly.HasCode());
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
StaticCallNode* call_bar =
new StaticCallNode(kPos, function_bar, no_arguments);
StaticCallNode* call_fly =
new StaticCallNode(kPos, function_fly, no_arguments);
BinaryOpNode* add_node =
new BinaryOpNode(kPos, Token::kADD, call_bar, call_fly);
test->node_sequence()->Add(new ReturnNode(kPos, add_node));
}
CODEGEN_TEST_RUN(StaticCallCodegen, Smi::New(42 + 5))
CODEGEN_TEST_GENERATE(InstanceCallCodegen, test) {
const char* kScriptChars =
"class A {\n"
" A() {}\n"
" int bar() { return 42; }\n"
"}\n";
String& url = String::Handle(String::New("dart-test:CompileScript"));
String& source = String::Handle(String::New(kScriptChars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::ProcessPendingClasses());
Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
EXPECT(!cls.IsNull());
String& constructor_name = String::Handle(String::New("A."));
Function& constructor =
Function::ZoneHandle(cls.LookupConstructor(constructor_name));
EXPECT(!constructor.IsNull());
// The unit test creates an instance of class A and calls function 'bar'.
String& function_bar_name =
String::ZoneHandle(Symbols::New(Thread::Current(), "bar"));
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
const TypeArguments& no_type_arguments = TypeArguments::ZoneHandle();
InstanceCallNode* call_bar = new InstanceCallNode(
kPos, new ConstructorCallNode(kPos, no_type_arguments, constructor,
no_arguments),
function_bar_name, no_arguments);
test->node_sequence()->Add(new ReturnNode(kPos, call_bar));
}
CODEGEN_TEST_RUN(InstanceCallCodegen, Smi::New(42))
// Test allocation of dart objects.
CODEGEN_TEST_GENERATE(AllocateNewObjectCodegen, test) {
const char* kScriptChars =
"class A {\n"
" A() {}\n"
" static bar() { return 42; }\n"
"}\n";
String& url = String::Handle(String::New("dart-test:CompileScript"));
String& source = String::Handle(String::New(kScriptChars));
Script& script =
Script::Handle(Script::New(url, source, RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::ProcessPendingClasses());
Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
EXPECT(!cls.IsNull());
String& constructor_name = String::Handle(String::New("A."));
Function& constructor =
Function::ZoneHandle(cls.LookupConstructor(constructor_name));
EXPECT(!constructor.IsNull());
const TypeArguments& no_type_arguments = TypeArguments::ZoneHandle();
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
test->node_sequence()->Add(
new ReturnNode(kPos, new ConstructorCallNode(kPos, no_type_arguments,
constructor, no_arguments)));
}
CODEGEN_TEST_RAW_RUN(AllocateNewObjectCodegen, function) {
const Object& result = Object::Handle(
DartEntry::InvokeFunction(function, Object::empty_array()));
EXPECT(!result.IsError());
const GrowableObjectArray& libs = GrowableObjectArray::Handle(
Isolate::Current()->object_store()->libraries());
ASSERT(!libs.IsNull());
// App lib is the last one that was loaded.
intptr_t num_libs = libs.Length();
Library& app_lib = Library::Handle();
app_lib ^= libs.At(num_libs - 1);
ASSERT(!app_lib.IsNull());
const Class& cls = Class::Handle(app_lib.LookupClass(
String::Handle(Symbols::New(Thread::Current(), "A"))));
EXPECT_EQ(cls.raw(), result.clazz());
}
} // namespace dart