OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include "vm/globals.h" | |
6 #if defined(TARGET_ARCH_IA32) | |
7 | |
8 #include "vm/assembler.h" | |
9 #include "vm/code_index_table.h" | |
10 #include "vm/ic_stubs.h" | |
11 #include "vm/stub_code.h" | |
12 #include "vm/unit_test.h" | |
13 | |
14 namespace dart { | |
15 | |
16 | |
17 #define __ assembler-> | |
18 | |
19 ASSEMBLER_TEST_GENERATE(NotAnIc, assembler) { | |
20 __ nop(); | |
21 __ addl(EAX, Immediate(1)); | |
22 __ ret(); | |
23 } | |
24 | |
25 #undef __ | |
26 | |
27 ASSEMBLER_TEST_RUN(NotAnIc, entry) { | |
28 GrowableArray<const Class*> classes; | |
29 GrowableArray<const Function*> targets; | |
30 bool is_ic = ICStubs::RecognizeICStub(entry, &classes, &targets); | |
31 EXPECT_EQ(false, is_ic); | |
32 EXPECT_EQ(0, classes.length()); | |
33 EXPECT_EQ(0, targets.length()); | |
34 } | |
35 | |
36 | |
37 TEST_CASE(UnresolvedIcTest) { | |
38 GrowableArray<const Class*> classes; | |
39 GrowableArray<const Function*> targets; | |
40 uword entry = StubCode::CallInstanceFunctionLabel().address(); | |
41 bool is_ic = ICStubs::RecognizeICStub(entry, &classes, &targets); | |
42 EXPECT_EQ(true, is_ic); | |
43 EXPECT_EQ(0, classes.length()); | |
44 EXPECT_EQ(0, targets.length()); | |
45 } | |
46 | |
47 | |
48 static RawFunction* GetDummyTarget(const char* name) { | |
49 Assembler assembler; | |
50 assembler.ret(); | |
51 const Code& code = | |
52 Code::Handle(Code::FinalizeCode(name, &assembler)); | |
53 const String& function_name = | |
54 String::ZoneHandle(String::NewSymbol(name)); | |
55 const Function& function = Function::Handle(Function::New( | |
56 function_name, RawFunction::kFunction, true, false, 0)); | |
57 function.SetCode(code); | |
58 CodeIndexTable* code_index_table = Isolate::Current()->code_index_table(); | |
59 ASSERT(code_index_table != NULL); | |
60 code_index_table->AddFunction(function); | |
61 return function.raw(); | |
62 } | |
63 | |
64 | |
65 TEST_CASE(SmiIcTest) { | |
66 const Function& function = Function::Handle(GetDummyTarget("Dummy")); | |
67 GrowableArray<const Class*> classes; | |
68 GrowableArray<const Function*> targets; | |
69 classes.Add( | |
70 &Class::ZoneHandle(Isolate::Current()->object_store()->smi_class())); | |
71 targets.Add(&function); | |
72 const Code& ic_stub = | |
73 Code::Handle(ICStubs::GetICStub(classes, targets)); | |
74 ASSERT(!ic_stub.IsNull()); | |
75 classes.Clear(); | |
76 targets.Clear(); | |
77 bool is_ic = ICStubs::RecognizeICStub( | |
78 ic_stub.EntryPoint(), &classes, &targets); | |
79 EXPECT_EQ(true, is_ic); | |
80 EXPECT(classes.length() == targets.length()); | |
81 EXPECT_EQ(1, classes.length()); | |
82 EXPECT(classes[0]->raw() == Isolate::Current()->object_store()->smi_class()); | |
83 EXPECT(targets[0]->raw() == function.raw()); | |
84 } | |
85 | |
86 | |
87 TEST_CASE(NonSmiIcTest) { | |
88 const Function& function = Function::Handle(GetDummyTarget("Dummy")); | |
89 GrowableArray<const Class*> classes; | |
90 GrowableArray<const Function*> targets; | |
91 classes.Add( | |
92 &Class::ZoneHandle(Isolate::Current()->object_store()->array_class())); | |
93 targets.Add(&function); | |
94 Code& ic_stub = Code::Handle(ICStubs::GetICStub(classes, targets)); | |
95 ASSERT(!ic_stub.IsNull()); | |
96 classes.Clear(); | |
97 targets.Clear(); | |
98 bool is_ic = | |
99 ICStubs::RecognizeICStub(ic_stub.EntryPoint(), &classes, &targets); | |
100 EXPECT_EQ(true, is_ic); | |
101 EXPECT(classes.length() == targets.length()); | |
102 EXPECT_EQ(1, classes.length()); | |
103 EXPECT(classes[0]->raw() == | |
104 Isolate::Current()->object_store()->array_class()); | |
105 EXPECT(targets[0]->raw() == function.raw()); | |
106 | |
107 // Also check for always-ic-miss case (e.g. with null receiver). | |
108 classes.Clear(); | |
109 targets.Clear(); | |
110 ic_stub = ICStubs::GetICStub(classes, targets); | |
111 EXPECT(classes.length() == targets.length()); | |
112 EXPECT(classes.is_empty()); | |
113 } | |
114 | |
115 TEST_CASE(MixedIcTest) { | |
116 const Function& function = Function::Handle(GetDummyTarget("Dummy")); | |
117 GrowableArray<const Class*> classes; | |
118 GrowableArray<const Function*> targets; | |
119 classes.Add( | |
120 &Class::ZoneHandle(Isolate::Current()->object_store()->array_class())); | |
121 targets.Add(&function); | |
122 classes.Add( | |
123 &Class::ZoneHandle(Isolate::Current()->object_store()->smi_class())); | |
124 targets.Add(&function); | |
125 const Code& ic_stub = Code::Handle(ICStubs::GetICStub(classes, targets)); | |
126 ASSERT(!ic_stub.IsNull()); | |
127 GrowableArray<const Class*> new_classes; | |
128 GrowableArray<const Function*> new_targets; | |
129 bool is_ic = ICStubs::RecognizeICStub( | |
130 ic_stub.EntryPoint(), &new_classes, &new_targets); | |
131 EXPECT_EQ(true, is_ic); | |
132 EXPECT(new_classes.length() == new_targets.length()); | |
133 EXPECT_EQ(2, new_classes.length()); | |
134 for (int i = 0; i < classes.length(); i++) { | |
135 EXPECT(ICStubs::IndexOfClass(new_classes, *classes[i]) >= 0); | |
136 EXPECT(targets[i]->raw() == function.raw()); | |
137 } | |
138 } | |
139 | |
140 | |
141 TEST_CASE(ManyClassesICTest) { | |
142 const Function& function1 = Function::Handle(GetDummyTarget("Dummy1")); | |
143 const Function& function2 = Function::Handle(GetDummyTarget("Dummy2")); | |
144 GrowableArray<const Class*> classes; | |
145 GrowableArray<const Function*> targets; | |
146 classes.Add( | |
147 &Class::ZoneHandle(Isolate::Current()->object_store()->array_class())); | |
148 targets.Add(&function1); | |
149 classes.Add( | |
150 &Class::ZoneHandle(Isolate::Current()->object_store()->double_class())); | |
151 targets.Add(&function1); | |
152 classes.Add( | |
153 &Class::ZoneHandle(Isolate::Current()->object_store()->bool_class())); | |
154 targets.Add(&function2); | |
155 EXPECT_EQ(3, classes.length()); | |
156 const Code& ic_stub = Code::Handle(ICStubs::GetICStub(classes, targets)); | |
157 ASSERT(!ic_stub.IsNull()); | |
158 GrowableArray<const Class*> new_classes; | |
159 GrowableArray<const Function*> new_targets; | |
160 bool is_ic = ICStubs::RecognizeICStub( | |
161 ic_stub.EntryPoint(), &new_classes, &new_targets); | |
162 EXPECT_EQ(true, is_ic); | |
163 EXPECT(new_classes.length() == new_targets.length()); | |
164 EXPECT_EQ(3, new_classes.length()); | |
165 for (int i = 0; i < new_classes.length(); i++) { | |
166 if (new_classes[i]->raw() == | |
167 Isolate::Current()->object_store()->array_class()) { | |
168 EXPECT_EQ(function1.raw(), new_targets[i]->raw()); | |
169 } else if (new_classes[i]->raw() == | |
170 Isolate::Current()->object_store()->double_class()) { | |
171 EXPECT_EQ(function1.raw(), new_targets[i]->raw()); | |
172 } else if (new_classes[i]->raw() == | |
173 Isolate::Current()->object_store()->bool_class()) { | |
174 EXPECT_EQ(function2.raw(), new_targets[i]->raw()); | |
175 } else { | |
176 UNREACHABLE(); | |
177 } | |
178 } | |
179 ICStubs::PatchTargets(ic_stub.EntryPoint(), | |
180 Code::Handle(function1.code()).EntryPoint(), | |
181 Code::Handle(function2.code()).EntryPoint()); | |
182 is_ic = ICStubs::RecognizeICStub( | |
183 ic_stub.EntryPoint(), &new_classes, &new_targets); | |
184 EXPECT_EQ(true, is_ic); | |
185 EXPECT(new_classes.length() == new_targets.length()); | |
186 EXPECT_EQ(3, new_classes.length()); | |
187 for (int i = 0; i < new_classes.length(); i++) { | |
188 if (new_classes[i]->raw() == | |
189 Isolate::Current()->object_store()->array_class()) { | |
190 EXPECT_EQ(function2.raw(), new_targets[i]->raw()); | |
191 } else if (new_classes[i]->raw() == | |
192 Isolate::Current()->object_store()->double_class()) { | |
193 EXPECT_EQ(function2.raw(), new_targets[i]->raw()); | |
194 } else if (new_classes[i]->raw() == | |
195 Isolate::Current()->object_store()->bool_class()) { | |
196 EXPECT_EQ(function2.raw(), new_targets[i]->raw()); | |
197 } else { | |
198 UNREACHABLE(); | |
199 } | |
200 } | |
201 } | |
202 | |
203 } // namespace dart | |
204 | |
205 #endif // defined TARGET_ARCH_IA32 | |
OLD | NEW |