| 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 |