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