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