ba0f59d1bc
The optimizing compiler currently recognizes a certain frequent native methods like array length or string length and provides an inlined implementation. Inlining does currently not work for polymorphic call sites of these methods. This CL enables also polymorphic inlining in the case of .length getters for arrays and strings. 1. The method is recognized at flow graph build time. The builder creates the body of the method for both compilers (non-optimizing and optimizing). Native methods that are not recognized, are translated as before using a NativeCall IL instruction. 2. The flow graph inliner handles recognized methods in the same manner as normal methods. Until now intrinsic and recognized method could not be inlined. This CL enables it. 3. There is no need for an intrinsic assembly implementation because recognized methods have an IL implementation that does not call into the C++ runtime. I left the intrinsics in for now, but they can be removed if there is not noticable performance benefit anymore. 4. The inlining heuristics are tweaked in a way that enables more aggressive inlining of recognized methods: +1 level of inlining depths, call sites of recognized methods are not counted in the inlining heuristic. R=kmillikin@google.com, srdjan@google.com Review URL: https://codereview.chromium.org//22839003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@26429 260f80e4-7a28-3924-810f-c04153c831b5
572 lines
23 KiB
C++
572 lines
23 KiB
C++
// 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/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::kDummyTokenIndex;
|
|
|
|
|
|
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->AddVariable(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->AddVariable(param1);
|
|
local_scope->AddVariable(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));
|
|
|
|
|
|
// Tested Dart code:
|
|
// int dec(int a, [int b = 1]) native: "TestSmiSub";
|
|
// The native entry TestSmiSub implements dec natively.
|
|
CODEGEN_TEST_GENERATE(NativeDecCodegen, test) {
|
|
// A NativeBodyNode, preceded by an EnterNode and followed by a ReturnNode,
|
|
// implements the body of a native Dart function. Let's take this native
|
|
// function as an example: int dec(int a, int b = 1) native;
|
|
// Since this function has an optional parameter, its prologue will copy
|
|
// incoming parameters to locals.
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
const int num_fixed_params = 1;
|
|
const int num_opt_params = 1;
|
|
const int num_params = num_fixed_params + num_opt_params;
|
|
LocalScope* local_scope = node_seq->scope();
|
|
local_scope->AddVariable(NewTestLocalVariable("a"));
|
|
local_scope->AddVariable(NewTestLocalVariable("b"));
|
|
ASSERT(local_scope->num_variables() == num_params);
|
|
const Array& default_values = Array::ZoneHandle(Array::New(num_opt_params));
|
|
default_values.SetAt(0, Smi::ZoneHandle(Smi::New(1))); // b = 1.
|
|
test->set_default_parameter_values(default_values);
|
|
const Function& function = test->function();
|
|
function.set_is_native(true);
|
|
function.set_num_fixed_parameters(num_fixed_params);
|
|
function.SetNumOptionalParameters(num_opt_params, true);
|
|
const String& native_name =
|
|
String::ZoneHandle(Symbols::New("TestSmiSub"));
|
|
NativeFunction native_function =
|
|
reinterpret_cast<NativeFunction>(TestSmiSub);
|
|
node_seq->Add(
|
|
new ReturnNode(kPos,
|
|
new NativeBodyNode(kPos,
|
|
function,
|
|
native_name,
|
|
native_function,
|
|
local_scope,
|
|
false /* not bootstrap native */)));
|
|
}
|
|
|
|
|
|
// Tested Dart code:
|
|
// return dec(5);
|
|
CODEGEN_TEST2_GENERATE(StaticDecCallCodegen, function, test) {
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
ArgumentListNode* arguments = new ArgumentListNode(kPos);
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(5))));
|
|
node_seq->Add(new ReturnNode(kPos,
|
|
new StaticCallNode(kPos, function, arguments)));
|
|
}
|
|
CODEGEN_TEST2_RUN(StaticDecCallCodegen, NativeDecCodegen, Smi::New(4))
|
|
|
|
|
|
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));
|
|
String& ambiguity_error_msg = String::Handle();
|
|
return lib.LookupClass(cls_name, &ambiguity_error_msg);
|
|
}
|
|
|
|
|
|
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::FinalizePendingClasses());
|
|
Class& cls = Class::Handle(LookupClass(lib, "A"));
|
|
EXPECT(!cls.IsNull()); // No ambiguity error expected.
|
|
|
|
// '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::FinalizePendingClasses());
|
|
Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
|
|
EXPECT(!cls.IsNull()); // No ambiguity error expected.
|
|
|
|
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))
|
|
|
|
|
|
// Tested Dart code:
|
|
// int sum(int a, int b,
|
|
// [int c = 10, int d = 21, int e = -32]) native: "TestSmiSum";
|
|
// The native entry TestSmiSum implements sum natively.
|
|
CODEGEN_TEST_GENERATE(NativeSumCodegen, test) {
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
const int num_fixed_params = 2;
|
|
const int num_opt_params = 3;
|
|
const int num_params = num_fixed_params + num_opt_params;
|
|
LocalScope* local_scope = node_seq->scope();
|
|
local_scope->AddVariable(NewTestLocalVariable("a"));
|
|
local_scope->AddVariable(NewTestLocalVariable("b"));
|
|
local_scope->AddVariable(NewTestLocalVariable("c"));
|
|
local_scope->AddVariable(NewTestLocalVariable("d"));
|
|
local_scope->AddVariable(NewTestLocalVariable("e"));
|
|
ASSERT(local_scope->num_variables() == num_params);
|
|
const Array& default_values = Array::ZoneHandle(Array::New(num_opt_params));
|
|
default_values.SetAt(0, Smi::ZoneHandle(Smi::New(10)));
|
|
default_values.SetAt(1, Smi::ZoneHandle(Smi::New(21)));
|
|
default_values.SetAt(2, Smi::ZoneHandle(Smi::New(-32)));
|
|
test->set_default_parameter_values(default_values);
|
|
const Function& function = test->function();
|
|
function.set_is_native(true);
|
|
function.set_num_fixed_parameters(num_fixed_params);
|
|
function.SetNumOptionalParameters(num_opt_params, true);
|
|
function.set_parameter_types(Array::Handle(Array::New(num_params)));
|
|
function.set_parameter_names(Array::Handle(Array::New(num_params)));
|
|
const Type& param_type = Type::Handle(Type::DynamicType());
|
|
for (int i = 0; i < num_params; i++) {
|
|
function.SetParameterTypeAt(i, param_type);
|
|
}
|
|
const String& native_name =
|
|
String::ZoneHandle(Symbols::New("TestSmiSum"));
|
|
NativeFunction native_function =
|
|
reinterpret_cast<NativeFunction>(TestSmiSum);
|
|
node_seq->Add(
|
|
new ReturnNode(kPos,
|
|
new NativeBodyNode(kPos,
|
|
function,
|
|
native_name,
|
|
native_function,
|
|
local_scope,
|
|
false /* Not bootstrap native */)));
|
|
}
|
|
|
|
|
|
// Tested Dart code, calling function sum declared above:
|
|
// return sum(1, 3);
|
|
// Optional arguments are not passed and hence are set to their default values.
|
|
CODEGEN_TEST2_GENERATE(StaticSumCallNoOptCodegen, function, test) {
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
ArgumentListNode* arguments = new ArgumentListNode(kPos);
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
|
|
node_seq->Add(new ReturnNode(kPos,
|
|
new StaticCallNode(kPos, function, arguments)));
|
|
}
|
|
CODEGEN_TEST2_RUN(StaticSumCallNoOptCodegen,
|
|
NativeSumCodegen,
|
|
Smi::New(1 + 3 + 10 + 21 - 32))
|
|
|
|
|
|
// Tested Dart code, calling function sum declared above:
|
|
// return sum(1, 3, 5);
|
|
// Only one out of three optional arguments is passed in; the second and third
|
|
// arguments are hence set to their default values.
|
|
CODEGEN_TEST2_GENERATE(StaticSumCallOneOptCodegen, function, test) {
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
ArgumentListNode* arguments = new ArgumentListNode(kPos);
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(5))));
|
|
node_seq->Add(new ReturnNode(kPos,
|
|
new StaticCallNode(kPos, function, arguments)));
|
|
}
|
|
CODEGEN_TEST2_RUN(StaticSumCallOneOptCodegen,
|
|
NativeSumCodegen,
|
|
Smi::New(1 + 3 + 5 + 21 - 32))
|
|
|
|
|
|
// Tested Dart code, calling function sum declared above:
|
|
// return sum(0, 1, 1, 2, 3);
|
|
// Optional arguments are passed in.
|
|
CODEGEN_TEST2_GENERATE(StaticSumCallTenFiboCodegen, function, test) {
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
ArgumentListNode* arguments = new ArgumentListNode(kPos);
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(0))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
|
|
node_seq->Add(new ReturnNode(kPos,
|
|
new StaticCallNode(kPos, function, arguments)));
|
|
}
|
|
CODEGEN_TEST2_RUN(
|
|
StaticSumCallTenFiboCodegen,
|
|
NativeSumCodegen,
|
|
Smi::New(0 + 1 + 1 + 2 + 3))
|
|
|
|
|
|
// Tested Dart code:
|
|
// int sum(a, b, c) native: "TestNonNullSmiSum";
|
|
// The native entry TestNonNullSmiSum implements sum natively.
|
|
CODEGEN_TEST_GENERATE(NativeNonNullSumCodegen, test) {
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
const int num_params = 3;
|
|
LocalScope* local_scope = node_seq->scope();
|
|
local_scope->AddVariable(NewTestLocalVariable("a"));
|
|
local_scope->AddVariable(NewTestLocalVariable("b"));
|
|
local_scope->AddVariable(NewTestLocalVariable("c"));
|
|
ASSERT(local_scope->num_variables() == num_params);
|
|
const Function& function = test->function();
|
|
function.set_is_native(true);
|
|
function.set_num_fixed_parameters(num_params);
|
|
ASSERT(!function.HasOptionalParameters());
|
|
function.set_parameter_types(Array::Handle(Array::New(num_params)));
|
|
function.set_parameter_names(Array::Handle(Array::New(num_params)));
|
|
const Type& param_type = Type::Handle(Type::DynamicType());
|
|
for (int i = 0; i < num_params; i++) {
|
|
function.SetParameterTypeAt(i, param_type);
|
|
}
|
|
const String& native_name =
|
|
String::ZoneHandle(Symbols::New("TestNonNullSmiSum"));
|
|
NativeFunction native_function =
|
|
reinterpret_cast<NativeFunction>(TestNonNullSmiSum);
|
|
node_seq->Add(
|
|
new ReturnNode(kPos,
|
|
new NativeBodyNode(kPos,
|
|
function,
|
|
native_name,
|
|
native_function,
|
|
local_scope,
|
|
false /* Not bootstrap native */)));
|
|
}
|
|
|
|
|
|
// Tested Dart code, calling function sum declared above:
|
|
// return sum(1, null, 3);
|
|
CODEGEN_TEST2_GENERATE(StaticNonNullSumCallCodegen, function, test) {
|
|
SequenceNode* node_seq = test->node_sequence();
|
|
ArgumentListNode* arguments = new ArgumentListNode(kPos);
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1))));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle()));
|
|
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
|
|
node_seq->Add(new ReturnNode(kPos,
|
|
new StaticCallNode(kPos, function, arguments)));
|
|
}
|
|
CODEGEN_TEST2_RUN(StaticNonNullSumCallCodegen,
|
|
NativeNonNullSumCodegen,
|
|
Smi::New(1 + 3))
|
|
|
|
|
|
// 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::FinalizePendingClasses());
|
|
Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
|
|
EXPECT(!cls.IsNull()); // No ambiguity error expected.
|
|
|
|
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());
|
|
String& ambiguity_error_msg = String::Handle();
|
|
const Class& cls = Class::Handle(
|
|
app_lib.LookupClass(String::Handle(Symbols::New("A")),
|
|
&ambiguity_error_msg));
|
|
EXPECT_EQ(cls.raw(), result.clazz()); // No ambiguity error expected.
|
|
}
|
|
|
|
} // namespace dart
|