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

Side by Side Diff: src/ic.cc

Issue 494153002: Avoid one repeated property lookup when computing store ICs. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/lookup.h » ('j') | src/lookup.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/api.h" 8 #include "src/api.h"
9 #include "src/arguments.h" 9 #include "src/arguments.h"
10 #include "src/codegen.h" 10 #include "src/codegen.h"
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 Code* IC::GetOriginalCode() const { 195 Code* IC::GetOriginalCode() const {
196 HandleScope scope(isolate()); 196 HandleScope scope(isolate());
197 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate()); 197 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
198 DCHECK(Debug::HasDebugInfo(shared)); 198 DCHECK(Debug::HasDebugInfo(shared));
199 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); 199 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
200 DCHECK(original_code->IsCode()); 200 DCHECK(original_code->IsCode());
201 return original_code; 201 return original_code;
202 } 202 }
203 203
204 204
205 static bool HasInterceptorSetter(JSObject* object) {
206 return !object->GetNamedInterceptor()->setter()->IsUndefined();
207 }
208
209
210 static void LookupForRead(LookupIterator* it) { 205 static void LookupForRead(LookupIterator* it) {
211 for (; it->IsFound(); it->Next()) { 206 for (; it->IsFound(); it->Next()) {
212 switch (it->state()) { 207 switch (it->state()) {
213 case LookupIterator::NOT_FOUND: 208 case LookupIterator::NOT_FOUND:
209 case LookupIterator::TRANSITION:
214 UNREACHABLE(); 210 UNREACHABLE();
215 case LookupIterator::JSPROXY: 211 case LookupIterator::JSPROXY:
216 return; 212 return;
217 case LookupIterator::INTERCEPTOR: { 213 case LookupIterator::INTERCEPTOR: {
218 // If there is a getter, return; otherwise loop to perform the lookup. 214 // If there is a getter, return; otherwise loop to perform the lookup.
219 Handle<JSObject> holder = it->GetHolder<JSObject>(); 215 Handle<JSObject> holder = it->GetHolder<JSObject>();
220 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) { 216 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
221 return; 217 return;
222 } 218 }
223 break; 219 break;
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 if (!name->IsName()) return false; 291 if (!name->IsName()) return false;
296 Name* stub_name = target()->FindFirstName(); 292 Name* stub_name = target()->FindFirstName();
297 if (*name != stub_name) return false; 293 if (*name != stub_name) return false;
298 } 294 }
299 295
300 return true; 296 return true;
301 } 297 }
302 298
303 299
304 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { 300 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
305 receiver_type_ = CurrentTypeOf(receiver, isolate()); 301 update_receiver_type(receiver);
306 if (!name->IsString()) return; 302 if (!name->IsString()) return;
307 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; 303 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
308 if (receiver->IsUndefined() || receiver->IsNull()) return; 304 if (receiver->IsUndefined() || receiver->IsNull()) return;
309 305
310 // Remove the target from the code cache if it became invalid 306 // Remove the target from the code cache if it became invalid
311 // because of changes in the prototype chain to avoid hitting it 307 // because of changes in the prototype chain to avoid hitting it
312 // again. 308 // again.
313 if (TryRemoveInvalidPrototypeDependentStub(receiver, 309 if (TryRemoveInvalidPrototypeDependentStub(receiver,
314 Handle<String>::cast(name))) { 310 Handle<String>::cast(name))) {
315 MarkPrototypeFailure(name); 311 MarkPrototypeFailure(name);
(...skipping 632 matching lines...) Expand 10 before | Expand all | Expand 10 after
948 DCHECK(code->is_handler()); 944 DCHECK(code->is_handler());
949 945
950 if (code->type() != Code::NORMAL) { 946 if (code->type() != Code::NORMAL) {
951 Map::UpdateCodeCache(stub_holder_map, name, code); 947 Map::UpdateCodeCache(stub_holder_map, name, code);
952 } 948 }
953 949
954 return code; 950 return code;
955 } 951 }
956 952
957 953
958 Handle<Code> IC::ComputeStoreHandler(LookupResult* lookup,
959 Handle<Object> object, Handle<Name> name,
960 Handle<Object> value) {
961 bool receiver_is_holder = lookup->ReceiverIsHolder(object);
962 CacheHolderFlag flag;
963 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
964 *receiver_type(), receiver_is_holder, isolate(), &flag);
965
966 Handle<Code> code = PropertyHandlerCompiler::Find(
967 name, stub_holder_map, handler_kind(), flag,
968 lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL);
969 // Use the cached value if it exists, and if it is different from the
970 // handler that just missed.
971 if (!code.is_null()) {
972 if (!maybe_handler_.is_null() &&
973 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
974 return code;
975 }
976 if (maybe_handler_.is_null()) {
977 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
978 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
979 // cache (which just missed) is different from the cached handler.
980 if (state() == MEGAMORPHIC && object->IsHeapObject()) {
981 Map* map = Handle<HeapObject>::cast(object)->map();
982 Code* megamorphic_cached_code =
983 isolate()->stub_cache()->Get(*name, map, code->flags());
984 if (megamorphic_cached_code != *code) return code;
985 } else {
986 return code;
987 }
988 }
989 }
990
991 code = CompileStoreHandler(lookup, object, name, value, flag);
992 DCHECK(code->is_handler());
993
994 if (code->type() != Code::NORMAL) {
995 Map::UpdateCodeCache(stub_holder_map, name, code);
996 }
997
998 return code;
999 }
1000
1001
1002 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, 954 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
1003 Handle<Object> object, Handle<Name> name, 955 Handle<Object> object, Handle<Name> name,
1004 Handle<Object> unused, 956 Handle<Object> unused,
1005 CacheHolderFlag cache_holder) { 957 CacheHolderFlag cache_holder) {
1006 if (object->IsString() && 958 if (object->IsString() &&
1007 Name::Equals(isolate()->factory()->length_string(), name)) { 959 Name::Equals(isolate()->factory()->length_string(), name)) {
1008 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); 960 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
1009 return SimpleFieldLoad(index); 961 return SimpleFieldLoad(index);
1010 } 962 }
1011 963
(...skipping 21 matching lines...) Expand all
1033 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined()); 985 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
1034 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, 986 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
1035 cache_holder); 987 cache_holder);
1036 // Perform a lookup behind the interceptor. Copy the LookupIterator since 988 // Perform a lookup behind the interceptor. Copy the LookupIterator since
1037 // the original iterator will be used to fetch the value. 989 // the original iterator will be used to fetch the value.
1038 LookupIterator it(lookup); 990 LookupIterator it(lookup);
1039 it.Next(); 991 it.Next();
1040 LookupForRead(&it); 992 LookupForRead(&it);
1041 return compiler.CompileLoadInterceptor(&it, name); 993 return compiler.CompileLoadInterceptor(&it, name);
1042 } 994 }
1043 DCHECK(lookup->state() == LookupIterator::PROPERTY);
1044 995
1045 // -------------- Accessors -------------- 996 // -------------- Accessors --------------
997 DCHECK(lookup->state() == LookupIterator::PROPERTY);
1046 if (lookup->property_kind() == LookupIterator::ACCESSOR) { 998 if (lookup->property_kind() == LookupIterator::ACCESSOR) {
1047 // Use simple field loads for some well-known callback properties. 999 // Use simple field loads for some well-known callback properties.
1048 if (receiver_is_holder) { 1000 if (receiver_is_holder) {
1049 DCHECK(object->IsJSObject()); 1001 DCHECK(object->IsJSObject());
1050 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1002 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1051 int object_offset; 1003 int object_offset;
1052 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name, 1004 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name,
1053 &object_offset)) { 1005 &object_offset)) {
1054 FieldIndex index = 1006 FieldIndex index =
1055 FieldIndex::ForInObjectOffset(object_offset, receiver->map()); 1007 FieldIndex::ForInObjectOffset(object_offset, receiver->map());
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
1277 Handle<Object> result; 1229 Handle<Object> result;
1278 ASSIGN_RETURN_ON_EXCEPTION( 1230 ASSIGN_RETURN_ON_EXCEPTION(
1279 isolate(), 1231 isolate(),
1280 result, 1232 result,
1281 Runtime::GetObjectProperty(isolate(), object, key), 1233 Runtime::GetObjectProperty(isolate(), object, key),
1282 Object); 1234 Object);
1283 return result; 1235 return result;
1284 } 1236 }
1285 1237
1286 1238
1287 static bool LookupForWrite(Handle<Object> object, Handle<Name> name, 1239 bool StoreIC::LookupForWrite(Handle<Object> object, Handle<Name> name,
1288 Handle<Object> value, LookupResult* lookup, IC* ic) { 1240 Handle<Object> value, LookupIterator* it,
1241 JSReceiver::StoreFromKeyed store_mode) {
1289 // Disable ICs for non-JSObjects for now. 1242 // Disable ICs for non-JSObjects for now.
1290 if (!object->IsJSObject()) return false; 1243 if (!object->IsJSObject()) return false;
1291 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1244 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1245 DCHECK(!receiver->map()->is_deprecated());
1292 1246
1293 Handle<JSObject> holder = receiver; 1247 for (; it->IsFound(); it->Next()) {
1294 receiver->Lookup(name, lookup); 1248 switch (it->state()) {
1295 if (lookup->IsFound()) { 1249 case LookupIterator::NOT_FOUND:
1296 if (lookup->IsInterceptor() && !HasInterceptorSetter(lookup->holder())) { 1250 case LookupIterator::TRANSITION:
1297 receiver->LookupOwnRealNamedProperty(name, lookup); 1251 UNREACHABLE();
1298 if (!lookup->IsFound()) return false; 1252 case LookupIterator::JSPROXY:
1253 return false;
1254 case LookupIterator::INTERCEPTOR: {
1255 Handle<JSObject> holder = it->GetHolder<JSObject>();
1256 InterceptorInfo* info = holder->GetNamedInterceptor();
1257 if (holder.is_identical_to(receiver)) {
1258 if (!info->setter()->IsUndefined()) return true;
1259 } else if (!info->getter()->IsUndefined() ||
1260 !info->query()->IsUndefined()) {
1261 return false;
1262 }
1263 break;
1264 }
1265 case LookupIterator::ACCESS_CHECK:
1266 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
1267 break;
1268 case LookupIterator::PROPERTY: {
1269 if (!it->HasProperty()) break;
1270 if (it->IsReadOnly()) return false;
1271 if (it->property_kind() == LookupIterator::ACCESSOR) return true;
1272 if (it->GetHolder<JSObject>().is_identical_to(receiver)) {
1273 it->PrepareForDataProperty(value);
1274 // The previous receiver map might just have been deprecated,
1275 // so reload it.
1276 update_receiver_type(receiver);
1277 return true;
1278 } else {
1279 // Receiver != holder.
1280 if (receiver->IsJSGlobalProxy()) {
1281 PrototypeIterator iter(it->isolate(), receiver);
1282 return it->GetHolder<Object>().is_identical_to(
1283 PrototypeIterator::GetCurrent(iter));
1284 }
1285 if (it->property_encoding() == LookupIterator::DICTIONARY) {
1286 // DICTIONARY on the prototype chain -> return false
1287 return false;
1288 }
Toon Verwaest 2014/08/21 15:07:05 You already found a property, so you need to make
Jakob Kummerow 2014/08/21 16:14:53 Done.
1289 }
1290 break;
1291 }
1299 } 1292 }
1300
1301 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
1302 if (lookup->holder() == *receiver) return lookup->CanHoldValue(value);
1303 if (lookup->IsPropertyCallbacks()) return true;
1304 // JSGlobalProxy either stores on the global object in the prototype, or
1305 // goes into the runtime if access checks are needed, so this is always
1306 // safe.
1307 if (receiver->IsJSGlobalProxy()) {
1308 PrototypeIterator iter(lookup->isolate(), receiver);
1309 return lookup->holder() == *PrototypeIterator::GetCurrent(iter);
1310 }
1311 // Currently normal holders in the prototype chain are not supported. They
1312 // would require a runtime positive lookup and verification that the details
1313 // have not changed.
1314 if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
1315 holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
1316 } 1293 }
1317 1294
1318 // While normally LookupTransition gets passed the receiver, in this case we 1295 it->PrepareTransitionToDataProperty(value, NONE, store_mode);
1319 // pass the holder of the property that we overwrite. This keeps the holder in 1296 return it->IsCacheableTransition();
1320 // the LookupResult intact so we can later use it to generate a prototype
1321 // chain check. This avoids a double lookup, but requires us to pass in the
1322 // receiver when trying to fetch extra information from the transition.
1323 receiver->map()->LookupTransition(*holder, *name, lookup);
1324 if (!lookup->IsTransition() || lookup->IsReadOnly()) return false;
1325
1326 // If the value that's being stored does not fit in the field that the
1327 // instance would transition to, create a new transition that fits the value.
1328 // This has to be done before generating the IC, since that IC will embed the
1329 // transition target.
1330 // Ensure the instance and its map were migrated before trying to update the
1331 // transition target.
1332 DCHECK(!receiver->map()->is_deprecated());
1333 if (!lookup->CanHoldValue(value)) {
1334 Handle<Map> target(lookup->GetTransitionTarget());
1335 Representation field_representation = value->OptimalRepresentation();
1336 Handle<HeapType> field_type = value->OptimalType(
1337 lookup->isolate(), field_representation);
1338 Map::GeneralizeRepresentation(
1339 target, target->LastAdded(),
1340 field_representation, field_type, FORCE_FIELD);
1341 // Lookup the transition again since the transition tree may have changed
1342 // entirely by the migration above.
1343 receiver->map()->LookupTransition(*holder, *name, lookup);
1344 if (!lookup->IsTransition()) return false;
1345 if (!ic->IsNameCompatibleWithPrototypeFailure(name)) return false;
1346 ic->MarkPrototypeFailure(name);
1347 return true;
1348 }
1349
1350 return true;
1351 } 1297 }
1352 1298
1353 1299
1354 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, 1300 MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
1355 Handle<Name> name, 1301 Handle<Name> name,
1356 Handle<Object> value, 1302 Handle<Object> value,
1357 JSReceiver::StoreFromKeyed store_mode) { 1303 JSReceiver::StoreFromKeyed store_mode) {
1358 // TODO(verwaest): Let SetProperty do the migration, since storing a property 1304 // TODO(verwaest): Let SetProperty do the migration, since storing a property
1359 // might deprecate the current map again, if value does not fit. 1305 // might deprecate the current map again, if value does not fit.
1360 if (MigrateDeprecated(object) || object->IsJSProxy()) { 1306 if (MigrateDeprecated(object) || object->IsJSProxy()) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1392 if (object->IsHeapObject() && 1338 if (object->IsHeapObject() &&
1393 Handle<HeapObject>::cast(object)->map()->is_observed()) { 1339 Handle<HeapObject>::cast(object)->map()->is_observed()) {
1394 Handle<Object> result; 1340 Handle<Object> result;
1395 ASSIGN_RETURN_ON_EXCEPTION( 1341 ASSIGN_RETURN_ON_EXCEPTION(
1396 isolate(), result, 1342 isolate(), result,
1397 Object::SetProperty(object, name, value, strict_mode(), store_mode), 1343 Object::SetProperty(object, name, value, strict_mode(), store_mode),
1398 Object); 1344 Object);
1399 return result; 1345 return result;
1400 } 1346 }
1401 1347
1402 LookupResult lookup(isolate()); 1348 // LookupResult lookup(isolate());
Toon Verwaest 2014/08/21 15:07:05 Remove leftover
Jakob Kummerow 2014/08/21 16:14:53 Done.
1403 bool can_store = LookupForWrite(object, name, value, &lookup, this); 1349 LookupIterator lookup(object, name);
1404 if (!can_store && 1350 bool can_store = LookupForWrite(object, name, value, &lookup, store_mode);
1405 strict_mode() == STRICT && 1351 if (!can_store && strict_mode() == STRICT && object->IsGlobalObject() &&
Toon Verwaest 2014/08/21 15:07:05 This shouldn't depend on "can_store". Before the r
Jakob Kummerow 2014/08/21 16:14:53 It does, actually, because we're interested in non
1406 !(lookup.IsProperty() && lookup.IsReadOnly()) && 1352 !(lookup.state() == LookupIterator::PROPERTY && lookup.has_property() &&
Toon Verwaest 2014/08/21 15:07:06 You shouldn't need to expose has_property(). Any i
Jakob Kummerow 2014/08/21 16:14:53 Done.
1407 object->IsGlobalObject()) { 1353 lookup.IsReadOnly())) {
1408 // Strict mode doesn't allow setting non-existent global property. 1354 // Strict mode doesn't allow setting non-existent global property.
1409 return ReferenceError("not_defined", name); 1355 return ReferenceError("not_defined", name);
1410 } 1356 }
1357
1411 if (FLAG_use_ic) { 1358 if (FLAG_use_ic) {
1412 if (state() == UNINITIALIZED) { 1359 if (state() == UNINITIALIZED) {
1413 Handle<Code> stub = pre_monomorphic_stub(); 1360 Handle<Code> stub = pre_monomorphic_stub();
1414 set_target(*stub); 1361 set_target(*stub);
1415 TRACE_IC("StoreIC", name); 1362 TRACE_IC("StoreIC", name);
1416 } else if (can_store) { 1363 } else if (can_store) {
1417 UpdateCaches(&lookup, Handle<JSObject>::cast(object), name, value); 1364 UpdateCaches(&lookup, Handle<JSObject>::cast(object), name, value);
1418 } else if (lookup.IsNormal() || 1365 } else {
1419 (lookup.IsField() && lookup.CanHoldValue(value))) { 1366 PatchCache(name, slow_stub());
1420 Handle<Code> stub = generic_stub(); 1367 TRACE_IC("StoreIC", name);
1421 set_target(*stub);
1422 } 1368 }
1423 } 1369 }
1424 1370
1425 // Set the property. 1371 // Set the property.
1426 Handle<Object> result; 1372 Handle<Object> result;
1427 ASSIGN_RETURN_ON_EXCEPTION( 1373 ASSIGN_RETURN_ON_EXCEPTION(
1428 isolate(), result, 1374 isolate(), result,
1429 Object::SetProperty(object, name, value, strict_mode(), store_mode), 1375 Object::SetProperty(&lookup, value, strict_mode(), store_mode), Object);
1430 Object);
1431 return result; 1376 return result;
1432 } 1377 }
1433 1378
1434 1379
1435 OStream& operator<<(OStream& os, const CallIC::State& s) { 1380 OStream& operator<<(OStream& os, const CallIC::State& s) {
1436 return os << "(args(" << s.arg_count() << "), " 1381 return os << "(args(" << s.arg_count() << "), "
1437 << (s.call_type() == CallIC::METHOD ? "METHOD" : "FUNCTION") 1382 << (s.call_type() == CallIC::METHOD ? "METHOD" : "FUNCTION")
1438 << ", "; 1383 << ", ";
1439 } 1384 }
1440 1385
(...skipping 27 matching lines...) Expand all
1468 } 1413 }
1469 1414
1470 1415
1471 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate, 1416 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
1472 StrictMode strict_mode) { 1417 StrictMode strict_mode) {
1473 ExtraICState state = ComputeExtraICState(strict_mode); 1418 ExtraICState state = ComputeExtraICState(strict_mode);
1474 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state); 1419 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state);
1475 } 1420 }
1476 1421
1477 1422
1478 void StoreIC::UpdateCaches(LookupResult* lookup, 1423 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<JSObject> receiver,
1479 Handle<JSObject> receiver, 1424 Handle<Name> name, Handle<Object> value) {
1480 Handle<Name> name, 1425 // These are not cacheable, so we never see such LookupResults here.
1481 Handle<Object> value) { 1426 DCHECK(lookup->state() != LookupIterator::JSPROXY);
Toon Verwaest 2014/08/21 15:07:06 DCHECK_NE
Jakob Kummerow 2014/08/21 16:14:53 Done.
1482 DCHECK(lookup->IsFound());
1483 1427
1484 // These are not cacheable, so we never see such LookupResults here. 1428 Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
1485 DCHECK(!lookup->IsHandler());
1486
1487 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value);
1488 1429
1489 PatchCache(name, code); 1430 PatchCache(name, code);
1490 TRACE_IC("StoreIC", name); 1431 TRACE_IC("StoreIC", name);
1491 } 1432 }
1492 1433
1493 1434
1494 Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup, 1435 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
1495 Handle<Object> object, 1436 Handle<Object> object, Handle<Name> name,
1496 Handle<Name> name, 1437 Handle<Object> value,
1497 Handle<Object> value, 1438 CacheHolderFlag cache_holder) {
1498 CacheHolderFlag cache_holder) { 1439 DCHECK(!object->IsAccessCheckNeeded());
1499 if (object->IsAccessCheckNeeded()) return slow_stub();
1500 DCHECK(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
1501 (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject()));
1502 // This is currently guaranteed by checks in StoreIC::Store. 1440 // This is currently guaranteed by checks in StoreIC::Store.
1503 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1441 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1442 Handle<JSObject> holder(lookup->GetHolder<JSObject>());
1504 1443
1505 Handle<JSObject> holder(lookup->holder()); 1444 // -------------- Transition --------------
1445 if (lookup->state() == LookupIterator::TRANSITION) {
1446 Handle<Map> transition = lookup->transition_map();
1506 1447
1507 if (lookup->IsTransition()) { 1448 DCHECK(lookup->IsCacheableTransition());
1508 // Explicitly pass in the receiver map since LookupForWrite may have 1449 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1509 // stored something else than the receiver in the holder. 1450 return compiler.CompileStoreTransition(transition, name);
1510 Handle<Map> transition(lookup->GetTransitionTarget()); 1451 }
1511 PropertyDetails details = lookup->GetPropertyDetails();
1512 1452
1513 if (details.type() != CALLBACKS && details.attributes() == NONE && 1453 // -------------- Interceptors --------------
1514 holder->HasFastProperties()) { 1454 if (lookup->state() == LookupIterator::INTERCEPTOR) {
1455 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
1456 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1457 return compiler.CompileStoreInterceptor(name);
1458 }
1459
1460 // -------------- Accessors --------------
1461 DCHECK(lookup->state() == LookupIterator::PROPERTY);
1462 if (lookup->property_kind() == LookupIterator::ACCESSOR) {
1463 if (!holder->HasFastProperties()) return slow_stub();
1464 Handle<Object> accessors = lookup->GetAccessors();
1465 if (accessors->IsExecutableAccessorInfo()) {
1466 Handle<ExecutableAccessorInfo> info =
1467 Handle<ExecutableAccessorInfo>::cast(accessors);
1468 if (v8::ToCData<Address>(info->setter()) == 0) return slow_stub();
1469 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
1470 receiver_type())) {
1471 return slow_stub();
1472 }
1515 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); 1473 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1516 return compiler.CompileStoreTransition(transition, name); 1474 return compiler.CompileStoreCallback(receiver, name, info);
1475 } else if (accessors->IsAccessorPair()) {
1476 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
1477 isolate());
1478 if (!setter->IsJSFunction()) return slow_stub();
1479 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1480 CallOptimization call_optimization(function);
1481 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1482 if (call_optimization.is_simple_api_call() &&
1483 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1484 return compiler.CompileStoreCallback(receiver, name, call_optimization);
1485 }
1486 return compiler.CompileStoreViaSetter(receiver, name,
1487 Handle<JSFunction>::cast(setter));
1517 } 1488 }
1518 } else { 1489 // TODO(dcarney): Handle correctly.
1519 switch (lookup->type()) { 1490 DCHECK(accessors->IsDeclaredAccessorInfo());
1520 case FIELD: { 1491 return slow_stub();
1521 bool use_stub = true; 1492 }
1522 if (lookup->representation().IsHeapObject()) { 1493
1523 // Only use a generic stub if no types need to be tracked. 1494 // -------------- Dictionary properties --------------
1524 HeapType* field_type = lookup->GetFieldType(); 1495 DCHECK(lookup->property_kind() == LookupIterator::DATA);
1525 HeapType::Iterator<Map> it = field_type->Classes(); 1496 if (lookup->property_encoding() == LookupIterator::DICTIONARY) {
1526 use_stub = it.Done(); 1497 if (holder->IsGlobalObject()) {
1527 } 1498 Handle<PropertyCell> cell = lookup->GetPropertyCell();
1528 if (use_stub) { 1499 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
1529 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), 1500 StoreGlobalStub stub(isolate(), union_type->IsConstant(),
1530 lookup->representation()); 1501 receiver->IsJSGlobalProxy());
1531 return stub.GetCode(); 1502 Handle<Code> code = stub.GetCodeCopyFromTemplate(
1532 } 1503 Handle<GlobalObject>::cast(holder), cell);
1533 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); 1504 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1534 return compiler.CompileStoreField(lookup, name); 1505 HeapObject::UpdateMapCodeCache(receiver, name, code);
1535 } 1506 return code;
1536 case NORMAL:
1537 if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {
1538 // The stub generated for the global object picks the value directly
1539 // from the property cell. So the property must be directly on the
1540 // global object.
1541 PrototypeIterator iter(isolate(), receiver);
1542 Handle<GlobalObject> global =
1543 receiver->IsJSGlobalProxy()
1544 ? Handle<GlobalObject>::cast(
1545 PrototypeIterator::GetCurrent(iter))
1546 : Handle<GlobalObject>::cast(receiver);
1547 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
1548 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
1549 StoreGlobalStub stub(
1550 isolate(), union_type->IsConstant(), receiver->IsJSGlobalProxy());
1551 Handle<Code> code = stub.GetCodeCopyFromTemplate(global, cell);
1552 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1553 HeapObject::UpdateMapCodeCache(receiver, name, code);
1554 return code;
1555 }
1556 DCHECK(holder.is_identical_to(receiver));
1557 return isolate()->builtins()->StoreIC_Normal();
1558 case CALLBACKS: {
1559 if (!holder->HasFastProperties()) break;
1560 Handle<Object> callback(lookup->GetValueFromMap(holder->map()),
1561 isolate());
1562 if (callback->IsExecutableAccessorInfo()) {
1563 Handle<ExecutableAccessorInfo> info =
1564 Handle<ExecutableAccessorInfo>::cast(callback);
1565 if (v8::ToCData<Address>(info->setter()) == 0) break;
1566 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(
1567 isolate(), info, receiver_type())) {
1568 break;
1569 }
1570 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
1571 holder);
1572 return compiler.CompileStoreCallback(receiver, name, info);
1573 } else if (callback->IsAccessorPair()) {
1574 Handle<Object> setter(
1575 Handle<AccessorPair>::cast(callback)->setter(), isolate());
1576 if (!setter->IsJSFunction()) break;
1577 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1578 CallOptimization call_optimization(function);
1579 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
1580 holder);
1581 if (call_optimization.is_simple_api_call() &&
1582 call_optimization.IsCompatibleReceiver(receiver, holder)) {
1583 return compiler.CompileStoreCallback(receiver, name,
1584 call_optimization);
1585 }
1586 return compiler.CompileStoreViaSetter(
1587 receiver, name, Handle<JSFunction>::cast(setter));
1588 }
1589 // TODO(dcarney): Handle correctly.
1590 DCHECK(callback->IsDeclaredAccessorInfo());
1591 break;
1592 }
1593 case INTERCEPTOR: {
1594 DCHECK(HasInterceptorSetter(*holder));
1595 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1596 return compiler.CompileStoreInterceptor(name);
1597 }
1598 case CONSTANT:
1599 break;
1600 case HANDLER:
1601 UNREACHABLE();
1602 break;
1603 } 1507 }
1508 DCHECK(holder.is_identical_to(receiver));
1509 return isolate()->builtins()->StoreIC_Normal();
1604 } 1510 }
1511
1512 // -------------- Fields --------------
1513 DCHECK(lookup->property_encoding() == LookupIterator::DESCRIPTOR);
1514 if (lookup->property_details().type() == FIELD) {
1515 bool use_stub = true;
1516 if (lookup->representation().IsHeapObject()) {
1517 // Only use a generic stub if no types need to be tracked.
1518 Handle<HeapType> field_type = lookup->GetFieldType();
1519 HeapType::Iterator<Map> it = field_type->Classes();
1520 use_stub = it.Done();
1521 }
1522 if (use_stub) {
1523 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
1524 lookup->representation());
1525 return stub.GetCode();
1526 }
1527 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
1528 return compiler.CompileStoreField(lookup, name);
1529 }
1530
1531 // -------------- Constant properties --------------
1532 DCHECK(lookup->property_details().type() == CONSTANT);
1605 return slow_stub(); 1533 return slow_stub();
1606 } 1534 }
1607 1535
1608 1536
1609 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, 1537 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
1610 KeyedAccessStoreMode store_mode) { 1538 KeyedAccessStoreMode store_mode) {
1611 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS 1539 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1612 // via megamorphic stubs, since they don't have a map in their relocation info 1540 // via megamorphic stubs, since they don't have a map in their relocation info
1613 // and so the stubs can't be harvested for the object needed for a map check. 1541 // and so the stubs can't be harvested for the object needed for a map check.
1614 if (target()->type() != Code::NORMAL) { 1542 if (target()->type() != Code::NORMAL) {
(...skipping 1557 matching lines...) Expand 10 before | Expand all | Expand 10 after
3172 #undef ADDR 3100 #undef ADDR
3173 }; 3101 };
3174 3102
3175 3103
3176 Address IC::AddressFromUtilityId(IC::UtilityId id) { 3104 Address IC::AddressFromUtilityId(IC::UtilityId id) {
3177 return IC_utilities[id]; 3105 return IC_utilities[id];
3178 } 3106 }
3179 3107
3180 3108
3181 } } // namespace v8::internal 3109 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/lookup.h » ('j') | src/lookup.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698