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/base/bits.h" | 10 #include "src/base/bits.h" |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 DCHECK(original_code->IsCode()); | 208 DCHECK(original_code->IsCode()); |
209 return original_code; | 209 return original_code; |
210 } | 210 } |
211 | 211 |
212 | 212 |
213 static void LookupForRead(LookupIterator* it) { | 213 static void LookupForRead(LookupIterator* it) { |
214 for (; it->IsFound(); it->Next()) { | 214 for (; it->IsFound(); it->Next()) { |
215 switch (it->state()) { | 215 switch (it->state()) { |
216 case LookupIterator::NOT_FOUND: | 216 case LookupIterator::NOT_FOUND: |
217 case LookupIterator::TRANSITION: | 217 case LookupIterator::TRANSITION: |
| 218 case LookupIterator::UNKNOWN: |
218 UNREACHABLE(); | 219 UNREACHABLE(); |
219 case LookupIterator::JSPROXY: | 220 case LookupIterator::JSPROXY: |
220 return; | 221 return; |
221 case LookupIterator::INTERCEPTOR: { | 222 case LookupIterator::INTERCEPTOR: { |
222 // If there is a getter, return; otherwise loop to perform the lookup. | 223 // If there is a getter, return; otherwise loop to perform the lookup. |
223 Handle<JSObject> holder = it->GetHolder<JSObject>(); | 224 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
224 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) { | 225 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) { |
225 return; | 226 return; |
226 } | 227 } |
227 break; | 228 break; |
228 } | 229 } |
229 case LookupIterator::ACCESS_CHECK: | 230 case LookupIterator::ACCESS_CHECK: |
230 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit | 231 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit |
231 // access checks for global proxies. | 232 // access checks for global proxies. |
232 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && | 233 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && |
233 it->HasAccess(v8::ACCESS_GET)) { | 234 it->HasAccess(v8::ACCESS_GET)) { |
234 break; | 235 break; |
235 } | 236 } |
236 return; | 237 return; |
237 case LookupIterator::PROPERTY: | 238 case LookupIterator::ACCESSOR: |
238 if (it->HasProperty()) return; // Yay! | 239 case LookupIterator::DATA: |
239 break; | 240 return; |
240 } | 241 } |
241 } | 242 } |
242 } | 243 } |
243 | 244 |
244 | 245 |
245 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, | 246 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, |
246 Handle<String> name) { | 247 Handle<String> name) { |
247 if (!IsNameCompatibleWithPrototypeFailure(name)) return false; | 248 if (!IsNameCompatibleWithPrototypeFailure(name)) return false; |
248 Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate()); | 249 Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate()); |
249 maybe_handler_ = target()->FindHandlerForMap(*receiver_map); | 250 maybe_handler_ = target()->FindHandlerForMap(*receiver_map); |
(...skipping 28 matching lines...) Expand all Loading... |
278 int index = ic_holder_map->IndexInCodeCache(*name, *target()); | 279 int index = ic_holder_map->IndexInCodeCache(*name, *target()); |
279 if (index >= 0) { | 280 if (index >= 0) { |
280 ic_holder_map->RemoveFromCodeCache(*name, *target(), index); | 281 ic_holder_map->RemoveFromCodeCache(*name, *target(), index); |
281 } | 282 } |
282 } | 283 } |
283 | 284 |
284 if (receiver->IsGlobalObject()) { | 285 if (receiver->IsGlobalObject()) { |
285 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 286 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
286 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR); | 287 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR); |
287 if (it.state() == LookupIterator::ACCESS_CHECK) return false; | 288 if (it.state() == LookupIterator::ACCESS_CHECK) return false; |
288 if (!it.IsFound() || !it.HasProperty()) return false; | 289 if (!it.IsFound()) return false; |
289 Handle<PropertyCell> cell = it.GetPropertyCell(); | 290 Handle<PropertyCell> cell = it.GetPropertyCell(); |
290 return cell->type()->IsConstant(); | 291 return cell->type()->IsConstant(); |
291 } | 292 } |
292 | 293 |
293 return true; | 294 return true; |
294 } | 295 } |
295 | 296 |
296 | 297 |
297 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) { | 298 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) { |
298 if (target()->is_keyed_stub()) { | 299 if (target()->is_keyed_stub()) { |
(...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 cache_holder); | 970 cache_holder); |
970 // Perform a lookup behind the interceptor. Copy the LookupIterator since | 971 // Perform a lookup behind the interceptor. Copy the LookupIterator since |
971 // the original iterator will be used to fetch the value. | 972 // the original iterator will be used to fetch the value. |
972 LookupIterator it = *lookup; | 973 LookupIterator it = *lookup; |
973 it.Next(); | 974 it.Next(); |
974 LookupForRead(&it); | 975 LookupForRead(&it); |
975 return compiler.CompileLoadInterceptor(&it); | 976 return compiler.CompileLoadInterceptor(&it); |
976 } | 977 } |
977 | 978 |
978 // -------------- Accessors -------------- | 979 // -------------- Accessors -------------- |
979 DCHECK(lookup->state() == LookupIterator::PROPERTY); | 980 if (lookup->state() == LookupIterator::ACCESSOR) { |
980 if (lookup->property_kind() == LookupIterator::ACCESSOR) { | |
981 // Use simple field loads for some well-known callback properties. | 981 // Use simple field loads for some well-known callback properties. |
982 if (receiver_is_holder) { | 982 if (receiver_is_holder) { |
983 DCHECK(receiver->IsJSObject()); | 983 DCHECK(receiver->IsJSObject()); |
984 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); | 984 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); |
985 int object_offset; | 985 int object_offset; |
986 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(), | 986 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(), |
987 &object_offset)) { | 987 &object_offset)) { |
988 FieldIndex index = | 988 FieldIndex index = |
989 FieldIndex::ForInObjectOffset(object_offset, js_receiver->map()); | 989 FieldIndex::ForInObjectOffset(object_offset, js_receiver->map()); |
990 return SimpleFieldLoad(index); | 990 return SimpleFieldLoad(index); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 return compiler.CompileLoadCallback(lookup->name(), call_optimization); | 1025 return compiler.CompileLoadCallback(lookup->name(), call_optimization); |
1026 } | 1026 } |
1027 return compiler.CompileLoadViaGetter(lookup->name(), function); | 1027 return compiler.CompileLoadViaGetter(lookup->name(), function); |
1028 } | 1028 } |
1029 // TODO(dcarney): Handle correctly. | 1029 // TODO(dcarney): Handle correctly. |
1030 DCHECK(accessors->IsDeclaredAccessorInfo()); | 1030 DCHECK(accessors->IsDeclaredAccessorInfo()); |
1031 return slow_stub(); | 1031 return slow_stub(); |
1032 } | 1032 } |
1033 | 1033 |
1034 // -------------- Dictionary properties -------------- | 1034 // -------------- Dictionary properties -------------- |
1035 DCHECK(lookup->property_kind() == LookupIterator::DATA); | 1035 DCHECK(lookup->state() == LookupIterator::DATA); |
1036 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { | 1036 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { |
1037 if (kind() != Code::LOAD_IC) return slow_stub(); | 1037 if (kind() != Code::LOAD_IC) return slow_stub(); |
1038 if (holder->IsGlobalObject()) { | 1038 if (holder->IsGlobalObject()) { |
1039 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 1039 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
1040 cache_holder); | 1040 cache_holder); |
1041 Handle<PropertyCell> cell = lookup->GetPropertyCell(); | 1041 Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
1042 Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(), | 1042 Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(), |
1043 lookup->IsConfigurable()); | 1043 lookup->IsConfigurable()); |
1044 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1044 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
1045 CacheHolderFlag flag; | 1045 CacheHolderFlag flag; |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1216 JSReceiver::StoreFromKeyed store_mode) { | 1216 JSReceiver::StoreFromKeyed store_mode) { |
1217 // Disable ICs for non-JSObjects for now. | 1217 // Disable ICs for non-JSObjects for now. |
1218 Handle<Object> receiver = it->GetReceiver(); | 1218 Handle<Object> receiver = it->GetReceiver(); |
1219 if (!receiver->IsJSObject()) return false; | 1219 if (!receiver->IsJSObject()) return false; |
1220 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated()); | 1220 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated()); |
1221 | 1221 |
1222 for (; it->IsFound(); it->Next()) { | 1222 for (; it->IsFound(); it->Next()) { |
1223 switch (it->state()) { | 1223 switch (it->state()) { |
1224 case LookupIterator::NOT_FOUND: | 1224 case LookupIterator::NOT_FOUND: |
1225 case LookupIterator::TRANSITION: | 1225 case LookupIterator::TRANSITION: |
| 1226 case LookupIterator::UNKNOWN: |
1226 UNREACHABLE(); | 1227 UNREACHABLE(); |
1227 case LookupIterator::JSPROXY: | 1228 case LookupIterator::JSPROXY: |
1228 return false; | 1229 return false; |
1229 case LookupIterator::INTERCEPTOR: { | 1230 case LookupIterator::INTERCEPTOR: { |
1230 Handle<JSObject> holder = it->GetHolder<JSObject>(); | 1231 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
1231 InterceptorInfo* info = holder->GetNamedInterceptor(); | 1232 InterceptorInfo* info = holder->GetNamedInterceptor(); |
1232 if (it->HolderIsReceiverOrHiddenPrototype()) { | 1233 if (it->HolderIsReceiverOrHiddenPrototype()) { |
1233 if (!info->setter()->IsUndefined()) return true; | 1234 if (!info->setter()->IsUndefined()) return true; |
1234 } else if (!info->getter()->IsUndefined() || | 1235 } else if (!info->getter()->IsUndefined() || |
1235 !info->query()->IsUndefined()) { | 1236 !info->query()->IsUndefined()) { |
1236 return false; | 1237 return false; |
1237 } | 1238 } |
1238 break; | 1239 break; |
1239 } | 1240 } |
1240 case LookupIterator::ACCESS_CHECK: | 1241 case LookupIterator::ACCESS_CHECK: |
1241 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false; | 1242 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false; |
1242 break; | 1243 break; |
1243 case LookupIterator::PROPERTY: | 1244 case LookupIterator::ACCESSOR: |
1244 if (!it->HasProperty()) break; | 1245 return !it->IsReadOnly(); |
| 1246 case LookupIterator::DATA: { |
1245 if (it->IsReadOnly()) return false; | 1247 if (it->IsReadOnly()) return false; |
1246 if (it->property_kind() == LookupIterator::ACCESSOR) return true; | 1248 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
1247 if (it->GetHolder<Object>().is_identical_to(receiver)) { | 1249 if (receiver.is_identical_to(holder)) { |
1248 it->PrepareForDataProperty(value); | 1250 it->PrepareForDataProperty(value); |
1249 // The previous receiver map might just have been deprecated, | 1251 // The previous receiver map might just have been deprecated, |
1250 // so reload it. | 1252 // so reload it. |
1251 update_receiver_type(receiver); | 1253 update_receiver_type(receiver); |
1252 return true; | 1254 return true; |
1253 } | 1255 } |
1254 | 1256 |
1255 // Receiver != holder. | 1257 // Receiver != holder. |
| 1258 PrototypeIterator iter(it->isolate(), receiver); |
1256 if (receiver->IsJSGlobalProxy()) { | 1259 if (receiver->IsJSGlobalProxy()) { |
1257 PrototypeIterator iter(it->isolate(), receiver); | |
1258 return it->GetHolder<Object>().is_identical_to( | 1260 return it->GetHolder<Object>().is_identical_to( |
1259 PrototypeIterator::GetCurrent(iter)); | 1261 PrototypeIterator::GetCurrent(iter)); |
1260 } | 1262 } |
1261 | 1263 |
1262 it->PrepareTransitionToDataProperty(value, NONE, store_mode); | 1264 it->PrepareTransitionToDataProperty(value, NONE, store_mode); |
1263 return it->IsCacheableTransition(); | 1265 return it->IsCacheableTransition(); |
| 1266 } |
1264 } | 1267 } |
1265 } | 1268 } |
1266 | 1269 |
1267 it->PrepareTransitionToDataProperty(value, NONE, store_mode); | 1270 it->PrepareTransitionToDataProperty(value, NONE, store_mode); |
1268 return it->IsCacheableTransition(); | 1271 return it->IsCacheableTransition(); |
1269 } | 1272 } |
1270 | 1273 |
1271 | 1274 |
1272 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, | 1275 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, |
1273 Handle<Object> value, | 1276 Handle<Object> value, |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1410 } | 1413 } |
1411 | 1414 |
1412 // -------------- Interceptors -------------- | 1415 // -------------- Interceptors -------------- |
1413 if (lookup->state() == LookupIterator::INTERCEPTOR) { | 1416 if (lookup->state() == LookupIterator::INTERCEPTOR) { |
1414 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); | 1417 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); |
1415 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1418 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
1416 return compiler.CompileStoreInterceptor(lookup->name()); | 1419 return compiler.CompileStoreInterceptor(lookup->name()); |
1417 } | 1420 } |
1418 | 1421 |
1419 // -------------- Accessors -------------- | 1422 // -------------- Accessors -------------- |
1420 DCHECK(lookup->state() == LookupIterator::PROPERTY); | 1423 if (lookup->state() == LookupIterator::ACCESSOR) { |
1421 if (lookup->property_kind() == LookupIterator::ACCESSOR) { | |
1422 if (!holder->HasFastProperties()) return slow_stub(); | 1424 if (!holder->HasFastProperties()) return slow_stub(); |
1423 Handle<Object> accessors = lookup->GetAccessors(); | 1425 Handle<Object> accessors = lookup->GetAccessors(); |
1424 if (accessors->IsExecutableAccessorInfo()) { | 1426 if (accessors->IsExecutableAccessorInfo()) { |
1425 Handle<ExecutableAccessorInfo> info = | 1427 Handle<ExecutableAccessorInfo> info = |
1426 Handle<ExecutableAccessorInfo>::cast(accessors); | 1428 Handle<ExecutableAccessorInfo>::cast(accessors); |
1427 if (v8::ToCData<Address>(info->setter()) == 0) return slow_stub(); | 1429 if (v8::ToCData<Address>(info->setter()) == 0) return slow_stub(); |
1428 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, | 1430 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, |
1429 receiver_type())) { | 1431 receiver_type())) { |
1430 return slow_stub(); | 1432 return slow_stub(); |
1431 } | 1433 } |
(...skipping 13 matching lines...) Expand all Loading... |
1445 } | 1447 } |
1446 return compiler.CompileStoreViaSetter(receiver, lookup->name(), | 1448 return compiler.CompileStoreViaSetter(receiver, lookup->name(), |
1447 Handle<JSFunction>::cast(setter)); | 1449 Handle<JSFunction>::cast(setter)); |
1448 } | 1450 } |
1449 // TODO(dcarney): Handle correctly. | 1451 // TODO(dcarney): Handle correctly. |
1450 DCHECK(accessors->IsDeclaredAccessorInfo()); | 1452 DCHECK(accessors->IsDeclaredAccessorInfo()); |
1451 return slow_stub(); | 1453 return slow_stub(); |
1452 } | 1454 } |
1453 | 1455 |
1454 // -------------- Dictionary properties -------------- | 1456 // -------------- Dictionary properties -------------- |
1455 DCHECK(lookup->property_kind() == LookupIterator::DATA); | 1457 DCHECK(lookup->state() == LookupIterator::DATA); |
1456 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { | 1458 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { |
1457 if (holder->IsGlobalObject()) { | 1459 if (holder->IsGlobalObject()) { |
1458 Handle<PropertyCell> cell = lookup->GetPropertyCell(); | 1460 Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
1459 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); | 1461 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); |
1460 StoreGlobalStub stub(isolate(), union_type->IsConstant(), | 1462 StoreGlobalStub stub(isolate(), union_type->IsConstant(), |
1461 receiver->IsJSGlobalProxy()); | 1463 receiver->IsJSGlobalProxy()); |
1462 Handle<Code> code = stub.GetCodeCopyFromTemplate( | 1464 Handle<Code> code = stub.GetCodeCopyFromTemplate( |
1463 Handle<GlobalObject>::cast(holder), cell); | 1465 Handle<GlobalObject>::cast(holder), cell); |
1464 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1466 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
1465 HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code); | 1467 HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code); |
(...skipping 1733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3199 static const Address IC_utilities[] = { | 3201 static const Address IC_utilities[] = { |
3200 #define ADDR(name) FUNCTION_ADDR(name), | 3202 #define ADDR(name) FUNCTION_ADDR(name), |
3201 IC_UTIL_LIST(ADDR) NULL | 3203 IC_UTIL_LIST(ADDR) NULL |
3202 #undef ADDR | 3204 #undef ADDR |
3203 }; | 3205 }; |
3204 | 3206 |
3205 | 3207 |
3206 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } | 3208 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } |
3207 } | 3209 } |
3208 } // namespace v8::internal | 3210 } // namespace v8::internal |
OLD | NEW |