• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "accessors.h"
31 #include "api.h"
32 #include "arguments.h"
33 #include "execution.h"
34 #include "ic-inl.h"
35 #include "runtime.h"
36 #include "stub-cache.h"
37 
38 namespace v8 {
39 namespace internal {
40 
41 #ifdef DEBUG
TransitionMarkFromState(IC::State state)42 static char TransitionMarkFromState(IC::State state) {
43   switch (state) {
44     case UNINITIALIZED: return '0';
45     case PREMONOMORPHIC: return 'P';
46     case MONOMORPHIC: return '1';
47     case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
48     case MEGAMORPHIC: return 'N';
49 
50     // We never see the debugger states here, because the state is
51     // computed from the original code - not the patched code. Let
52     // these cases fall through to the unreachable code below.
53     case DEBUG_BREAK: break;
54     case DEBUG_PREPARE_STEP_IN: break;
55   }
56   UNREACHABLE();
57   return 0;
58 }
59 
TraceIC(const char * type,Handle<String> name,State old_state,Code * new_target,const char * extra_info)60 void IC::TraceIC(const char* type,
61                  Handle<String> name,
62                  State old_state,
63                  Code* new_target,
64                  const char* extra_info) {
65   if (FLAG_trace_ic) {
66     State new_state = StateFrom(new_target, Heap::undefined_value());
67     PrintF("[%s (%c->%c)%s", type,
68            TransitionMarkFromState(old_state),
69            TransitionMarkFromState(new_state),
70            extra_info);
71     name->Print();
72     PrintF("]\n");
73   }
74 }
75 #endif
76 
77 
IC(FrameDepth depth)78 IC::IC(FrameDepth depth) {
79   // To improve the performance of the (much used) IC code, we unfold
80   // a few levels of the stack frame iteration code. This yields a
81   // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.
82   const Address entry = Top::c_entry_fp(Top::GetCurrentThread());
83   Address* pc_address =
84       reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
85   Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
86   // If there's another JavaScript frame on the stack, we need to look
87   // one frame further down the stack to find the frame pointer and
88   // the return address stack slot.
89   if (depth == EXTRA_CALL_FRAME) {
90     const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
91     pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
92     fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
93   }
94 #ifdef DEBUG
95   StackFrameIterator it;
96   for (int i = 0; i < depth + 1; i++) it.Advance();
97   StackFrame* frame = it.frame();
98   ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
99 #endif
100   fp_ = fp;
101   pc_address_ = pc_address;
102 }
103 
104 
105 #ifdef ENABLE_DEBUGGER_SUPPORT
OriginalCodeAddress()106 Address IC::OriginalCodeAddress() {
107   HandleScope scope;
108   // Compute the JavaScript frame for the frame pointer of this IC
109   // structure. We need this to be able to find the function
110   // corresponding to the frame.
111   StackFrameIterator it;
112   while (it.frame()->fp() != this->fp()) it.Advance();
113   JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
114   // Find the function on the stack and both the active code for the
115   // function and the original code.
116   JSFunction* function = JSFunction::cast(frame->function());
117   Handle<SharedFunctionInfo> shared(function->shared());
118   Code* code = shared->code();
119   ASSERT(Debug::HasDebugInfo(shared));
120   Code* original_code = Debug::GetDebugInfo(shared)->original_code();
121   ASSERT(original_code->IsCode());
122   // Get the address of the call site in the active code. This is the
123   // place where the call to DebugBreakXXX is and where the IC
124   // normally would be.
125   Address addr = pc() - Assembler::kPatchReturnSequenceLength;
126   // Return the address in the original code. This is the place where
127   // the call which has been overwritten by the DebugBreakXXX resides
128   // and the place where the inline cache system should look.
129   int delta = original_code->instruction_start() - code->instruction_start();
130   return addr + delta;
131 }
132 #endif
133 
StateFrom(Code * target,Object * receiver)134 IC::State IC::StateFrom(Code* target, Object* receiver) {
135   IC::State state = target->ic_state();
136 
137   if (state != MONOMORPHIC) return state;
138   if (receiver->IsUndefined() || receiver->IsNull()) return state;
139 
140   Map* map = GetCodeCacheMapForObject(receiver);
141 
142   // Decide whether the inline cache failed because of changes to the
143   // receiver itself or changes to one of its prototypes.
144   //
145   // If there are changes to the receiver itself, the map of the
146   // receiver will have changed and the current target will not be in
147   // the receiver map's code cache.  Therefore, if the current target
148   // is in the receiver map's code cache, the inline cache failed due
149   // to prototype check failure.
150   int index = map->IndexInCodeCache(target);
151   if (index >= 0) {
152     // For keyed load/store, the most likely cause of cache failure is
153     // that the key has changed.  We do not distinguish between
154     // prototype and non-prototype failures for keyed access.
155     Code::Kind kind = target->kind();
156     if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) {
157       return MONOMORPHIC;
158     }
159 
160     // Remove the target from the code cache to avoid hitting the same
161     // invalid stub again.
162     map->RemoveFromCodeCache(index);
163 
164     return MONOMORPHIC_PROTOTYPE_FAILURE;
165   }
166 
167   // The builtins object is special.  It only changes when JavaScript
168   // builtins are loaded lazily.  It is important to keep inline
169   // caches for the builtins object monomorphic.  Therefore, if we get
170   // an inline cache miss for the builtins object after lazily loading
171   // JavaScript builtins, we return uninitialized as the state to
172   // force the inline cache back to monomorphic state.
173   if (receiver->IsJSBuiltinsObject()) {
174     return UNINITIALIZED;
175   }
176 
177   return MONOMORPHIC;
178 }
179 
180 
ComputeMode()181 RelocInfo::Mode IC::ComputeMode() {
182   Address addr = address();
183   Code* code = Code::cast(Heap::FindCodeObject(addr));
184   for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
185        !it.done(); it.next()) {
186     RelocInfo* info = it.rinfo();
187     if (info->pc() == addr) return info->rmode();
188   }
189   UNREACHABLE();
190   return RelocInfo::NONE;
191 }
192 
193 
TypeError(const char * type,Handle<Object> object,Handle<String> name)194 Failure* IC::TypeError(const char* type,
195                        Handle<Object> object,
196                        Handle<String> name) {
197   HandleScope scope;
198   Handle<Object> args[2] = { name, object };
199   Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2));
200   return Top::Throw(*error);
201 }
202 
203 
ReferenceError(const char * type,Handle<String> name)204 Failure* IC::ReferenceError(const char* type, Handle<String> name) {
205   HandleScope scope;
206   Handle<Object> error =
207       Factory::NewReferenceError(type, HandleVector(&name, 1));
208   return Top::Throw(*error);
209 }
210 
211 
Clear(Address address)212 void IC::Clear(Address address) {
213   Code* target = GetTargetAtAddress(address);
214 
215   // Don't clear debug break inline cache as it will remove the break point.
216   if (target->ic_state() == DEBUG_BREAK) return;
217 
218   switch (target->kind()) {
219     case Code::LOAD_IC: return LoadIC::Clear(address, target);
220     case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
221     case Code::STORE_IC: return StoreIC::Clear(address, target);
222     case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
223     case Code::CALL_IC: return CallIC::Clear(address, target);
224     default: UNREACHABLE();
225   }
226 }
227 
228 
Clear(Address address,Code * target)229 void CallIC::Clear(Address address, Code* target) {
230   State state = target->ic_state();
231   InLoopFlag in_loop = target->ic_in_loop();
232   if (state == UNINITIALIZED) return;
233   Code* code =
234       StubCache::FindCallInitialize(target->arguments_count(), in_loop);
235   SetTargetAtAddress(address, code);
236 }
237 
238 
Clear(Address address,Code * target)239 void KeyedLoadIC::Clear(Address address, Code* target) {
240   if (target->ic_state() == UNINITIALIZED) return;
241   // Make sure to also clear the map used in inline fast cases.  If we
242   // do not clear these maps, cached code can keep objects alive
243   // through the embedded maps.
244   ClearInlinedVersion(address);
245   SetTargetAtAddress(address, initialize_stub());
246 }
247 
248 
Clear(Address address,Code * target)249 void LoadIC::Clear(Address address, Code* target) {
250   if (target->ic_state() == UNINITIALIZED) return;
251   ClearInlinedVersion(address);
252   SetTargetAtAddress(address, initialize_stub());
253 }
254 
255 
Clear(Address address,Code * target)256 void StoreIC::Clear(Address address, Code* target) {
257   if (target->ic_state() == UNINITIALIZED) return;
258   SetTargetAtAddress(address, initialize_stub());
259 }
260 
261 
Clear(Address address,Code * target)262 void KeyedStoreIC::Clear(Address address, Code* target) {
263   if (target->ic_state() == UNINITIALIZED) return;
264   SetTargetAtAddress(address, initialize_stub());
265 }
266 
267 
HasInterceptorGetter(JSObject * object)268 static bool HasInterceptorGetter(JSObject* object) {
269   return !object->GetNamedInterceptor()->getter()->IsUndefined();
270 }
271 
272 
LookupForRead(Object * object,String * name,LookupResult * lookup)273 static void LookupForRead(Object* object,
274                           String* name,
275                           LookupResult* lookup) {
276   AssertNoAllocation no_gc;  // pointers must stay valid
277 
278   // Skip all the objects with named interceptors, but
279   // without actual getter.
280   while (true) {
281     object->Lookup(name, lookup);
282     // Besides normal conditions (property not found or it's not
283     // an interceptor), bail out of lookup is not cacheable: we won't
284     // be able to IC it anyway and regular lookup should work fine.
285     if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR ||
286         !lookup->IsCacheable()) {
287       return;
288     }
289 
290     JSObject* holder = lookup->holder();
291     if (HasInterceptorGetter(holder)) {
292       return;
293     }
294 
295     holder->LocalLookupRealNamedProperty(name, lookup);
296     if (lookup->IsValid()) {
297       ASSERT(lookup->type() != INTERCEPTOR);
298       return;
299     }
300 
301     Object* proto = holder->GetPrototype();
302     if (proto->IsNull()) {
303       lookup->NotFound();
304       return;
305     }
306 
307     object = proto;
308   }
309 }
310 
311 
TryCallAsFunction(Object * object)312 Object* CallIC::TryCallAsFunction(Object* object) {
313   HandleScope scope;
314   Handle<Object> target(object);
315   Handle<Object> delegate = Execution::GetFunctionDelegate(target);
316 
317   if (delegate->IsJSFunction()) {
318     // Patch the receiver and use the delegate as the function to
319     // invoke. This is used for invoking objects as if they were
320     // functions.
321     const int argc = this->target()->arguments_count();
322     StackFrameLocator locator;
323     JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
324     int index = frame->ComputeExpressionsCount() - (argc + 1);
325     frame->SetExpression(index, *target);
326   }
327 
328   return *delegate;
329 }
330 
331 
LoadFunction(State state,Handle<Object> object,Handle<String> name)332 Object* CallIC::LoadFunction(State state,
333                              Handle<Object> object,
334                              Handle<String> name) {
335   // If the object is undefined or null it's illegal to try to get any
336   // of its properties; throw a TypeError in that case.
337   if (object->IsUndefined() || object->IsNull()) {
338     return TypeError("non_object_property_call", object, name);
339   }
340 
341   // Check if the name is trivially convertible to an index and get
342   // the element if so.
343   uint32_t index;
344   if (name->AsArrayIndex(&index)) {
345     Object* result = object->GetElement(index);
346     if (result->IsJSFunction()) return result;
347 
348     // Try to find a suitable function delegate for the object at hand.
349     result = TryCallAsFunction(result);
350     if (result->IsJSFunction()) return result;
351 
352     // Otherwise, it will fail in the lookup step.
353   }
354 
355   // Lookup the property in the object.
356   LookupResult lookup;
357   LookupForRead(*object, *name, &lookup);
358 
359   if (!lookup.IsValid()) {
360     // If the object does not have the requested property, check which
361     // exception we need to throw.
362     if (is_contextual()) {
363       return ReferenceError("not_defined", name);
364     }
365     return TypeError("undefined_method", object, name);
366   }
367 
368   // Lookup is valid: Update inline cache and stub cache.
369   if (FLAG_use_ic && lookup.IsLoaded()) {
370     UpdateCaches(&lookup, state, object, name);
371   }
372 
373   // Get the property.
374   PropertyAttributes attr;
375   Object* result = object->GetProperty(*object, &lookup, *name, &attr);
376   if (result->IsFailure()) return result;
377   if (lookup.type() == INTERCEPTOR) {
378     // If the object does not have the requested property, check which
379     // exception we need to throw.
380     if (attr == ABSENT) {
381       if (is_contextual()) {
382         return ReferenceError("not_defined", name);
383       }
384       return TypeError("undefined_method", object, name);
385     }
386   }
387 
388   ASSERT(result != Heap::the_hole_value());
389 
390   if (result->IsJSFunction()) {
391     // Check if there is an optimized (builtin) version of the function.
392     // Ignored this will degrade performance for Array.prototype.{push,pop}.
393     // Please note we only return the optimized function iff
394     // the JSObject has FastElements.
395     if (object->IsJSObject() && JSObject::cast(*object)->HasFastElements()) {
396       Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object),
397                                                lookup.holder(),
398                                                JSFunction::cast(result));
399       if (opt->IsJSFunction()) return opt;
400     }
401 
402 #ifdef ENABLE_DEBUGGER_SUPPORT
403     // Handle stepping into a function if step into is active.
404     if (Debug::StepInActive()) {
405       // Protect the result in a handle as the debugger can allocate and might
406       // cause GC.
407       HandleScope scope;
408       Handle<JSFunction> function(JSFunction::cast(result));
409       Debug::HandleStepIn(function, object, fp(), false);
410       return *function;
411     }
412 #endif
413 
414     return result;
415   }
416 
417   // Try to find a suitable function delegate for the object at hand.
418   result = TryCallAsFunction(result);
419   return result->IsJSFunction() ?
420       result : TypeError("property_not_function", object, name);
421 }
422 
423 
UpdateCaches(LookupResult * lookup,State state,Handle<Object> object,Handle<String> name)424 void CallIC::UpdateCaches(LookupResult* lookup,
425                           State state,
426                           Handle<Object> object,
427                           Handle<String> name) {
428   ASSERT(lookup->IsLoaded());
429   // Bail out if we didn't find a result.
430   if (!lookup->IsValid() || !lookup->IsCacheable()) return;
431 
432   // Compute the number of arguments.
433   int argc = target()->arguments_count();
434   InLoopFlag in_loop = target()->ic_in_loop();
435   Object* code = NULL;
436 
437   if (state == UNINITIALIZED) {
438     // This is the first time we execute this inline cache.
439     // Set the target to the pre monomorphic stub to delay
440     // setting the monomorphic state.
441     code = StubCache::ComputeCallPreMonomorphic(argc, in_loop);
442   } else if (state == MONOMORPHIC) {
443     code = StubCache::ComputeCallMegamorphic(argc, in_loop);
444   } else {
445     // Compute monomorphic stub.
446     switch (lookup->type()) {
447       case FIELD: {
448         int index = lookup->GetFieldIndex();
449         code = StubCache::ComputeCallField(argc, in_loop, *name, *object,
450                                            lookup->holder(), index);
451         break;
452       }
453       case CONSTANT_FUNCTION: {
454         // Get the constant function and compute the code stub for this
455         // call; used for rewriting to monomorphic state and making sure
456         // that the code stub is in the stub cache.
457         JSFunction* function = lookup->GetConstantFunction();
458         code = StubCache::ComputeCallConstant(argc, in_loop, *name, *object,
459                                               lookup->holder(), function);
460         break;
461       }
462       case NORMAL: {
463         if (!object->IsJSObject()) return;
464         Handle<JSObject> receiver = Handle<JSObject>::cast(object);
465 
466         if (lookup->holder()->IsGlobalObject()) {
467           GlobalObject* global = GlobalObject::cast(lookup->holder());
468           JSGlobalPropertyCell* cell =
469               JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
470           if (!cell->value()->IsJSFunction()) return;
471           JSFunction* function = JSFunction::cast(cell->value());
472           code = StubCache::ComputeCallGlobal(argc,
473                                               in_loop,
474                                               *name,
475                                               *receiver,
476                                               global,
477                                               cell,
478                                               function);
479         } else {
480           // There is only one shared stub for calling normalized
481           // properties. It does not traverse the prototype chain, so the
482           // property must be found in the receiver for the stub to be
483           // applicable.
484           if (lookup->holder() != *receiver) return;
485           code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver);
486         }
487         break;
488       }
489       case INTERCEPTOR: {
490         ASSERT(HasInterceptorGetter(lookup->holder()));
491         code = StubCache::ComputeCallInterceptor(argc, *name, *object,
492                                                  lookup->holder());
493         break;
494       }
495       default:
496         return;
497     }
498   }
499 
500   // If we're unable to compute the stub (not enough memory left), we
501   // simply avoid updating the caches.
502   if (code == NULL || code->IsFailure()) return;
503 
504   // Patch the call site depending on the state of the cache.
505   if (state == UNINITIALIZED ||
506       state == PREMONOMORPHIC ||
507       state == MONOMORPHIC ||
508       state == MONOMORPHIC_PROTOTYPE_FAILURE) {
509     set_target(Code::cast(code));
510   }
511 
512 #ifdef DEBUG
513   TraceIC("CallIC", name, state, target(), in_loop ? " (in-loop)" : "");
514 #endif
515 }
516 
517 
Load(State state,Handle<Object> object,Handle<String> name)518 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
519   // If the object is undefined or null it's illegal to try to get any
520   // of its properties; throw a TypeError in that case.
521   if (object->IsUndefined() || object->IsNull()) {
522     return TypeError("non_object_property_load", object, name);
523   }
524 
525   if (FLAG_use_ic) {
526     // Use specialized code for getting the length of strings and
527     // string wrapper objects.  The length property of string wrapper
528     // objects is read-only and therefore always returns the length of
529     // the underlying string value.  See ECMA-262 15.5.5.1.
530     if ((object->IsString() || object->IsStringWrapper()) &&
531         name->Equals(Heap::length_symbol())) {
532       HandleScope scope;
533       // Get the string if we have a string wrapper object.
534       if (object->IsJSValue()) {
535         object = Handle<Object>(Handle<JSValue>::cast(object)->value());
536       }
537 #ifdef DEBUG
538       if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
539 #endif
540       Code* target = NULL;
541       target = Builtins::builtin(Builtins::LoadIC_StringLength);
542       set_target(target);
543       StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
544       return Smi::FromInt(String::cast(*object)->length());
545     }
546 
547     // Use specialized code for getting the length of arrays.
548     if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
549 #ifdef DEBUG
550       if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
551 #endif
552       Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength);
553       set_target(target);
554       StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
555       return JSArray::cast(*object)->length();
556     }
557 
558     // Use specialized code for getting prototype of functions.
559     if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
560 #ifdef DEBUG
561       if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
562 #endif
563       Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype);
564       set_target(target);
565       StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
566       return Accessors::FunctionGetPrototype(*object, 0);
567     }
568   }
569 
570   // Check if the name is trivially convertible to an index and get
571   // the element if so.
572   uint32_t index;
573   if (name->AsArrayIndex(&index)) return object->GetElement(index);
574 
575   // Named lookup in the object.
576   LookupResult lookup;
577   LookupForRead(*object, *name, &lookup);
578 
579   // If lookup is invalid, check if we need to throw an exception.
580   if (!lookup.IsValid()) {
581     if (FLAG_strict || is_contextual()) {
582       return ReferenceError("not_defined", name);
583     }
584     LOG(SuspectReadEvent(*name, *object));
585   }
586 
587   bool can_be_inlined =
588       FLAG_use_ic &&
589       state == PREMONOMORPHIC &&
590       lookup.IsValid() &&
591       lookup.IsLoaded() &&
592       lookup.IsCacheable() &&
593       lookup.holder() == *object &&
594       lookup.type() == FIELD &&
595       !object->IsAccessCheckNeeded();
596 
597   if (can_be_inlined) {
598     Map* map = lookup.holder()->map();
599     // Property's index in the properties array.  If negative we have
600     // an inobject property.
601     int index = lookup.GetFieldIndex() - map->inobject_properties();
602     if (index < 0) {
603       // Index is an offset from the end of the object.
604       int offset = map->instance_size() + (index * kPointerSize);
605       if (PatchInlinedLoad(address(), map, offset)) {
606         set_target(megamorphic_stub());
607         return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
608       }
609     }
610   }
611 
612   // Update inline cache and stub cache.
613   if (FLAG_use_ic && lookup.IsLoaded()) {
614     UpdateCaches(&lookup, state, object, name);
615   }
616 
617   PropertyAttributes attr;
618   if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
619     // Get the property.
620     Object* result = object->GetProperty(*object, &lookup, *name, &attr);
621     if (result->IsFailure()) return result;
622     // If the property is not present, check if we need to throw an
623     // exception.
624     if (attr == ABSENT && is_contextual()) {
625       return ReferenceError("not_defined", name);
626     }
627     return result;
628   }
629 
630   // Get the property.
631   return object->GetProperty(*object, &lookup, *name, &attr);
632 }
633 
634 
UpdateCaches(LookupResult * lookup,State state,Handle<Object> object,Handle<String> name)635 void LoadIC::UpdateCaches(LookupResult* lookup,
636                           State state,
637                           Handle<Object> object,
638                           Handle<String> name) {
639   ASSERT(lookup->IsLoaded());
640   // Bail out if we didn't find a result.
641   if (!lookup->IsValid() || !lookup->IsCacheable()) return;
642 
643   // Loading properties from values is not common, so don't try to
644   // deal with non-JS objects here.
645   if (!object->IsJSObject()) return;
646   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
647 
648   // Compute the code stub for this load.
649   Object* code = NULL;
650   if (state == UNINITIALIZED) {
651     // This is the first time we execute this inline cache.
652     // Set the target to the pre monomorphic stub to delay
653     // setting the monomorphic state.
654     code = pre_monomorphic_stub();
655   } else {
656     // Compute monomorphic stub.
657     switch (lookup->type()) {
658       case FIELD: {
659         code = StubCache::ComputeLoadField(*name, *receiver,
660                                            lookup->holder(),
661                                            lookup->GetFieldIndex());
662         break;
663       }
664       case CONSTANT_FUNCTION: {
665         Object* constant = lookup->GetConstantFunction();
666         code = StubCache::ComputeLoadConstant(*name, *receiver,
667                                               lookup->holder(), constant);
668         break;
669       }
670       case NORMAL: {
671         if (lookup->holder()->IsGlobalObject()) {
672           GlobalObject* global = GlobalObject::cast(lookup->holder());
673           JSGlobalPropertyCell* cell =
674               JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
675           code = StubCache::ComputeLoadGlobal(*name,
676                                               *receiver,
677                                               global,
678                                               cell,
679                                               lookup->IsDontDelete());
680         } else {
681           // There is only one shared stub for loading normalized
682           // properties. It does not traverse the prototype chain, so the
683           // property must be found in the receiver for the stub to be
684           // applicable.
685           if (lookup->holder() != *receiver) return;
686           code = StubCache::ComputeLoadNormal(*name, *receiver);
687         }
688         break;
689       }
690       case CALLBACKS: {
691         if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
692         AccessorInfo* callback =
693             AccessorInfo::cast(lookup->GetCallbackObject());
694         if (v8::ToCData<Address>(callback->getter()) == 0) return;
695         code = StubCache::ComputeLoadCallback(*name, *receiver,
696                                               lookup->holder(), callback);
697         break;
698       }
699       case INTERCEPTOR: {
700         ASSERT(HasInterceptorGetter(lookup->holder()));
701         code = StubCache::ComputeLoadInterceptor(*name, *receiver,
702                                                  lookup->holder());
703         break;
704       }
705       default:
706         return;
707     }
708   }
709 
710   // If we're unable to compute the stub (not enough memory left), we
711   // simply avoid updating the caches.
712   if (code == NULL || code->IsFailure()) return;
713 
714   // Patch the call site depending on the state of the cache.
715   if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
716       state == MONOMORPHIC_PROTOTYPE_FAILURE) {
717     set_target(Code::cast(code));
718   } else if (state == MONOMORPHIC) {
719     set_target(megamorphic_stub());
720   }
721 
722 #ifdef DEBUG
723   TraceIC("LoadIC", name, state, target());
724 #endif
725 }
726 
727 
Load(State state,Handle<Object> object,Handle<Object> key)728 Object* KeyedLoadIC::Load(State state,
729                           Handle<Object> object,
730                           Handle<Object> key) {
731   if (key->IsSymbol()) {
732     Handle<String> name = Handle<String>::cast(key);
733 
734     // If the object is undefined or null it's illegal to try to get any
735     // of its properties; throw a TypeError in that case.
736     if (object->IsUndefined() || object->IsNull()) {
737       return TypeError("non_object_property_load", object, name);
738     }
739 
740     if (FLAG_use_ic) {
741       // Use specialized code for getting the length of strings.
742       if (object->IsString() && name->Equals(Heap::length_symbol())) {
743         Handle<String> string = Handle<String>::cast(object);
744         Object* code = NULL;
745         code = StubCache::ComputeKeyedLoadStringLength(*name, *string);
746         if (code->IsFailure()) return code;
747         set_target(Code::cast(code));
748 #ifdef DEBUG
749         TraceIC("KeyedLoadIC", name, state, target());
750 #endif  // DEBUG
751         return Smi::FromInt(string->length());
752       }
753 
754       // Use specialized code for getting the length of arrays.
755       if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
756         Handle<JSArray> array = Handle<JSArray>::cast(object);
757         Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array);
758         if (code->IsFailure()) return code;
759         set_target(Code::cast(code));
760 #ifdef DEBUG
761         TraceIC("KeyedLoadIC", name, state, target());
762 #endif  // DEBUG
763         return JSArray::cast(*object)->length();
764       }
765 
766       // Use specialized code for getting prototype of functions.
767       if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
768         Handle<JSFunction> function = Handle<JSFunction>::cast(object);
769         Object* code =
770             StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function);
771         if (code->IsFailure()) return code;
772         set_target(Code::cast(code));
773 #ifdef DEBUG
774         TraceIC("KeyedLoadIC", name, state, target());
775 #endif  // DEBUG
776         return Accessors::FunctionGetPrototype(*object, 0);
777       }
778     }
779 
780     // Check if the name is trivially convertible to an index and get
781     // the element or char if so.
782     uint32_t index = 0;
783     if (name->AsArrayIndex(&index)) {
784       HandleScope scope;
785       // Rewrite to the generic keyed load stub.
786       if (FLAG_use_ic) set_target(generic_stub());
787       return Runtime::GetElementOrCharAt(object, index);
788     }
789 
790     // Named lookup.
791     LookupResult lookup;
792     LookupForRead(*object, *name, &lookup);
793 
794     // If lookup is invalid, check if we need to throw an exception.
795     if (!lookup.IsValid()) {
796       if (FLAG_strict || is_contextual()) {
797         return ReferenceError("not_defined", name);
798       }
799     }
800 
801     if (FLAG_use_ic && lookup.IsLoaded()) {
802       UpdateCaches(&lookup, state, object, name);
803     }
804 
805     PropertyAttributes attr;
806     if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
807       // Get the property.
808       Object* result = object->GetProperty(*object, &lookup, *name, &attr);
809       if (result->IsFailure()) return result;
810       // If the property is not present, check if we need to throw an
811       // exception.
812       if (attr == ABSENT && is_contextual()) {
813         return ReferenceError("not_defined", name);
814       }
815       return result;
816     }
817 
818     return object->GetProperty(*object, &lookup, *name, &attr);
819   }
820 
821   // Do not use ICs for objects that require access checks (including
822   // the global object).
823   bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
824 
825   if (use_ic) {
826     set_target(generic_stub());
827     // For JSObjects that are not value wrappers and that do not have
828     // indexed interceptors, we initialize the inlined fast case (if
829     // present) by patching the inlined map check.
830     if (object->IsJSObject() &&
831         !object->IsJSValue() &&
832         !JSObject::cast(*object)->HasIndexedInterceptor()) {
833       Map* map = JSObject::cast(*object)->map();
834       PatchInlinedLoad(address(), map);
835     }
836   }
837 
838   // Get the property.
839   return Runtime::GetObjectProperty(object, key);
840 }
841 
842 
UpdateCaches(LookupResult * lookup,State state,Handle<Object> object,Handle<String> name)843 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
844                                Handle<Object> object, Handle<String> name) {
845   ASSERT(lookup->IsLoaded());
846   // Bail out if we didn't find a result.
847   if (!lookup->IsValid() || !lookup->IsCacheable()) return;
848 
849   if (!object->IsJSObject()) return;
850   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
851 
852   // Compute the code stub for this load.
853   Object* code = NULL;
854 
855   if (state == UNINITIALIZED) {
856     // This is the first time we execute this inline cache.
857     // Set the target to the pre monomorphic stub to delay
858     // setting the monomorphic state.
859     code = pre_monomorphic_stub();
860   } else {
861     // Compute a monomorphic stub.
862     switch (lookup->type()) {
863       case FIELD: {
864         code = StubCache::ComputeKeyedLoadField(*name, *receiver,
865                                                 lookup->holder(),
866                                                 lookup->GetFieldIndex());
867         break;
868       }
869       case CONSTANT_FUNCTION: {
870         Object* constant = lookup->GetConstantFunction();
871         code = StubCache::ComputeKeyedLoadConstant(*name, *receiver,
872                                                    lookup->holder(), constant);
873         break;
874       }
875       case CALLBACKS: {
876         if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
877         AccessorInfo* callback =
878             AccessorInfo::cast(lookup->GetCallbackObject());
879         if (v8::ToCData<Address>(callback->getter()) == 0) return;
880         code = StubCache::ComputeKeyedLoadCallback(*name, *receiver,
881                                                    lookup->holder(), callback);
882         break;
883       }
884       case INTERCEPTOR: {
885         ASSERT(HasInterceptorGetter(lookup->holder()));
886         code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver,
887                                                       lookup->holder());
888         break;
889       }
890       default: {
891         // Always rewrite to the generic case so that we do not
892         // repeatedly try to rewrite.
893         code = generic_stub();
894         break;
895       }
896     }
897   }
898 
899   // If we're unable to compute the stub (not enough memory left), we
900   // simply avoid updating the caches.
901   if (code == NULL || code->IsFailure()) return;
902 
903   // Patch the call site depending on the state of the cache.  Make
904   // sure to always rewrite from monomorphic to megamorphic.
905   ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
906   if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
907     set_target(Code::cast(code));
908   } else if (state == MONOMORPHIC) {
909     set_target(megamorphic_stub());
910   }
911 
912 #ifdef DEBUG
913   TraceIC("KeyedLoadIC", name, state, target());
914 #endif
915 }
916 
917 
StoreICableLookup(LookupResult * lookup)918 static bool StoreICableLookup(LookupResult* lookup) {
919   // Bail out if we didn't find a result.
920   if (!lookup->IsValid() || !lookup->IsCacheable()) return false;
921 
922   // If the property is read-only, we leave the IC in its current
923   // state.
924   if (lookup->IsReadOnly()) return false;
925 
926   if (!lookup->IsLoaded()) return false;
927 
928   return true;
929 }
930 
931 
LookupForWrite(JSObject * object,String * name,LookupResult * lookup)932 static bool LookupForWrite(JSObject* object,
933                            String* name,
934                            LookupResult* lookup) {
935   object->LocalLookup(name, lookup);
936   if (!StoreICableLookup(lookup)) {
937     return false;
938   }
939 
940   if (lookup->type() == INTERCEPTOR) {
941     if (object->GetNamedInterceptor()->setter()->IsUndefined()) {
942       object->LocalLookupRealNamedProperty(name, lookup);
943       return StoreICableLookup(lookup);
944     }
945   }
946 
947   return true;
948 }
949 
950 
Store(State state,Handle<Object> object,Handle<String> name,Handle<Object> value)951 Object* StoreIC::Store(State state,
952                        Handle<Object> object,
953                        Handle<String> name,
954                        Handle<Object> value) {
955   // If the object is undefined or null it's illegal to try to set any
956   // properties on it; throw a TypeError in that case.
957   if (object->IsUndefined() || object->IsNull()) {
958     return TypeError("non_object_property_store", object, name);
959   }
960 
961   // Ignore stores where the receiver is not a JSObject.
962   if (!object->IsJSObject()) return *value;
963   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
964 
965   // Check if the given name is an array index.
966   uint32_t index;
967   if (name->AsArrayIndex(&index)) {
968     HandleScope scope;
969     Handle<Object> result = SetElement(receiver, index, value);
970     if (result.is_null()) return Failure::Exception();
971     return *value;
972   }
973 
974   // Lookup the property locally in the receiver.
975   if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
976     LookupResult lookup;
977     if (LookupForWrite(*receiver, *name, &lookup)) {
978       UpdateCaches(&lookup, state, receiver, name, value);
979     }
980   }
981 
982   // Set the property.
983   return receiver->SetProperty(*name, *value, NONE);
984 }
985 
986 
UpdateCaches(LookupResult * lookup,State state,Handle<JSObject> receiver,Handle<String> name,Handle<Object> value)987 void StoreIC::UpdateCaches(LookupResult* lookup,
988                            State state,
989                            Handle<JSObject> receiver,
990                            Handle<String> name,
991                            Handle<Object> value) {
992   ASSERT(lookup->IsLoaded());
993   // Skip JSGlobalProxy.
994   ASSERT(!receiver->IsJSGlobalProxy());
995 
996   ASSERT(StoreICableLookup(lookup));
997 
998   // If the property has a non-field type allowing map transitions
999   // where there is extra room in the object, we leave the IC in its
1000   // current state.
1001   PropertyType type = lookup->type();
1002 
1003   // Compute the code stub for this store; used for rewriting to
1004   // monomorphic state and making sure that the code stub is in the
1005   // stub cache.
1006   Object* code = NULL;
1007   switch (type) {
1008     case FIELD: {
1009       code = StubCache::ComputeStoreField(*name, *receiver,
1010                                           lookup->GetFieldIndex());
1011       break;
1012     }
1013     case MAP_TRANSITION: {
1014       if (lookup->GetAttributes() != NONE) return;
1015       HandleScope scope;
1016       ASSERT(type == MAP_TRANSITION);
1017       Handle<Map> transition(lookup->GetTransitionMap());
1018       int index = transition->PropertyIndexFor(*name);
1019       code = StubCache::ComputeStoreField(*name, *receiver, index, *transition);
1020       break;
1021     }
1022     case NORMAL: {
1023       if (!receiver->IsGlobalObject()) {
1024         return;
1025       }
1026       // The stub generated for the global object picks the value directly
1027       // from the property cell. So the property must be directly on the
1028       // global object.
1029       Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1030       JSGlobalPropertyCell* cell =
1031           JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
1032       code = StubCache::ComputeStoreGlobal(*name, *global, cell);
1033       break;
1034     }
1035     case CALLBACKS: {
1036       if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1037       AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1038       if (v8::ToCData<Address>(callback->setter()) == 0) return;
1039       code = StubCache::ComputeStoreCallback(*name, *receiver, callback);
1040       break;
1041     }
1042     case INTERCEPTOR: {
1043       ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
1044       code = StubCache::ComputeStoreInterceptor(*name, *receiver);
1045       break;
1046     }
1047     default:
1048       return;
1049   }
1050 
1051   // If we're unable to compute the stub (not enough memory left), we
1052   // simply avoid updating the caches.
1053   if (code == NULL || code->IsFailure()) return;
1054 
1055   // Patch the call site depending on the state of the cache.
1056   if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1057     set_target(Code::cast(code));
1058   } else if (state == MONOMORPHIC) {
1059     // Only move to mega morphic if the target changes.
1060     if (target() != Code::cast(code)) set_target(megamorphic_stub());
1061   }
1062 
1063 #ifdef DEBUG
1064   TraceIC("StoreIC", name, state, target());
1065 #endif
1066 }
1067 
1068 
Store(State state,Handle<Object> object,Handle<Object> key,Handle<Object> value)1069 Object* KeyedStoreIC::Store(State state,
1070                             Handle<Object> object,
1071                             Handle<Object> key,
1072                             Handle<Object> value) {
1073   if (key->IsSymbol()) {
1074     Handle<String> name = Handle<String>::cast(key);
1075 
1076     // If the object is undefined or null it's illegal to try to set any
1077     // properties on it; throw a TypeError in that case.
1078     if (object->IsUndefined() || object->IsNull()) {
1079       return TypeError("non_object_property_store", object, name);
1080     }
1081 
1082     // Ignore stores where the receiver is not a JSObject.
1083     if (!object->IsJSObject()) return *value;
1084     Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1085 
1086     // Check if the given name is an array index.
1087     uint32_t index;
1088     if (name->AsArrayIndex(&index)) {
1089       HandleScope scope;
1090       Handle<Object> result = SetElement(receiver, index, value);
1091       if (result.is_null()) return Failure::Exception();
1092       return *value;
1093     }
1094 
1095     // Lookup the property locally in the receiver.
1096     LookupResult lookup;
1097     receiver->LocalLookup(*name, &lookup);
1098 
1099     // Update inline cache and stub cache.
1100     if (FLAG_use_ic && lookup.IsLoaded()) {
1101       UpdateCaches(&lookup, state, receiver, name, value);
1102     }
1103 
1104     // Set the property.
1105     return receiver->SetProperty(*name, *value, NONE);
1106   }
1107 
1108   // Do not use ICs for objects that require access checks (including
1109   // the global object).
1110   bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1111   ASSERT(!(use_ic && object->IsJSGlobalProxy()));
1112 
1113   if (use_ic) set_target(generic_stub());
1114 
1115   // Set the property.
1116   return Runtime::SetObjectProperty(object, key, value, NONE);
1117 }
1118 
1119 
UpdateCaches(LookupResult * lookup,State state,Handle<JSObject> receiver,Handle<String> name,Handle<Object> value)1120 void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
1121                                 State state,
1122                                 Handle<JSObject> receiver,
1123                                 Handle<String> name,
1124                                 Handle<Object> value) {
1125   ASSERT(lookup->IsLoaded());
1126 
1127   // Skip JSGlobalProxy.
1128   if (receiver->IsJSGlobalProxy()) return;
1129 
1130   // Bail out if we didn't find a result.
1131   if (!lookup->IsValid() || !lookup->IsCacheable()) return;
1132 
1133   // If the property is read-only, we leave the IC in its current
1134   // state.
1135   if (lookup->IsReadOnly()) return;
1136 
1137   // If the property has a non-field type allowing map transitions
1138   // where there is extra room in the object, we leave the IC in its
1139   // current state.
1140   PropertyType type = lookup->type();
1141 
1142   // Compute the code stub for this store; used for rewriting to
1143   // monomorphic state and making sure that the code stub is in the
1144   // stub cache.
1145   Object* code = NULL;
1146 
1147   switch (type) {
1148     case FIELD: {
1149       code = StubCache::ComputeKeyedStoreField(*name, *receiver,
1150                                                lookup->GetFieldIndex());
1151       break;
1152     }
1153     case MAP_TRANSITION: {
1154       if (lookup->GetAttributes() == NONE) {
1155         HandleScope scope;
1156         ASSERT(type == MAP_TRANSITION);
1157         Handle<Map> transition(lookup->GetTransitionMap());
1158         int index = transition->PropertyIndexFor(*name);
1159         code = StubCache::ComputeKeyedStoreField(*name, *receiver,
1160                                                  index, *transition);
1161         break;
1162       }
1163       // fall through.
1164     }
1165     default: {
1166       // Always rewrite to the generic case so that we do not
1167       // repeatedly try to rewrite.
1168       code = generic_stub();
1169       break;
1170     }
1171   }
1172 
1173   // If we're unable to compute the stub (not enough memory left), we
1174   // simply avoid updating the caches.
1175   if (code == NULL || code->IsFailure()) return;
1176 
1177   // Patch the call site depending on the state of the cache.  Make
1178   // sure to always rewrite from monomorphic to megamorphic.
1179   ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1180   if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1181     set_target(Code::cast(code));
1182   } else if (state == MONOMORPHIC) {
1183     set_target(megamorphic_stub());
1184   }
1185 
1186 #ifdef DEBUG
1187   TraceIC("KeyedStoreIC", name, state, target());
1188 #endif
1189 }
1190 
1191 
1192 // ----------------------------------------------------------------------------
1193 // Static IC stub generators.
1194 //
1195 
1196 // Used from ic_<arch>.cc.
CallIC_Miss(Arguments args)1197 Object* CallIC_Miss(Arguments args) {
1198   NoHandleAllocation na;
1199   ASSERT(args.length() == 2);
1200   CallIC ic;
1201   IC::State state = IC::StateFrom(ic.target(), args[0]);
1202   Object* result =
1203       ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
1204 
1205   // The first time the inline cache is updated may be the first time the
1206   // function it references gets called.  If the function was lazily compiled
1207   // then the first call will trigger a compilation.  We check for this case
1208   // and we do the compilation immediately, instead of waiting for the stub
1209   // currently attached to the JSFunction object to trigger compilation.  We
1210   // do this in the case where we know that the inline cache is inside a loop,
1211   // because then we know that we want to optimize the function.
1212   if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1213     return result;
1214   }
1215 
1216   // Compile now with optimization.
1217   HandleScope scope;
1218   Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result));
1219   InLoopFlag in_loop = ic.target()->ic_in_loop();
1220   if (in_loop == IN_LOOP) {
1221     CompileLazyInLoop(function, CLEAR_EXCEPTION);
1222   } else {
1223     CompileLazy(function, CLEAR_EXCEPTION);
1224   }
1225   return *function;
1226 }
1227 
1228 
GenerateInitialize(MacroAssembler * masm,int argc)1229 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) {
1230   Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
1231 }
1232 
1233 
GenerateMiss(MacroAssembler * masm,int argc)1234 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1235   Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
1236 }
1237 
1238 
1239 // Used from ic_<arch>.cc.
LoadIC_Miss(Arguments args)1240 Object* LoadIC_Miss(Arguments args) {
1241   NoHandleAllocation na;
1242   ASSERT(args.length() == 2);
1243   LoadIC ic;
1244   IC::State state = IC::StateFrom(ic.target(), args[0]);
1245   return ic.Load(state, args.at<Object>(0), args.at<String>(1));
1246 }
1247 
1248 
GenerateInitialize(MacroAssembler * masm)1249 void LoadIC::GenerateInitialize(MacroAssembler* masm) {
1250   Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
1251 }
1252 
1253 
GeneratePreMonomorphic(MacroAssembler * masm)1254 void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
1255   Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
1256 }
1257 
1258 
1259 // Used from ic_<arch>.cc
KeyedLoadIC_Miss(Arguments args)1260 Object* KeyedLoadIC_Miss(Arguments args) {
1261   NoHandleAllocation na;
1262   ASSERT(args.length() == 2);
1263   KeyedLoadIC ic;
1264   IC::State state = IC::StateFrom(ic.target(), args[0]);
1265   return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
1266 }
1267 
1268 
GenerateInitialize(MacroAssembler * masm)1269 void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) {
1270   Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
1271 }
1272 
1273 
GeneratePreMonomorphic(MacroAssembler * masm)1274 void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
1275   Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
1276 }
1277 
1278 
1279 // Used from ic_<arch>.cc.
StoreIC_Miss(Arguments args)1280 Object* StoreIC_Miss(Arguments args) {
1281   NoHandleAllocation na;
1282   ASSERT(args.length() == 3);
1283   StoreIC ic;
1284   IC::State state = IC::StateFrom(ic.target(), args[0]);
1285   return ic.Store(state, args.at<Object>(0), args.at<String>(1),
1286                   args.at<Object>(2));
1287 }
1288 
1289 
1290 // Extend storage is called in a store inline cache when
1291 // it is necessary to extend the properties array of a
1292 // JSObject.
SharedStoreIC_ExtendStorage(Arguments args)1293 Object* SharedStoreIC_ExtendStorage(Arguments args) {
1294   NoHandleAllocation na;
1295   ASSERT(args.length() == 3);
1296 
1297   // Convert the parameters
1298   JSObject* object = JSObject::cast(args[0]);
1299   Map* transition = Map::cast(args[1]);
1300   Object* value = args[2];
1301 
1302   // Check the object has run out out property space.
1303   ASSERT(object->HasFastProperties());
1304   ASSERT(object->map()->unused_property_fields() == 0);
1305 
1306   // Expand the properties array.
1307   FixedArray* old_storage = object->properties();
1308   int new_unused = transition->unused_property_fields();
1309   int new_size = old_storage->length() + new_unused + 1;
1310   Object* result = old_storage->CopySize(new_size);
1311   if (result->IsFailure()) return result;
1312   FixedArray* new_storage = FixedArray::cast(result);
1313   new_storage->set(old_storage->length(), value);
1314 
1315   // Set the new property value and do the map transition.
1316   object->set_properties(new_storage);
1317   object->set_map(transition);
1318 
1319   // Return the stored value.
1320   return value;
1321 }
1322 
1323 
GenerateInitialize(MacroAssembler * masm)1324 void StoreIC::GenerateInitialize(MacroAssembler* masm) {
1325   Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
1326 }
1327 
1328 
GenerateMiss(MacroAssembler * masm)1329 void StoreIC::GenerateMiss(MacroAssembler* masm) {
1330   Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
1331 }
1332 
1333 
1334 // Used from ic_<arch>.cc.
KeyedStoreIC_Miss(Arguments args)1335 Object* KeyedStoreIC_Miss(Arguments args) {
1336   NoHandleAllocation na;
1337   ASSERT(args.length() == 3);
1338   KeyedStoreIC ic;
1339   IC::State state = IC::StateFrom(ic.target(), args[0]);
1340   return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
1341                   args.at<Object>(2));
1342 }
1343 
1344 
GenerateInitialize(MacroAssembler * masm)1345 void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) {
1346   Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
1347 }
1348 
1349 
GenerateMiss(MacroAssembler * masm)1350 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1351   Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
1352 }
1353 
1354 
1355 static Address IC_utilities[] = {
1356 #define ADDR(name) FUNCTION_ADDR(name),
1357     IC_UTIL_LIST(ADDR)
1358     NULL
1359 #undef ADDR
1360 };
1361 
1362 
AddressFromUtilityId(IC::UtilityId id)1363 Address IC::AddressFromUtilityId(IC::UtilityId id) {
1364   return IC_utilities[id];
1365 }
1366 
1367 
1368 } }  // namespace v8::internal
1369