| // 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 intptr_t kPos = Scanner::kNoSourcePos; |
| |
| |
| 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(name)); |
| const Type& variable_type = Type::ZoneHandle(Type::DynamicType()); |
| return new LocalVariable(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) { |
| const String& lib_url = String::ZoneHandle(Symbols::New(url)); |
| Library& lib = Library::ZoneHandle(Library::New(lib_url)); |
| lib.Register(); |
| Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| ASSERT(!core_lib.IsNull()); |
| const Namespace& core_ns = Namespace::Handle( |
| Namespace::New(core_lib, Array::Handle(), Array::Handle())); |
| lib.AddImport(core_ns); |
| return lib; |
| } |
| |
| |
| static RawClass* LookupClass(const Library& lib, const char* name) { |
| const String& cls_name = String::ZoneHandle(Symbols::New(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("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("A")))); |
| EXPECT_EQ(cls.raw(), result.clazz()); |
| } |
| |
| } // namespace dart |