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