Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: test/cctest/test-code-stub-assembler.cc

Issue 2031753003: [stubs] Introducing LoadICTFStub and LoadICTrampolineTFStub and a switch to enable them instead of … (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Addressing comments Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ic/stub-cache.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/interface-descriptors.h" 7 #include "src/interface-descriptors.h"
7 #include "src/isolate.h" 8 #include "src/isolate.h"
8 #include "test/cctest/compiler/function-tester.h" 9 #include "test/cctest/compiler/function-tester.h"
9 10
10 namespace v8 { 11 namespace v8 {
11 namespace internal { 12 namespace internal {
12 13
13 using compiler::FunctionTester; 14 using compiler::FunctionTester;
14 using compiler::Node; 15 using compiler::Node;
15 16
(...skipping 18 matching lines...) Expand all
34 Code::ComputeFlags(Code::STUB), "test"), 35 Code::ComputeFlags(Code::STUB), "test"),
35 scope_(isolate) {} 36 scope_(isolate) {}
36 37
37 // Test generating code for a JS function (e.g. builtins). 38 // Test generating code for a JS function (e.g. builtins).
38 CodeStubAssemblerTester(Isolate* isolate, int parameter_count) 39 CodeStubAssemblerTester(Isolate* isolate, int parameter_count)
39 : ZoneHolder(isolate), 40 : ZoneHolder(isolate),
40 CodeStubAssembler(isolate, ZoneHolder::zone(), parameter_count, 41 CodeStubAssembler(isolate, ZoneHolder::zone(), parameter_count,
41 Code::ComputeFlags(Code::FUNCTION), "test"), 42 Code::ComputeFlags(Code::FUNCTION), "test"),
42 scope_(isolate) {} 43 scope_(isolate) {}
43 44
45 // This constructor is intended to be used for creating code objects with
46 // specific flags.
47 CodeStubAssemblerTester(Isolate* isolate, Code::Flags flags)
48 : ZoneHolder(isolate),
49 CodeStubAssembler(isolate, ZoneHolder::zone(), 0, flags, "test"),
50 scope_(isolate) {}
51
52 Handle<Code> GenerateCodeCloseAndEscape() {
53 return scope_.CloseAndEscape(GenerateCode());
54 }
55
44 private: 56 private:
45 HandleScope scope_; 57 HandleScope scope_;
46 LocalContext context_; 58 LocalContext context_;
47 }; 59 };
48 60
49 TEST(SimpleSmiReturn) { 61 TEST(SimpleSmiReturn) {
50 Isolate* isolate(CcTest::InitIsolateOnce()); 62 Isolate* isolate(CcTest::InitIsolateOnce());
51 VoidDescriptor descriptor(isolate); 63 VoidDescriptor descriptor(isolate);
52 CodeStubAssemblerTester m(isolate, descriptor); 64 CodeStubAssemblerTester m(isolate, descriptor);
53 m.Return(m.SmiTag(m.Int32Constant(37))); 65 m.Return(m.SmiTag(m.Int32Constant(37)));
(...skipping 1058 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 m.Goto(&block1); 1124 m.Goto(&block1);
1113 1125
1114 m.Bind(&block3); 1126 m.Bind(&block3);
1115 var_object.Bind(m.IntPtrConstant(66)); 1127 var_object.Bind(m.IntPtrConstant(66));
1116 m.Goto(&block1); 1128 m.Goto(&block1);
1117 } 1129 }
1118 m.Bind(&block1); 1130 m.Bind(&block1);
1119 CHECK(!m.GenerateCode().is_null()); 1131 CHECK(!m.GenerateCode().is_null());
1120 } 1132 }
1121 1133
1134 namespace {
1135
1136 void TestStubCacheOffsetCalculation(StubCache::Table table,
1137 Code::Kind handler_kind) {
1138 Isolate* isolate(CcTest::InitIsolateOnce());
1139 const int param_count = 2;
1140 CodeStubAssemblerTester m(isolate, param_count);
1141
1142 Code::Flags code_flags =
1143 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(handler_kind));
1144 {
1145 Node* name = m.Parameter(0);
1146 Node* map = m.Parameter(1);
1147 Node* primary_offset = m.StubCachePrimaryOffset(name, code_flags, map);
1148 Node* result;
1149 if (table == StubCache::kPrimary) {
1150 result = primary_offset;
1151 } else {
1152 CHECK_EQ(StubCache::kSecondary, table);
1153 result = m.StubCacheSecondaryOffset(name, code_flags, primary_offset);
1154 }
1155 m.Return(m.SmiFromWord32(result));
1156 }
1157
1158 Handle<Code> code = m.GenerateCode();
1159 FunctionTester ft(code, param_count);
1160
1161 Factory* factory = isolate->factory();
1162 Handle<Name> names[] = {
1163 factory->NewSymbol(),
1164 factory->InternalizeUtf8String("a"),
1165 factory->InternalizeUtf8String("bb"),
1166 factory->InternalizeUtf8String("ccc"),
1167 factory->NewPrivateSymbol(),
1168 factory->InternalizeUtf8String("dddd"),
1169 factory->InternalizeUtf8String("eeeee"),
1170 factory->InternalizeUtf8String("name"),
1171 factory->NewSymbol(),
1172 factory->NewPrivateSymbol(),
1173 };
1174
1175 Handle<Map> maps[] = {
1176 Handle<Map>(nullptr, isolate),
1177 factory->cell_map(),
1178 Map::Create(isolate, 0),
1179 factory->meta_map(),
1180 factory->code_map(),
1181 Map::Create(isolate, 0),
1182 factory->hash_table_map(),
1183 factory->symbol_map(),
1184 factory->string_map(),
1185 Map::Create(isolate, 0),
1186 factory->sloppy_arguments_elements_map(),
1187 };
1188
1189 for (int name_index = 0; name_index < arraysize(names); name_index++) {
1190 Handle<Name> name = names[name_index];
1191 for (int map_index = 0; map_index < arraysize(maps); map_index++) {
1192 Handle<Map> map = maps[map_index];
1193
1194 int expected_result;
1195 {
1196 int primary_offset =
1197 StubCache::PrimaryOffsetForTesting(*name, code_flags, *map);
1198 if (table == StubCache::kPrimary) {
1199 expected_result = primary_offset;
1200 } else {
1201 expected_result = StubCache::SecondaryOffsetForTesting(
1202 *name, code_flags, primary_offset);
1203 }
1204 }
1205 Handle<Object> result = ft.Call(name, map).ToHandleChecked();
1206
1207 Smi* expected = Smi::FromInt(expected_result & Smi::kMaxValue);
1208 CHECK_EQ(expected, Smi::cast(*result));
1209 }
1210 }
1211 }
1212
1213 } // namespace
1214
1215 TEST(StubCachePrimaryOffsetLoadIC) {
1216 TestStubCacheOffsetCalculation(StubCache::kPrimary, Code::LOAD_IC);
1217 }
1218
1219 TEST(StubCachePrimaryOffsetStoreIC) {
1220 TestStubCacheOffsetCalculation(StubCache::kPrimary, Code::STORE_IC);
1221 }
1222
1223 TEST(StubCacheSecondaryOffsetLoadIC) {
1224 TestStubCacheOffsetCalculation(StubCache::kSecondary, Code::LOAD_IC);
1225 }
1226
1227 TEST(StubCacheSecondaryOffsetStoreIC) {
1228 TestStubCacheOffsetCalculation(StubCache::kSecondary, Code::STORE_IC);
1229 }
1230
1231 namespace {
1232
1233 Handle<Code> CreateCodeWithFlags(Code::Flags flags) {
1234 Isolate* isolate(CcTest::InitIsolateOnce());
1235 CodeStubAssemblerTester m(isolate, flags);
1236 m.Return(m.UndefinedConstant());
1237 return m.GenerateCodeCloseAndEscape();
1238 }
1239
1240 } // namespace
1241
1242 TEST(TryProbeStubCache) {
adamk 2016/06/06 19:08:29 This test seems to flake consistently on Linux nos
1243 typedef CodeStubAssembler::Label Label;
1244 typedef CodeStubAssembler::Variable Variable;
1245 Isolate* isolate(CcTest::InitIsolateOnce());
1246 const int param_count = 3;
1247 CodeStubAssemblerTester m(isolate, param_count);
1248
1249 Code::Flags flags_to_query =
1250 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::LOAD_IC));
1251
1252 StubCache stub_cache(isolate);
1253 stub_cache.Clear();
1254
1255 {
1256 Node* receiver = m.Parameter(0);
1257 Node* name = m.Parameter(1);
1258 Node* expected_handler = m.Parameter(2);
1259
1260 Label passed(&m), failed(&m);
1261
1262 Variable var_handler(&m, MachineRepresentation::kTagged);
1263 Label if_handler(&m), if_miss(&m);
1264
1265 m.TryProbeStubCache(&stub_cache, flags_to_query, receiver, name,
1266 &if_handler, &var_handler, &if_miss);
1267 m.Bind(&if_handler);
1268 m.BranchIfWordEqual(expected_handler, var_handler.value(), &passed,
1269 &failed);
1270
1271 m.Bind(&if_miss);
1272 m.BranchIfWordEqual(expected_handler, m.IntPtrConstant(0), &passed,
1273 &failed);
1274
1275 m.Bind(&passed);
1276 m.Return(m.BooleanConstant(true));
1277
1278 m.Bind(&failed);
1279 m.Return(m.BooleanConstant(false));
1280 }
1281
1282 Handle<Code> code = m.GenerateCode();
1283 FunctionTester ft(code, param_count);
1284
1285 std::vector<Handle<Name>> names;
1286 std::vector<Handle<JSObject>> receivers;
1287 std::vector<Handle<Code>> handlers;
1288
1289 base::RandomNumberGenerator rand_gen(FLAG_random_seed);
1290
1291 Factory* factory = isolate->factory();
1292
1293 // Generate some number of names.
1294 for (int i = 0; i < StubCache::kPrimaryTableSize / 7; i++) {
1295 Handle<Name> name;
1296 switch (rand_gen.NextInt(3)) {
1297 case 0: {
1298 // Generate string.
1299 std::stringstream ss;
1300 ss << "s" << std::hex
1301 << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
1302 name = factory->InternalizeUtf8String(ss.str().c_str());
1303 break;
1304 }
1305 case 1: {
1306 // Generate number string.
1307 std::stringstream ss;
1308 ss << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
1309 name = factory->InternalizeUtf8String(ss.str().c_str());
1310 break;
1311 }
1312 case 2: {
1313 // Generate symbol.
1314 name = factory->NewSymbol();
1315 break;
1316 }
1317 default:
1318 UNREACHABLE();
1319 }
1320 names.push_back(name);
1321 }
1322
1323 // Generate some number of receiver maps and receivers.
1324 for (int i = 0; i < StubCache::kSecondaryTableSize / 2; i++) {
1325 Handle<Map> map = Map::Create(isolate, 0);
1326 receivers.push_back(factory->NewJSObjectFromMap(map));
1327 }
1328
1329 // Generate some number of handlers.
1330 for (int i = 0; i < StubCache::kSecondaryTableSize; i++) {
1331 Code::Kind code_kind;
1332 switch (rand_gen.NextInt(4)) {
1333 case 0:
1334 code_kind = Code::LOAD_IC;
1335 break;
1336 case 1:
1337 code_kind = Code::KEYED_LOAD_IC;
1338 break;
1339 case 2:
1340 code_kind = Code::STORE_IC;
1341 break;
1342 case 3:
1343 code_kind = Code::KEYED_STORE_IC;
1344 break;
1345 default:
1346 UNREACHABLE();
1347 }
1348 Code::Flags flags =
1349 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(code_kind));
1350 handlers.push_back(CreateCodeWithFlags(flags));
1351 }
1352
1353 // Ensure that GC does happen because from now on we are going to fill our
1354 // own stub cache instance with raw values.
1355 DisallowHeapAllocation no_gc;
1356
1357 // Populate {stub_cache}.
1358 const int N = StubCache::kPrimaryTableSize + StubCache::kSecondaryTableSize;
1359 for (int i = 0; i < N; i++) {
1360 int index = rand_gen.NextInt();
1361 Handle<Name> name = names[index % names.size()];
1362 Handle<JSObject> receiver = receivers[index % receivers.size()];
1363 Handle<Code> handler = handlers[index % handlers.size()];
1364 stub_cache.Set(*name, receiver->map(), *handler);
1365 }
1366
1367 // Perform some queries.
1368 bool queried_existing = false;
1369 bool queried_non_existing = false;
1370 for (int i = 0; i < N; i++) {
1371 int index = rand_gen.NextInt();
1372 Handle<Name> name = names[index % names.size()];
1373 Handle<JSObject> receiver = receivers[index % receivers.size()];
1374 Code* handler = stub_cache.Get(*name, receiver->map(), flags_to_query);
1375 if (handler == nullptr) {
1376 queried_non_existing = true;
1377 } else {
1378 queried_existing = true;
1379 }
1380
1381 Handle<Code> expected_handler(handler, isolate);
1382 ft.CheckTrue(receiver, name, expected_handler);
1383 }
1384
1385 for (int i = 0; i < N; i++) {
1386 int index1 = rand_gen.NextInt();
1387 int index2 = rand_gen.NextInt();
1388 Handle<Name> name = names[index1 % names.size()];
1389 Handle<JSObject> receiver = receivers[index2 % receivers.size()];
1390 Code* handler = stub_cache.Get(*name, receiver->map(), flags_to_query);
1391 if (handler == nullptr) {
1392 queried_non_existing = true;
1393 } else {
1394 queried_existing = true;
1395 }
1396
1397 Handle<Code> expected_handler(handler, isolate);
1398 ft.CheckTrue(receiver, name, expected_handler);
1399 }
1400 // Ensure we performed both kind of queries.
1401 CHECK(queried_existing && queried_non_existing);
1402 }
1403
1122 } // namespace internal 1404 } // namespace internal
1123 } // namespace v8 1405 } // namespace v8
OLDNEW
« no previous file with comments | « src/ic/stub-cache.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698