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

Side by Side Diff: src/ic.cc

Issue 39973003: Merge bleeding_edge. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: again Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/isolate.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // 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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/isolate.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698