| 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 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 } \ | 110 } \ |
| 111 } while (false) | 111 } while (false) |
| 112 | 112 |
| 113 #else | 113 #else |
| 114 #define TRACE_GENERIC_IC(isolate, type, reason) | 114 #define TRACE_GENERIC_IC(isolate, type, reason) |
| 115 #endif // DEBUG | 115 #endif // DEBUG |
| 116 | 116 |
| 117 #define TRACE_IC(type, name) \ | 117 #define TRACE_IC(type, name) \ |
| 118 ASSERT((TraceIC(type, name), true)) | 118 ASSERT((TraceIC(type, name), true)) |
| 119 | 119 |
| 120 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { | 120 IC::IC(FrameDepth depth, Isolate* isolate) |
| 121 : isolate_(isolate), |
| 122 target_set_(false) { |
| 121 // To improve the performance of the (much used) IC code, we unfold a few | 123 // To improve the performance of the (much used) IC code, we unfold a few |
| 122 // levels of the stack frame iteration code. This yields a ~35% speedup when | 124 // levels of the stack frame iteration code. This yields a ~35% speedup when |
| 123 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. | 125 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. |
| 124 const Address entry = | 126 const Address entry = |
| 125 Isolate::c_entry_fp(isolate->thread_local_top()); | 127 Isolate::c_entry_fp(isolate->thread_local_top()); |
| 126 Address* pc_address = | 128 Address* pc_address = |
| 127 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); | 129 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); |
| 128 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 130 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
| 129 // If there's another JavaScript frame on the stack or a | 131 // If there's another JavaScript frame on the stack or a |
| 130 // StubFailureTrampoline, we need to look one frame further down the stack to | 132 // StubFailureTrampoline, we need to look one frame further down the stack to |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 // The stub was generated for JSObject but called for non-JSObject. | 295 // The stub was generated for JSObject but called for non-JSObject. |
| 294 // IC::GetCodeCacheHolder is not applicable. | 296 // IC::GetCodeCacheHolder is not applicable. |
| 295 if (!receiver->IsJSObject()) return false; | 297 if (!receiver->IsJSObject()) return false; |
| 296 break; | 298 break; |
| 297 case PROTOTYPE_MAP: | 299 case PROTOTYPE_MAP: |
| 298 // IC::GetCodeCacheHolder is not applicable. | 300 // IC::GetCodeCacheHolder is not applicable. |
| 299 if (receiver->GetPrototype(isolate())->IsNull()) return false; | 301 if (receiver->GetPrototype(isolate())->IsNull()) return false; |
| 300 break; | 302 break; |
| 301 } | 303 } |
| 302 | 304 |
| 303 Map* map = IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map(); | 305 Handle<Map> map( |
| 306 IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map()); |
| 304 | 307 |
| 305 // Decide whether the inline cache failed because of changes to the | 308 // Decide whether the inline cache failed because of changes to the |
| 306 // receiver itself or changes to one of its prototypes. | 309 // receiver itself or changes to one of its prototypes. |
| 307 // | 310 // |
| 308 // If there are changes to the receiver itself, the map of the | 311 // If there are changes to the receiver itself, the map of the |
| 309 // receiver will have changed and the current target will not be in | 312 // receiver will have changed and the current target will not be in |
| 310 // the receiver map's code cache. Therefore, if the current target | 313 // the receiver map's code cache. Therefore, if the current target |
| 311 // is in the receiver map's code cache, the inline cache failed due | 314 // is in the receiver map's code cache, the inline cache failed due |
| 312 // to prototype check failure. | 315 // to prototype check failure. |
| 313 int index = map->IndexInCodeCache(*name, *target()); | 316 int index = map->IndexInCodeCache(*name, *target()); |
| 314 if (index >= 0) { | 317 if (index >= 0) { |
| 315 map->RemoveFromCodeCache(*name, *target(), index); | 318 map->RemoveFromCodeCache(*name, *target(), index); |
| 316 // Handlers are stored in addition to the ICs on the map. Remove those, too. | 319 // Handlers are stored in addition to the ICs on the map. Remove those, too. |
| 317 Code* handler = target()->FindFirstHandler(); | 320 TryRemoveInvalidHandlers(map, name); |
| 318 if (handler != NULL) { | |
| 319 index = map->IndexInCodeCache(*name, handler); | |
| 320 if (index >= 0) { | |
| 321 map->RemoveFromCodeCache(*name, handler, index); | |
| 322 } | |
| 323 } | |
| 324 return true; | 321 return true; |
| 325 } | 322 } |
| 326 | 323 |
| 327 // The stub is not in the cache. We've ruled out all other kinds of failure | 324 // The stub is not in the cache. We've ruled out all other kinds of failure |
| 328 // except for proptotype chain changes, a deprecated map, a map that's | 325 // except for proptotype chain changes, a deprecated map, a map that's |
| 329 // different from the one that the stub expects, elements kind changes, or a | 326 // different from the one that the stub expects, elements kind changes, or a |
| 330 // constant global property that will become mutable. Threat all those | 327 // constant global property that will become mutable. Threat all those |
| 331 // situations as prototype failures (stay monomorphic if possible). | 328 // situations as prototype failures (stay monomorphic if possible). |
| 332 | 329 |
| 333 // If the IC is shared between multiple receivers (slow dictionary mode), then | 330 // If the IC is shared between multiple receivers (slow dictionary mode), then |
| 334 // the map cannot be deprecated and the stub invalidated. | 331 // the map cannot be deprecated and the stub invalidated. |
| 335 if (cache_holder == OWN_MAP) { | 332 if (cache_holder == OWN_MAP) { |
| 336 Map* old_map = target()->FindFirstMap(); | 333 Map* old_map = target()->FindFirstMap(); |
| 337 if (old_map == map) return true; | 334 if (old_map == *map) return true; |
| 338 if (old_map != NULL) { | 335 if (old_map != NULL) { |
| 339 if (old_map->is_deprecated()) return true; | 336 if (old_map->is_deprecated()) return true; |
| 340 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), | 337 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), |
| 341 map->elements_kind())) { | 338 map->elements_kind())) { |
| 342 return true; | 339 return true; |
| 343 } | 340 } |
| 344 } | 341 } |
| 345 } | 342 } |
| 346 | 343 |
| 347 if (receiver->IsGlobalObject()) { | 344 if (receiver->IsGlobalObject()) { |
| 348 LookupResult lookup(isolate()); | 345 LookupResult lookup(isolate()); |
| 349 GlobalObject* global = GlobalObject::cast(*receiver); | 346 GlobalObject* global = GlobalObject::cast(*receiver); |
| 350 global->LocalLookupRealNamedProperty(*name, &lookup); | 347 global->LocalLookupRealNamedProperty(*name, &lookup); |
| 351 if (!lookup.IsFound()) return false; | 348 if (!lookup.IsFound()) return false; |
| 352 PropertyCell* cell = global->GetPropertyCell(&lookup); | 349 PropertyCell* cell = global->GetPropertyCell(&lookup); |
| 353 return cell->type()->IsConstant(); | 350 return cell->type()->IsConstant(); |
| 354 } | 351 } |
| 355 | 352 |
| 356 return false; | 353 return false; |
| 357 } | 354 } |
| 358 | 355 |
| 359 | 356 |
| 357 void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) { |
| 358 CodeHandleList handlers; |
| 359 target()->FindHandlers(&handlers); |
| 360 for (int i = 0; i < handlers.length(); i++) { |
| 361 Handle<Code> handler = handlers.at(i); |
| 362 int index = map->IndexInCodeCache(*name, *handler); |
| 363 if (index >= 0) { |
| 364 map->RemoveFromCodeCache(*name, *handler, index); |
| 365 return; |
| 366 } |
| 367 } |
| 368 } |
| 369 |
| 370 |
| 360 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { | 371 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { |
| 361 if (state() != MONOMORPHIC || !name->IsString()) return; | 372 if (!name->IsString()) return; |
| 373 if (state() != MONOMORPHIC) { |
| 374 if (state() == POLYMORPHIC && receiver->IsHeapObject()) { |
| 375 TryRemoveInvalidHandlers( |
| 376 handle(Handle<HeapObject>::cast(receiver)->map()), |
| 377 Handle<String>::cast(name)); |
| 378 } |
| 379 return; |
| 380 } |
| 362 if (receiver->IsUndefined() || receiver->IsNull()) return; | 381 if (receiver->IsUndefined() || receiver->IsNull()) return; |
| 363 | 382 |
| 364 // Remove the target from the code cache if it became invalid | 383 // Remove the target from the code cache if it became invalid |
| 365 // because of changes in the prototype chain to avoid hitting it | 384 // because of changes in the prototype chain to avoid hitting it |
| 366 // again. | 385 // again. |
| 367 if (TryRemoveInvalidPrototypeDependentStub( | 386 if (TryRemoveInvalidPrototypeDependentStub( |
| 368 receiver, Handle<String>::cast(name))) { | 387 receiver, Handle<String>::cast(name))) { |
| 369 return MarkMonomorphicPrototypeFailure(); | 388 return MarkMonomorphicPrototypeFailure(); |
| 370 } | 389 } |
| 371 | 390 |
| (...skipping 709 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 break; | 1100 break; |
| 1082 case DEBUG_STUB: | 1101 case DEBUG_STUB: |
| 1083 break; | 1102 break; |
| 1084 case GENERIC: | 1103 case GENERIC: |
| 1085 UNREACHABLE(); | 1104 UNREACHABLE(); |
| 1086 break; | 1105 break; |
| 1087 } | 1106 } |
| 1088 } | 1107 } |
| 1089 | 1108 |
| 1090 | 1109 |
| 1110 Handle<Code> LoadIC::SimpleFieldLoad(int offset, |
| 1111 bool inobject, |
| 1112 Representation representation) { |
| 1113 if (kind() == Code::LOAD_IC) { |
| 1114 LoadFieldStub stub(inobject, offset, representation); |
| 1115 return stub.GetCode(isolate()); |
| 1116 } else { |
| 1117 KeyedLoadFieldStub stub(inobject, offset, representation); |
| 1118 return stub.GetCode(isolate()); |
| 1119 } |
| 1120 } |
| 1121 |
| 1091 void LoadIC::UpdateCaches(LookupResult* lookup, | 1122 void LoadIC::UpdateCaches(LookupResult* lookup, |
| 1092 Handle<Object> object, | 1123 Handle<Object> object, |
| 1093 Handle<String> name) { | 1124 Handle<String> name) { |
| 1094 // TODO(verwaest): It would be nice to support loading fields from smis as | 1125 // TODO(verwaest): It would be nice to support loading fields from smis as |
| 1095 // well. For now just fail to update the cache. | 1126 // well. For now just fail to update the cache. |
| 1096 if (!object->IsHeapObject()) return; | 1127 if (!object->IsHeapObject()) return; |
| 1097 | 1128 |
| 1098 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); | 1129 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); |
| 1099 | 1130 |
| 1100 Handle<Code> code; | 1131 Handle<Code> code; |
| 1101 if (state() == UNINITIALIZED) { | 1132 if (state() == UNINITIALIZED) { |
| 1102 // This is the first time we execute this inline cache. | 1133 // This is the first time we execute this inline cache. |
| 1103 // Set the target to the pre monomorphic stub to delay | 1134 // Set the target to the pre monomorphic stub to delay |
| 1104 // setting the monomorphic state. | 1135 // setting the monomorphic state. |
| 1105 code = pre_monomorphic_stub(); | 1136 code = pre_monomorphic_stub(); |
| 1106 } else if (!lookup->IsCacheable()) { | 1137 } else if (!lookup->IsCacheable()) { |
| 1107 // Bail out if the result is not cacheable. | 1138 // Bail out if the result is not cacheable. |
| 1108 code = slow_stub(); | 1139 code = slow_stub(); |
| 1109 } else if (object->IsString() && | 1140 } else if (object->IsString() && |
| 1110 name->Equals(isolate()->heap()->length_string())) { | 1141 name->Equals(isolate()->heap()->length_string())) { |
| 1111 int length_index = String::kLengthOffset / kPointerSize; | 1142 int length_index = String::kLengthOffset / kPointerSize; |
| 1112 if (target()->is_load_stub()) { | 1143 code = SimpleFieldLoad(length_index); |
| 1113 LoadFieldStub stub(true, length_index, Representation::Tagged()); | |
| 1114 code = stub.GetCode(isolate()); | |
| 1115 } else { | |
| 1116 KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); | |
| 1117 code = stub.GetCode(isolate()); | |
| 1118 } | |
| 1119 } else if (!object->IsJSObject()) { | 1144 } else if (!object->IsJSObject()) { |
| 1120 // TODO(jkummerow): It would be nice to support non-JSObjects in | 1145 // TODO(jkummerow): It would be nice to support non-JSObjects in |
| 1121 // ComputeLoadHandler, then we wouldn't need to go generic here. | 1146 // ComputeLoadHandler, then we wouldn't need to go generic here. |
| 1122 code = slow_stub(); | 1147 code = slow_stub(); |
| 1148 } else if (!lookup->IsProperty()) { |
| 1149 code = kind() == Code::LOAD_IC |
| 1150 ? isolate()->stub_cache()->ComputeLoadNonexistent( |
| 1151 name, Handle<JSObject>::cast(receiver)) |
| 1152 : slow_stub(); |
| 1123 } else { | 1153 } else { |
| 1124 code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name); | 1154 code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name); |
| 1125 if (code.is_null()) code = slow_stub(); | |
| 1126 } | 1155 } |
| 1127 | 1156 |
| 1128 PatchCache(receiver, name, code); | 1157 PatchCache(receiver, name, code); |
| 1129 TRACE_IC("LoadIC", name); | 1158 TRACE_IC("LoadIC", name); |
| 1130 } | 1159 } |
| 1131 | 1160 |
| 1132 | 1161 |
| 1133 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { | 1162 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { |
| 1134 // Cache code holding map should be consistent with | 1163 // Cache code holding map should be consistent with |
| 1135 // GenerateMonomorphicCacheProbe. | 1164 // GenerateMonomorphicCacheProbe. |
| 1136 isolate()->stub_cache()->Set(name, map, code); | 1165 isolate()->stub_cache()->Set(name, map, code); |
| 1137 } | 1166 } |
| 1138 | 1167 |
| 1139 | 1168 |
| 1140 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, | 1169 Handle<Code> IC::ComputeHandler(LookupResult* lookup, |
| 1141 Handle<JSObject> receiver, | 1170 Handle<JSObject> receiver, |
| 1142 Handle<String> name) { | 1171 Handle<String> name, |
| 1143 if (!lookup->IsProperty()) { | 1172 Handle<Object> value) { |
| 1144 // Nonexistent property. The result is undefined. | 1173 Handle<Code> code = isolate()->stub_cache()->FindHandler( |
| 1145 return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); | 1174 name, receiver, kind()); |
| 1175 if (!code.is_null()) return code; |
| 1176 |
| 1177 code = CompileHandler(lookup, receiver, name, value); |
| 1178 |
| 1179 if (code->is_handler() && code->type() != Code::NORMAL) { |
| 1180 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1146 } | 1181 } |
| 1147 | 1182 |
| 1148 // Compute monomorphic stub. | 1183 return code; |
| 1184 } |
| 1185 |
| 1186 |
| 1187 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
| 1188 Handle<JSObject> receiver, |
| 1189 Handle<String> name, |
| 1190 Handle<Object> unused) { |
| 1149 Handle<JSObject> holder(lookup->holder()); | 1191 Handle<JSObject> holder(lookup->holder()); |
| 1192 LoadStubCompiler compiler(isolate(), kind()); |
| 1193 |
| 1150 switch (lookup->type()) { | 1194 switch (lookup->type()) { |
| 1151 case FIELD: | 1195 case FIELD: { |
| 1152 return isolate()->stub_cache()->ComputeLoadField( | 1196 PropertyIndex field = lookup->GetFieldIndex(); |
| 1153 name, receiver, holder, | 1197 if (receiver.is_identical_to(holder)) { |
| 1154 lookup->GetFieldIndex(), lookup->representation()); | 1198 return SimpleFieldLoad(field.translate(holder), |
| 1199 field.is_inobject(holder), |
| 1200 lookup->representation()); |
| 1201 } |
| 1202 return compiler.CompileLoadField( |
| 1203 receiver, holder, name, field, lookup->representation()); |
| 1204 } |
| 1155 case CONSTANT: { | 1205 case CONSTANT: { |
| 1156 Handle<Object> constant(lookup->GetConstant(), isolate()); | 1206 Handle<Object> constant(lookup->GetConstant(), isolate()); |
| 1157 // TODO(2803): Don't compute a stub for cons strings because they cannot | 1207 // TODO(2803): Don't compute a stub for cons strings because they cannot |
| 1158 // be embedded into code. | 1208 // be embedded into code. |
| 1159 if (constant->IsConsString()) return Handle<Code>::null(); | 1209 if (constant->IsConsString()) break; |
| 1160 return isolate()->stub_cache()->ComputeLoadConstant( | 1210 return compiler.CompileLoadConstant(receiver, holder, name, constant); |
| 1161 name, receiver, holder, constant); | |
| 1162 } | 1211 } |
| 1163 case NORMAL: | 1212 case NORMAL: |
| 1213 if (kind() != Code::LOAD_IC) break; |
| 1164 if (holder->IsGlobalObject()) { | 1214 if (holder->IsGlobalObject()) { |
| 1165 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 1215 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
| 1166 Handle<PropertyCell> cell( | 1216 Handle<PropertyCell> cell( |
| 1167 global->GetPropertyCell(lookup), isolate()); | 1217 global->GetPropertyCell(lookup), isolate()); |
| 1218 // TODO(verwaest): Turn into a handler. |
| 1168 return isolate()->stub_cache()->ComputeLoadGlobal( | 1219 return isolate()->stub_cache()->ComputeLoadGlobal( |
| 1169 name, receiver, global, cell, lookup->IsDontDelete()); | 1220 name, receiver, global, cell, lookup->IsDontDelete()); |
| 1170 } | 1221 } |
| 1171 // There is only one shared stub for loading normalized | 1222 // There is only one shared stub for loading normalized |
| 1172 // properties. It does not traverse the prototype chain, so the | 1223 // properties. It does not traverse the prototype chain, so the |
| 1173 // property must be found in the receiver for the stub to be | 1224 // property must be found in the receiver for the stub to be |
| 1174 // applicable. | 1225 // applicable. |
| 1175 if (!holder.is_identical_to(receiver)) break; | 1226 if (!holder.is_identical_to(receiver)) break; |
| 1176 return isolate()->stub_cache()->ComputeLoadNormal(name, receiver); | 1227 return isolate()->builtins()->LoadIC_Normal(); |
| 1177 case CALLBACKS: { | 1228 case CALLBACKS: { |
| 1178 { | 1229 // Use simple field loads for some well-known callback properties. |
| 1179 // Use simple field loads for some well-known callback properties. | 1230 int object_offset; |
| 1180 int object_offset; | 1231 Handle<Map> map(receiver->map()); |
| 1181 Handle<Map> map(receiver->map()); | 1232 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { |
| 1182 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { | 1233 PropertyIndex index = |
| 1183 PropertyIndex index = | 1234 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); |
| 1184 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); | 1235 return compiler.CompileLoadField( |
| 1185 return isolate()->stub_cache()->ComputeLoadField( | 1236 receiver, receiver, name, index, Representation::Tagged()); |
| 1186 name, receiver, receiver, index, Representation::Tagged()); | |
| 1187 } | |
| 1188 } | 1237 } |
| 1189 | 1238 |
| 1190 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1239 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1191 if (callback->IsExecutableAccessorInfo()) { | 1240 if (callback->IsExecutableAccessorInfo()) { |
| 1192 Handle<ExecutableAccessorInfo> info = | 1241 Handle<ExecutableAccessorInfo> info = |
| 1193 Handle<ExecutableAccessorInfo>::cast(callback); | 1242 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1194 if (v8::ToCData<Address>(info->getter()) == 0) break; | 1243 if (v8::ToCData<Address>(info->getter()) == 0) break; |
| 1195 if (!info->IsCompatibleReceiver(*receiver)) break; | 1244 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1196 return isolate()->stub_cache()->ComputeLoadCallback( | 1245 return compiler.CompileLoadCallback(receiver, holder, name, info); |
| 1197 name, receiver, holder, info); | |
| 1198 } else if (callback->IsAccessorPair()) { | 1246 } else if (callback->IsAccessorPair()) { |
| 1199 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), | 1247 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), |
| 1200 isolate()); | 1248 isolate()); |
| 1201 if (!getter->IsJSFunction()) break; | 1249 if (!getter->IsJSFunction()) break; |
| 1202 if (holder->IsGlobalObject()) break; | 1250 if (holder->IsGlobalObject()) break; |
| 1203 if (!holder->HasFastProperties()) break; | 1251 if (!holder->HasFastProperties()) break; |
| 1204 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | 1252 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
| 1205 CallOptimization call_optimization(function); | 1253 CallOptimization call_optimization(function); |
| 1206 if (call_optimization.is_simple_api_call() && | 1254 if (call_optimization.is_simple_api_call() && |
| 1207 call_optimization.IsCompatibleReceiver(*receiver)) { | 1255 call_optimization.IsCompatibleReceiver(*receiver)) { |
| 1208 return isolate()->stub_cache()->ComputeLoadCallback( | 1256 return compiler.CompileLoadCallback( |
| 1209 name, receiver, holder, call_optimization); | 1257 receiver, holder, name, call_optimization); |
| 1210 } | 1258 } |
| 1211 return isolate()->stub_cache()->ComputeLoadViaGetter( | 1259 return compiler.CompileLoadViaGetter(receiver, holder, name, function); |
| 1212 name, receiver, holder, function); | |
| 1213 } | 1260 } |
| 1214 // TODO(dcarney): Handle correctly. | 1261 // TODO(dcarney): Handle correctly. |
| 1215 if (callback->IsDeclaredAccessorInfo()) break; | 1262 if (callback->IsDeclaredAccessorInfo()) break; |
| 1216 ASSERT(callback->IsForeign()); | 1263 ASSERT(callback->IsForeign()); |
| 1217 // No IC support for old-style native accessors. | 1264 // No IC support for old-style native accessors. |
| 1218 break; | 1265 break; |
| 1219 } | 1266 } |
| 1220 case INTERCEPTOR: | 1267 case INTERCEPTOR: |
| 1221 ASSERT(HasInterceptorGetter(*holder)); | 1268 ASSERT(HasInterceptorGetter(*holder)); |
| 1222 return isolate()->stub_cache()->ComputeLoadInterceptor( | 1269 return compiler.CompileLoadInterceptor(receiver, holder, name); |
| 1223 name, receiver, holder); | |
| 1224 default: | 1270 default: |
| 1225 break; | 1271 break; |
| 1226 } | 1272 } |
| 1227 return Handle<Code>::null(); | 1273 |
| 1274 return slow_stub(); |
| 1228 } | 1275 } |
| 1229 | 1276 |
| 1230 | 1277 |
| 1231 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1278 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
| 1232 // This helper implements a few common fast cases for converting | 1279 // This helper implements a few common fast cases for converting |
| 1233 // non-smi keys of keyed loads/stores to a smi or a string. | 1280 // non-smi keys of keyed loads/stores to a smi or a string. |
| 1234 if (key->IsHeapNumber()) { | 1281 if (key->IsHeapNumber()) { |
| 1235 double value = Handle<HeapNumber>::cast(key)->value(); | 1282 double value = Handle<HeapNumber>::cast(key)->value(); |
| 1236 if (std::isnan(value)) { | 1283 if (std::isnan(value)) { |
| 1237 key = isolate->factory()->nan_string(); | 1284 key = isolate->factory()->nan_string(); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1311 } | 1358 } |
| 1312 | 1359 |
| 1313 | 1360 |
| 1314 MaybeObject* KeyedLoadIC::Load(Handle<Object> object, | 1361 MaybeObject* KeyedLoadIC::Load(Handle<Object> object, |
| 1315 Handle<Object> key, | 1362 Handle<Object> key, |
| 1316 ICMissMode miss_mode) { | 1363 ICMissMode miss_mode) { |
| 1317 if (MigrateDeprecated(object)) { | 1364 if (MigrateDeprecated(object)) { |
| 1318 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); | 1365 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
| 1319 } | 1366 } |
| 1320 | 1367 |
| 1368 MaybeObject* maybe_object = NULL; |
| 1369 Handle<Code> stub = generic_stub(); |
| 1370 |
| 1321 // Check for values that can be converted into an internalized string directly | 1371 // Check for values that can be converted into an internalized string directly |
| 1322 // or is representable as a smi. | 1372 // or is representable as a smi. |
| 1323 key = TryConvertKey(key, isolate()); | 1373 key = TryConvertKey(key, isolate()); |
| 1324 | 1374 |
| 1325 if (key->IsInternalizedString()) { | 1375 if (key->IsInternalizedString()) { |
| 1326 return LoadIC::Load(object, Handle<String>::cast(key)); | 1376 maybe_object = LoadIC::Load(object, Handle<String>::cast(key)); |
| 1377 if (maybe_object->IsFailure()) return maybe_object; |
| 1378 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { |
| 1379 ASSERT(!object->IsJSGlobalProxy()); |
| 1380 if (miss_mode != MISS_FORCE_GENERIC) { |
| 1381 if (object->IsString() && key->IsNumber()) { |
| 1382 if (state() == UNINITIALIZED) stub = string_stub(); |
| 1383 } else if (object->IsJSObject()) { |
| 1384 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1385 if (receiver->elements()->map() == |
| 1386 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 1387 stub = non_strict_arguments_stub(); |
| 1388 } else if (receiver->HasIndexedInterceptor()) { |
| 1389 stub = indexed_interceptor_stub(); |
| 1390 } else if (!key->ToSmi()->IsFailure() && |
| 1391 (!target().is_identical_to(non_strict_arguments_stub()))) { |
| 1392 stub = LoadElementStub(receiver); |
| 1393 } |
| 1394 } |
| 1395 } |
| 1327 } | 1396 } |
| 1328 | 1397 |
| 1329 if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { | 1398 if (!is_target_set()) { |
| 1330 ASSERT(!object->IsJSGlobalProxy()); | 1399 if (*stub == *generic_stub()) { |
| 1331 Handle<Code> stub = generic_stub(); | 1400 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic"); |
| 1332 if (miss_mode == MISS_FORCE_GENERIC) { | |
| 1333 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic"); | |
| 1334 } else if (object->IsString() && key->IsNumber()) { | |
| 1335 if (state() == UNINITIALIZED) stub = string_stub(); | |
| 1336 } else if (object->IsJSObject()) { | |
| 1337 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 1338 if (receiver->elements()->map() == | |
| 1339 isolate()->heap()->non_strict_arguments_elements_map()) { | |
| 1340 stub = non_strict_arguments_stub(); | |
| 1341 } else if (receiver->HasIndexedInterceptor()) { | |
| 1342 stub = indexed_interceptor_stub(); | |
| 1343 } else if (!key->ToSmi()->IsFailure() && | |
| 1344 (!target().is_identical_to(non_strict_arguments_stub()))) { | |
| 1345 stub = LoadElementStub(receiver); | |
| 1346 } | |
| 1347 } | 1401 } |
| 1348 | |
| 1349 ASSERT(!stub.is_null()); | 1402 ASSERT(!stub.is_null()); |
| 1350 set_target(*stub); | 1403 set_target(*stub); |
| 1351 TRACE_IC("LoadIC", key); | 1404 TRACE_IC("LoadIC", key); |
| 1352 } | 1405 } |
| 1353 | 1406 |
| 1354 | 1407 if (maybe_object != NULL) return maybe_object; |
| 1355 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); | 1408 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
| 1356 } | 1409 } |
| 1357 | 1410 |
| 1358 | 1411 |
| 1359 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, | |
| 1360 Handle<JSObject> receiver, | |
| 1361 Handle<String> name) { | |
| 1362 // Bail out if we didn't find a result. | |
| 1363 if (!lookup->IsProperty()) return Handle<Code>::null(); | |
| 1364 | |
| 1365 // Compute a monomorphic stub. | |
| 1366 Handle<JSObject> holder(lookup->holder(), isolate()); | |
| 1367 switch (lookup->type()) { | |
| 1368 case FIELD: | |
| 1369 return isolate()->stub_cache()->ComputeKeyedLoadField( | |
| 1370 name, receiver, holder, | |
| 1371 lookup->GetFieldIndex(), lookup->representation()); | |
| 1372 case CONSTANT: { | |
| 1373 Handle<Object> constant(lookup->GetConstant(), isolate()); | |
| 1374 // TODO(2803): Don't compute a stub for cons strings because they cannot | |
| 1375 // be embedded into code. | |
| 1376 if (constant->IsConsString()) return Handle<Code>::null(); | |
| 1377 return isolate()->stub_cache()->ComputeKeyedLoadConstant( | |
| 1378 name, receiver, holder, constant); | |
| 1379 } | |
| 1380 case CALLBACKS: { | |
| 1381 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate()); | |
| 1382 // TODO(dcarney): Handle DeclaredAccessorInfo correctly. | |
| 1383 if (callback_object->IsExecutableAccessorInfo()) { | |
| 1384 Handle<ExecutableAccessorInfo> callback = | |
| 1385 Handle<ExecutableAccessorInfo>::cast(callback_object); | |
| 1386 if (v8::ToCData<Address>(callback->getter()) == 0) break; | |
| 1387 if (!callback->IsCompatibleReceiver(*receiver)) break; | |
| 1388 return isolate()->stub_cache()->ComputeKeyedLoadCallback( | |
| 1389 name, receiver, holder, callback); | |
| 1390 } else if (callback_object->IsAccessorPair()) { | |
| 1391 Handle<Object> getter( | |
| 1392 Handle<AccessorPair>::cast(callback_object)->getter(), | |
| 1393 isolate()); | |
| 1394 if (!getter->IsJSFunction()) break; | |
| 1395 if (holder->IsGlobalObject()) break; | |
| 1396 if (!holder->HasFastProperties()) break; | |
| 1397 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | |
| 1398 CallOptimization call_optimization(function); | |
| 1399 if (call_optimization.is_simple_api_call() && | |
| 1400 call_optimization.IsCompatibleReceiver(*receiver)) { | |
| 1401 return isolate()->stub_cache()->ComputeKeyedLoadCallback( | |
| 1402 name, receiver, holder, call_optimization); | |
| 1403 } | |
| 1404 } | |
| 1405 break; | |
| 1406 } | |
| 1407 case INTERCEPTOR: | |
| 1408 ASSERT(HasInterceptorGetter(lookup->holder())); | |
| 1409 return isolate()->stub_cache()->ComputeKeyedLoadInterceptor( | |
| 1410 name, receiver, holder); | |
| 1411 default: | |
| 1412 // Always rewrite to the generic case so that we do not | |
| 1413 // repeatedly try to rewrite. | |
| 1414 return generic_stub(); | |
| 1415 } | |
| 1416 return Handle<Code>::null(); | |
| 1417 } | |
| 1418 | |
| 1419 | |
| 1420 static bool LookupForWrite(Handle<JSObject> receiver, | 1412 static bool LookupForWrite(Handle<JSObject> receiver, |
| 1421 Handle<String> name, | 1413 Handle<String> name, |
| 1422 Handle<Object> value, | 1414 Handle<Object> value, |
| 1423 LookupResult* lookup, | 1415 LookupResult* lookup, |
| 1424 IC* ic) { | 1416 IC* ic) { |
| 1425 Handle<JSObject> holder = receiver; | 1417 Handle<JSObject> holder = receiver; |
| 1426 receiver->Lookup(*name, lookup); | 1418 receiver->Lookup(*name, lookup); |
| 1427 if (lookup->IsFound()) { | 1419 if (lookup->IsFound()) { |
| 1428 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | 1420 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
| 1429 | 1421 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 void StoreIC::UpdateCaches(LookupResult* lookup, | 1587 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1596 Handle<JSObject> receiver, | 1588 Handle<JSObject> receiver, |
| 1597 Handle<String> name, | 1589 Handle<String> name, |
| 1598 Handle<Object> value) { | 1590 Handle<Object> value) { |
| 1599 ASSERT(!receiver->IsJSGlobalProxy()); | 1591 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1600 ASSERT(lookup->IsFound()); | 1592 ASSERT(lookup->IsFound()); |
| 1601 | 1593 |
| 1602 // These are not cacheable, so we never see such LookupResults here. | 1594 // These are not cacheable, so we never see such LookupResults here. |
| 1603 ASSERT(!lookup->IsHandler()); | 1595 ASSERT(!lookup->IsHandler()); |
| 1604 | 1596 |
| 1605 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); | 1597 Handle<Code> code = ComputeHandler(lookup, receiver, name, value); |
| 1606 if (code.is_null()) { | |
| 1607 set_target(*generic_stub()); | |
| 1608 return; | |
| 1609 } | |
| 1610 | 1598 |
| 1611 PatchCache(receiver, name, code); | 1599 PatchCache(receiver, name, code); |
| 1612 TRACE_IC("StoreIC", name); | 1600 TRACE_IC("StoreIC", name); |
| 1613 } | 1601 } |
| 1614 | 1602 |
| 1615 | 1603 |
| 1616 Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup, | 1604 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
| 1617 Handle<JSObject> receiver, | 1605 Handle<JSObject> receiver, |
| 1618 Handle<String> name, | 1606 Handle<String> name, |
| 1619 Handle<Object> value) { | 1607 Handle<Object> value) { |
| 1620 Handle<JSObject> holder(lookup->holder()); | 1608 Handle<JSObject> holder(lookup->holder()); |
| 1609 StoreStubCompiler compiler(isolate(), strict_mode(), kind()); |
| 1621 switch (lookup->type()) { | 1610 switch (lookup->type()) { |
| 1622 case FIELD: | 1611 case FIELD: |
| 1623 return isolate()->stub_cache()->ComputeStoreField( | 1612 return compiler.CompileStoreField(receiver, lookup, name); |
| 1624 name, receiver, lookup, strict_mode()); | 1613 case TRANSITION: { |
| 1614 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1615 // stored something else than the receiver in the holder. |
| 1616 Handle<Map> transition( |
| 1617 lookup->GetTransitionTarget(receiver->map()), isolate()); |
| 1618 int descriptor = transition->LastAdded(); |
| 1619 |
| 1620 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 1621 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 1622 |
| 1623 if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
| 1624 |
| 1625 return compiler.CompileStoreTransition( |
| 1626 receiver, lookup, transition, name); |
| 1627 } |
| 1625 case NORMAL: | 1628 case NORMAL: |
| 1629 if (kind() == Code::KEYED_STORE_IC) break; |
| 1626 if (receiver->IsGlobalObject()) { | 1630 if (receiver->IsGlobalObject()) { |
| 1627 // The stub generated for the global object picks the value directly | 1631 // The stub generated for the global object picks the value directly |
| 1628 // from the property cell. So the property must be directly on the | 1632 // from the property cell. So the property must be directly on the |
| 1629 // global object. | 1633 // global object. |
| 1630 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1634 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1631 Handle<PropertyCell> cell( | 1635 Handle<PropertyCell> cell( |
| 1632 global->GetPropertyCell(lookup), isolate()); | 1636 global->GetPropertyCell(lookup), isolate()); |
| 1637 // TODO(verwaest): Turn into a handler. |
| 1633 return isolate()->stub_cache()->ComputeStoreGlobal( | 1638 return isolate()->stub_cache()->ComputeStoreGlobal( |
| 1634 name, global, cell, value, strict_mode()); | 1639 name, global, cell, value, strict_mode()); |
| 1635 } | 1640 } |
| 1636 ASSERT(holder.is_identical_to(receiver)); | 1641 ASSERT(holder.is_identical_to(receiver)); |
| 1637 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode()); | 1642 return strict_mode() == kStrictMode |
| 1643 ? isolate()->builtins()->StoreIC_Normal_Strict() |
| 1644 : isolate()->builtins()->StoreIC_Normal(); |
| 1638 case CALLBACKS: { | 1645 case CALLBACKS: { |
| 1646 if (kind() == Code::KEYED_STORE_IC) break; |
| 1639 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1647 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1640 if (callback->IsExecutableAccessorInfo()) { | 1648 if (callback->IsExecutableAccessorInfo()) { |
| 1641 Handle<ExecutableAccessorInfo> info = | 1649 Handle<ExecutableAccessorInfo> info = |
| 1642 Handle<ExecutableAccessorInfo>::cast(callback); | 1650 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1643 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1651 if (v8::ToCData<Address>(info->setter()) == 0) break; |
| 1644 if (!holder->HasFastProperties()) break; | 1652 if (!holder->HasFastProperties()) break; |
| 1645 if (!info->IsCompatibleReceiver(*receiver)) break; | 1653 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1646 return isolate()->stub_cache()->ComputeStoreCallback( | 1654 return compiler.CompileStoreCallback(receiver, holder, name, info); |
| 1647 name, receiver, holder, info, strict_mode()); | |
| 1648 } else if (callback->IsAccessorPair()) { | 1655 } else if (callback->IsAccessorPair()) { |
| 1649 Handle<Object> setter( | 1656 Handle<Object> setter( |
| 1650 Handle<AccessorPair>::cast(callback)->setter(), isolate()); | 1657 Handle<AccessorPair>::cast(callback)->setter(), isolate()); |
| 1651 if (!setter->IsJSFunction()) break; | 1658 if (!setter->IsJSFunction()) break; |
| 1652 if (holder->IsGlobalObject()) break; | 1659 if (holder->IsGlobalObject()) break; |
| 1653 if (!holder->HasFastProperties()) break; | 1660 if (!holder->HasFastProperties()) break; |
| 1654 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); | 1661 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
| 1655 CallOptimization call_optimization(function); | 1662 CallOptimization call_optimization(function); |
| 1656 if (call_optimization.is_simple_api_call() && | 1663 if (call_optimization.is_simple_api_call() && |
| 1657 call_optimization.IsCompatibleReceiver(*receiver)) { | 1664 call_optimization.IsCompatibleReceiver(*receiver)) { |
| 1658 return isolate()->stub_cache()->ComputeStoreCallback( | 1665 return compiler.CompileStoreCallback( |
| 1659 name, receiver, holder, call_optimization, strict_mode()); | 1666 receiver, holder, name, call_optimization); |
| 1660 } | 1667 } |
| 1661 return isolate()->stub_cache()->ComputeStoreViaSetter( | 1668 return compiler.CompileStoreViaSetter( |
| 1662 name, receiver, holder, Handle<JSFunction>::cast(setter), | 1669 receiver, holder, name, Handle<JSFunction>::cast(setter)); |
| 1663 strict_mode()); | |
| 1664 } | 1670 } |
| 1665 // TODO(dcarney): Handle correctly. | 1671 // TODO(dcarney): Handle correctly. |
| 1666 if (callback->IsDeclaredAccessorInfo()) break; | 1672 if (callback->IsDeclaredAccessorInfo()) break; |
| 1667 ASSERT(callback->IsForeign()); | 1673 ASSERT(callback->IsForeign()); |
| 1668 // No IC support for old-style native accessors. | 1674 // No IC support for old-style native accessors. |
| 1669 break; | 1675 break; |
| 1670 } | 1676 } |
| 1671 case INTERCEPTOR: | 1677 case INTERCEPTOR: |
| 1678 if (kind() == Code::KEYED_STORE_IC) break; |
| 1672 ASSERT(HasInterceptorSetter(*receiver)); | 1679 ASSERT(HasInterceptorSetter(*receiver)); |
| 1673 return isolate()->stub_cache()->ComputeStoreInterceptor( | 1680 return compiler.CompileStoreInterceptor(receiver, name); |
| 1674 name, receiver, strict_mode()); | |
| 1675 case CONSTANT: | 1681 case CONSTANT: |
| 1676 break; | 1682 break; |
| 1677 case TRANSITION: { | |
| 1678 // Explicitly pass in the receiver map since LookupForWrite may have | |
| 1679 // stored something else than the receiver in the holder. | |
| 1680 Handle<Map> transition( | |
| 1681 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
| 1682 int descriptor = transition->LastAdded(); | |
| 1683 | |
| 1684 DescriptorArray* target_descriptors = transition->instance_descriptors(); | |
| 1685 PropertyDetails details = target_descriptors->GetDetails(descriptor); | |
| 1686 | |
| 1687 if (details.type() == CALLBACKS || details.attributes() != NONE) break; | |
| 1688 | |
| 1689 return isolate()->stub_cache()->ComputeStoreTransition( | |
| 1690 name, receiver, lookup, transition, strict_mode()); | |
| 1691 } | |
| 1692 case NONEXISTENT: | 1683 case NONEXISTENT: |
| 1693 case HANDLER: | 1684 case HANDLER: |
| 1694 UNREACHABLE(); | 1685 UNREACHABLE(); |
| 1695 break; | 1686 break; |
| 1696 } | 1687 } |
| 1697 return Handle<Code>::null(); | 1688 return slow_stub(); |
| 1698 } | 1689 } |
| 1699 | 1690 |
| 1700 | 1691 |
| 1701 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 1692 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, |
| 1702 KeyedAccessStoreMode store_mode) { | 1693 KeyedAccessStoreMode store_mode) { |
| 1703 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1694 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
| 1704 // via megamorphic stubs, since they don't have a map in their relocation info | 1695 // via megamorphic stubs, since they don't have a map in their relocation info |
| 1705 // and so the stubs can't be harvested for the object needed for a map check. | 1696 // and so the stubs can't be harvested for the object needed for a map check. |
| 1706 if (target()->type() != Code::NORMAL) { | 1697 if (target()->type() != Code::NORMAL) { |
| 1707 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); | 1698 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1946 ICMissMode miss_mode) { | 1937 ICMissMode miss_mode) { |
| 1947 if (MigrateDeprecated(object)) { | 1938 if (MigrateDeprecated(object)) { |
| 1948 return Runtime::SetObjectPropertyOrFail( | 1939 return Runtime::SetObjectPropertyOrFail( |
| 1949 isolate(), object , key, value, NONE, strict_mode()); | 1940 isolate(), object , key, value, NONE, strict_mode()); |
| 1950 } | 1941 } |
| 1951 | 1942 |
| 1952 // Check for values that can be converted into an internalized string directly | 1943 // Check for values that can be converted into an internalized string directly |
| 1953 // or is representable as a smi. | 1944 // or is representable as a smi. |
| 1954 key = TryConvertKey(key, isolate()); | 1945 key = TryConvertKey(key, isolate()); |
| 1955 | 1946 |
| 1947 MaybeObject* maybe_object = NULL; |
| 1948 Handle<Code> stub = generic_stub(); |
| 1949 |
| 1956 if (key->IsInternalizedString()) { | 1950 if (key->IsInternalizedString()) { |
| 1957 return StoreIC::Store(object, | 1951 maybe_object = StoreIC::Store(object, |
| 1958 Handle<String>::cast(key), | 1952 Handle<String>::cast(key), |
| 1959 value, | 1953 value, |
| 1960 JSReceiver::MAY_BE_STORE_FROM_KEYED); | 1954 JSReceiver::MAY_BE_STORE_FROM_KEYED); |
| 1955 if (maybe_object->IsFailure()) return maybe_object; |
| 1956 } else { |
| 1957 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && |
| 1958 !(FLAG_harmony_observation && object->IsJSObject() && |
| 1959 JSObject::cast(*object)->map()->is_observed()); |
| 1960 if (use_ic && !object->IsSmi()) { |
| 1961 // Don't use ICs for maps of the objects in Array's prototype chain. We |
| 1962 // expect to be able to trap element sets to objects with those maps in |
| 1963 // the runtime to enable optimization of element hole access. |
| 1964 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); |
| 1965 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; |
| 1966 } |
| 1967 |
| 1968 if (use_ic) { |
| 1969 ASSERT(!object->IsJSGlobalProxy()); |
| 1970 |
| 1971 if (miss_mode != MISS_FORCE_GENERIC) { |
| 1972 if (object->IsJSObject()) { |
| 1973 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1974 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); |
| 1975 if (receiver->elements()->map() == |
| 1976 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 1977 stub = non_strict_arguments_stub(); |
| 1978 } else if (key_is_smi_like && |
| 1979 (!target().is_identical_to(non_strict_arguments_stub()))) { |
| 1980 KeyedAccessStoreMode store_mode = |
| 1981 GetStoreMode(receiver, key, value); |
| 1982 stub = StoreElementStub(receiver, store_mode); |
| 1983 } |
| 1984 } |
| 1985 } |
| 1986 } |
| 1961 } | 1987 } |
| 1962 | 1988 |
| 1963 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && | 1989 if (!is_target_set()) { |
| 1964 !(FLAG_harmony_observation && object->IsJSObject() && | 1990 if (*stub == *generic_stub()) { |
| 1965 JSObject::cast(*object)->map()->is_observed()); | 1991 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); |
| 1966 if (use_ic && !object->IsSmi()) { | |
| 1967 // Don't use ICs for maps of the objects in Array's prototype chain. We | |
| 1968 // expect to be able to trap element sets to objects with those maps in the | |
| 1969 // runtime to enable optimization of element hole access. | |
| 1970 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); | |
| 1971 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; | |
| 1972 } | |
| 1973 | |
| 1974 if (use_ic) { | |
| 1975 ASSERT(!object->IsJSGlobalProxy()); | |
| 1976 | |
| 1977 Handle<Code> stub = generic_stub(); | |
| 1978 if (miss_mode != MISS_FORCE_GENERIC) { | |
| 1979 if (object->IsJSObject()) { | |
| 1980 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 1981 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); | |
| 1982 if (receiver->elements()->map() == | |
| 1983 isolate()->heap()->non_strict_arguments_elements_map()) { | |
| 1984 stub = non_strict_arguments_stub(); | |
| 1985 } else if (key_is_smi_like && | |
| 1986 (!target().is_identical_to(non_strict_arguments_stub()))) { | |
| 1987 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); | |
| 1988 stub = StoreElementStub(receiver, store_mode); | |
| 1989 } else { | |
| 1990 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number"); | |
| 1991 } | |
| 1992 } else { | |
| 1993 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object"); | |
| 1994 } | |
| 1995 } else { | |
| 1996 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic"); | |
| 1997 } | 1992 } |
| 1998 ASSERT(!stub.is_null()); | 1993 ASSERT(!stub.is_null()); |
| 1999 set_target(*stub); | 1994 set_target(*stub); |
| 2000 TRACE_IC("StoreIC", key); | 1995 TRACE_IC("StoreIC", key); |
| 2001 } | 1996 } |
| 2002 | 1997 |
| 1998 if (maybe_object) return maybe_object; |
| 2003 return Runtime::SetObjectPropertyOrFail( | 1999 return Runtime::SetObjectPropertyOrFail( |
| 2004 isolate(), object , key, value, NONE, strict_mode()); | 2000 isolate(), object , key, value, NONE, strict_mode()); |
| 2005 } | 2001 } |
| 2006 | 2002 |
| 2007 | 2003 |
| 2008 Handle<Code> KeyedStoreIC::ComputeStoreHandler(LookupResult* lookup, | |
| 2009 Handle<JSObject> receiver, | |
| 2010 Handle<String> name, | |
| 2011 Handle<Object> value) { | |
| 2012 // If the property has a non-field type allowing map transitions | |
| 2013 // where there is extra room in the object, we leave the IC in its | |
| 2014 // current state. | |
| 2015 switch (lookup->type()) { | |
| 2016 case FIELD: | |
| 2017 return isolate()->stub_cache()->ComputeKeyedStoreField( | |
| 2018 name, receiver, lookup, strict_mode()); | |
| 2019 case TRANSITION: { | |
| 2020 // Explicitly pass in the receiver map since LookupForWrite may have | |
| 2021 // stored something else than the receiver in the holder. | |
| 2022 Handle<Map> transition( | |
| 2023 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
| 2024 int descriptor = transition->LastAdded(); | |
| 2025 | |
| 2026 DescriptorArray* target_descriptors = transition->instance_descriptors(); | |
| 2027 PropertyDetails details = target_descriptors->GetDetails(descriptor); | |
| 2028 | |
| 2029 if (details.type() != CALLBACKS && details.attributes() == NONE) { | |
| 2030 return isolate()->stub_cache()->ComputeKeyedStoreTransition( | |
| 2031 name, receiver, lookup, transition, strict_mode()); | |
| 2032 } | |
| 2033 // fall through. | |
| 2034 } | |
| 2035 case NORMAL: | |
| 2036 case CONSTANT: | |
| 2037 case CALLBACKS: | |
| 2038 case INTERCEPTOR: | |
| 2039 // Always rewrite to the generic case so that we do not | |
| 2040 // repeatedly try to rewrite. | |
| 2041 return generic_stub(); | |
| 2042 case HANDLER: | |
| 2043 case NONEXISTENT: | |
| 2044 UNREACHABLE(); | |
| 2045 break; | |
| 2046 } | |
| 2047 return Handle<Code>::null(); | |
| 2048 } | |
| 2049 | |
| 2050 | |
| 2051 #undef TRACE_IC | 2004 #undef TRACE_IC |
| 2052 | 2005 |
| 2053 | 2006 |
| 2054 // ---------------------------------------------------------------------------- | 2007 // ---------------------------------------------------------------------------- |
| 2055 // Static IC stub generators. | 2008 // Static IC stub generators. |
| 2056 // | 2009 // |
| 2057 | 2010 |
| 2058 // Used from ic-<arch>.cc. | 2011 // Used from ic-<arch>.cc. |
| 2059 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { | 2012 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { |
| 2060 HandleScope scope(isolate); | 2013 HandleScope scope(isolate); |
| (...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2773 #undef ADDR | 2726 #undef ADDR |
| 2774 }; | 2727 }; |
| 2775 | 2728 |
| 2776 | 2729 |
| 2777 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2730 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2778 return IC_utilities[id]; | 2731 return IC_utilities[id]; |
| 2779 } | 2732 } |
| 2780 | 2733 |
| 2781 | 2734 |
| 2782 } } // namespace v8::internal | 2735 } } // namespace v8::internal |
| OLD | NEW |