| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 break; | 1098 break; |
| 1099 case DEBUG_STUB: | 1099 case DEBUG_STUB: |
| 1100 break; | 1100 break; |
| 1101 case GENERIC: | 1101 case GENERIC: |
| 1102 UNREACHABLE(); | 1102 UNREACHABLE(); |
| 1103 break; | 1103 break; |
| 1104 } | 1104 } |
| 1105 } | 1105 } |
| 1106 | 1106 |
| 1107 | 1107 |
| 1108 Handle<Code> LoadIC::SimpleFieldLoad(int offset, |
| 1109 bool inobject, |
| 1110 Representation representation) { |
| 1111 if (kind() == Code::LOAD_IC) { |
| 1112 LoadFieldStub stub(inobject, offset, representation); |
| 1113 return stub.GetCode(isolate()); |
| 1114 } else { |
| 1115 KeyedLoadFieldStub stub(inobject, offset, representation); |
| 1116 return stub.GetCode(isolate()); |
| 1117 } |
| 1118 } |
| 1119 |
| 1108 void LoadIC::UpdateCaches(LookupResult* lookup, | 1120 void LoadIC::UpdateCaches(LookupResult* lookup, |
| 1109 Handle<Object> object, | 1121 Handle<Object> object, |
| 1110 Handle<String> name) { | 1122 Handle<String> name) { |
| 1111 // TODO(verwaest): It would be nice to support loading fields from smis as | 1123 // TODO(verwaest): It would be nice to support loading fields from smis as |
| 1112 // well. For now just fail to update the cache. | 1124 // well. For now just fail to update the cache. |
| 1113 if (!object->IsHeapObject()) return; | 1125 if (!object->IsHeapObject()) return; |
| 1114 | 1126 |
| 1115 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); | 1127 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); |
| 1116 | 1128 |
| 1117 Handle<Code> code; | 1129 Handle<Code> code; |
| 1118 if (state() == UNINITIALIZED) { | 1130 if (state() == UNINITIALIZED) { |
| 1119 // This is the first time we execute this inline cache. | 1131 // This is the first time we execute this inline cache. |
| 1120 // Set the target to the pre monomorphic stub to delay | 1132 // Set the target to the pre monomorphic stub to delay |
| 1121 // setting the monomorphic state. | 1133 // setting the monomorphic state. |
| 1122 code = pre_monomorphic_stub(); | 1134 code = pre_monomorphic_stub(); |
| 1123 } else if (!lookup->IsCacheable()) { | 1135 } else if (!lookup->IsCacheable()) { |
| 1124 // Bail out if the result is not cacheable. | 1136 // Bail out if the result is not cacheable. |
| 1125 code = slow_stub(); | 1137 code = slow_stub(); |
| 1126 } else if (object->IsString() && | 1138 } else if (object->IsString() && |
| 1127 name->Equals(isolate()->heap()->length_string())) { | 1139 name->Equals(isolate()->heap()->length_string())) { |
| 1128 int length_index = String::kLengthOffset / kPointerSize; | 1140 int length_index = String::kLengthOffset / kPointerSize; |
| 1129 if (target()->is_load_stub()) { | 1141 code = SimpleFieldLoad(length_index); |
| 1130 LoadFieldStub stub(true, length_index, Representation::Tagged()); | |
| 1131 code = stub.GetCode(isolate()); | |
| 1132 } else { | |
| 1133 KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); | |
| 1134 code = stub.GetCode(isolate()); | |
| 1135 } | |
| 1136 } else if (!object->IsJSObject()) { | 1142 } else if (!object->IsJSObject()) { |
| 1137 // TODO(jkummerow): It would be nice to support non-JSObjects in | 1143 // TODO(jkummerow): It would be nice to support non-JSObjects in |
| 1138 // ComputeLoadHandler, then we wouldn't need to go generic here. | 1144 // ComputeLoadHandler, then we wouldn't need to go generic here. |
| 1139 code = slow_stub(); | 1145 code = slow_stub(); |
| 1140 } else if (!lookup->IsProperty()) { | 1146 } else if (!lookup->IsProperty()) { |
| 1141 code = kind() == Code::LOAD_IC | 1147 code = kind() == Code::LOAD_IC |
| 1142 ? isolate()->stub_cache()->ComputeLoadNonexistent( | 1148 ? isolate()->stub_cache()->ComputeLoadNonexistent( |
| 1143 name, Handle<JSObject>::cast(receiver)) | 1149 name, Handle<JSObject>::cast(receiver)) |
| 1144 : slow_stub(); | 1150 : slow_stub(); |
| 1145 } else { | 1151 } else { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1160 | 1166 |
| 1161 Handle<Code> IC::ComputeHandler(LookupResult* lookup, | 1167 Handle<Code> IC::ComputeHandler(LookupResult* lookup, |
| 1162 Handle<JSObject> receiver, | 1168 Handle<JSObject> receiver, |
| 1163 Handle<String> name, | 1169 Handle<String> name, |
| 1164 Handle<Object> value) { | 1170 Handle<Object> value) { |
| 1165 Handle<Code> code = isolate()->stub_cache()->FindHandler( | 1171 Handle<Code> code = isolate()->stub_cache()->FindHandler( |
| 1166 name, receiver, kind()); | 1172 name, receiver, kind()); |
| 1167 if (!code.is_null()) return code; | 1173 if (!code.is_null()) return code; |
| 1168 | 1174 |
| 1169 code = CompileHandler(lookup, receiver, name, value); | 1175 code = CompileHandler(lookup, receiver, name, value); |
| 1170 if (code.is_null()) return slow_stub(); | |
| 1171 | 1176 |
| 1172 if (code->is_handler() && code->type() != Code::NORMAL) { | 1177 if (code->is_handler() && code->type() != Code::NORMAL) { |
| 1173 HeapObject::UpdateMapCodeCache(receiver, name, code); | 1178 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1174 } | 1179 } |
| 1175 | 1180 |
| 1176 return code; | 1181 return code; |
| 1177 } | 1182 } |
| 1178 | 1183 |
| 1179 | 1184 |
| 1180 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, | 1185 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
| 1181 Handle<JSObject> receiver, | 1186 Handle<JSObject> receiver, |
| 1182 Handle<String> name, | 1187 Handle<String> name, |
| 1183 Handle<Object> unused) { | 1188 Handle<Object> unused) { |
| 1184 Handle<JSObject> holder(lookup->holder()); | 1189 Handle<JSObject> holder(lookup->holder()); |
| 1190 LoadStubCompiler compiler(isolate(), kind()); |
| 1191 |
| 1185 switch (lookup->type()) { | 1192 switch (lookup->type()) { |
| 1186 case FIELD: | 1193 case FIELD: { |
| 1187 return isolate()->stub_cache()->ComputeLoadField( | 1194 PropertyIndex field = lookup->GetFieldIndex(); |
| 1188 name, receiver, holder, | 1195 if (receiver.is_identical_to(holder)) { |
| 1189 lookup->GetFieldIndex(), lookup->representation()); | 1196 return SimpleFieldLoad(field.translate(holder), |
| 1197 field.is_inobject(holder), |
| 1198 lookup->representation()); |
| 1199 } |
| 1200 return compiler.CompileLoadField( |
| 1201 receiver, holder, name, field, lookup->representation()); |
| 1202 } |
| 1190 case CONSTANT: { | 1203 case CONSTANT: { |
| 1191 Handle<Object> constant(lookup->GetConstant(), isolate()); | 1204 Handle<Object> constant(lookup->GetConstant(), isolate()); |
| 1192 // TODO(2803): Don't compute a stub for cons strings because they cannot | 1205 // TODO(2803): Don't compute a stub for cons strings because they cannot |
| 1193 // be embedded into code. | 1206 // be embedded into code. |
| 1194 if (constant->IsConsString()) return Handle<Code>::null(); | 1207 if (constant->IsConsString()) break; |
| 1195 return isolate()->stub_cache()->ComputeLoadConstant( | 1208 return compiler.CompileLoadConstant(receiver, holder, name, constant); |
| 1196 name, receiver, holder, constant); | |
| 1197 } | 1209 } |
| 1198 case NORMAL: | 1210 case NORMAL: |
| 1211 if (kind() != Code::LOAD_IC) break; |
| 1199 if (holder->IsGlobalObject()) { | 1212 if (holder->IsGlobalObject()) { |
| 1200 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 1213 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
| 1201 Handle<PropertyCell> cell( | 1214 Handle<PropertyCell> cell( |
| 1202 global->GetPropertyCell(lookup), isolate()); | 1215 global->GetPropertyCell(lookup), isolate()); |
| 1216 // TODO(verwaest): Turn into a handler. |
| 1203 return isolate()->stub_cache()->ComputeLoadGlobal( | 1217 return isolate()->stub_cache()->ComputeLoadGlobal( |
| 1204 name, receiver, global, cell, lookup->IsDontDelete()); | 1218 name, receiver, global, cell, lookup->IsDontDelete()); |
| 1205 } | 1219 } |
| 1206 // There is only one shared stub for loading normalized | 1220 // There is only one shared stub for loading normalized |
| 1207 // properties. It does not traverse the prototype chain, so the | 1221 // properties. It does not traverse the prototype chain, so the |
| 1208 // property must be found in the receiver for the stub to be | 1222 // property must be found in the receiver for the stub to be |
| 1209 // applicable. | 1223 // applicable. |
| 1210 if (!holder.is_identical_to(receiver)) break; | 1224 if (!holder.is_identical_to(receiver)) break; |
| 1211 return isolate()->stub_cache()->ComputeLoadNormal(name, receiver); | 1225 return isolate()->builtins()->LoadIC_Normal(); |
| 1212 case CALLBACKS: { | 1226 case CALLBACKS: { |
| 1213 { | 1227 // Use simple field loads for some well-known callback properties. |
| 1214 // Use simple field loads for some well-known callback properties. | 1228 int object_offset; |
| 1215 int object_offset; | 1229 Handle<Map> map(receiver->map()); |
| 1216 Handle<Map> map(receiver->map()); | 1230 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { |
| 1217 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { | 1231 PropertyIndex index = |
| 1218 PropertyIndex index = | 1232 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); |
| 1219 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); | 1233 return compiler.CompileLoadField( |
| 1220 return isolate()->stub_cache()->ComputeLoadField( | 1234 receiver, receiver, name, index, Representation::Tagged()); |
| 1221 name, receiver, receiver, index, Representation::Tagged()); | |
| 1222 } | |
| 1223 } | 1235 } |
| 1224 | 1236 |
| 1225 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1237 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1226 if (callback->IsExecutableAccessorInfo()) { | 1238 if (callback->IsExecutableAccessorInfo()) { |
| 1227 Handle<ExecutableAccessorInfo> info = | 1239 Handle<ExecutableAccessorInfo> info = |
| 1228 Handle<ExecutableAccessorInfo>::cast(callback); | 1240 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1229 if (v8::ToCData<Address>(info->getter()) == 0) break; | 1241 if (v8::ToCData<Address>(info->getter()) == 0) break; |
| 1230 if (!info->IsCompatibleReceiver(*receiver)) break; | 1242 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1231 return isolate()->stub_cache()->ComputeLoadCallback( | 1243 return compiler.CompileLoadCallback(receiver, holder, name, info); |
| 1232 name, receiver, holder, info); | |
| 1233 } else if (callback->IsAccessorPair()) { | 1244 } else if (callback->IsAccessorPair()) { |
| 1234 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), | 1245 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), |
| 1235 isolate()); | 1246 isolate()); |
| 1236 if (!getter->IsJSFunction()) break; | 1247 if (!getter->IsJSFunction()) break; |
| 1237 if (holder->IsGlobalObject()) break; | 1248 if (holder->IsGlobalObject()) break; |
| 1238 if (!holder->HasFastProperties()) break; | 1249 if (!holder->HasFastProperties()) break; |
| 1239 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | 1250 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
| 1240 CallOptimization call_optimization(function); | 1251 CallOptimization call_optimization(function); |
| 1241 if (call_optimization.is_simple_api_call() && | 1252 if (call_optimization.is_simple_api_call() && |
| 1242 call_optimization.IsCompatibleReceiver(*receiver)) { | 1253 call_optimization.IsCompatibleReceiver(*receiver)) { |
| 1243 return isolate()->stub_cache()->ComputeLoadCallback( | 1254 return compiler.CompileLoadCallback( |
| 1244 name, receiver, holder, call_optimization); | 1255 receiver, holder, name, call_optimization); |
| 1245 } | 1256 } |
| 1246 return isolate()->stub_cache()->ComputeLoadViaGetter( | 1257 return compiler.CompileLoadViaGetter(receiver, holder, name, function); |
| 1247 name, receiver, holder, function); | |
| 1248 } | 1258 } |
| 1249 // TODO(dcarney): Handle correctly. | 1259 // TODO(dcarney): Handle correctly. |
| 1250 if (callback->IsDeclaredAccessorInfo()) break; | 1260 if (callback->IsDeclaredAccessorInfo()) break; |
| 1251 ASSERT(callback->IsForeign()); | 1261 ASSERT(callback->IsForeign()); |
| 1252 // No IC support for old-style native accessors. | 1262 // No IC support for old-style native accessors. |
| 1253 break; | 1263 break; |
| 1254 } | 1264 } |
| 1255 case INTERCEPTOR: | 1265 case INTERCEPTOR: |
| 1256 ASSERT(HasInterceptorGetter(*holder)); | 1266 ASSERT(HasInterceptorGetter(*holder)); |
| 1257 return isolate()->stub_cache()->ComputeLoadInterceptor( | 1267 return compiler.CompileLoadInterceptor(receiver, holder, name); |
| 1258 name, receiver, holder); | |
| 1259 default: | 1268 default: |
| 1260 break; | 1269 break; |
| 1261 } | 1270 } |
| 1262 return Handle<Code>::null(); | 1271 |
| 1272 return slow_stub(); |
| 1263 } | 1273 } |
| 1264 | 1274 |
| 1265 | 1275 |
| 1266 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1276 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
| 1267 // This helper implements a few common fast cases for converting | 1277 // This helper implements a few common fast cases for converting |
| 1268 // non-smi keys of keyed loads/stores to a smi or a string. | 1278 // non-smi keys of keyed loads/stores to a smi or a string. |
| 1269 if (key->IsHeapNumber()) { | 1279 if (key->IsHeapNumber()) { |
| 1270 double value = Handle<HeapNumber>::cast(key)->value(); | 1280 double value = Handle<HeapNumber>::cast(key)->value(); |
| 1271 if (std::isnan(value)) { | 1281 if (std::isnan(value)) { |
| 1272 key = isolate->factory()->nan_string(); | 1282 key = isolate->factory()->nan_string(); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1384 ASSERT(!stub.is_null()); | 1394 ASSERT(!stub.is_null()); |
| 1385 set_target(*stub); | 1395 set_target(*stub); |
| 1386 TRACE_IC("LoadIC", key); | 1396 TRACE_IC("LoadIC", key); |
| 1387 } | 1397 } |
| 1388 | 1398 |
| 1389 | 1399 |
| 1390 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); | 1400 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
| 1391 } | 1401 } |
| 1392 | 1402 |
| 1393 | 1403 |
| 1394 Handle<Code> KeyedLoadIC::CompileHandler(LookupResult* lookup, | |
| 1395 Handle<JSObject> receiver, | |
| 1396 Handle<String> name, | |
| 1397 Handle<Object> value) { | |
| 1398 // Compute a monomorphic stub. | |
| 1399 Handle<JSObject> holder(lookup->holder(), isolate()); | |
| 1400 switch (lookup->type()) { | |
| 1401 case FIELD: | |
| 1402 return isolate()->stub_cache()->ComputeKeyedLoadField( | |
| 1403 name, receiver, holder, | |
| 1404 lookup->GetFieldIndex(), lookup->representation()); | |
| 1405 case CONSTANT: { | |
| 1406 Handle<Object> constant(lookup->GetConstant(), isolate()); | |
| 1407 // TODO(2803): Don't compute a stub for cons strings because they cannot | |
| 1408 // be embedded into code. | |
| 1409 if (constant->IsConsString()) return Handle<Code>::null(); | |
| 1410 return isolate()->stub_cache()->ComputeKeyedLoadConstant( | |
| 1411 name, receiver, holder, constant); | |
| 1412 } | |
| 1413 case CALLBACKS: { | |
| 1414 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate()); | |
| 1415 // TODO(dcarney): Handle DeclaredAccessorInfo correctly. | |
| 1416 if (callback_object->IsExecutableAccessorInfo()) { | |
| 1417 Handle<ExecutableAccessorInfo> callback = | |
| 1418 Handle<ExecutableAccessorInfo>::cast(callback_object); | |
| 1419 if (v8::ToCData<Address>(callback->getter()) == 0) break; | |
| 1420 if (!callback->IsCompatibleReceiver(*receiver)) break; | |
| 1421 return isolate()->stub_cache()->ComputeKeyedLoadCallback( | |
| 1422 name, receiver, holder, callback); | |
| 1423 } else if (callback_object->IsAccessorPair()) { | |
| 1424 Handle<Object> getter( | |
| 1425 Handle<AccessorPair>::cast(callback_object)->getter(), | |
| 1426 isolate()); | |
| 1427 if (!getter->IsJSFunction()) break; | |
| 1428 if (holder->IsGlobalObject()) break; | |
| 1429 if (!holder->HasFastProperties()) break; | |
| 1430 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | |
| 1431 CallOptimization call_optimization(function); | |
| 1432 if (call_optimization.is_simple_api_call() && | |
| 1433 call_optimization.IsCompatibleReceiver(*receiver)) { | |
| 1434 return isolate()->stub_cache()->ComputeKeyedLoadCallback( | |
| 1435 name, receiver, holder, call_optimization); | |
| 1436 } | |
| 1437 } | |
| 1438 break; | |
| 1439 } | |
| 1440 case INTERCEPTOR: | |
| 1441 ASSERT(HasInterceptorGetter(lookup->holder())); | |
| 1442 return isolate()->stub_cache()->ComputeKeyedLoadInterceptor( | |
| 1443 name, receiver, holder); | |
| 1444 default: | |
| 1445 // Always rewrite to the generic case so that we do not | |
| 1446 // repeatedly try to rewrite. | |
| 1447 return generic_stub(); | |
| 1448 } | |
| 1449 return Handle<Code>::null(); | |
| 1450 } | |
| 1451 | |
| 1452 | |
| 1453 static bool LookupForWrite(Handle<JSObject> receiver, | 1404 static bool LookupForWrite(Handle<JSObject> receiver, |
| 1454 Handle<String> name, | 1405 Handle<String> name, |
| 1455 Handle<Object> value, | 1406 Handle<Object> value, |
| 1456 LookupResult* lookup, | 1407 LookupResult* lookup, |
| 1457 IC* ic) { | 1408 IC* ic) { |
| 1458 Handle<JSObject> holder = receiver; | 1409 Handle<JSObject> holder = receiver; |
| 1459 receiver->Lookup(*name, lookup); | 1410 receiver->Lookup(*name, lookup); |
| 1460 if (lookup->IsFound()) { | 1411 if (lookup->IsFound()) { |
| 1461 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | 1412 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
| 1462 | 1413 |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1640 PatchCache(receiver, name, code); | 1591 PatchCache(receiver, name, code); |
| 1641 TRACE_IC("StoreIC", name); | 1592 TRACE_IC("StoreIC", name); |
| 1642 } | 1593 } |
| 1643 | 1594 |
| 1644 | 1595 |
| 1645 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, | 1596 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
| 1646 Handle<JSObject> receiver, | 1597 Handle<JSObject> receiver, |
| 1647 Handle<String> name, | 1598 Handle<String> name, |
| 1648 Handle<Object> value) { | 1599 Handle<Object> value) { |
| 1649 Handle<JSObject> holder(lookup->holder()); | 1600 Handle<JSObject> holder(lookup->holder()); |
| 1601 StoreStubCompiler compiler(isolate(), strict_mode(), kind()); |
| 1650 switch (lookup->type()) { | 1602 switch (lookup->type()) { |
| 1651 case FIELD: | 1603 case FIELD: |
| 1652 return isolate()->stub_cache()->ComputeStoreField( | 1604 return compiler.CompileStoreField(receiver, lookup, name); |
| 1653 name, receiver, lookup, strict_mode()); | 1605 case TRANSITION: { |
| 1606 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1607 // stored something else than the receiver in the holder. |
| 1608 Handle<Map> transition( |
| 1609 lookup->GetTransitionTarget(receiver->map()), isolate()); |
| 1610 int descriptor = transition->LastAdded(); |
| 1611 |
| 1612 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 1613 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 1614 |
| 1615 if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
| 1616 |
| 1617 return compiler.CompileStoreTransition( |
| 1618 receiver, lookup, transition, name); |
| 1619 } |
| 1654 case NORMAL: | 1620 case NORMAL: |
| 1621 if (kind() == Code::KEYED_STORE_IC) break; |
| 1655 if (receiver->IsGlobalObject()) { | 1622 if (receiver->IsGlobalObject()) { |
| 1656 // The stub generated for the global object picks the value directly | 1623 // The stub generated for the global object picks the value directly |
| 1657 // from the property cell. So the property must be directly on the | 1624 // from the property cell. So the property must be directly on the |
| 1658 // global object. | 1625 // global object. |
| 1659 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1626 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1660 Handle<PropertyCell> cell( | 1627 Handle<PropertyCell> cell( |
| 1661 global->GetPropertyCell(lookup), isolate()); | 1628 global->GetPropertyCell(lookup), isolate()); |
| 1629 // TODO(verwaest): Turn into a handler. |
| 1662 return isolate()->stub_cache()->ComputeStoreGlobal( | 1630 return isolate()->stub_cache()->ComputeStoreGlobal( |
| 1663 name, global, cell, value, strict_mode()); | 1631 name, global, cell, value, strict_mode()); |
| 1664 } | 1632 } |
| 1665 ASSERT(holder.is_identical_to(receiver)); | 1633 ASSERT(holder.is_identical_to(receiver)); |
| 1666 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode()); | 1634 return strict_mode() == kStrictMode |
| 1635 ? isolate()->builtins()->StoreIC_Normal_Strict() |
| 1636 : isolate()->builtins()->StoreIC_Normal(); |
| 1667 case CALLBACKS: { | 1637 case CALLBACKS: { |
| 1638 if (kind() == Code::KEYED_STORE_IC) break; |
| 1668 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1639 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1669 if (callback->IsExecutableAccessorInfo()) { | 1640 if (callback->IsExecutableAccessorInfo()) { |
| 1670 Handle<ExecutableAccessorInfo> info = | 1641 Handle<ExecutableAccessorInfo> info = |
| 1671 Handle<ExecutableAccessorInfo>::cast(callback); | 1642 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1672 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1643 if (v8::ToCData<Address>(info->setter()) == 0) break; |
| 1673 if (!holder->HasFastProperties()) break; | 1644 if (!holder->HasFastProperties()) break; |
| 1674 if (!info->IsCompatibleReceiver(*receiver)) break; | 1645 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1675 return isolate()->stub_cache()->ComputeStoreCallback( | 1646 return compiler.CompileStoreCallback(receiver, holder, name, info); |
| 1676 name, receiver, holder, info, strict_mode()); | |
| 1677 } else if (callback->IsAccessorPair()) { | 1647 } else if (callback->IsAccessorPair()) { |
| 1678 Handle<Object> setter( | 1648 Handle<Object> setter( |
| 1679 Handle<AccessorPair>::cast(callback)->setter(), isolate()); | 1649 Handle<AccessorPair>::cast(callback)->setter(), isolate()); |
| 1680 if (!setter->IsJSFunction()) break; | 1650 if (!setter->IsJSFunction()) break; |
| 1681 if (holder->IsGlobalObject()) break; | 1651 if (holder->IsGlobalObject()) break; |
| 1682 if (!holder->HasFastProperties()) break; | 1652 if (!holder->HasFastProperties()) break; |
| 1683 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); | 1653 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
| 1684 CallOptimization call_optimization(function); | 1654 CallOptimization call_optimization(function); |
| 1685 if (call_optimization.is_simple_api_call() && | 1655 if (call_optimization.is_simple_api_call() && |
| 1686 call_optimization.IsCompatibleReceiver(*receiver)) { | 1656 call_optimization.IsCompatibleReceiver(*receiver)) { |
| 1687 return isolate()->stub_cache()->ComputeStoreCallback( | 1657 return compiler.CompileStoreCallback( |
| 1688 name, receiver, holder, call_optimization, strict_mode()); | 1658 receiver, holder, name, call_optimization); |
| 1689 } | 1659 } |
| 1690 return isolate()->stub_cache()->ComputeStoreViaSetter( | 1660 return compiler.CompileStoreViaSetter( |
| 1691 name, receiver, holder, Handle<JSFunction>::cast(setter), | 1661 receiver, holder, name, Handle<JSFunction>::cast(setter)); |
| 1692 strict_mode()); | |
| 1693 } | 1662 } |
| 1694 // TODO(dcarney): Handle correctly. | 1663 // TODO(dcarney): Handle correctly. |
| 1695 if (callback->IsDeclaredAccessorInfo()) break; | 1664 if (callback->IsDeclaredAccessorInfo()) break; |
| 1696 ASSERT(callback->IsForeign()); | 1665 ASSERT(callback->IsForeign()); |
| 1697 // No IC support for old-style native accessors. | 1666 // No IC support for old-style native accessors. |
| 1698 break; | 1667 break; |
| 1699 } | 1668 } |
| 1700 case INTERCEPTOR: | 1669 case INTERCEPTOR: |
| 1670 if (kind() == Code::KEYED_STORE_IC) break; |
| 1701 ASSERT(HasInterceptorSetter(*receiver)); | 1671 ASSERT(HasInterceptorSetter(*receiver)); |
| 1702 return isolate()->stub_cache()->ComputeStoreInterceptor( | 1672 return compiler.CompileStoreInterceptor(receiver, name); |
| 1703 name, receiver, strict_mode()); | |
| 1704 case CONSTANT: | 1673 case CONSTANT: |
| 1705 break; | 1674 break; |
| 1706 case TRANSITION: { | |
| 1707 // Explicitly pass in the receiver map since LookupForWrite may have | |
| 1708 // stored something else than the receiver in the holder. | |
| 1709 Handle<Map> transition( | |
| 1710 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
| 1711 int descriptor = transition->LastAdded(); | |
| 1712 | |
| 1713 DescriptorArray* target_descriptors = transition->instance_descriptors(); | |
| 1714 PropertyDetails details = target_descriptors->GetDetails(descriptor); | |
| 1715 | |
| 1716 if (details.type() == CALLBACKS || details.attributes() != NONE) break; | |
| 1717 | |
| 1718 return isolate()->stub_cache()->ComputeStoreTransition( | |
| 1719 name, receiver, lookup, transition, strict_mode()); | |
| 1720 } | |
| 1721 case NONEXISTENT: | 1675 case NONEXISTENT: |
| 1722 case HANDLER: | 1676 case HANDLER: |
| 1723 UNREACHABLE(); | 1677 UNREACHABLE(); |
| 1724 break; | 1678 break; |
| 1725 } | 1679 } |
| 1726 return Handle<Code>::null(); | 1680 return slow_stub(); |
| 1727 } | 1681 } |
| 1728 | 1682 |
| 1729 | 1683 |
| 1730 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 1684 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, |
| 1731 KeyedAccessStoreMode store_mode) { | 1685 KeyedAccessStoreMode store_mode) { |
| 1732 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1686 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1733 // via megamorphic stubs, since they don't have a map in their relocation info | 1687 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1734 // and so the stubs can't be harvested for the object needed for a map check. | 1688 // and so the stubs can't be harvested for the object needed for a map check. |
| 1735 if (target()->type() != Code::NORMAL) { | 1689 if (target()->type() != Code::NORMAL) { |
| 1736 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); | 1690 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2027 ASSERT(!stub.is_null()); | 1981 ASSERT(!stub.is_null()); |
| 2028 set_target(*stub); | 1982 set_target(*stub); |
| 2029 TRACE_IC("StoreIC", key); | 1983 TRACE_IC("StoreIC", key); |
| 2030 } | 1984 } |
| 2031 | 1985 |
| 2032 return Runtime::SetObjectPropertyOrFail( | 1986 return Runtime::SetObjectPropertyOrFail( |
| 2033 isolate(), object , key, value, NONE, strict_mode()); | 1987 isolate(), object , key, value, NONE, strict_mode()); |
| 2034 } | 1988 } |
| 2035 | 1989 |
| 2036 | 1990 |
| 2037 Handle<Code> KeyedStoreIC::CompileHandler(LookupResult* lookup, | |
| 2038 Handle<JSObject> receiver, | |
| 2039 Handle<String> name, | |
| 2040 Handle<Object> value) { | |
| 2041 // If the property has a non-field type allowing map transitions | |
| 2042 // where there is extra room in the object, we leave the IC in its | |
| 2043 // current state. | |
| 2044 switch (lookup->type()) { | |
| 2045 case FIELD: | |
| 2046 return isolate()->stub_cache()->ComputeKeyedStoreField( | |
| 2047 name, receiver, lookup, strict_mode()); | |
| 2048 case TRANSITION: { | |
| 2049 // Explicitly pass in the receiver map since LookupForWrite may have | |
| 2050 // stored something else than the receiver in the holder. | |
| 2051 Handle<Map> transition( | |
| 2052 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
| 2053 int descriptor = transition->LastAdded(); | |
| 2054 | |
| 2055 DescriptorArray* target_descriptors = transition->instance_descriptors(); | |
| 2056 PropertyDetails details = target_descriptors->GetDetails(descriptor); | |
| 2057 | |
| 2058 if (details.type() != CALLBACKS && details.attributes() == NONE) { | |
| 2059 return isolate()->stub_cache()->ComputeKeyedStoreTransition( | |
| 2060 name, receiver, lookup, transition, strict_mode()); | |
| 2061 } | |
| 2062 // fall through. | |
| 2063 } | |
| 2064 case NORMAL: | |
| 2065 case CONSTANT: | |
| 2066 case CALLBACKS: | |
| 2067 case INTERCEPTOR: | |
| 2068 // Always rewrite to the generic case so that we do not | |
| 2069 // repeatedly try to rewrite. | |
| 2070 return generic_stub(); | |
| 2071 case HANDLER: | |
| 2072 case NONEXISTENT: | |
| 2073 UNREACHABLE(); | |
| 2074 break; | |
| 2075 } | |
| 2076 return Handle<Code>::null(); | |
| 2077 } | |
| 2078 | |
| 2079 | |
| 2080 #undef TRACE_IC | 1991 #undef TRACE_IC |
| 2081 | 1992 |
| 2082 | 1993 |
| 2083 // ---------------------------------------------------------------------------- | 1994 // ---------------------------------------------------------------------------- |
| 2084 // Static IC stub generators. | 1995 // Static IC stub generators. |
| 2085 // | 1996 // |
| 2086 | 1997 |
| 2087 // Used from ic-<arch>.cc. | 1998 // Used from ic-<arch>.cc. |
| 2088 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { | 1999 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { |
| 2089 HandleScope scope(isolate); | 2000 HandleScope scope(isolate); |
| (...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2802 #undef ADDR | 2713 #undef ADDR |
| 2803 }; | 2714 }; |
| 2804 | 2715 |
| 2805 | 2716 |
| 2806 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2717 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2807 return IC_utilities[id]; | 2718 return IC_utilities[id]; |
| 2808 } | 2719 } |
| 2809 | 2720 |
| 2810 | 2721 |
| 2811 } } // namespace v8::internal | 2722 } } // namespace v8::internal |
| OLD | NEW |