| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/utils/random-number-generator.h" | 5 #include "src/base/utils/random-number-generator.h" |
| 6 #include "src/ic/stub-cache.h" | 6 #include "src/ic/stub-cache.h" |
| 7 #include "src/isolate.h" | 7 #include "src/isolate.h" |
| 8 #include "test/cctest/compiler/code-assembler-tester.h" | 8 #include "test/cctest/compiler/code-assembler-tester.h" |
| 9 #include "test/cctest/compiler/function-tester.h" | 9 #include "test/cctest/compiler/function-tester.h" |
| 10 | 10 |
| (...skipping 1085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 m.Bind(&block3); | 1096 m.Bind(&block3); |
| 1097 var_object.Bind(m.IntPtrConstant(66)); | 1097 var_object.Bind(m.IntPtrConstant(66)); |
| 1098 m.Goto(&block1); | 1098 m.Goto(&block1); |
| 1099 } | 1099 } |
| 1100 m.Bind(&block1); | 1100 m.Bind(&block1); |
| 1101 CHECK(!m.GenerateCode().is_null()); | 1101 CHECK(!m.GenerateCode().is_null()); |
| 1102 } | 1102 } |
| 1103 | 1103 |
| 1104 namespace { | 1104 namespace { |
| 1105 | 1105 |
| 1106 void TestStubCacheOffsetCalculation(StubCache::Table table, | 1106 void TestStubCacheOffsetCalculation(StubCache::Table table) { |
| 1107 Code::Kind handler_kind) { | |
| 1108 Isolate* isolate(CcTest::InitIsolateOnce()); | 1107 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 1109 const int kNumParams = 2; | 1108 const int kNumParams = 2; |
| 1110 CodeStubAssemblerTester m(isolate, kNumParams); | 1109 CodeStubAssemblerTester m(isolate, kNumParams); |
| 1111 | 1110 |
| 1112 Code::Flags code_flags = | |
| 1113 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(handler_kind)); | |
| 1114 { | 1111 { |
| 1115 Node* name = m.Parameter(0); | 1112 Node* name = m.Parameter(0); |
| 1116 Node* map = m.Parameter(1); | 1113 Node* map = m.Parameter(1); |
| 1117 Node* primary_offset = m.StubCachePrimaryOffset(name, code_flags, map); | 1114 Node* primary_offset = m.StubCachePrimaryOffset(name, map); |
| 1118 Node* result; | 1115 Node* result; |
| 1119 if (table == StubCache::kPrimary) { | 1116 if (table == StubCache::kPrimary) { |
| 1120 result = primary_offset; | 1117 result = primary_offset; |
| 1121 } else { | 1118 } else { |
| 1122 CHECK_EQ(StubCache::kSecondary, table); | 1119 CHECK_EQ(StubCache::kSecondary, table); |
| 1123 result = m.StubCacheSecondaryOffset(name, code_flags, primary_offset); | 1120 result = m.StubCacheSecondaryOffset(name, primary_offset); |
| 1124 } | 1121 } |
| 1125 m.Return(m.SmiFromWord32(result)); | 1122 m.Return(m.SmiFromWord32(result)); |
| 1126 } | 1123 } |
| 1127 | 1124 |
| 1128 Handle<Code> code = m.GenerateCode(); | 1125 Handle<Code> code = m.GenerateCode(); |
| 1129 FunctionTester ft(code, kNumParams); | 1126 FunctionTester ft(code, kNumParams); |
| 1130 | 1127 |
| 1131 Factory* factory = isolate->factory(); | 1128 Factory* factory = isolate->factory(); |
| 1132 Handle<Name> names[] = { | 1129 Handle<Name> names[] = { |
| 1133 factory->NewSymbol(), | 1130 factory->NewSymbol(), |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1156 factory->sloppy_arguments_elements_map(), | 1153 factory->sloppy_arguments_elements_map(), |
| 1157 }; | 1154 }; |
| 1158 | 1155 |
| 1159 for (int name_index = 0; name_index < arraysize(names); name_index++) { | 1156 for (int name_index = 0; name_index < arraysize(names); name_index++) { |
| 1160 Handle<Name> name = names[name_index]; | 1157 Handle<Name> name = names[name_index]; |
| 1161 for (int map_index = 0; map_index < arraysize(maps); map_index++) { | 1158 for (int map_index = 0; map_index < arraysize(maps); map_index++) { |
| 1162 Handle<Map> map = maps[map_index]; | 1159 Handle<Map> map = maps[map_index]; |
| 1163 | 1160 |
| 1164 int expected_result; | 1161 int expected_result; |
| 1165 { | 1162 { |
| 1166 int primary_offset = | 1163 int primary_offset = StubCache::PrimaryOffsetForTesting(*name, *map); |
| 1167 StubCache::PrimaryOffsetForTesting(*name, code_flags, *map); | |
| 1168 if (table == StubCache::kPrimary) { | 1164 if (table == StubCache::kPrimary) { |
| 1169 expected_result = primary_offset; | 1165 expected_result = primary_offset; |
| 1170 } else { | 1166 } else { |
| 1171 expected_result = StubCache::SecondaryOffsetForTesting( | 1167 expected_result = |
| 1172 *name, code_flags, primary_offset); | 1168 StubCache::SecondaryOffsetForTesting(*name, primary_offset); |
| 1173 } | 1169 } |
| 1174 } | 1170 } |
| 1175 Handle<Object> result = ft.Call(name, map).ToHandleChecked(); | 1171 Handle<Object> result = ft.Call(name, map).ToHandleChecked(); |
| 1176 | 1172 |
| 1177 Smi* expected = Smi::FromInt(expected_result & Smi::kMaxValue); | 1173 Smi* expected = Smi::FromInt(expected_result & Smi::kMaxValue); |
| 1178 CHECK_EQ(expected, Smi::cast(*result)); | 1174 CHECK_EQ(expected, Smi::cast(*result)); |
| 1179 } | 1175 } |
| 1180 } | 1176 } |
| 1181 } | 1177 } |
| 1182 | 1178 |
| 1183 } // namespace | 1179 } // namespace |
| 1184 | 1180 |
| 1185 TEST(StubCachePrimaryOffsetLoadIC) { | 1181 TEST(StubCachePrimaryOffset) { |
| 1186 TestStubCacheOffsetCalculation(StubCache::kPrimary, Code::LOAD_IC); | 1182 TestStubCacheOffsetCalculation(StubCache::kPrimary); |
| 1187 } | 1183 } |
| 1188 | 1184 |
| 1189 TEST(StubCachePrimaryOffsetStoreIC) { | 1185 TEST(StubCacheSecondaryOffset) { |
| 1190 TestStubCacheOffsetCalculation(StubCache::kPrimary, Code::STORE_IC); | 1186 TestStubCacheOffsetCalculation(StubCache::kSecondary); |
| 1191 } | |
| 1192 | |
| 1193 TEST(StubCacheSecondaryOffsetLoadIC) { | |
| 1194 TestStubCacheOffsetCalculation(StubCache::kSecondary, Code::LOAD_IC); | |
| 1195 } | |
| 1196 | |
| 1197 TEST(StubCacheSecondaryOffsetStoreIC) { | |
| 1198 TestStubCacheOffsetCalculation(StubCache::kSecondary, Code::STORE_IC); | |
| 1199 } | 1187 } |
| 1200 | 1188 |
| 1201 namespace { | 1189 namespace { |
| 1202 | 1190 |
| 1203 Handle<Code> CreateCodeWithFlags(Code::Flags flags) { | 1191 Handle<Code> CreateCodeWithFlags(Code::Flags flags) { |
| 1204 Isolate* isolate(CcTest::InitIsolateOnce()); | 1192 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 1205 CodeStubAssemblerTester m(isolate, flags); | 1193 CodeStubAssemblerTester m(isolate, flags); |
| 1206 m.Return(m.UndefinedConstant()); | 1194 m.Return(m.UndefinedConstant()); |
| 1207 return m.GenerateCodeCloseAndEscape(); | 1195 return m.GenerateCodeCloseAndEscape(); |
| 1208 } | 1196 } |
| 1209 | 1197 |
| 1210 } // namespace | 1198 } // namespace |
| 1211 | 1199 |
| 1212 TEST(TryProbeStubCache) { | 1200 TEST(TryProbeStubCache) { |
| 1213 typedef CodeStubAssembler::Label Label; | 1201 typedef CodeStubAssembler::Label Label; |
| 1214 typedef CodeStubAssembler::Variable Variable; | 1202 typedef CodeStubAssembler::Variable Variable; |
| 1215 Isolate* isolate(CcTest::InitIsolateOnce()); | 1203 Isolate* isolate(CcTest::InitIsolateOnce()); |
| 1216 const int kNumParams = 3; | 1204 const int kNumParams = 3; |
| 1217 CodeStubAssemblerTester m(isolate, kNumParams); | 1205 CodeStubAssemblerTester m(isolate, kNumParams); |
| 1218 | 1206 |
| 1219 Code::Kind ic_kind = Code::LOAD_IC; | 1207 Code::Kind ic_kind = Code::LOAD_IC; |
| 1220 Code::Flags flags_to_query = | |
| 1221 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(ic_kind)); | |
| 1222 | |
| 1223 StubCache stub_cache(isolate, ic_kind); | 1208 StubCache stub_cache(isolate, ic_kind); |
| 1224 stub_cache.Clear(); | 1209 stub_cache.Clear(); |
| 1225 | 1210 |
| 1226 { | 1211 { |
| 1227 Node* receiver = m.Parameter(0); | 1212 Node* receiver = m.Parameter(0); |
| 1228 Node* name = m.Parameter(1); | 1213 Node* name = m.Parameter(1); |
| 1229 Node* expected_handler = m.Parameter(2); | 1214 Node* expected_handler = m.Parameter(2); |
| 1230 | 1215 |
| 1231 Label passed(&m), failed(&m); | 1216 Label passed(&m), failed(&m); |
| 1232 | 1217 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1292 } | 1277 } |
| 1293 | 1278 |
| 1294 // Generate some number of receiver maps and receivers. | 1279 // Generate some number of receiver maps and receivers. |
| 1295 for (int i = 0; i < StubCache::kSecondaryTableSize / 2; i++) { | 1280 for (int i = 0; i < StubCache::kSecondaryTableSize / 2; i++) { |
| 1296 Handle<Map> map = Map::Create(isolate, 0); | 1281 Handle<Map> map = Map::Create(isolate, 0); |
| 1297 receivers.push_back(factory->NewJSObjectFromMap(map)); | 1282 receivers.push_back(factory->NewJSObjectFromMap(map)); |
| 1298 } | 1283 } |
| 1299 | 1284 |
| 1300 // Generate some number of handlers. | 1285 // Generate some number of handlers. |
| 1301 for (int i = 0; i < 30; i++) { | 1286 for (int i = 0; i < 30; i++) { |
| 1302 Code::Kind code_kind; | |
| 1303 switch (rand_gen.NextInt(4)) { | |
| 1304 case 0: | |
| 1305 code_kind = Code::LOAD_IC; | |
| 1306 break; | |
| 1307 case 1: | |
| 1308 code_kind = Code::KEYED_LOAD_IC; | |
| 1309 break; | |
| 1310 case 2: | |
| 1311 code_kind = Code::STORE_IC; | |
| 1312 break; | |
| 1313 case 3: | |
| 1314 code_kind = Code::KEYED_STORE_IC; | |
| 1315 break; | |
| 1316 default: | |
| 1317 UNREACHABLE(); | |
| 1318 } | |
| 1319 Code::Flags flags = | 1287 Code::Flags flags = |
| 1320 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(code_kind)); | 1288 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(ic_kind)); |
| 1321 handlers.push_back(CreateCodeWithFlags(flags)); | 1289 handlers.push_back(CreateCodeWithFlags(flags)); |
| 1322 } | 1290 } |
| 1323 | 1291 |
| 1324 // Ensure that GC does happen because from now on we are going to fill our | 1292 // Ensure that GC does happen because from now on we are going to fill our |
| 1325 // own stub cache instance with raw values. | 1293 // own stub cache instance with raw values. |
| 1326 DisallowHeapAllocation no_gc; | 1294 DisallowHeapAllocation no_gc; |
| 1327 | 1295 |
| 1328 // Populate {stub_cache}. | 1296 // Populate {stub_cache}. |
| 1329 const int N = StubCache::kPrimaryTableSize + StubCache::kSecondaryTableSize; | 1297 const int N = StubCache::kPrimaryTableSize + StubCache::kSecondaryTableSize; |
| 1330 for (int i = 0; i < N; i++) { | 1298 for (int i = 0; i < N; i++) { |
| 1331 int index = rand_gen.NextInt(); | 1299 int index = rand_gen.NextInt(); |
| 1332 Handle<Name> name = names[index % names.size()]; | 1300 Handle<Name> name = names[index % names.size()]; |
| 1333 Handle<JSObject> receiver = receivers[index % receivers.size()]; | 1301 Handle<JSObject> receiver = receivers[index % receivers.size()]; |
| 1334 Handle<Code> handler = handlers[index % handlers.size()]; | 1302 Handle<Code> handler = handlers[index % handlers.size()]; |
| 1335 stub_cache.Set(*name, receiver->map(), *handler); | 1303 stub_cache.Set(*name, receiver->map(), *handler); |
| 1336 } | 1304 } |
| 1337 | 1305 |
| 1338 // Perform some queries. | 1306 // Perform some queries. |
| 1339 bool queried_existing = false; | 1307 bool queried_existing = false; |
| 1340 bool queried_non_existing = false; | 1308 bool queried_non_existing = false; |
| 1341 for (int i = 0; i < N; i++) { | 1309 for (int i = 0; i < N; i++) { |
| 1342 int index = rand_gen.NextInt(); | 1310 int index = rand_gen.NextInt(); |
| 1343 Handle<Name> name = names[index % names.size()]; | 1311 Handle<Name> name = names[index % names.size()]; |
| 1344 Handle<JSObject> receiver = receivers[index % receivers.size()]; | 1312 Handle<JSObject> receiver = receivers[index % receivers.size()]; |
| 1345 Code* handler = stub_cache.Get(*name, receiver->map(), flags_to_query); | 1313 Code* handler = stub_cache.Get(*name, receiver->map()); |
| 1346 if (handler == nullptr) { | 1314 if (handler == nullptr) { |
| 1347 queried_non_existing = true; | 1315 queried_non_existing = true; |
| 1348 } else { | 1316 } else { |
| 1349 queried_existing = true; | 1317 queried_existing = true; |
| 1350 } | 1318 } |
| 1351 | 1319 |
| 1352 Handle<Code> expected_handler(handler, isolate); | 1320 Handle<Code> expected_handler(handler, isolate); |
| 1353 ft.CheckTrue(receiver, name, expected_handler); | 1321 ft.CheckTrue(receiver, name, expected_handler); |
| 1354 } | 1322 } |
| 1355 | 1323 |
| 1356 for (int i = 0; i < N; i++) { | 1324 for (int i = 0; i < N; i++) { |
| 1357 int index1 = rand_gen.NextInt(); | 1325 int index1 = rand_gen.NextInt(); |
| 1358 int index2 = rand_gen.NextInt(); | 1326 int index2 = rand_gen.NextInt(); |
| 1359 Handle<Name> name = names[index1 % names.size()]; | 1327 Handle<Name> name = names[index1 % names.size()]; |
| 1360 Handle<JSObject> receiver = receivers[index2 % receivers.size()]; | 1328 Handle<JSObject> receiver = receivers[index2 % receivers.size()]; |
| 1361 Code* handler = stub_cache.Get(*name, receiver->map(), flags_to_query); | 1329 Code* handler = stub_cache.Get(*name, receiver->map()); |
| 1362 if (handler == nullptr) { | 1330 if (handler == nullptr) { |
| 1363 queried_non_existing = true; | 1331 queried_non_existing = true; |
| 1364 } else { | 1332 } else { |
| 1365 queried_existing = true; | 1333 queried_existing = true; |
| 1366 } | 1334 } |
| 1367 | 1335 |
| 1368 Handle<Code> expected_handler(handler, isolate); | 1336 Handle<Code> expected_handler(handler, isolate); |
| 1369 ft.CheckTrue(receiver, name, expected_handler); | 1337 ft.CheckTrue(receiver, name, expected_handler); |
| 1370 } | 1338 } |
| 1371 // Ensure we performed both kind of queries. | 1339 // Ensure we performed both kind of queries. |
| 1372 CHECK(queried_existing && queried_non_existing); | 1340 CHECK(queried_existing && queried_non_existing); |
| 1373 } | 1341 } |
| 1374 | 1342 |
| 1375 } // namespace internal | 1343 } // namespace internal |
| 1376 } // namespace v8 | 1344 } // namespace v8 |
| OLD | NEW |