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