• 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 "codegen.h"
34 #include "execution.h"
35 #include "ic-inl.h"
36 #include "runtime.h"
37 #include "stub-cache.h"
38 
39 namespace v8 {
40 namespace internal {
41 
42 #ifdef DEBUG
TransitionMarkFromState(IC::State state)43 static char TransitionMarkFromState(IC::State state) {
44   switch (state) {
45     case UNINITIALIZED: return '0';
46     case PREMONOMORPHIC: return 'P';
47     case MONOMORPHIC: return '1';
48     case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
49     case MEGAMORPHIC: return 'N';
50 
51     // We never see the debugger states here, because the state is
52     // computed from the original code - not the patched code. Let
53     // these cases fall through to the unreachable code below.
54     case DEBUG_BREAK: break;
55     case DEBUG_PREPARE_STEP_IN: break;
56   }
57   UNREACHABLE();
58   return 0;
59 }
60 
TraceIC(const char * type,Handle<Object> name,State old_state,Code * new_target,const char * extra_info)61 void IC::TraceIC(const char* type,
62                  Handle<Object> name,
63                  State old_state,
64                  Code* new_target,
65                  const char* extra_info) {
66   if (FLAG_trace_ic) {
67     State new_state = StateFrom(new_target,
68                                 HEAP->undefined_value(),
69                                 HEAP->undefined_value());
70     PrintF("[%s (%c->%c)%s", type,
71            TransitionMarkFromState(old_state),
72            TransitionMarkFromState(new_state),
73            extra_info);
74     name->Print();
75     PrintF("]\n");
76   }
77 }
78 #endif
79 
80 
IC(FrameDepth depth,Isolate * isolate)81 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
82   ASSERT(isolate == Isolate::Current());
83   // To improve the performance of the (much used) IC code, we unfold
84   // a few levels of the stack frame iteration code. This yields a
85   // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.
86   const Address entry =
87       Isolate::c_entry_fp(isolate->thread_local_top());
88   Address* pc_address =
89       reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
90   Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
91   // If there's another JavaScript frame on the stack, we need to look
92   // one frame further down the stack to find the frame pointer and
93   // the return address stack slot.
94   if (depth == EXTRA_CALL_FRAME) {
95     const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
96     pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
97     fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
98   }
99 #ifdef DEBUG
100   StackFrameIterator it;
101   for (int i = 0; i < depth + 1; i++) it.Advance();
102   StackFrame* frame = it.frame();
103   ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
104 #endif
105   fp_ = fp;
106   pc_address_ = pc_address;
107 }
108 
109 
110 #ifdef ENABLE_DEBUGGER_SUPPORT
OriginalCodeAddress()111 Address IC::OriginalCodeAddress() {
112   HandleScope scope;
113   // Compute the JavaScript frame for the frame pointer of this IC
114   // structure. We need this to be able to find the function
115   // corresponding to the frame.
116   StackFrameIterator it;
117   while (it.frame()->fp() != this->fp()) it.Advance();
118   JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
119   // Find the function on the stack and both the active code for the
120   // function and the original code.
121   JSFunction* function = JSFunction::cast(frame->function());
122   Handle<SharedFunctionInfo> shared(function->shared());
123   Code* code = shared->code();
124   ASSERT(Debug::HasDebugInfo(shared));
125   Code* original_code = Debug::GetDebugInfo(shared)->original_code();
126   ASSERT(original_code->IsCode());
127   // Get the address of the call site in the active code. This is the
128   // place where the call to DebugBreakXXX is and where the IC
129   // normally would be.
130   Address addr = pc() - Assembler::kCallTargetAddressOffset;
131   // Return the address in the original code. This is the place where
132   // the call which has been overwritten by the DebugBreakXXX resides
133   // and the place where the inline cache system should look.
134   intptr_t delta =
135       original_code->instruction_start() - code->instruction_start();
136   return addr + delta;
137 }
138 #endif
139 
140 
HasNormalObjectsInPrototypeChain(Isolate * isolate,LookupResult * lookup,Object * receiver)141 static bool HasNormalObjectsInPrototypeChain(Isolate* isolate,
142                                              LookupResult* lookup,
143                                              Object* receiver) {
144   Object* end = lookup->IsProperty()
145       ? lookup->holder() : isolate->heap()->null_value();
146   for (Object* current = receiver;
147        current != end;
148        current = current->GetPrototype()) {
149     if (current->IsJSObject() &&
150         !JSObject::cast(current)->HasFastProperties() &&
151         !current->IsJSGlobalProxy() &&
152         !current->IsJSGlobalObject()) {
153       return true;
154     }
155   }
156 
157   return false;
158 }
159 
160 
TryRemoveInvalidPrototypeDependentStub(Code * target,Object * receiver,Object * name)161 static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
162                                                    Object* receiver,
163                                                    Object* name) {
164   InlineCacheHolderFlag cache_holder =
165       Code::ExtractCacheHolderFromFlags(target->flags());
166 
167   if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
168     // The stub was generated for JSObject but called for non-JSObject.
169     // IC::GetCodeCacheHolder is not applicable.
170     return false;
171   } else if (cache_holder == PROTOTYPE_MAP &&
172              receiver->GetPrototype()->IsNull()) {
173     // IC::GetCodeCacheHolder is not applicable.
174     return false;
175   }
176   Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map();
177 
178   // Decide whether the inline cache failed because of changes to the
179   // receiver itself or changes to one of its prototypes.
180   //
181   // If there are changes to the receiver itself, the map of the
182   // receiver will have changed and the current target will not be in
183   // the receiver map's code cache.  Therefore, if the current target
184   // is in the receiver map's code cache, the inline cache failed due
185   // to prototype check failure.
186   int index = map->IndexInCodeCache(name, target);
187   if (index >= 0) {
188     map->RemoveFromCodeCache(String::cast(name), target, index);
189     return true;
190   }
191 
192   return false;
193 }
194 
195 
StateFrom(Code * target,Object * receiver,Object * name)196 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
197   IC::State state = target->ic_state();
198 
199   if (state != MONOMORPHIC || !name->IsString()) return state;
200   if (receiver->IsUndefined() || receiver->IsNull()) return state;
201 
202   // For keyed load/store/call, the most likely cause of cache failure is
203   // that the key has changed.  We do not distinguish between
204   // prototype and non-prototype failures for keyed access.
205   Code::Kind kind = target->kind();
206   if (kind == Code::KEYED_LOAD_IC ||
207       kind == Code::KEYED_STORE_IC ||
208       kind == Code::KEYED_CALL_IC) {
209     return MONOMORPHIC;
210   }
211 
212   // Remove the target from the code cache if it became invalid
213   // because of changes in the prototype chain to avoid hitting it
214   // again.
215   // Call stubs handle this later to allow extra IC state
216   // transitions.
217   if (kind != Code::CALL_IC &&
218       TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
219     return MONOMORPHIC_PROTOTYPE_FAILURE;
220   }
221 
222   // The builtins object is special.  It only changes when JavaScript
223   // builtins are loaded lazily.  It is important to keep inline
224   // caches for the builtins object monomorphic.  Therefore, if we get
225   // an inline cache miss for the builtins object after lazily loading
226   // JavaScript builtins, we return uninitialized as the state to
227   // force the inline cache back to monomorphic state.
228   if (receiver->IsJSBuiltinsObject()) {
229     return UNINITIALIZED;
230   }
231 
232   return MONOMORPHIC;
233 }
234 
235 
ComputeMode()236 RelocInfo::Mode IC::ComputeMode() {
237   Address addr = address();
238   Code* code = Code::cast(isolate()->heap()->FindCodeObject(addr));
239   for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
240        !it.done(); it.next()) {
241     RelocInfo* info = it.rinfo();
242     if (info->pc() == addr) return info->rmode();
243   }
244   UNREACHABLE();
245   return RelocInfo::NONE;
246 }
247 
248 
TypeError(const char * type,Handle<Object> object,Handle<Object> key)249 Failure* IC::TypeError(const char* type,
250                        Handle<Object> object,
251                        Handle<Object> key) {
252   HandleScope scope(isolate());
253   Handle<Object> args[2] = { key, object };
254   Handle<Object> error = isolate()->factory()->NewTypeError(
255       type, HandleVector(args, 2));
256   return isolate()->Throw(*error);
257 }
258 
259 
ReferenceError(const char * type,Handle<String> name)260 Failure* IC::ReferenceError(const char* type, Handle<String> name) {
261   HandleScope scope(isolate());
262   Handle<Object> error = isolate()->factory()->NewReferenceError(
263       type, HandleVector(&name, 1));
264   return isolate()->Throw(*error);
265 }
266 
267 
Clear(Address address)268 void IC::Clear(Address address) {
269   Code* target = GetTargetAtAddress(address);
270 
271   // Don't clear debug break inline cache as it will remove the break point.
272   if (target->ic_state() == DEBUG_BREAK) return;
273 
274   switch (target->kind()) {
275     case Code::LOAD_IC: return LoadIC::Clear(address, target);
276     case Code::KEYED_LOAD_IC:
277     case Code::KEYED_EXTERNAL_ARRAY_LOAD_IC:
278       return KeyedLoadIC::Clear(address, target);
279     case Code::STORE_IC: return StoreIC::Clear(address, target);
280     case Code::KEYED_STORE_IC:
281     case Code::KEYED_EXTERNAL_ARRAY_STORE_IC:
282       return KeyedStoreIC::Clear(address, target);
283     case Code::CALL_IC: return CallIC::Clear(address, target);
284     case Code::KEYED_CALL_IC:  return KeyedCallIC::Clear(address, target);
285     case Code::TYPE_RECORDING_BINARY_OP_IC:
286     case Code::COMPARE_IC:
287       // Clearing these is tricky and does not
288       // make any performance difference.
289       return;
290     default: UNREACHABLE();
291   }
292 }
293 
294 
Clear(Address address,Code * target)295 void CallICBase::Clear(Address address, Code* target) {
296   State state = target->ic_state();
297   if (state == UNINITIALIZED) return;
298   Code* code =
299       Isolate::Current()->stub_cache()->FindCallInitialize(
300           target->arguments_count(),
301           target->ic_in_loop(),
302           target->kind());
303   SetTargetAtAddress(address, code);
304 }
305 
306 
ClearInlinedVersion(Address address)307 void KeyedLoadIC::ClearInlinedVersion(Address address) {
308   // Insert null as the map to check for to make sure the map check fails
309   // sending control flow to the IC instead of the inlined version.
310   PatchInlinedLoad(address, HEAP->null_value());
311 }
312 
313 
Clear(Address address,Code * target)314 void KeyedLoadIC::Clear(Address address, Code* target) {
315   if (target->ic_state() == UNINITIALIZED) return;
316   // Make sure to also clear the map used in inline fast cases.  If we
317   // do not clear these maps, cached code can keep objects alive
318   // through the embedded maps.
319   ClearInlinedVersion(address);
320   SetTargetAtAddress(address, initialize_stub());
321 }
322 
323 
ClearInlinedVersion(Address address)324 void LoadIC::ClearInlinedVersion(Address address) {
325   // Reset the map check of the inlined inobject property load (if
326   // present) to guarantee failure by holding an invalid map (the null
327   // value).  The offset can be patched to anything.
328   Heap* heap = HEAP;
329   PatchInlinedLoad(address, heap->null_value(), 0);
330   PatchInlinedContextualLoad(address,
331                              heap->null_value(),
332                              heap->null_value(),
333                              true);
334 }
335 
336 
Clear(Address address,Code * target)337 void LoadIC::Clear(Address address, Code* target) {
338   if (target->ic_state() == UNINITIALIZED) return;
339   ClearInlinedVersion(address);
340   SetTargetAtAddress(address, initialize_stub());
341 }
342 
343 
ClearInlinedVersion(Address address)344 void StoreIC::ClearInlinedVersion(Address address) {
345   // Reset the map check of the inlined inobject property store (if
346   // present) to guarantee failure by holding an invalid map (the null
347   // value).  The offset can be patched to anything.
348   PatchInlinedStore(address, HEAP->null_value(), 0);
349 }
350 
351 
Clear(Address address,Code * target)352 void StoreIC::Clear(Address address, Code* target) {
353   if (target->ic_state() == UNINITIALIZED) return;
354   ClearInlinedVersion(address);
355   SetTargetAtAddress(address,
356       (target->extra_ic_state() == kStrictMode)
357         ? initialize_stub_strict()
358         : initialize_stub());
359 }
360 
361 
ClearInlinedVersion(Address address)362 void KeyedStoreIC::ClearInlinedVersion(Address address) {
363   // Insert null as the elements map to check for.  This will make
364   // sure that the elements fast-case map check fails so that control
365   // flows to the IC instead of the inlined version.
366   PatchInlinedStore(address, HEAP->null_value());
367 }
368 
369 
RestoreInlinedVersion(Address address)370 void KeyedStoreIC::RestoreInlinedVersion(Address address) {
371   // Restore the fast-case elements map check so that the inlined
372   // version can be used again.
373   PatchInlinedStore(address, HEAP->fixed_array_map());
374 }
375 
376 
Clear(Address address,Code * target)377 void KeyedStoreIC::Clear(Address address, Code* target) {
378   if (target->ic_state() == UNINITIALIZED) return;
379   SetTargetAtAddress(address,
380       (target->extra_ic_state() == kStrictMode)
381         ? initialize_stub_strict()
382         : initialize_stub());
383 }
384 
385 
HasInterceptorGetter(JSObject * object)386 static bool HasInterceptorGetter(JSObject* object) {
387   return !object->GetNamedInterceptor()->getter()->IsUndefined();
388 }
389 
390 
LookupForRead(Object * object,String * name,LookupResult * lookup)391 static void LookupForRead(Object* object,
392                           String* name,
393                           LookupResult* lookup) {
394   AssertNoAllocation no_gc;  // pointers must stay valid
395 
396   // Skip all the objects with named interceptors, but
397   // without actual getter.
398   while (true) {
399     object->Lookup(name, lookup);
400     // Besides normal conditions (property not found or it's not
401     // an interceptor), bail out if lookup is not cacheable: we won't
402     // be able to IC it anyway and regular lookup should work fine.
403     if (!lookup->IsFound()
404         || (lookup->type() != INTERCEPTOR)
405         || !lookup->IsCacheable()) {
406       return;
407     }
408 
409     JSObject* holder = lookup->holder();
410     if (HasInterceptorGetter(holder)) {
411       return;
412     }
413 
414     holder->LocalLookupRealNamedProperty(name, lookup);
415     if (lookup->IsProperty()) {
416       ASSERT(lookup->type() != INTERCEPTOR);
417       return;
418     }
419 
420     Object* proto = holder->GetPrototype();
421     if (proto->IsNull()) {
422       lookup->NotFound();
423       return;
424     }
425 
426     object = proto;
427   }
428 }
429 
430 
TryCallAsFunction(Object * object)431 Object* CallICBase::TryCallAsFunction(Object* object) {
432   HandleScope scope(isolate());
433   Handle<Object> target(object, isolate());
434   Handle<Object> delegate = Execution::GetFunctionDelegate(target);
435 
436   if (delegate->IsJSFunction()) {
437     // Patch the receiver and use the delegate as the function to
438     // invoke. This is used for invoking objects as if they were
439     // functions.
440     const int argc = this->target()->arguments_count();
441     StackFrameLocator locator;
442     JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
443     int index = frame->ComputeExpressionsCount() - (argc + 1);
444     frame->SetExpression(index, *target);
445   }
446 
447   return *delegate;
448 }
449 
450 
ReceiverToObjectIfRequired(Handle<Object> callee,Handle<Object> object)451 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
452                                             Handle<Object> object) {
453   if (callee->IsJSFunction()) {
454     Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
455     if (function->shared()->strict_mode() || function->IsBuiltin()) {
456       // Do not wrap receiver for strict mode functions or for builtins.
457       return;
458     }
459   }
460 
461   // And only wrap string, number or boolean.
462   if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
463     // Change the receiver to the result of calling ToObject on it.
464     const int argc = this->target()->arguments_count();
465     StackFrameLocator locator;
466     JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
467     int index = frame->ComputeExpressionsCount() - (argc + 1);
468     frame->SetExpression(index, *isolate()->factory()->ToObject(object));
469   }
470 }
471 
472 
LoadFunction(State state,Code::ExtraICState extra_ic_state,Handle<Object> object,Handle<String> name)473 MaybeObject* CallICBase::LoadFunction(State state,
474                                       Code::ExtraICState extra_ic_state,
475                                       Handle<Object> object,
476                                       Handle<String> name) {
477   // If the object is undefined or null it's illegal to try to get any
478   // of its properties; throw a TypeError in that case.
479   if (object->IsUndefined() || object->IsNull()) {
480     return TypeError("non_object_property_call", object, name);
481   }
482 
483   // Check if the name is trivially convertible to an index and get
484   // the element if so.
485   uint32_t index;
486   if (name->AsArrayIndex(&index)) {
487     Object* result;
488     { MaybeObject* maybe_result = object->GetElement(index);
489       if (!maybe_result->ToObject(&result)) return maybe_result;
490     }
491 
492     if (result->IsJSFunction()) return result;
493 
494     // Try to find a suitable function delegate for the object at hand.
495     result = TryCallAsFunction(result);
496     if (result->IsJSFunction()) return result;
497 
498     // Otherwise, it will fail in the lookup step.
499   }
500 
501   // Lookup the property in the object.
502   LookupResult lookup;
503   LookupForRead(*object, *name, &lookup);
504 
505   if (!lookup.IsProperty()) {
506     // If the object does not have the requested property, check which
507     // exception we need to throw.
508     if (IsContextual(object)) {
509       return ReferenceError("not_defined", name);
510     }
511     return TypeError("undefined_method", object, name);
512   }
513 
514   // Lookup is valid: Update inline cache and stub cache.
515   if (FLAG_use_ic) {
516     UpdateCaches(&lookup, state, extra_ic_state, object, name);
517   }
518 
519   // Get the property.
520   PropertyAttributes attr;
521   Object* result;
522   { MaybeObject* maybe_result =
523         object->GetProperty(*object, &lookup, *name, &attr);
524     if (!maybe_result->ToObject(&result)) return maybe_result;
525   }
526 
527   if (lookup.type() == INTERCEPTOR) {
528     // If the object does not have the requested property, check which
529     // exception we need to throw.
530     if (attr == ABSENT) {
531       if (IsContextual(object)) {
532         return ReferenceError("not_defined", name);
533       }
534       return TypeError("undefined_method", object, name);
535     }
536   }
537 
538   ASSERT(!result->IsTheHole());
539 
540   HandleScope scope(isolate());
541   // Wrap result in a handle because ReceiverToObjectIfRequired may allocate
542   // new object and cause GC.
543   Handle<Object> result_handle(result);
544   // Make receiver an object if the callee requires it. Strict mode or builtin
545   // functions do not wrap the receiver, non-strict functions and objects
546   // called as functions do.
547   ReceiverToObjectIfRequired(result_handle, object);
548 
549   if (result_handle->IsJSFunction()) {
550 #ifdef ENABLE_DEBUGGER_SUPPORT
551     // Handle stepping into a function if step into is active.
552     Debug* debug = isolate()->debug();
553     if (debug->StepInActive()) {
554       // Protect the result in a handle as the debugger can allocate and might
555       // cause GC.
556       Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate());
557       debug->HandleStepIn(function, object, fp(), false);
558       return *function;
559     }
560 #endif
561 
562     return *result_handle;
563   }
564 
565   // Try to find a suitable function delegate for the object at hand.
566   result_handle = Handle<Object>(TryCallAsFunction(*result_handle));
567   if (result_handle->IsJSFunction()) return *result_handle;
568 
569   return TypeError("property_not_function", object, name);
570 }
571 
572 
TryUpdateExtraICState(LookupResult * lookup,Handle<Object> object,Code::ExtraICState * extra_ic_state)573 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
574                                        Handle<Object> object,
575                                        Code::ExtraICState* extra_ic_state) {
576   ASSERT(kind_ == Code::CALL_IC);
577   if (lookup->type() != CONSTANT_FUNCTION) return false;
578   JSFunction* function = lookup->GetConstantFunction();
579   if (!function->shared()->HasBuiltinFunctionId()) return false;
580 
581   // Fetch the arguments passed to the called function.
582   const int argc = target()->arguments_count();
583   Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
584   Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
585   Arguments args(argc + 1,
586                  &Memory::Object_at(fp +
587                                     StandardFrameConstants::kCallerSPOffset +
588                                     argc * kPointerSize));
589   switch (function->shared()->builtin_function_id()) {
590     case kStringCharCodeAt:
591     case kStringCharAt:
592       if (object->IsString()) {
593         String* string = String::cast(*object);
594         // Check there's the right string value or wrapper in the receiver slot.
595         ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
596         // If we're in the default (fastest) state and the index is
597         // out of bounds, update the state to record this fact.
598         if (*extra_ic_state == DEFAULT_STRING_STUB &&
599             argc >= 1 && args[1]->IsNumber()) {
600           double index;
601           if (args[1]->IsSmi()) {
602             index = Smi::cast(args[1])->value();
603           } else {
604             ASSERT(args[1]->IsHeapNumber());
605             index = DoubleToInteger(HeapNumber::cast(args[1])->value());
606           }
607           if (index < 0 || index >= string->length()) {
608             *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS;
609             return true;
610           }
611         }
612       }
613       break;
614     default:
615       return false;
616   }
617   return false;
618 }
619 
620 
ComputeMonomorphicStub(LookupResult * lookup,State state,Code::ExtraICState extra_ic_state,Handle<Object> object,Handle<String> name)621 MaybeObject* CallICBase::ComputeMonomorphicStub(
622     LookupResult* lookup,
623     State state,
624     Code::ExtraICState extra_ic_state,
625     Handle<Object> object,
626     Handle<String> name) {
627   int argc = target()->arguments_count();
628   InLoopFlag in_loop = target()->ic_in_loop();
629   MaybeObject* maybe_code = NULL;
630   switch (lookup->type()) {
631     case FIELD: {
632       int index = lookup->GetFieldIndex();
633       maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
634                                                              in_loop,
635                                                              kind_,
636                                                              *name,
637                                                              *object,
638                                                              lookup->holder(),
639                                                              index);
640       break;
641     }
642     case CONSTANT_FUNCTION: {
643       // Get the constant function and compute the code stub for this
644       // call; used for rewriting to monomorphic state and making sure
645       // that the code stub is in the stub cache.
646       JSFunction* function = lookup->GetConstantFunction();
647       maybe_code =
648           isolate()->stub_cache()->ComputeCallConstant(argc,
649                                                        in_loop,
650                                                        kind_,
651                                                        extra_ic_state,
652                                                        *name,
653                                                        *object,
654                                                        lookup->holder(),
655                                                        function);
656       break;
657     }
658     case NORMAL: {
659       if (!object->IsJSObject()) return NULL;
660       Handle<JSObject> receiver = Handle<JSObject>::cast(object);
661 
662       if (lookup->holder()->IsGlobalObject()) {
663         GlobalObject* global = GlobalObject::cast(lookup->holder());
664         JSGlobalPropertyCell* cell =
665             JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
666         if (!cell->value()->IsJSFunction()) return NULL;
667         JSFunction* function = JSFunction::cast(cell->value());
668         maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
669                                                                 in_loop,
670                                                                 kind_,
671                                                                 *name,
672                                                                 *receiver,
673                                                                 global,
674                                                                 cell,
675                                                                 function);
676       } else {
677         // There is only one shared stub for calling normalized
678         // properties. It does not traverse the prototype chain, so the
679         // property must be found in the receiver for the stub to be
680         // applicable.
681         if (lookup->holder() != *receiver) return NULL;
682         maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
683                                                                 in_loop,
684                                                                 kind_,
685                                                                 *name,
686                                                                 *receiver);
687       }
688       break;
689     }
690     case INTERCEPTOR: {
691       ASSERT(HasInterceptorGetter(lookup->holder()));
692       maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
693           argc,
694           kind_,
695           *name,
696           *object,
697           lookup->holder());
698       break;
699     }
700     default:
701       maybe_code = NULL;
702       break;
703   }
704   return maybe_code;
705 }
706 
707 
UpdateCaches(LookupResult * lookup,State state,Code::ExtraICState extra_ic_state,Handle<Object> object,Handle<String> name)708 void CallICBase::UpdateCaches(LookupResult* lookup,
709                               State state,
710                               Code::ExtraICState extra_ic_state,
711                               Handle<Object> object,
712                               Handle<String> name) {
713   // Bail out if we didn't find a result.
714   if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
715 
716   if (lookup->holder() != *object &&
717       HasNormalObjectsInPrototypeChain(
718           isolate(), lookup, object->GetPrototype())) {
719     // Suppress optimization for prototype chains with slow properties objects
720     // in the middle.
721     return;
722   }
723 
724   // Compute the number of arguments.
725   int argc = target()->arguments_count();
726   InLoopFlag in_loop = target()->ic_in_loop();
727   MaybeObject* maybe_code = NULL;
728   bool had_proto_failure = false;
729   if (state == UNINITIALIZED) {
730     // This is the first time we execute this inline cache.
731     // Set the target to the pre monomorphic stub to delay
732     // setting the monomorphic state.
733     maybe_code = isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
734                                                                     in_loop,
735                                                                     kind_);
736   } else if (state == MONOMORPHIC) {
737     if (kind_ == Code::CALL_IC &&
738         TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
739       maybe_code = ComputeMonomorphicStub(lookup,
740                                           state,
741                                           extra_ic_state,
742                                           object,
743                                           name);
744     } else if (kind_ == Code::CALL_IC &&
745                TryRemoveInvalidPrototypeDependentStub(target(),
746                                                       *object,
747                                                       *name)) {
748       had_proto_failure = true;
749       maybe_code = ComputeMonomorphicStub(lookup,
750                                           state,
751                                           extra_ic_state,
752                                           object,
753                                           name);
754     } else {
755       maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(argc,
756                                                                    in_loop,
757                                                                    kind_);
758     }
759   } else {
760     maybe_code = ComputeMonomorphicStub(lookup,
761                                         state,
762                                         extra_ic_state,
763                                         object,
764                                         name);
765   }
766 
767   // If we're unable to compute the stub (not enough memory left), we
768   // simply avoid updating the caches.
769   Object* code;
770   if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
771 
772   // Patch the call site depending on the state of the cache.
773   if (state == UNINITIALIZED ||
774       state == PREMONOMORPHIC ||
775       state == MONOMORPHIC ||
776       state == MONOMORPHIC_PROTOTYPE_FAILURE) {
777     set_target(Code::cast(code));
778   } else if (state == MEGAMORPHIC) {
779     // Cache code holding map should be consistent with
780     // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
781     Map* map = JSObject::cast(object->IsJSObject() ? *object :
782                               object->GetPrototype())->map();
783 
784     // Update the stub cache.
785     isolate()->stub_cache()->Set(*name, map, Code::cast(code));
786   }
787 
788   USE(had_proto_failure);
789 #ifdef DEBUG
790   if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
791   TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
792       name, state, target(), in_loop ? " (in-loop)" : "");
793 #endif
794 }
795 
796 
LoadFunction(State state,Handle<Object> object,Handle<Object> key)797 MaybeObject* KeyedCallIC::LoadFunction(State state,
798                                        Handle<Object> object,
799                                        Handle<Object> key) {
800   if (key->IsSymbol()) {
801     return CallICBase::LoadFunction(state,
802                                     Code::kNoExtraICState,
803                                     object,
804                                     Handle<String>::cast(key));
805   }
806 
807   if (object->IsUndefined() || object->IsNull()) {
808     return TypeError("non_object_property_call", object, key);
809   }
810 
811   if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) {
812     int argc = target()->arguments_count();
813     InLoopFlag in_loop = target()->ic_in_loop();
814     MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
815         argc, in_loop, Code::KEYED_CALL_IC);
816     Object* code;
817     if (maybe_code->ToObject(&code)) {
818       set_target(Code::cast(code));
819 #ifdef DEBUG
820       TraceIC(
821           "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
822 #endif
823     }
824   }
825 
826   HandleScope scope(isolate());
827   Handle<Object> result = GetProperty(object, key);
828   RETURN_IF_EMPTY_HANDLE(isolate(), result);
829 
830   // Make receiver an object if the callee requires it. Strict mode or builtin
831   // functions do not wrap the receiver, non-strict functions and objects
832   // called as functions do.
833   ReceiverToObjectIfRequired(result, object);
834 
835   if (result->IsJSFunction()) return *result;
836   result = Handle<Object>(TryCallAsFunction(*result));
837   if (result->IsJSFunction()) return *result;
838 
839   return TypeError("property_not_function", object, key);
840 }
841 
842 
843 #ifdef DEBUG
844 #define TRACE_IC_NAMED(msg, name) \
845   if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString())
846 #else
847 #define TRACE_IC_NAMED(msg, name)
848 #endif
849 
850 
Load(State state,Handle<Object> object,Handle<String> name)851 MaybeObject* LoadIC::Load(State state,
852                           Handle<Object> object,
853                           Handle<String> name) {
854   // If the object is undefined or null it's illegal to try to get any
855   // of its properties; throw a TypeError in that case.
856   if (object->IsUndefined() || object->IsNull()) {
857     return TypeError("non_object_property_load", object, name);
858   }
859 
860   if (FLAG_use_ic) {
861     Code* non_monomorphic_stub =
862         (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub();
863 
864     // Use specialized code for getting the length of strings and
865     // string wrapper objects.  The length property of string wrapper
866     // objects is read-only and therefore always returns the length of
867     // the underlying string value.  See ECMA-262 15.5.5.1.
868     if ((object->IsString() || object->IsStringWrapper()) &&
869         name->Equals(isolate()->heap()->length_symbol())) {
870       HandleScope scope(isolate());
871 #ifdef DEBUG
872       if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
873 #endif
874       if (state == PREMONOMORPHIC) {
875         if (object->IsString()) {
876           Map* map = HeapObject::cast(*object)->map();
877           const int offset = String::kLengthOffset;
878           PatchInlinedLoad(address(), map, offset);
879           set_target(isolate()->builtins()->builtin(
880               Builtins::kLoadIC_StringLength));
881         } else {
882           set_target(isolate()->builtins()->builtin(
883               Builtins::kLoadIC_StringWrapperLength));
884         }
885       } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
886         set_target(isolate()->builtins()->builtin(
887             Builtins::kLoadIC_StringWrapperLength));
888       } else {
889         set_target(non_monomorphic_stub);
890       }
891       // Get the string if we have a string wrapper object.
892       if (object->IsJSValue()) {
893         object = Handle<Object>(Handle<JSValue>::cast(object)->value(),
894                                 isolate());
895       }
896       return Smi::FromInt(String::cast(*object)->length());
897     }
898 
899     // Use specialized code for getting the length of arrays.
900     if (object->IsJSArray() &&
901         name->Equals(isolate()->heap()->length_symbol())) {
902 #ifdef DEBUG
903       if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
904 #endif
905       if (state == PREMONOMORPHIC) {
906         Map* map = HeapObject::cast(*object)->map();
907         const int offset = JSArray::kLengthOffset;
908         PatchInlinedLoad(address(), map, offset);
909         set_target(isolate()->builtins()->builtin(
910             Builtins::kLoadIC_ArrayLength));
911       } else {
912         set_target(non_monomorphic_stub);
913       }
914       return JSArray::cast(*object)->length();
915     }
916 
917     // Use specialized code for getting prototype of functions.
918     if (object->IsJSFunction() &&
919         name->Equals(isolate()->heap()->prototype_symbol()) &&
920         JSFunction::cast(*object)->should_have_prototype()) {
921 #ifdef DEBUG
922       if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
923 #endif
924       if (state == PREMONOMORPHIC) {
925         set_target(isolate()->builtins()->builtin(
926             Builtins::kLoadIC_FunctionPrototype));
927       } else {
928         set_target(non_monomorphic_stub);
929       }
930       return Accessors::FunctionGetPrototype(*object, 0);
931     }
932   }
933 
934   // Check if the name is trivially convertible to an index and get
935   // the element if so.
936   uint32_t index;
937   if (name->AsArrayIndex(&index)) return object->GetElement(index);
938 
939   // Named lookup in the object.
940   LookupResult lookup;
941   LookupForRead(*object, *name, &lookup);
942 
943   // If we did not find a property, check if we need to throw an exception.
944   if (!lookup.IsProperty()) {
945     if (FLAG_strict || IsContextual(object)) {
946       return ReferenceError("not_defined", name);
947     }
948     LOG(isolate(), SuspectReadEvent(*name, *object));
949   }
950 
951   bool can_be_inlined_precheck =
952       FLAG_use_ic &&
953       lookup.IsProperty() &&
954       lookup.IsCacheable() &&
955       lookup.holder() == *object &&
956       !object->IsAccessCheckNeeded();
957 
958   bool can_be_inlined =
959       can_be_inlined_precheck &&
960       state == PREMONOMORPHIC &&
961       lookup.type() == FIELD;
962 
963   bool can_be_inlined_contextual =
964       can_be_inlined_precheck &&
965       state == UNINITIALIZED &&
966       lookup.holder()->IsGlobalObject() &&
967       lookup.type() == NORMAL;
968 
969   if (can_be_inlined) {
970     Map* map = lookup.holder()->map();
971     // Property's index in the properties array.  If negative we have
972     // an inobject property.
973     int index = lookup.GetFieldIndex() - map->inobject_properties();
974     if (index < 0) {
975       // Index is an offset from the end of the object.
976       int offset = map->instance_size() + (index * kPointerSize);
977       if (PatchInlinedLoad(address(), map, offset)) {
978         set_target(megamorphic_stub());
979         TRACE_IC_NAMED("[LoadIC : inline patch %s]\n", name);
980         return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
981       } else {
982         TRACE_IC_NAMED("[LoadIC : no inline patch %s (patching failed)]\n",
983                        name);
984       }
985     } else {
986       TRACE_IC_NAMED("[LoadIC : no inline patch %s (not inobject)]\n", name);
987     }
988   } else if (can_be_inlined_contextual) {
989     Map* map = lookup.holder()->map();
990     JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(
991         lookup.holder()->property_dictionary()->ValueAt(
992             lookup.GetDictionaryEntry()));
993     if (PatchInlinedContextualLoad(address(),
994                                    map,
995                                    cell,
996                                    lookup.IsDontDelete())) {
997       set_target(megamorphic_stub());
998       TRACE_IC_NAMED("[LoadIC : inline contextual patch %s]\n", name);
999       ASSERT(cell->value() != isolate()->heap()->the_hole_value());
1000       return cell->value();
1001     }
1002   } else {
1003     if (FLAG_use_ic && state == PREMONOMORPHIC) {
1004       TRACE_IC_NAMED("[LoadIC : no inline patch %s (not inlinable)]\n", name);
1005     }
1006   }
1007 
1008   // Update inline cache and stub cache.
1009   if (FLAG_use_ic) {
1010     UpdateCaches(&lookup, state, object, name);
1011   }
1012 
1013   PropertyAttributes attr;
1014   if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1015     // Get the property.
1016     Object* result;
1017     { MaybeObject* maybe_result =
1018           object->GetProperty(*object, &lookup, *name, &attr);
1019       if (!maybe_result->ToObject(&result)) return maybe_result;
1020     }
1021     // If the property is not present, check if we need to throw an
1022     // exception.
1023     if (attr == ABSENT && IsContextual(object)) {
1024       return ReferenceError("not_defined", name);
1025     }
1026     return result;
1027   }
1028 
1029   // Get the property.
1030   return object->GetProperty(*object, &lookup, *name, &attr);
1031 }
1032 
1033 
UpdateCaches(LookupResult * lookup,State state,Handle<Object> object,Handle<String> name)1034 void LoadIC::UpdateCaches(LookupResult* lookup,
1035                           State state,
1036                           Handle<Object> object,
1037                           Handle<String> name) {
1038   // Bail out if the result is not cacheable.
1039   if (!lookup->IsCacheable()) return;
1040 
1041   // Loading properties from values is not common, so don't try to
1042   // deal with non-JS objects here.
1043   if (!object->IsJSObject()) return;
1044   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1045 
1046   if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
1047 
1048   // Compute the code stub for this load.
1049   MaybeObject* maybe_code = NULL;
1050   Object* code;
1051   if (state == UNINITIALIZED) {
1052     // This is the first time we execute this inline cache.
1053     // Set the target to the pre monomorphic stub to delay
1054     // setting the monomorphic state.
1055     maybe_code = pre_monomorphic_stub();
1056   } else if (!lookup->IsProperty()) {
1057     // Nonexistent property. The result is undefined.
1058     maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name,
1059                                                                  *receiver);
1060   } else {
1061     // Compute monomorphic stub.
1062     switch (lookup->type()) {
1063       case FIELD: {
1064         maybe_code = isolate()->stub_cache()->ComputeLoadField(
1065             *name,
1066             *receiver,
1067             lookup->holder(),
1068             lookup->GetFieldIndex());
1069         break;
1070       }
1071       case CONSTANT_FUNCTION: {
1072         Object* constant = lookup->GetConstantFunction();
1073         maybe_code = isolate()->stub_cache()->ComputeLoadConstant(
1074             *name, *receiver, lookup->holder(), constant);
1075         break;
1076       }
1077       case NORMAL: {
1078         if (lookup->holder()->IsGlobalObject()) {
1079           GlobalObject* global = GlobalObject::cast(lookup->holder());
1080           JSGlobalPropertyCell* cell =
1081               JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
1082           maybe_code = isolate()->stub_cache()->ComputeLoadGlobal(*name,
1083                                                     *receiver,
1084                                                     global,
1085                                                     cell,
1086                                                     lookup->IsDontDelete());
1087         } else {
1088           // There is only one shared stub for loading normalized
1089           // properties. It does not traverse the prototype chain, so the
1090           // property must be found in the receiver for the stub to be
1091           // applicable.
1092           if (lookup->holder() != *receiver) return;
1093           maybe_code = isolate()->stub_cache()->ComputeLoadNormal();
1094         }
1095         break;
1096       }
1097       case CALLBACKS: {
1098         if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1099         AccessorInfo* callback =
1100             AccessorInfo::cast(lookup->GetCallbackObject());
1101         if (v8::ToCData<Address>(callback->getter()) == 0) return;
1102         maybe_code = isolate()->stub_cache()->ComputeLoadCallback(
1103             *name, *receiver, lookup->holder(), callback);
1104         break;
1105       }
1106       case INTERCEPTOR: {
1107         ASSERT(HasInterceptorGetter(lookup->holder()));
1108         maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor(
1109             *name, *receiver, lookup->holder());
1110         break;
1111       }
1112       default:
1113         return;
1114     }
1115   }
1116 
1117   // If we're unable to compute the stub (not enough memory left), we
1118   // simply avoid updating the caches.
1119   if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
1120 
1121   // Patch the call site depending on the state of the cache.
1122   if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
1123       state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1124     set_target(Code::cast(code));
1125   } else if (state == MONOMORPHIC) {
1126     set_target(megamorphic_stub());
1127   } else if (state == MEGAMORPHIC) {
1128     // Cache code holding map should be consistent with
1129     // GenerateMonomorphicCacheProbe.
1130     Map* map = JSObject::cast(object->IsJSObject() ? *object :
1131                               object->GetPrototype())->map();
1132 
1133     isolate()->stub_cache()->Set(*name, map, Code::cast(code));
1134   }
1135 
1136 #ifdef DEBUG
1137   TraceIC("LoadIC", name, state, target());
1138 #endif
1139 }
1140 
1141 
Load(State state,Handle<Object> object,Handle<Object> key)1142 MaybeObject* KeyedLoadIC::Load(State state,
1143                                Handle<Object> object,
1144                                Handle<Object> key) {
1145   // Check for values that can be converted into a symbol.
1146   // TODO(1295): Remove this code.
1147   HandleScope scope(isolate());
1148   if (key->IsHeapNumber() &&
1149       isnan(HeapNumber::cast(*key)->value())) {
1150     key = isolate()->factory()->nan_symbol();
1151   } else if (key->IsUndefined()) {
1152     key = isolate()->factory()->undefined_symbol();
1153   }
1154 
1155   if (key->IsSymbol()) {
1156     Handle<String> name = Handle<String>::cast(key);
1157 
1158     // If the object is undefined or null it's illegal to try to get any
1159     // of its properties; throw a TypeError in that case.
1160     if (object->IsUndefined() || object->IsNull()) {
1161       return TypeError("non_object_property_load", object, name);
1162     }
1163 
1164     if (FLAG_use_ic) {
1165       // TODO(1073): don't ignore the current stub state.
1166 
1167       // Use specialized code for getting the length of strings.
1168       if (object->IsString() &&
1169           name->Equals(isolate()->heap()->length_symbol())) {
1170         Handle<String> string = Handle<String>::cast(object);
1171         Object* code = NULL;
1172         { MaybeObject* maybe_code =
1173               isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name,
1174                                                                     *string);
1175           if (!maybe_code->ToObject(&code)) return maybe_code;
1176         }
1177         set_target(Code::cast(code));
1178 #ifdef DEBUG
1179         TraceIC("KeyedLoadIC", name, state, target());
1180 #endif  // DEBUG
1181         return Smi::FromInt(string->length());
1182       }
1183 
1184       // Use specialized code for getting the length of arrays.
1185       if (object->IsJSArray() &&
1186           name->Equals(isolate()->heap()->length_symbol())) {
1187         Handle<JSArray> array = Handle<JSArray>::cast(object);
1188         Object* code;
1189         { MaybeObject* maybe_code =
1190               isolate()->stub_cache()->ComputeKeyedLoadArrayLength(*name,
1191                                                                    *array);
1192           if (!maybe_code->ToObject(&code)) return maybe_code;
1193         }
1194         set_target(Code::cast(code));
1195 #ifdef DEBUG
1196         TraceIC("KeyedLoadIC", name, state, target());
1197 #endif  // DEBUG
1198         return JSArray::cast(*object)->length();
1199       }
1200 
1201       // Use specialized code for getting prototype of functions.
1202       if (object->IsJSFunction() &&
1203           name->Equals(isolate()->heap()->prototype_symbol()) &&
1204         JSFunction::cast(*object)->should_have_prototype()) {
1205         Handle<JSFunction> function = Handle<JSFunction>::cast(object);
1206         Object* code;
1207         { MaybeObject* maybe_code =
1208               isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
1209                   *name, *function);
1210           if (!maybe_code->ToObject(&code)) return maybe_code;
1211         }
1212         set_target(Code::cast(code));
1213 #ifdef DEBUG
1214         TraceIC("KeyedLoadIC", name, state, target());
1215 #endif  // DEBUG
1216         return Accessors::FunctionGetPrototype(*object, 0);
1217       }
1218     }
1219 
1220     // Check if the name is trivially convertible to an index and get
1221     // the element or char if so.
1222     uint32_t index = 0;
1223     if (name->AsArrayIndex(&index)) {
1224       HandleScope scope(isolate());
1225       // Rewrite to the generic keyed load stub.
1226       if (FLAG_use_ic) set_target(generic_stub());
1227       return Runtime::GetElementOrCharAt(isolate(), object, index);
1228     }
1229 
1230     // Named lookup.
1231     LookupResult lookup;
1232     LookupForRead(*object, *name, &lookup);
1233 
1234     // If we did not find a property, check if we need to throw an exception.
1235     if (!lookup.IsProperty()) {
1236       if (FLAG_strict || IsContextual(object)) {
1237         return ReferenceError("not_defined", name);
1238       }
1239     }
1240 
1241     if (FLAG_use_ic) {
1242       UpdateCaches(&lookup, state, object, name);
1243     }
1244 
1245     PropertyAttributes attr;
1246     if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1247       // Get the property.
1248       Object* result;
1249       { MaybeObject* maybe_result =
1250             object->GetProperty(*object, &lookup, *name, &attr);
1251         if (!maybe_result->ToObject(&result)) return maybe_result;
1252       }
1253       // If the property is not present, check if we need to throw an
1254       // exception.
1255       if (attr == ABSENT && IsContextual(object)) {
1256         return ReferenceError("not_defined", name);
1257       }
1258       return result;
1259     }
1260 
1261     return object->GetProperty(*object, &lookup, *name, &attr);
1262   }
1263 
1264   // Do not use ICs for objects that require access checks (including
1265   // the global object).
1266   bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1267 
1268   if (use_ic) {
1269     Code* stub = generic_stub();
1270     if (state == UNINITIALIZED) {
1271       if (object->IsString() && key->IsNumber()) {
1272         stub = string_stub();
1273       } else if (object->IsJSObject()) {
1274         Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1275         if (receiver->HasExternalArrayElements()) {
1276           MaybeObject* probe =
1277               isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
1278                   *receiver, false, kNonStrictMode);
1279           stub = probe->IsFailure() ?
1280               NULL : Code::cast(probe->ToObjectUnchecked());
1281         } else if (receiver->HasIndexedInterceptor()) {
1282           stub = indexed_interceptor_stub();
1283         } else if (key->IsSmi() &&
1284                    receiver->map()->has_fast_elements()) {
1285           MaybeObject* probe =
1286               isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver);
1287           stub = probe->IsFailure() ?
1288               NULL : Code::cast(probe->ToObjectUnchecked());
1289         }
1290       }
1291     }
1292     if (stub != NULL) set_target(stub);
1293 
1294 #ifdef DEBUG
1295     TraceIC("KeyedLoadIC", key, state, target());
1296 #endif  // DEBUG
1297 
1298     // For JSObjects with fast elements that are not value wrappers
1299     // and that do not have indexed interceptors, we initialize the
1300     // inlined fast case (if present) by patching the inlined map
1301     // check.
1302     if (object->IsJSObject() &&
1303         !object->IsJSValue() &&
1304         !JSObject::cast(*object)->HasIndexedInterceptor() &&
1305         JSObject::cast(*object)->HasFastElements()) {
1306       Map* map = JSObject::cast(*object)->map();
1307       PatchInlinedLoad(address(), map);
1308     }
1309   }
1310 
1311   // Get the property.
1312   return Runtime::GetObjectProperty(isolate(), object, key);
1313 }
1314 
1315 
UpdateCaches(LookupResult * lookup,State state,Handle<Object> object,Handle<String> name)1316 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
1317                                Handle<Object> object, Handle<String> name) {
1318   // Bail out if we didn't find a result.
1319   if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
1320 
1321   if (!object->IsJSObject()) return;
1322   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1323 
1324   if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
1325 
1326   // Compute the code stub for this load.
1327   MaybeObject* maybe_code = NULL;
1328   Object* code;
1329 
1330   if (state == UNINITIALIZED) {
1331     // This is the first time we execute this inline cache.
1332     // Set the target to the pre monomorphic stub to delay
1333     // setting the monomorphic state.
1334     maybe_code = pre_monomorphic_stub();
1335   } else {
1336     // Compute a monomorphic stub.
1337     switch (lookup->type()) {
1338       case FIELD: {
1339         maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField(
1340             *name, *receiver, lookup->holder(), lookup->GetFieldIndex());
1341         break;
1342       }
1343       case CONSTANT_FUNCTION: {
1344         Object* constant = lookup->GetConstantFunction();
1345         maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
1346             *name, *receiver, lookup->holder(), constant);
1347         break;
1348       }
1349       case CALLBACKS: {
1350         if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1351         AccessorInfo* callback =
1352             AccessorInfo::cast(lookup->GetCallbackObject());
1353         if (v8::ToCData<Address>(callback->getter()) == 0) return;
1354         maybe_code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
1355             *name, *receiver, lookup->holder(), callback);
1356         break;
1357       }
1358       case INTERCEPTOR: {
1359         ASSERT(HasInterceptorGetter(lookup->holder()));
1360         maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
1361             *name, *receiver, lookup->holder());
1362         break;
1363       }
1364       default: {
1365         // Always rewrite to the generic case so that we do not
1366         // repeatedly try to rewrite.
1367         maybe_code = generic_stub();
1368         break;
1369       }
1370     }
1371   }
1372 
1373   // If we're unable to compute the stub (not enough memory left), we
1374   // simply avoid updating the caches.
1375   if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
1376 
1377   // Patch the call site depending on the state of the cache.  Make
1378   // sure to always rewrite from monomorphic to megamorphic.
1379   ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1380   if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1381     set_target(Code::cast(code));
1382   } else if (state == MONOMORPHIC) {
1383     set_target(megamorphic_stub());
1384   }
1385 
1386 #ifdef DEBUG
1387   TraceIC("KeyedLoadIC", name, state, target());
1388 #endif
1389 }
1390 
1391 
StoreICableLookup(LookupResult * lookup)1392 static bool StoreICableLookup(LookupResult* lookup) {
1393   // Bail out if we didn't find a result.
1394   if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false;
1395 
1396   // If the property is read-only, we leave the IC in its current
1397   // state.
1398   if (lookup->IsReadOnly()) return false;
1399 
1400   return true;
1401 }
1402 
1403 
LookupForWrite(JSObject * object,String * name,LookupResult * lookup)1404 static bool LookupForWrite(JSObject* object,
1405                            String* name,
1406                            LookupResult* lookup) {
1407   object->LocalLookup(name, lookup);
1408   if (!StoreICableLookup(lookup)) {
1409     return false;
1410   }
1411 
1412   if (lookup->type() == INTERCEPTOR) {
1413     if (object->GetNamedInterceptor()->setter()->IsUndefined()) {
1414       object->LocalLookupRealNamedProperty(name, lookup);
1415       return StoreICableLookup(lookup);
1416     }
1417   }
1418 
1419   return true;
1420 }
1421 
1422 
Store(State state,StrictModeFlag strict_mode,Handle<Object> object,Handle<String> name,Handle<Object> value)1423 MaybeObject* StoreIC::Store(State state,
1424                             StrictModeFlag strict_mode,
1425                             Handle<Object> object,
1426                             Handle<String> name,
1427                             Handle<Object> value) {
1428   // If the object is undefined or null it's illegal to try to set any
1429   // properties on it; throw a TypeError in that case.
1430   if (object->IsUndefined() || object->IsNull()) {
1431     return TypeError("non_object_property_store", object, name);
1432   }
1433 
1434   if (!object->IsJSObject()) {
1435     // The length property of string values is read-only. Throw in strict mode.
1436     if (strict_mode == kStrictMode && object->IsString() &&
1437         name->Equals(isolate()->heap()->length_symbol())) {
1438       return TypeError("strict_read_only_property", object, name);
1439     }
1440     // Ignore stores where the receiver is not a JSObject.
1441     return *value;
1442   }
1443 
1444   Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1445 
1446   // Check if the given name is an array index.
1447   uint32_t index;
1448   if (name->AsArrayIndex(&index)) {
1449     HandleScope scope(isolate());
1450     Handle<Object> result = SetElement(receiver, index, value, strict_mode);
1451     if (result.is_null()) return Failure::Exception();
1452     return *value;
1453   }
1454 
1455   // Use specialized code for setting the length of arrays.
1456   if (receiver->IsJSArray()
1457       && name->Equals(isolate()->heap()->length_symbol())
1458       && receiver->AllowsSetElementsLength()) {
1459 #ifdef DEBUG
1460     if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
1461 #endif
1462     Builtins::Name target = (strict_mode == kStrictMode)
1463         ? Builtins::kStoreIC_ArrayLength_Strict
1464         : Builtins::kStoreIC_ArrayLength;
1465     set_target(isolate()->builtins()->builtin(target));
1466     return receiver->SetProperty(*name, *value, NONE, strict_mode);
1467   }
1468 
1469   // Lookup the property locally in the receiver.
1470   if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
1471     LookupResult lookup;
1472 
1473     if (LookupForWrite(*receiver, *name, &lookup)) {
1474       bool can_be_inlined =
1475           state == UNINITIALIZED &&
1476           lookup.IsProperty() &&
1477           lookup.holder() == *receiver &&
1478           lookup.type() == FIELD &&
1479           !receiver->IsAccessCheckNeeded();
1480 
1481       if (can_be_inlined) {
1482         Map* map = lookup.holder()->map();
1483         // Property's index in the properties array.  If negative we have
1484         // an inobject property.
1485         int index = lookup.GetFieldIndex() - map->inobject_properties();
1486         if (index < 0) {
1487           // Index is an offset from the end of the object.
1488           int offset = map->instance_size() + (index * kPointerSize);
1489           if (PatchInlinedStore(address(), map, offset)) {
1490             set_target((strict_mode == kStrictMode)
1491                          ? megamorphic_stub_strict()
1492                          : megamorphic_stub());
1493 #ifdef DEBUG
1494             if (FLAG_trace_ic) {
1495               PrintF("[StoreIC : inline patch %s]\n", *name->ToCString());
1496             }
1497 #endif
1498             return receiver->SetProperty(*name, *value, NONE, strict_mode);
1499 #ifdef DEBUG
1500 
1501           } else {
1502             if (FLAG_trace_ic) {
1503               PrintF("[StoreIC : no inline patch %s (patching failed)]\n",
1504                      *name->ToCString());
1505             }
1506           }
1507         } else {
1508           if (FLAG_trace_ic) {
1509             PrintF("[StoreIC : no inline patch %s (not inobject)]\n",
1510                    *name->ToCString());
1511           }
1512         }
1513       } else {
1514         if (state == PREMONOMORPHIC) {
1515           if (FLAG_trace_ic) {
1516             PrintF("[StoreIC : no inline patch %s (not inlinable)]\n",
1517                    *name->ToCString());
1518 #endif
1519           }
1520         }
1521       }
1522 
1523       // If no inlined store ic was patched, generate a stub for this
1524       // store.
1525       UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
1526     } else {
1527       // Strict mode doesn't allow setting non-existent global property
1528       // or an assignment to a read only property.
1529       if (strict_mode == kStrictMode) {
1530         if (lookup.IsFound() && lookup.IsReadOnly()) {
1531           return TypeError("strict_read_only_property", object, name);
1532         } else if (IsContextual(object)) {
1533           return ReferenceError("not_defined", name);
1534         }
1535       }
1536     }
1537   }
1538 
1539   if (receiver->IsJSGlobalProxy()) {
1540     // Generate a generic stub that goes to the runtime when we see a global
1541     // proxy as receiver.
1542     Code* stub = (strict_mode == kStrictMode)
1543         ? global_proxy_stub_strict()
1544         : global_proxy_stub();
1545     if (target() != stub) {
1546       set_target(stub);
1547 #ifdef DEBUG
1548       TraceIC("StoreIC", name, state, target());
1549 #endif
1550     }
1551   }
1552 
1553   // Set the property.
1554   return receiver->SetProperty(*name, *value, NONE, strict_mode);
1555 }
1556 
1557 
UpdateCaches(LookupResult * lookup,State state,StrictModeFlag strict_mode,Handle<JSObject> receiver,Handle<String> name,Handle<Object> value)1558 void StoreIC::UpdateCaches(LookupResult* lookup,
1559                            State state,
1560                            StrictModeFlag strict_mode,
1561                            Handle<JSObject> receiver,
1562                            Handle<String> name,
1563                            Handle<Object> value) {
1564   // Skip JSGlobalProxy.
1565   ASSERT(!receiver->IsJSGlobalProxy());
1566 
1567   ASSERT(StoreICableLookup(lookup));
1568 
1569   // If the property has a non-field type allowing map transitions
1570   // where there is extra room in the object, we leave the IC in its
1571   // current state.
1572   PropertyType type = lookup->type();
1573 
1574   // Compute the code stub for this store; used for rewriting to
1575   // monomorphic state and making sure that the code stub is in the
1576   // stub cache.
1577   MaybeObject* maybe_code = NULL;
1578   Object* code = NULL;
1579   switch (type) {
1580     case FIELD: {
1581       maybe_code = isolate()->stub_cache()->ComputeStoreField(
1582           *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
1583       break;
1584     }
1585     case MAP_TRANSITION: {
1586       if (lookup->GetAttributes() != NONE) return;
1587       HandleScope scope(isolate());
1588       ASSERT(type == MAP_TRANSITION);
1589       Handle<Map> transition(lookup->GetTransitionMap());
1590       int index = transition->PropertyIndexFor(*name);
1591       maybe_code = isolate()->stub_cache()->ComputeStoreField(
1592           *name, *receiver, index, *transition, strict_mode);
1593       break;
1594     }
1595     case NORMAL: {
1596       if (receiver->IsGlobalObject()) {
1597         // The stub generated for the global object picks the value directly
1598         // from the property cell. So the property must be directly on the
1599         // global object.
1600         Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1601         JSGlobalPropertyCell* cell =
1602             JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
1603         maybe_code = isolate()->stub_cache()->ComputeStoreGlobal(
1604             *name, *global, cell, strict_mode);
1605       } else {
1606         if (lookup->holder() != *receiver) return;
1607         maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
1608       }
1609       break;
1610     }
1611     case CALLBACKS: {
1612       if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1613       AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1614       if (v8::ToCData<Address>(callback->setter()) == 0) return;
1615       maybe_code = isolate()->stub_cache()->ComputeStoreCallback(
1616           *name, *receiver, callback, strict_mode);
1617       break;
1618     }
1619     case INTERCEPTOR: {
1620       ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
1621       maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(
1622           *name, *receiver, strict_mode);
1623       break;
1624     }
1625     default:
1626       return;
1627   }
1628 
1629   // If we're unable to compute the stub (not enough memory left), we
1630   // simply avoid updating the caches.
1631   if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
1632 
1633   // Patch the call site depending on the state of the cache.
1634   if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1635     set_target(Code::cast(code));
1636   } else if (state == MONOMORPHIC) {
1637     // Only move to megamorphic if the target changes.
1638     if (target() != Code::cast(code)) {
1639       set_target((strict_mode == kStrictMode)
1640                    ? megamorphic_stub_strict()
1641                    : megamorphic_stub());
1642     }
1643   } else if (state == MEGAMORPHIC) {
1644     // Update the stub cache.
1645     isolate()->stub_cache()->Set(*name,
1646                                  receiver->map(),
1647                                  Code::cast(code));
1648   }
1649 
1650 #ifdef DEBUG
1651   TraceIC("StoreIC", name, state, target());
1652 #endif
1653 }
1654 
1655 
Store(State state,StrictModeFlag strict_mode,Handle<Object> object,Handle<Object> key,Handle<Object> value)1656 MaybeObject* KeyedStoreIC::Store(State state,
1657                                  StrictModeFlag strict_mode,
1658                                  Handle<Object> object,
1659                                  Handle<Object> key,
1660                                  Handle<Object> value) {
1661   if (key->IsSymbol()) {
1662     Handle<String> name = Handle<String>::cast(key);
1663 
1664     // If the object is undefined or null it's illegal to try to set any
1665     // properties on it; throw a TypeError in that case.
1666     if (object->IsUndefined() || object->IsNull()) {
1667       return TypeError("non_object_property_store", object, name);
1668     }
1669 
1670     // Ignore stores where the receiver is not a JSObject.
1671     if (!object->IsJSObject()) return *value;
1672     Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1673 
1674     // Check if the given name is an array index.
1675     uint32_t index;
1676     if (name->AsArrayIndex(&index)) {
1677       HandleScope scope(isolate());
1678       Handle<Object> result = SetElement(receiver, index, value, strict_mode);
1679       if (result.is_null()) return Failure::Exception();
1680       return *value;
1681     }
1682 
1683     // Lookup the property locally in the receiver.
1684     LookupResult lookup;
1685     receiver->LocalLookup(*name, &lookup);
1686 
1687     // Update inline cache and stub cache.
1688     if (FLAG_use_ic) {
1689       UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
1690     }
1691 
1692     // Set the property.
1693     return receiver->SetProperty(*name, *value, NONE, strict_mode);
1694   }
1695 
1696   // Do not use ICs for objects that require access checks (including
1697   // the global object).
1698   bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1699   ASSERT(!(use_ic && object->IsJSGlobalProxy()));
1700 
1701   if (use_ic) {
1702     Code* stub =
1703         (strict_mode == kStrictMode) ? generic_stub_strict() : generic_stub();
1704     if (state == UNINITIALIZED) {
1705       if (object->IsJSObject()) {
1706         Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1707         if (receiver->HasExternalArrayElements()) {
1708           MaybeObject* probe =
1709               isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
1710                   *receiver, true, strict_mode);
1711           stub = probe->IsFailure() ?
1712               NULL : Code::cast(probe->ToObjectUnchecked());
1713         } else if (key->IsSmi() && receiver->map()->has_fast_elements()) {
1714           MaybeObject* probe =
1715               isolate()->stub_cache()->ComputeKeyedStoreSpecialized(
1716                   *receiver, strict_mode);
1717           stub = probe->IsFailure() ?
1718               NULL : Code::cast(probe->ToObjectUnchecked());
1719         }
1720       }
1721     }
1722     if (stub != NULL) set_target(stub);
1723   }
1724 
1725   // Set the property.
1726   return Runtime::SetObjectProperty(
1727       isolate(), object , key, value, NONE, strict_mode);
1728 }
1729 
1730 
UpdateCaches(LookupResult * lookup,State state,StrictModeFlag strict_mode,Handle<JSObject> receiver,Handle<String> name,Handle<Object> value)1731 void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
1732                                 State state,
1733                                 StrictModeFlag strict_mode,
1734                                 Handle<JSObject> receiver,
1735                                 Handle<String> name,
1736                                 Handle<Object> value) {
1737   // Skip JSGlobalProxy.
1738   if (receiver->IsJSGlobalProxy()) return;
1739 
1740   // Bail out if we didn't find a result.
1741   if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return;
1742 
1743   // If the property is read-only, we leave the IC in its current
1744   // state.
1745   if (lookup->IsReadOnly()) return;
1746 
1747   // If the property has a non-field type allowing map transitions
1748   // where there is extra room in the object, we leave the IC in its
1749   // current state.
1750   PropertyType type = lookup->type();
1751 
1752   // Compute the code stub for this store; used for rewriting to
1753   // monomorphic state and making sure that the code stub is in the
1754   // stub cache.
1755   MaybeObject* maybe_code = NULL;
1756   Object* code = NULL;
1757 
1758   switch (type) {
1759     case FIELD: {
1760       maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
1761           *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
1762       break;
1763     }
1764     case MAP_TRANSITION: {
1765       if (lookup->GetAttributes() == NONE) {
1766         HandleScope scope(isolate());
1767         ASSERT(type == MAP_TRANSITION);
1768         Handle<Map> transition(lookup->GetTransitionMap());
1769         int index = transition->PropertyIndexFor(*name);
1770         maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
1771             *name, *receiver, index, *transition, strict_mode);
1772         break;
1773       }
1774       // fall through.
1775     }
1776     default: {
1777       // Always rewrite to the generic case so that we do not
1778       // repeatedly try to rewrite.
1779       maybe_code = (strict_mode == kStrictMode)
1780           ? generic_stub_strict()
1781           : generic_stub();
1782       break;
1783     }
1784   }
1785 
1786   // If we're unable to compute the stub (not enough memory left), we
1787   // simply avoid updating the caches.
1788   if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
1789 
1790   // Patch the call site depending on the state of the cache.  Make
1791   // sure to always rewrite from monomorphic to megamorphic.
1792   ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1793   if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1794     set_target(Code::cast(code));
1795   } else if (state == MONOMORPHIC) {
1796     set_target((strict_mode == kStrictMode)
1797                  ? megamorphic_stub_strict()
1798                  : megamorphic_stub());
1799   }
1800 
1801 #ifdef DEBUG
1802   TraceIC("KeyedStoreIC", name, state, target());
1803 #endif
1804 }
1805 
1806 
1807 // ----------------------------------------------------------------------------
1808 // Static IC stub generators.
1809 //
1810 
CompileFunction(Isolate * isolate,JSFunction * function,InLoopFlag in_loop)1811 static JSFunction* CompileFunction(Isolate* isolate,
1812                                    JSFunction* function,
1813                                    InLoopFlag in_loop) {
1814   // Compile now with optimization.
1815   HandleScope scope(isolate);
1816   Handle<JSFunction> function_handle(function, isolate);
1817   if (in_loop == IN_LOOP) {
1818     CompileLazyInLoop(function_handle, CLEAR_EXCEPTION);
1819   } else {
1820     CompileLazy(function_handle, CLEAR_EXCEPTION);
1821   }
1822   return *function_handle;
1823 }
1824 
1825 
1826 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject *,CallIC_Miss)1827 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
1828   NoHandleAllocation na;
1829   ASSERT(args.length() == 2);
1830   CallIC ic(isolate);
1831   IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1832   Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1833   MaybeObject* maybe_result = ic.LoadFunction(state,
1834                                               extra_ic_state,
1835                                               args.at<Object>(0),
1836                                               args.at<String>(1));
1837   Object* result;
1838   if (!maybe_result->ToObject(&result)) return maybe_result;
1839 
1840   // The first time the inline cache is updated may be the first time the
1841   // function it references gets called.  If the function was lazily compiled
1842   // then the first call will trigger a compilation.  We check for this case
1843   // and we do the compilation immediately, instead of waiting for the stub
1844   // currently attached to the JSFunction object to trigger compilation.  We
1845   // do this in the case where we know that the inline cache is inside a loop,
1846   // because then we know that we want to optimize the function.
1847   if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1848     return result;
1849   }
1850   return CompileFunction(isolate,
1851                          JSFunction::cast(result),
1852                          ic.target()->ic_in_loop());
1853 }
1854 
1855 
1856 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject *,KeyedCallIC_Miss)1857 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
1858   NoHandleAllocation na;
1859   ASSERT(args.length() == 2);
1860   KeyedCallIC ic(isolate);
1861   IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1862   Object* result;
1863   { MaybeObject* maybe_result =
1864       ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1));
1865     if (!maybe_result->ToObject(&result)) return maybe_result;
1866   }
1867 
1868   if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1869     return result;
1870   }
1871   return CompileFunction(isolate,
1872                          JSFunction::cast(result),
1873                          ic.target()->ic_in_loop());
1874 }
1875 
1876 
1877 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject *,LoadIC_Miss)1878 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
1879   NoHandleAllocation na;
1880   ASSERT(args.length() == 2);
1881   LoadIC ic(isolate);
1882   IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1883   return ic.Load(state, args.at<Object>(0), args.at<String>(1));
1884 }
1885 
1886 
1887 // Used from ic-<arch>.cc
RUNTIME_FUNCTION(MaybeObject *,KeyedLoadIC_Miss)1888 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
1889   NoHandleAllocation na;
1890   ASSERT(args.length() == 2);
1891   KeyedLoadIC ic(isolate);
1892   IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1893   return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
1894 }
1895 
1896 
1897 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject *,StoreIC_Miss)1898 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
1899   NoHandleAllocation na;
1900   ASSERT(args.length() == 3);
1901   StoreIC ic(isolate);
1902   IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1903   Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1904   return ic.Store(state,
1905                   static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
1906                   args.at<Object>(0),
1907                   args.at<String>(1),
1908                   args.at<Object>(2));
1909 }
1910 
1911 
RUNTIME_FUNCTION(MaybeObject *,StoreIC_ArrayLength)1912 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
1913   NoHandleAllocation nha;
1914 
1915   ASSERT(args.length() == 2);
1916   JSObject* receiver = JSObject::cast(args[0]);
1917   Object* len = args[1];
1918 
1919   // The generated code should filter out non-Smis before we get here.
1920   ASSERT(len->IsSmi());
1921 
1922   Object* result;
1923   { MaybeObject* maybe_result = receiver->SetElementsLength(len);
1924     if (!maybe_result->ToObject(&result)) return maybe_result;
1925   }
1926   return len;
1927 }
1928 
1929 
1930 // Extend storage is called in a store inline cache when
1931 // it is necessary to extend the properties array of a
1932 // JSObject.
RUNTIME_FUNCTION(MaybeObject *,SharedStoreIC_ExtendStorage)1933 RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
1934   NoHandleAllocation na;
1935   ASSERT(args.length() == 3);
1936 
1937   // Convert the parameters
1938   JSObject* object = JSObject::cast(args[0]);
1939   Map* transition = Map::cast(args[1]);
1940   Object* value = args[2];
1941 
1942   // Check the object has run out out property space.
1943   ASSERT(object->HasFastProperties());
1944   ASSERT(object->map()->unused_property_fields() == 0);
1945 
1946   // Expand the properties array.
1947   FixedArray* old_storage = object->properties();
1948   int new_unused = transition->unused_property_fields();
1949   int new_size = old_storage->length() + new_unused + 1;
1950   Object* result;
1951   { MaybeObject* maybe_result = old_storage->CopySize(new_size);
1952     if (!maybe_result->ToObject(&result)) return maybe_result;
1953   }
1954   FixedArray* new_storage = FixedArray::cast(result);
1955   new_storage->set(old_storage->length(), value);
1956 
1957   // Set the new property value and do the map transition.
1958   object->set_properties(new_storage);
1959   object->set_map(transition);
1960 
1961   // Return the stored value.
1962   return value;
1963 }
1964 
1965 
1966 // Used from ic-<arch>.cc.
RUNTIME_FUNCTION(MaybeObject *,KeyedStoreIC_Miss)1967 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
1968   NoHandleAllocation na;
1969   ASSERT(args.length() == 3);
1970   KeyedStoreIC ic(isolate);
1971   IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1972   Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1973   return ic.Store(state,
1974                   static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
1975                   args.at<Object>(0),
1976                   args.at<Object>(1),
1977                   args.at<Object>(2));
1978 }
1979 
1980 
patch(Code * code)1981 void TRBinaryOpIC::patch(Code* code) {
1982   set_target(code);
1983 }
1984 
1985 
GetName(TypeInfo type_info)1986 const char* TRBinaryOpIC::GetName(TypeInfo type_info) {
1987   switch (type_info) {
1988     case UNINITIALIZED: return "Uninitialized";
1989     case SMI: return "SMI";
1990     case INT32: return "Int32s";
1991     case HEAP_NUMBER: return "HeapNumbers";
1992     case ODDBALL: return "Oddball";
1993     case STRING: return "Strings";
1994     case GENERIC: return "Generic";
1995     default: return "Invalid";
1996   }
1997 }
1998 
1999 
ToState(TypeInfo type_info)2000 TRBinaryOpIC::State TRBinaryOpIC::ToState(TypeInfo type_info) {
2001   switch (type_info) {
2002     case UNINITIALIZED:
2003       return ::v8::internal::UNINITIALIZED;
2004     case SMI:
2005     case INT32:
2006     case HEAP_NUMBER:
2007     case ODDBALL:
2008     case STRING:
2009       return MONOMORPHIC;
2010     case GENERIC:
2011       return MEGAMORPHIC;
2012   }
2013   UNREACHABLE();
2014   return ::v8::internal::UNINITIALIZED;
2015 }
2016 
2017 
JoinTypes(TRBinaryOpIC::TypeInfo x,TRBinaryOpIC::TypeInfo y)2018 TRBinaryOpIC::TypeInfo TRBinaryOpIC::JoinTypes(TRBinaryOpIC::TypeInfo x,
2019                                                TRBinaryOpIC::TypeInfo y) {
2020   if (x == UNINITIALIZED) return y;
2021   if (y == UNINITIALIZED) return x;
2022   if (x == STRING && y == STRING) return STRING;
2023   if (x == STRING || y == STRING) return GENERIC;
2024   if (x >= y) return x;
2025   return y;
2026 }
2027 
GetTypeInfo(Handle<Object> left,Handle<Object> right)2028 TRBinaryOpIC::TypeInfo TRBinaryOpIC::GetTypeInfo(Handle<Object> left,
2029                                                  Handle<Object> right) {
2030   ::v8::internal::TypeInfo left_type =
2031       ::v8::internal::TypeInfo::TypeFromValue(left);
2032   ::v8::internal::TypeInfo right_type =
2033       ::v8::internal::TypeInfo::TypeFromValue(right);
2034 
2035   if (left_type.IsSmi() && right_type.IsSmi()) {
2036     return SMI;
2037   }
2038 
2039   if (left_type.IsInteger32() && right_type.IsInteger32()) {
2040     // Platforms with 32-bit Smis have no distinct INT32 type.
2041     if (kSmiValueSize == 32) return SMI;
2042     return INT32;
2043   }
2044 
2045   if (left_type.IsNumber() && right_type.IsNumber()) {
2046     return HEAP_NUMBER;
2047   }
2048 
2049   if (left_type.IsString() || right_type.IsString()) {
2050     // Patching for fast string ADD makes sense even if only one of the
2051     // arguments is a string.
2052     return STRING;
2053   }
2054 
2055   // Check for oddball objects.
2056   if (left->IsUndefined() && right->IsNumber()) return ODDBALL;
2057   if (left->IsNumber() && right->IsUndefined()) return ODDBALL;
2058 
2059   return GENERIC;
2060 }
2061 
2062 
2063 // defined in code-stubs-<arch>.cc
2064 // Only needed to remove dependency of ic.cc on code-stubs-<arch>.h.
2065 Handle<Code> GetTypeRecordingBinaryOpStub(int key,
2066                                           TRBinaryOpIC::TypeInfo type_info,
2067                                           TRBinaryOpIC::TypeInfo result_type);
2068 
2069 
RUNTIME_FUNCTION(MaybeObject *,TypeRecordingBinaryOp_Patch)2070 RUNTIME_FUNCTION(MaybeObject*, TypeRecordingBinaryOp_Patch) {
2071   ASSERT(args.length() == 5);
2072 
2073   HandleScope scope(isolate);
2074   Handle<Object> left = args.at<Object>(0);
2075   Handle<Object> right = args.at<Object>(1);
2076   int key = Smi::cast(args[2])->value();
2077   Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value());
2078   TRBinaryOpIC::TypeInfo previous_type =
2079       static_cast<TRBinaryOpIC::TypeInfo>(Smi::cast(args[4])->value());
2080 
2081   TRBinaryOpIC::TypeInfo type = TRBinaryOpIC::GetTypeInfo(left, right);
2082   type = TRBinaryOpIC::JoinTypes(type, previous_type);
2083   TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED;
2084   if (type == TRBinaryOpIC::STRING && op != Token::ADD) {
2085     type = TRBinaryOpIC::GENERIC;
2086   }
2087   if (type == TRBinaryOpIC::SMI &&
2088       previous_type == TRBinaryOpIC::SMI) {
2089     if (op == Token::DIV || op == Token::MUL || kSmiValueSize == 32) {
2090       // Arithmetic on two Smi inputs has yielded a heap number.
2091       // That is the only way to get here from the Smi stub.
2092       // With 32-bit Smis, all overflows give heap numbers, but with
2093       // 31-bit Smis, most operations overflow to int32 results.
2094       result_type = TRBinaryOpIC::HEAP_NUMBER;
2095     } else {
2096       // Other operations on SMIs that overflow yield int32s.
2097       result_type = TRBinaryOpIC::INT32;
2098     }
2099   }
2100   if (type == TRBinaryOpIC::INT32 &&
2101       previous_type == TRBinaryOpIC::INT32) {
2102     // We must be here because an operation on two INT32 types overflowed.
2103     result_type = TRBinaryOpIC::HEAP_NUMBER;
2104   }
2105 
2106   Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type);
2107   if (!code.is_null()) {
2108     if (FLAG_trace_ic) {
2109       PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n",
2110              TRBinaryOpIC::GetName(previous_type),
2111              TRBinaryOpIC::GetName(type),
2112              TRBinaryOpIC::GetName(result_type),
2113              Token::Name(op));
2114     }
2115     TRBinaryOpIC ic(isolate);
2116     ic.patch(*code);
2117 
2118     // Activate inlined smi code.
2119     if (previous_type == TRBinaryOpIC::UNINITIALIZED) {
2120       PatchInlinedSmiCode(ic.address());
2121     }
2122   }
2123 
2124   Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
2125       isolate->thread_local_top()->context_->builtins(), isolate);
2126   Object* builtin = NULL;  // Initialization calms down the compiler.
2127   switch (op) {
2128     case Token::ADD:
2129       builtin = builtins->javascript_builtin(Builtins::ADD);
2130       break;
2131     case Token::SUB:
2132       builtin = builtins->javascript_builtin(Builtins::SUB);
2133       break;
2134     case Token::MUL:
2135       builtin = builtins->javascript_builtin(Builtins::MUL);
2136       break;
2137     case Token::DIV:
2138       builtin = builtins->javascript_builtin(Builtins::DIV);
2139       break;
2140     case Token::MOD:
2141       builtin = builtins->javascript_builtin(Builtins::MOD);
2142       break;
2143     case Token::BIT_AND:
2144       builtin = builtins->javascript_builtin(Builtins::BIT_AND);
2145       break;
2146     case Token::BIT_OR:
2147       builtin = builtins->javascript_builtin(Builtins::BIT_OR);
2148       break;
2149     case Token::BIT_XOR:
2150       builtin = builtins->javascript_builtin(Builtins::BIT_XOR);
2151       break;
2152     case Token::SHR:
2153       builtin = builtins->javascript_builtin(Builtins::SHR);
2154       break;
2155     case Token::SAR:
2156       builtin = builtins->javascript_builtin(Builtins::SAR);
2157       break;
2158     case Token::SHL:
2159       builtin = builtins->javascript_builtin(Builtins::SHL);
2160       break;
2161     default:
2162       UNREACHABLE();
2163   }
2164 
2165   Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
2166 
2167   bool caught_exception;
2168   Object** builtin_args[] = { right.location() };
2169   Handle<Object> result = Execution::Call(builtin_function,
2170                                           left,
2171                                           ARRAY_SIZE(builtin_args),
2172                                           builtin_args,
2173                                           &caught_exception);
2174   if (caught_exception) {
2175     return Failure::Exception();
2176   }
2177   return *result;
2178 }
2179 
2180 
GetUninitialized(Token::Value op)2181 Handle<Code> CompareIC::GetUninitialized(Token::Value op) {
2182   ICCompareStub stub(op, UNINITIALIZED);
2183   return stub.GetCode();
2184 }
2185 
2186 
ComputeState(Code * target)2187 CompareIC::State CompareIC::ComputeState(Code* target) {
2188   int key = target->major_key();
2189   if (key == CodeStub::Compare) return GENERIC;
2190   ASSERT(key == CodeStub::CompareIC);
2191   return static_cast<State>(target->compare_state());
2192 }
2193 
2194 
GetStateName(State state)2195 const char* CompareIC::GetStateName(State state) {
2196   switch (state) {
2197     case UNINITIALIZED: return "UNINITIALIZED";
2198     case SMIS: return "SMIS";
2199     case HEAP_NUMBERS: return "HEAP_NUMBERS";
2200     case OBJECTS: return "OBJECTS";
2201     case GENERIC: return "GENERIC";
2202     default:
2203       UNREACHABLE();
2204       return NULL;
2205   }
2206 }
2207 
2208 
TargetState(State state,bool has_inlined_smi_code,Handle<Object> x,Handle<Object> y)2209 CompareIC::State CompareIC::TargetState(State state,
2210                                         bool has_inlined_smi_code,
2211                                         Handle<Object> x,
2212                                         Handle<Object> y) {
2213   if (!has_inlined_smi_code && state != UNINITIALIZED) return GENERIC;
2214   if (state == UNINITIALIZED && x->IsSmi() && y->IsSmi()) return SMIS;
2215   if ((state == UNINITIALIZED || (state == SMIS && has_inlined_smi_code)) &&
2216       x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS;
2217   if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return GENERIC;
2218   if (state == UNINITIALIZED &&
2219       x->IsJSObject() && y->IsJSObject()) return OBJECTS;
2220   return GENERIC;
2221 }
2222 
2223 
2224 // Used from ic_<arch>.cc.
RUNTIME_FUNCTION(Code *,CompareIC_Miss)2225 RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
2226   NoHandleAllocation na;
2227   ASSERT(args.length() == 3);
2228   CompareIC ic(isolate, static_cast<Token::Value>(Smi::cast(args[2])->value()));
2229   ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2230   return ic.target();
2231 }
2232 
2233 
2234 static const Address IC_utilities[] = {
2235 #define ADDR(name) FUNCTION_ADDR(name),
2236     IC_UTIL_LIST(ADDR)
2237     NULL
2238 #undef ADDR
2239 };
2240 
2241 
AddressFromUtilityId(IC::UtilityId id)2242 Address IC::AddressFromUtilityId(IC::UtilityId id) {
2243   return IC_utilities[id];
2244 }
2245 
2246 
2247 } }  // namespace v8::internal
2248