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