Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |