Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: src/ic.cc

Issue 6597029: [Isolates] Merge r 6300:6500 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/inspector.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 !current->IsJSGlobalProxy() && 151 !current->IsJSGlobalProxy() &&
152 !current->IsJSGlobalObject()) { 152 !current->IsJSGlobalObject()) {
153 return true; 153 return true;
154 } 154 }
155 } 155 }
156 156
157 return false; 157 return false;
158 } 158 }
159 159
160 160
161 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { 161 static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
162 IC::State state = target->ic_state(); 162 Object* receiver,
163 163 Object* name) {
164 if (state != MONOMORPHIC || !name->IsString()) return state;
165 if (receiver->IsUndefined() || receiver->IsNull()) return state;
166
167 InlineCacheHolderFlag cache_holder = 164 InlineCacheHolderFlag cache_holder =
168 Code::ExtractCacheHolderFromFlags(target->flags()); 165 Code::ExtractCacheHolderFromFlags(target->flags());
169 166
170
171 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { 167 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
172 // The stub was generated for JSObject but called for non-JSObject. 168 // The stub was generated for JSObject but called for non-JSObject.
173 // IC::GetCodeCacheHolder is not applicable. 169 // IC::GetCodeCacheHolder is not applicable.
174 return MONOMORPHIC; 170 return false;
175 } else if (cache_holder == PROTOTYPE_MAP && 171 } else if (cache_holder == PROTOTYPE_MAP &&
176 receiver->GetPrototype()->IsNull()) { 172 receiver->GetPrototype()->IsNull()) {
177 // IC::GetCodeCacheHolder is not applicable. 173 // IC::GetCodeCacheHolder is not applicable.
178 return MONOMORPHIC; 174 return false;
179 } 175 }
180 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); 176 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map();
181 177
182 // Decide whether the inline cache failed because of changes to the 178 // Decide whether the inline cache failed because of changes to the
183 // receiver itself or changes to one of its prototypes. 179 // receiver itself or changes to one of its prototypes.
184 // 180 //
185 // If there are changes to the receiver itself, the map of the 181 // If there are changes to the receiver itself, the map of the
186 // receiver will have changed and the current target will not be in 182 // receiver will have changed and the current target will not be in
187 // the receiver map's code cache. Therefore, if the current target 183 // the receiver map's code cache. Therefore, if the current target
188 // is in the receiver map's code cache, the inline cache failed due 184 // is in the receiver map's code cache, the inline cache failed due
189 // to prototype check failure. 185 // to prototype check failure.
190 int index = map->IndexInCodeCache(name, target); 186 int index = map->IndexInCodeCache(name, target);
191 if (index >= 0) { 187 if (index >= 0) {
192 // For keyed load/store/call, the most likely cause of cache failure is 188 map->RemoveFromCodeCache(String::cast(name), target, index);
193 // that the key has changed. We do not distinguish between 189 return true;
194 // prototype and non-prototype failures for keyed access. 190 }
195 Code::Kind kind = target->kind();
196 if (kind == Code::KEYED_LOAD_IC ||
197 kind == Code::KEYED_STORE_IC ||
198 kind == Code::KEYED_CALL_IC) {
199 return MONOMORPHIC;
200 }
201 191
202 // Remove the target from the code cache to avoid hitting the same 192 return false;
203 // invalid stub again. 193 }
204 map->RemoveFromCodeCache(String::cast(name), target, index);
205 194
195
196 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
197 IC::State state = target->ic_state();
198
199 if (state != MONOMORPHIC || !name->IsString()) return state;
200 if (receiver->IsUndefined() || receiver->IsNull()) return state;
201
202 // For keyed load/store/call, the most likely cause of cache failure is
203 // that the key has changed. We do not distinguish between
204 // prototype and non-prototype failures for keyed access.
205 Code::Kind kind = target->kind();
206 if (kind == Code::KEYED_LOAD_IC ||
207 kind == Code::KEYED_STORE_IC ||
208 kind == Code::KEYED_CALL_IC) {
209 return MONOMORPHIC;
210 }
211
212 // Remove the target from the code cache if it became invalid
213 // because of changes in the prototype chain to avoid hitting it
214 // again.
215 // Call stubs handle this later to allow extra IC state
216 // transitions.
217 if (kind != Code::CALL_IC &&
218 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
206 return MONOMORPHIC_PROTOTYPE_FAILURE; 219 return MONOMORPHIC_PROTOTYPE_FAILURE;
207 } 220 }
208 221
209 // The builtins object is special. It only changes when JavaScript 222 // The builtins object is special. It only changes when JavaScript
210 // builtins are loaded lazily. It is important to keep inline 223 // builtins are loaded lazily. It is important to keep inline
211 // caches for the builtins object monomorphic. Therefore, if we get 224 // caches for the builtins object monomorphic. Therefore, if we get
212 // an inline cache miss for the builtins object after lazily loading 225 // an inline cache miss for the builtins object after lazily loading
213 // JavaScript builtins, we return uninitialized as the state to 226 // JavaScript builtins, we return uninitialized as the state to
214 // force the inline cache back to monomorphic state. 227 // force the inline cache back to monomorphic state.
215 if (receiver->IsJSBuiltinsObject()) { 228 if (receiver->IsJSBuiltinsObject()) {
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 PatchInlinedStore(address, HEAP->fixed_array_map()); 367 PatchInlinedStore(address, HEAP->fixed_array_map());
355 } 368 }
356 369
357 370
358 void KeyedStoreIC::Clear(Address address, Code* target) { 371 void KeyedStoreIC::Clear(Address address, Code* target) {
359 if (target->ic_state() == UNINITIALIZED) return; 372 if (target->ic_state() == UNINITIALIZED) return;
360 SetTargetAtAddress(address, initialize_stub()); 373 SetTargetAtAddress(address, initialize_stub());
361 } 374 }
362 375
363 376
364 Code* KeyedLoadIC::external_array_stub(JSObject::ElementsKind elements_kind) {
365 switch (elements_kind) {
366 case JSObject::EXTERNAL_BYTE_ELEMENTS:
367 return isolate()->builtins()->builtin(
368 Builtins::KeyedLoadIC_ExternalByteArray);
369 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
370 return isolate()->builtins()->builtin(
371 Builtins::KeyedLoadIC_ExternalUnsignedByteArray);
372 case JSObject::EXTERNAL_SHORT_ELEMENTS:
373 return isolate()->builtins()->builtin(
374 Builtins::KeyedLoadIC_ExternalShortArray);
375 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
376 return isolate()->builtins()->builtin(
377 Builtins::KeyedLoadIC_ExternalUnsignedShortArray);
378 case JSObject::EXTERNAL_INT_ELEMENTS:
379 return isolate()->builtins()->builtin(
380 Builtins::KeyedLoadIC_ExternalIntArray);
381 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
382 return isolate()->builtins()->builtin(
383 Builtins::KeyedLoadIC_ExternalUnsignedIntArray);
384 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
385 return isolate()->builtins()->builtin(
386 Builtins::KeyedLoadIC_ExternalFloatArray);
387 default:
388 UNREACHABLE();
389 return NULL;
390 }
391 }
392
393
394 Code* KeyedStoreIC::external_array_stub(JSObject::ElementsKind elements_kind) {
395 switch (elements_kind) {
396 case JSObject::EXTERNAL_BYTE_ELEMENTS:
397 return isolate()->builtins()->builtin(
398 Builtins::KeyedStoreIC_ExternalByteArray);
399 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
400 return isolate()->builtins()->builtin(
401 Builtins::KeyedStoreIC_ExternalUnsignedByteArray);
402 case JSObject::EXTERNAL_SHORT_ELEMENTS:
403 return isolate()->builtins()->builtin(
404 Builtins::KeyedStoreIC_ExternalShortArray);
405 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
406 return isolate()->builtins()->builtin(
407 Builtins::KeyedStoreIC_ExternalUnsignedShortArray);
408 case JSObject::EXTERNAL_INT_ELEMENTS:
409 return isolate()->builtins()->builtin(
410 Builtins::KeyedStoreIC_ExternalIntArray);
411 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
412 return isolate()->builtins()->builtin(
413 Builtins::KeyedStoreIC_ExternalUnsignedIntArray);
414 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
415 return isolate()->builtins()->builtin(
416 Builtins::KeyedStoreIC_ExternalFloatArray);
417 default:
418 UNREACHABLE();
419 return NULL;
420 }
421 }
422
423
424 static bool HasInterceptorGetter(JSObject* object) { 377 static bool HasInterceptorGetter(JSObject* object) {
425 return !object->GetNamedInterceptor()->getter()->IsUndefined(); 378 return !object->GetNamedInterceptor()->getter()->IsUndefined();
426 } 379 }
427 380
428 381
429 static void LookupForRead(Object* object, 382 static void LookupForRead(Object* object,
430 String* name, 383 String* name,
431 LookupResult* lookup) { 384 LookupResult* lookup) {
432 AssertNoAllocation no_gc; // pointers must stay valid 385 AssertNoAllocation no_gc; // pointers must stay valid
433 386
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 // Change the receiver to the result of calling ToObject on it. 446 // Change the receiver to the result of calling ToObject on it.
494 const int argc = this->target()->arguments_count(); 447 const int argc = this->target()->arguments_count();
495 StackFrameLocator locator; 448 StackFrameLocator locator;
496 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 449 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
497 int index = frame->ComputeExpressionsCount() - (argc + 1); 450 int index = frame->ComputeExpressionsCount() - (argc + 1);
498 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); 451 frame->SetExpression(index, *isolate()->factory()->ToObject(object));
499 } 452 }
500 453
501 454
502 MaybeObject* CallICBase::LoadFunction(State state, 455 MaybeObject* CallICBase::LoadFunction(State state,
456 Code::ExtraICState extra_ic_state,
503 Handle<Object> object, 457 Handle<Object> object,
504 Handle<String> name) { 458 Handle<String> name) {
505 // If the object is undefined or null it's illegal to try to get any 459 // If the object is undefined or null it's illegal to try to get any
506 // of its properties; throw a TypeError in that case. 460 // of its properties; throw a TypeError in that case.
507 if (object->IsUndefined() || object->IsNull()) { 461 if (object->IsUndefined() || object->IsNull()) {
508 return TypeError("non_object_property_call", object, name); 462 return TypeError("non_object_property_call", object, name);
509 } 463 }
510 464
511 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 465 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
512 ReceiverToObject(object); 466 ReceiverToObject(object);
(...skipping 25 matching lines...) Expand all
538 // If the object does not have the requested property, check which 492 // If the object does not have the requested property, check which
539 // exception we need to throw. 493 // exception we need to throw.
540 if (IsContextual(object)) { 494 if (IsContextual(object)) {
541 return ReferenceError("not_defined", name); 495 return ReferenceError("not_defined", name);
542 } 496 }
543 return TypeError("undefined_method", object, name); 497 return TypeError("undefined_method", object, name);
544 } 498 }
545 499
546 // Lookup is valid: Update inline cache and stub cache. 500 // Lookup is valid: Update inline cache and stub cache.
547 if (FLAG_use_ic) { 501 if (FLAG_use_ic) {
548 UpdateCaches(&lookup, state, object, name); 502 UpdateCaches(&lookup, state, extra_ic_state, object, name);
549 } 503 }
550 504
551 // Get the property. 505 // Get the property.
552 PropertyAttributes attr; 506 PropertyAttributes attr;
553 Object* result; 507 Object* result;
554 { MaybeObject* maybe_result = 508 { MaybeObject* maybe_result =
555 object->GetProperty(*object, &lookup, *name, &attr); 509 object->GetProperty(*object, &lookup, *name, &attr);
556 if (!maybe_result->ToObject(&result)) return maybe_result; 510 if (!maybe_result->ToObject(&result)) return maybe_result;
557 } 511 }
558 if (lookup.type() == INTERCEPTOR) { 512 if (lookup.type() == INTERCEPTOR) {
(...skipping 29 matching lines...) Expand all
588 // Try to find a suitable function delegate for the object at hand. 542 // Try to find a suitable function delegate for the object at hand.
589 result = TryCallAsFunction(result); 543 result = TryCallAsFunction(result);
590 MaybeObject* answer = result; 544 MaybeObject* answer = result;
591 if (!result->IsJSFunction()) { 545 if (!result->IsJSFunction()) {
592 answer = TypeError("property_not_function", object, name); 546 answer = TypeError("property_not_function", object, name);
593 } 547 }
594 return answer; 548 return answer;
595 } 549 }
596 550
597 551
552 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
553 Handle<Object> object,
554 Code::ExtraICState* extra_ic_state) {
555 ASSERT(kind_ == Code::CALL_IC);
556 if (lookup->type() != CONSTANT_FUNCTION) return false;
557 JSFunction* function = lookup->GetConstantFunction();
558 if (!function->shared()->HasBuiltinFunctionId()) return false;
559
560 // Fetch the arguments passed to the called function.
561 const int argc = target()->arguments_count();
562 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
563 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
564 Arguments args(argc + 1,
565 &Memory::Object_at(fp +
566 StandardFrameConstants::kCallerSPOffset +
567 argc * kPointerSize));
568 switch (function->shared()->builtin_function_id()) {
569 case kStringCharCodeAt:
570 case kStringCharAt:
571 if (object->IsString()) {
572 String* string = String::cast(*object);
573 // Check that there's the right wrapper in the receiver slot.
574 ASSERT(string == JSValue::cast(args[0])->value());
575 // If we're in the default (fastest) state and the index is
576 // out of bounds, update the state to record this fact.
577 if (*extra_ic_state == DEFAULT_STRING_STUB &&
578 argc >= 1 && args[1]->IsNumber()) {
579 double index;
580 if (args[1]->IsSmi()) {
581 index = Smi::cast(args[1])->value();
582 } else {
583 ASSERT(args[1]->IsHeapNumber());
584 index = DoubleToInteger(HeapNumber::cast(args[1])->value());
585 }
586 if (index < 0 || index >= string->length()) {
587 *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS;
588 return true;
589 }
590 }
591 }
592 break;
593 default:
594 return false;
595 }
596 return false;
597 }
598
599
600 MaybeObject* CallICBase::ComputeMonomorphicStub(
601 LookupResult* lookup,
602 State state,
603 Code::ExtraICState extra_ic_state,
604 Handle<Object> object,
605 Handle<String> name) {
606 int argc = target()->arguments_count();
607 InLoopFlag in_loop = target()->ic_in_loop();
608 MaybeObject* maybe_code = NULL;
609 switch (lookup->type()) {
610 case FIELD: {
611 int index = lookup->GetFieldIndex();
612 maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
613 in_loop,
614 kind_,
615 *name,
616 *object,
617 lookup->holder(),
618 index);
619 break;
620 }
621 case CONSTANT_FUNCTION: {
622 // Get the constant function and compute the code stub for this
623 // call; used for rewriting to monomorphic state and making sure
624 // that the code stub is in the stub cache.
625 JSFunction* function = lookup->GetConstantFunction();
626 maybe_code =
627 isolate()->stub_cache()->ComputeCallConstant(argc,
628 in_loop,
629 kind_,
630 extra_ic_state,
631 *name,
632 *object,
633 lookup->holder(),
634 function);
635 break;
636 }
637 case NORMAL: {
638 if (!object->IsJSObject()) return NULL;
639 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
640
641 if (lookup->holder()->IsGlobalObject()) {
642 GlobalObject* global = GlobalObject::cast(lookup->holder());
643 JSGlobalPropertyCell* cell =
644 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
645 if (!cell->value()->IsJSFunction()) return NULL;
646 JSFunction* function = JSFunction::cast(cell->value());
647 maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
648 in_loop,
649 kind_,
650 *name,
651 *receiver,
652 global,
653 cell,
654 function);
655 } else {
656 // There is only one shared stub for calling normalized
657 // properties. It does not traverse the prototype chain, so the
658 // property must be found in the receiver for the stub to be
659 // applicable.
660 if (lookup->holder() != *receiver) return NULL;
661 maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
662 in_loop,
663 kind_,
664 *name,
665 *receiver);
666 }
667 break;
668 }
669 case INTERCEPTOR: {
670 ASSERT(HasInterceptorGetter(lookup->holder()));
671 maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
672 argc,
673 kind_,
674 *name,
675 *object,
676 lookup->holder());
677 break;
678 }
679 default:
680 maybe_code = NULL;
681 break;
682 }
683 return maybe_code;
684 }
685
686
598 void CallICBase::UpdateCaches(LookupResult* lookup, 687 void CallICBase::UpdateCaches(LookupResult* lookup,
599 State state, 688 State state,
689 Code::ExtraICState extra_ic_state,
600 Handle<Object> object, 690 Handle<Object> object,
601 Handle<String> name) { 691 Handle<String> name) {
602 // Bail out if we didn't find a result. 692 // Bail out if we didn't find a result.
603 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; 693 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
604 694
605 if (lookup->holder() != *object && 695 if (lookup->holder() != *object &&
606 HasNormalObjectsInPrototypeChain( 696 HasNormalObjectsInPrototypeChain(
607 isolate(), lookup, object->GetPrototype())) { 697 isolate(), lookup, object->GetPrototype())) {
608 // Suppress optimization for prototype chains with slow properties objects 698 // Suppress optimization for prototype chains with slow properties objects
609 // in the middle. 699 // in the middle.
610 return; 700 return;
611 } 701 }
612 702
613 // Compute the number of arguments. 703 // Compute the number of arguments.
614 int argc = target()->arguments_count(); 704 int argc = target()->arguments_count();
615 InLoopFlag in_loop = target()->ic_in_loop(); 705 InLoopFlag in_loop = target()->ic_in_loop();
616 MaybeObject* maybe_code = NULL; 706 MaybeObject* maybe_code = NULL;
617 Object* code; 707 bool had_proto_failure = false;
618 if (state == UNINITIALIZED) { 708 if (state == UNINITIALIZED) {
619 // This is the first time we execute this inline cache. 709 // This is the first time we execute this inline cache.
620 // Set the target to the pre monomorphic stub to delay 710 // Set the target to the pre monomorphic stub to delay
621 // setting the monomorphic state. 711 // setting the monomorphic state.
622 maybe_code = isolate()->stub_cache()->ComputeCallPreMonomorphic(argc, 712 maybe_code = isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
623 in_loop, 713 in_loop,
624 kind_); 714 kind_);
625 } else if (state == MONOMORPHIC) { 715 } else if (state == MONOMORPHIC) {
626 maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(argc, 716 if (kind_ == Code::CALL_IC &&
627 in_loop, 717 TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
628 kind_); 718 maybe_code = ComputeMonomorphicStub(lookup,
719 state,
720 extra_ic_state,
721 object,
722 name);
723 } else if (kind_ == Code::CALL_IC &&
724 TryRemoveInvalidPrototypeDependentStub(target(),
725 *object,
726 *name)) {
727 had_proto_failure = true;
728 maybe_code = ComputeMonomorphicStub(lookup,
729 state,
730 extra_ic_state,
731 object,
732 name);
733 } else {
734 maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(argc,
735 in_loop,
736 kind_);
737 }
629 } else { 738 } else {
630 // Compute monomorphic stub. 739 maybe_code = ComputeMonomorphicStub(lookup,
631 switch (lookup->type()) { 740 state,
632 case FIELD: { 741 extra_ic_state,
633 int index = lookup->GetFieldIndex(); 742 object,
634 maybe_code = isolate()->stub_cache()->ComputeCallField(argc, 743 name);
635 in_loop,
636 kind_,
637 *name,
638 *object,
639 lookup->holder(),
640 index);
641 break;
642 }
643 case CONSTANT_FUNCTION: {
644 // Get the constant function and compute the code stub for this
645 // call; used for rewriting to monomorphic state and making sure
646 // that the code stub is in the stub cache.
647 JSFunction* function = lookup->GetConstantFunction();
648 maybe_code = isolate()->stub_cache()->ComputeCallConstant(
649 argc,
650 in_loop,
651 kind_,
652 *name,
653 *object,
654 lookup->holder(),
655 function);
656 break;
657 }
658 case NORMAL: {
659 if (!object->IsJSObject()) return;
660 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
661
662 if (lookup->holder()->IsGlobalObject()) {
663 GlobalObject* global = GlobalObject::cast(lookup->holder());
664 JSGlobalPropertyCell* cell =
665 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
666 if (!cell->value()->IsJSFunction()) return;
667 JSFunction* function = JSFunction::cast(cell->value());
668 maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
669 in_loop,
670 kind_,
671 *name,
672 *receiver,
673 global,
674 cell,
675 function);
676 } else {
677 // There is only one shared stub for calling normalized
678 // properties. It does not traverse the prototype chain, so the
679 // property must be found in the receiver for the stub to be
680 // applicable.
681 if (lookup->holder() != *receiver) return;
682 maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
683 in_loop,
684 kind_,
685 *name,
686 *receiver);
687 }
688 break;
689 }
690 case INTERCEPTOR: {
691 ASSERT(HasInterceptorGetter(lookup->holder()));
692 maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
693 argc,
694 kind_,
695 *name,
696 *object,
697 lookup->holder());
698 break;
699 }
700 default:
701 return;
702 }
703 } 744 }
704 745
705 // If we're unable to compute the stub (not enough memory left), we 746 // If we're unable to compute the stub (not enough memory left), we
706 // simply avoid updating the caches. 747 // simply avoid updating the caches.
748 Object* code;
707 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; 749 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
708 750
709 // Patch the call site depending on the state of the cache. 751 // Patch the call site depending on the state of the cache.
710 if (state == UNINITIALIZED || 752 if (state == UNINITIALIZED ||
711 state == PREMONOMORPHIC || 753 state == PREMONOMORPHIC ||
712 state == MONOMORPHIC || 754 state == MONOMORPHIC ||
713 state == MONOMORPHIC_PROTOTYPE_FAILURE) { 755 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
714 set_target(Code::cast(code)); 756 set_target(Code::cast(code));
715 } else if (state == MEGAMORPHIC) { 757 } else if (state == MEGAMORPHIC) {
716 // Cache code holding map should be consistent with 758 // Cache code holding map should be consistent with
717 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. 759 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
718 Map* map = JSObject::cast(object->IsJSObject() ? *object : 760 Map* map = JSObject::cast(object->IsJSObject() ? *object :
719 object->GetPrototype())->map(); 761 object->GetPrototype())->map();
720 762
721 // Update the stub cache. 763 // Update the stub cache.
722 isolate()->stub_cache()->Set(*name, map, Code::cast(code)); 764 isolate()->stub_cache()->Set(*name, map, Code::cast(code));
723 } 765 }
724 766
767 USE(had_proto_failure);
725 #ifdef DEBUG 768 #ifdef DEBUG
769 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
726 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", 770 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
727 name, state, target(), in_loop ? " (in-loop)" : ""); 771 name, state, target(), in_loop ? " (in-loop)" : "");
728 #endif 772 #endif
729 } 773 }
730 774
731 775
732 MaybeObject* KeyedCallIC::LoadFunction(State state, 776 MaybeObject* KeyedCallIC::LoadFunction(State state,
733 Handle<Object> object, 777 Handle<Object> object,
734 Handle<Object> key) { 778 Handle<Object> key) {
735 if (key->IsSymbol()) { 779 if (key->IsSymbol()) {
736 return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); 780 return CallICBase::LoadFunction(state,
781 Code::kNoExtraICState,
782 object,
783 Handle<String>::cast(key));
737 } 784 }
738 785
739 if (object->IsUndefined() || object->IsNull()) { 786 if (object->IsUndefined() || object->IsNull()) {
740 return TypeError("non_object_property_call", object, key); 787 return TypeError("non_object_property_call", object, key);
741 } 788 }
742 789
743 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 790 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
744 ReceiverToObject(object); 791 ReceiverToObject(object);
745 } 792 }
746 793
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 MaybeObject* LoadIC::Load(State state, 832 MaybeObject* LoadIC::Load(State state,
786 Handle<Object> object, 833 Handle<Object> object,
787 Handle<String> name) { 834 Handle<String> name) {
788 // If the object is undefined or null it's illegal to try to get any 835 // If the object is undefined or null it's illegal to try to get any
789 // of its properties; throw a TypeError in that case. 836 // of its properties; throw a TypeError in that case.
790 if (object->IsUndefined() || object->IsNull()) { 837 if (object->IsUndefined() || object->IsNull()) {
791 return TypeError("non_object_property_load", object, name); 838 return TypeError("non_object_property_load", object, name);
792 } 839 }
793 840
794 if (FLAG_use_ic) { 841 if (FLAG_use_ic) {
842 Code* non_monomorphic_stub =
843 (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub();
844
795 // Use specialized code for getting the length of strings and 845 // Use specialized code for getting the length of strings and
796 // string wrapper objects. The length property of string wrapper 846 // string wrapper objects. The length property of string wrapper
797 // objects is read-only and therefore always returns the length of 847 // objects is read-only and therefore always returns the length of
798 // the underlying string value. See ECMA-262 15.5.5.1. 848 // the underlying string value. See ECMA-262 15.5.5.1.
799 if ((object->IsString() || object->IsStringWrapper()) && 849 if ((object->IsString() || object->IsStringWrapper()) &&
800 name->Equals(isolate()->heap()->length_symbol())) { 850 name->Equals(isolate()->heap()->length_symbol())) {
801 HandleScope scope(isolate()); 851 HandleScope scope(isolate());
852 #ifdef DEBUG
853 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
854 #endif
855 if (state == PREMONOMORPHIC) {
856 if (object->IsString()) {
857 Map* map = HeapObject::cast(*object)->map();
858 const int offset = String::kLengthOffset;
859 PatchInlinedLoad(address(), map, offset);
860 set_target(isolate()->builtins()->builtin(
861 Builtins::LoadIC_StringLength));
862 } else {
863 set_target(isolate()->builtins()->builtin(
864 Builtins::LoadIC_StringWrapperLength));
865 }
866 } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
867 set_target(isolate()->builtins()->builtin(
868 Builtins::LoadIC_StringWrapperLength));
869 } else {
870 set_target(non_monomorphic_stub);
871 }
802 // Get the string if we have a string wrapper object. 872 // Get the string if we have a string wrapper object.
803 if (object->IsJSValue()) { 873 if (object->IsJSValue()) {
804 object = Handle<Object>(Handle<JSValue>::cast(object)->value(), 874 object = Handle<Object>(Handle<JSValue>::cast(object)->value(),
805 isolate()); 875 isolate());
806 } 876 }
807 #ifdef DEBUG
808 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
809 #endif
810 Map* map = HeapObject::cast(*object)->map();
811 if (object->IsString()) {
812 const int offset = String::kLengthOffset;
813 PatchInlinedLoad(address(), map, offset);
814 }
815
816 Code* target = NULL;
817 target = isolate()->builtins()->builtin(
818 Builtins::LoadIC_StringLength);
819 set_target(target);
820 return Smi::FromInt(String::cast(*object)->length()); 877 return Smi::FromInt(String::cast(*object)->length());
821 } 878 }
822 879
823 // Use specialized code for getting the length of arrays. 880 // Use specialized code for getting the length of arrays.
824 if (object->IsJSArray() && 881 if (object->IsJSArray() &&
825 name->Equals(isolate()->heap()->length_symbol())) { 882 name->Equals(isolate()->heap()->length_symbol())) {
826 #ifdef DEBUG 883 #ifdef DEBUG
827 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); 884 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
828 #endif 885 #endif
829 Map* map = HeapObject::cast(*object)->map(); 886 if (state == PREMONOMORPHIC) {
830 const int offset = JSArray::kLengthOffset; 887 Map* map = HeapObject::cast(*object)->map();
831 PatchInlinedLoad(address(), map, offset); 888 const int offset = JSArray::kLengthOffset;
832 889 PatchInlinedLoad(address(), map, offset);
833 Code* target = isolate()->builtins()->builtin( 890 set_target(isolate()->builtins()->builtin(
834 Builtins::LoadIC_ArrayLength); 891 Builtins::LoadIC_ArrayLength));
835 set_target(target); 892 } else {
893 set_target(non_monomorphic_stub);
894 }
836 return JSArray::cast(*object)->length(); 895 return JSArray::cast(*object)->length();
837 } 896 }
838 897
839 // Use specialized code for getting prototype of functions. 898 // Use specialized code for getting prototype of functions.
840 if (object->IsJSFunction() && 899 if (object->IsJSFunction() &&
841 name->Equals(isolate()->heap()->prototype_symbol()) && 900 name->Equals(isolate()->heap()->prototype_symbol()) &&
842 JSFunction::cast(*object)->should_have_prototype()) { 901 JSFunction::cast(*object)->should_have_prototype()) {
843 #ifdef DEBUG 902 #ifdef DEBUG
844 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); 903 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
845 #endif 904 #endif
846 Code* target = isolate()->builtins()->builtin( 905 if (state == PREMONOMORPHIC) {
847 Builtins::LoadIC_FunctionPrototype); 906 set_target(isolate()->builtins()->builtin(
848 set_target(target); 907 Builtins::LoadIC_FunctionPrototype));
908 } else {
909 set_target(non_monomorphic_stub);
910 }
849 return Accessors::FunctionGetPrototype(*object, 0); 911 return Accessors::FunctionGetPrototype(*object, 0);
850 } 912 }
851 } 913 }
852 914
853 // Check if the name is trivially convertible to an index and get 915 // Check if the name is trivially convertible to an index and get
854 // the element if so. 916 // the element if so.
855 uint32_t index; 917 uint32_t index;
856 if (name->AsArrayIndex(&index)) return object->GetElement(index); 918 if (name->AsArrayIndex(&index)) return object->GetElement(index);
857 919
858 // Named lookup in the object. 920 // Named lookup in the object.
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
1064 if (key->IsSymbol()) { 1126 if (key->IsSymbol()) {
1065 Handle<String> name = Handle<String>::cast(key); 1127 Handle<String> name = Handle<String>::cast(key);
1066 1128
1067 // If the object is undefined or null it's illegal to try to get any 1129 // If the object is undefined or null it's illegal to try to get any
1068 // of its properties; throw a TypeError in that case. 1130 // of its properties; throw a TypeError in that case.
1069 if (object->IsUndefined() || object->IsNull()) { 1131 if (object->IsUndefined() || object->IsNull()) {
1070 return TypeError("non_object_property_load", object, name); 1132 return TypeError("non_object_property_load", object, name);
1071 } 1133 }
1072 1134
1073 if (FLAG_use_ic) { 1135 if (FLAG_use_ic) {
1136 // TODO(1073): don't ignore the current stub state.
1137
1074 // Use specialized code for getting the length of strings. 1138 // Use specialized code for getting the length of strings.
1075 if (object->IsString() && 1139 if (object->IsString() &&
1076 name->Equals(isolate()->heap()->length_symbol())) { 1140 name->Equals(isolate()->heap()->length_symbol())) {
1077 Handle<String> string = Handle<String>::cast(object); 1141 Handle<String> string = Handle<String>::cast(object);
1078 Object* code = NULL; 1142 Object* code = NULL;
1079 { MaybeObject* maybe_code = 1143 { MaybeObject* maybe_code =
1080 isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name, 1144 isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name,
1081 *string); 1145 *string);
1082 if (!maybe_code->ToObject(&code)) return maybe_code; 1146 if (!maybe_code->ToObject(&code)) return maybe_code;
1083 } 1147 }
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1172 // the global object). 1236 // the global object).
1173 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1237 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1174 1238
1175 if (use_ic) { 1239 if (use_ic) {
1176 Code* stub = generic_stub(); 1240 Code* stub = generic_stub();
1177 if (object->IsString() && key->IsNumber()) { 1241 if (object->IsString() && key->IsNumber()) {
1178 stub = string_stub(); 1242 stub = string_stub();
1179 } else if (object->IsJSObject()) { 1243 } else if (object->IsJSObject()) {
1180 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1244 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1181 if (receiver->HasExternalArrayElements()) { 1245 if (receiver->HasExternalArrayElements()) {
1182 stub = external_array_stub(receiver->GetElementsKind()); 1246 MaybeObject* probe =
1247 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
1248 *receiver, false);
1249 stub =
1250 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
1183 } else if (receiver->HasIndexedInterceptor()) { 1251 } else if (receiver->HasIndexedInterceptor()) {
1184 stub = indexed_interceptor_stub(); 1252 stub = indexed_interceptor_stub();
1185 } else if (state == UNINITIALIZED && 1253 } else if (state == UNINITIALIZED &&
1186 key->IsSmi() && 1254 key->IsSmi() &&
1187 receiver->map()->has_fast_elements()) { 1255 receiver->map()->has_fast_elements()) {
1188 StubCache* stub_cache = isolate()->stub_cache(); 1256 MaybeObject* probe =
1189 MaybeObject* probe = stub_cache->ComputeKeyedLoadSpecialized(*receiver); 1257 isolate()->stub_cache()->ComputeKeyedLoadSpecialized(*receiver);
1190 stub = 1258 stub =
1191 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); 1259 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
1192 } 1260 }
1193 } 1261 }
1194 if (stub != NULL) set_target(stub); 1262 if (stub != NULL) set_target(stub);
1195 1263
1196 #ifdef DEBUG 1264 #ifdef DEBUG
1197 TraceIC("KeyedLoadIC", key, state, target()); 1265 TraceIC("KeyedLoadIC", key, state, target());
1198 #endif // DEBUG 1266 #endif // DEBUG
1199 1267
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 // Do not use ICs for objects that require access checks (including 1636 // Do not use ICs for objects that require access checks (including
1569 // the global object). 1637 // the global object).
1570 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1638 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1571 ASSERT(!(use_ic && object->IsJSGlobalProxy())); 1639 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
1572 1640
1573 if (use_ic) { 1641 if (use_ic) {
1574 Code* stub = generic_stub(); 1642 Code* stub = generic_stub();
1575 if (object->IsJSObject()) { 1643 if (object->IsJSObject()) {
1576 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1644 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1577 if (receiver->HasExternalArrayElements()) { 1645 if (receiver->HasExternalArrayElements()) {
1578 stub = external_array_stub(receiver->GetElementsKind()); 1646 MaybeObject* probe =
1647 isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
1648 *receiver, true);
1649 stub =
1650 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
1579 } else if (state == UNINITIALIZED && 1651 } else if (state == UNINITIALIZED &&
1580 key->IsSmi() && 1652 key->IsSmi() &&
1581 receiver->map()->has_fast_elements()) { 1653 receiver->map()->has_fast_elements()) {
1582 MaybeObject* probe = 1654 MaybeObject* probe =
1583 isolate()->stub_cache()->ComputeKeyedStoreSpecialized(*receiver); 1655 isolate()->stub_cache()->ComputeKeyedStoreSpecialized(*receiver);
1584 stub = 1656 stub =
1585 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); 1657 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked());
1586 } 1658 }
1587 } 1659 }
1588 if (stub != NULL) set_target(stub); 1660 if (stub != NULL) set_target(stub);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1683 } 1755 }
1684 1756
1685 1757
1686 // Used from ic-<arch>.cc. 1758 // Used from ic-<arch>.cc.
1687 MUST_USE_RESULT MaybeObject* CallIC_Miss(RUNTIME_CALLING_CONVENTION) { 1759 MUST_USE_RESULT MaybeObject* CallIC_Miss(RUNTIME_CALLING_CONVENTION) {
1688 RUNTIME_GET_ISOLATE; 1760 RUNTIME_GET_ISOLATE;
1689 NoHandleAllocation na; 1761 NoHandleAllocation na;
1690 ASSERT(args.length() == 2); 1762 ASSERT(args.length() == 2);
1691 CallIC ic(isolate); 1763 CallIC ic(isolate);
1692 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1764 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1765 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1766 MaybeObject* maybe_result = ic.LoadFunction(state,
1767 extra_ic_state,
1768 args.at<Object>(0),
1769 args.at<String>(1));
1693 Object* result; 1770 Object* result;
1694 { MaybeObject* maybe_result = 1771 if (!maybe_result->ToObject(&result)) return maybe_result;
1695 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
1696 if (!maybe_result->ToObject(&result)) return maybe_result;
1697 }
1698 1772
1699 // The first time the inline cache is updated may be the first time the 1773 // The first time the inline cache is updated may be the first time the
1700 // function it references gets called. If the function was lazily compiled 1774 // function it references gets called. If the function was lazily compiled
1701 // then the first call will trigger a compilation. We check for this case 1775 // then the first call will trigger a compilation. We check for this case
1702 // and we do the compilation immediately, instead of waiting for the stub 1776 // and we do the compilation immediately, instead of waiting for the stub
1703 // currently attached to the JSFunction object to trigger compilation. We 1777 // currently attached to the JSFunction object to trigger compilation. We
1704 // do this in the case where we know that the inline cache is inside a loop, 1778 // do this in the case where we know that the inline cache is inside a loop,
1705 // because then we know that we want to optimize the function. 1779 // because then we know that we want to optimize the function.
1706 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { 1780 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1707 return result; 1781 return result;
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
2090 } 2164 }
2091 } 2165 }
2092 if (type == TRBinaryOpIC::INT32 && 2166 if (type == TRBinaryOpIC::INT32 &&
2093 previous_type == TRBinaryOpIC::INT32) { 2167 previous_type == TRBinaryOpIC::INT32) {
2094 // We must be here because an operation on two INT32 types overflowed. 2168 // We must be here because an operation on two INT32 types overflowed.
2095 result_type = TRBinaryOpIC::HEAP_NUMBER; 2169 result_type = TRBinaryOpIC::HEAP_NUMBER;
2096 } 2170 }
2097 2171
2098 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type); 2172 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type);
2099 if (!code.is_null()) { 2173 if (!code.is_null()) {
2100 TRBinaryOpIC ic(isolate);
2101 ic.patch(*code);
2102 if (FLAG_trace_ic) { 2174 if (FLAG_trace_ic) {
2103 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", 2175 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n",
2104 TRBinaryOpIC::GetName(previous_type), 2176 TRBinaryOpIC::GetName(previous_type),
2105 TRBinaryOpIC::GetName(type), 2177 TRBinaryOpIC::GetName(type),
2106 TRBinaryOpIC::GetName(result_type), 2178 TRBinaryOpIC::GetName(result_type),
2107 Token::Name(op)); 2179 Token::Name(op));
2108 } 2180 }
2181 TRBinaryOpIC ic(isolate);
2182 ic.patch(*code);
2109 2183
2110 // Activate inlined smi code. 2184 // Activate inlined smi code.
2111 if (previous_type == TRBinaryOpIC::UNINITIALIZED) { 2185 if (previous_type == TRBinaryOpIC::UNINITIALIZED) {
2112 PatchInlinedSmiCode(ic.address()); 2186 PatchInlinedSmiCode(ic.address());
2113 } 2187 }
2114 } 2188 }
2115 2189
2116 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( 2190 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
2117 isolate->thread_local_top()->context_->builtins(), isolate); 2191 isolate->thread_local_top()->context_->builtins(), isolate);
2118 Object* builtin = NULL; // Initialization calms down the compiler. 2192 Object* builtin = NULL; // Initialization calms down the compiler.
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
2231 #undef ADDR 2305 #undef ADDR
2232 }; 2306 };
2233 2307
2234 2308
2235 Address IC::AddressFromUtilityId(IC::UtilityId id) { 2309 Address IC::AddressFromUtilityId(IC::UtilityId id) {
2236 return IC_utilities[id]; 2310 return IC_utilities[id];
2237 } 2311 }
2238 2312
2239 2313
2240 } } // namespace v8::internal 2314 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/inspector.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698