00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "v8.h"
00029
00030 #include "accessors.h"
00031 #include "api.h"
00032 #include "arguments.h"
00033 #include "execution.h"
00034 #include "ic-inl.h"
00035 #include "runtime.h"
00036 #include "stub-cache.h"
00037
00038 namespace v8 { namespace internal {
00039
00040 #ifdef DEBUG
00041 static char TransitionMarkFromState(IC::State state) {
00042 switch (state) {
00043 case UNINITIALIZED: return '0';
00044 case PREMONOMORPHIC: return '0';
00045 case MONOMORPHIC: return '1';
00046 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
00047 case MEGAMORPHIC: return 'N';
00048
00049
00050
00051
00052 case DEBUG_BREAK: break;
00053 case DEBUG_PREPARE_STEP_IN: break;
00054 }
00055 UNREACHABLE();
00056 return 0;
00057 }
00058
00059 void IC::TraceIC(const char* type,
00060 Handle<String> name,
00061 State old_state,
00062 Code* new_target) {
00063 if (FLAG_trace_ic) {
00064 State new_state = StateFrom(new_target, Heap::undefined_value());
00065 PrintF("[%s (%c->%c) ", type,
00066 TransitionMarkFromState(old_state),
00067 TransitionMarkFromState(new_state));
00068 name->Print();
00069 PrintF("]\n");
00070 }
00071 }
00072 #endif
00073
00074
00075 IC::IC(FrameDepth depth) {
00076
00077
00078
00079 const Address entry = Top::c_entry_fp(Top::GetCurrentThread());
00080 Address* pc_address =
00081 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
00082 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
00083
00084
00085
00086 if (depth == EXTRA_CALL_FRAME) {
00087 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
00088 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
00089 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
00090 }
00091 #ifdef DEBUG
00092 StackFrameIterator it;
00093 for (int i = 0; i < depth + 1; i++) it.Advance();
00094 StackFrame* frame = it.frame();
00095 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
00096 #endif
00097 fp_ = fp;
00098 pc_address_ = pc_address;
00099 }
00100
00101
00102 Address IC::OriginalCodeAddress() {
00103 HandleScope scope;
00104
00105
00106
00107 StackFrameIterator it;
00108 while (it.frame()->fp() != this->fp()) it.Advance();
00109 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
00110
00111
00112 JSFunction* function = JSFunction::cast(frame->function());
00113 Handle<SharedFunctionInfo> shared(function->shared());
00114 Code* code = shared->code();
00115 ASSERT(Debug::HasDebugInfo(shared));
00116 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
00117 ASSERT(original_code->IsCode());
00118
00119
00120
00121 Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist;
00122
00123
00124
00125 int delta = original_code->instruction_start() - code->instruction_start();
00126 return addr + delta;
00127 }
00128
00129
00130 IC::State IC::StateFrom(Code* target, Object* receiver) {
00131 IC::State state = target->ic_state();
00132
00133 if (state != MONOMORPHIC) return state;
00134 if (receiver->IsUndefined() || receiver->IsNull()) return state;
00135
00136 Map* map = GetCodeCacheMapForObject(receiver);
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 int index = map->IndexInCodeCache(target);
00147 if (index >= 0) {
00148
00149
00150
00151 Code::Kind kind = target->kind();
00152 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) {
00153 return MONOMORPHIC;
00154 }
00155
00156
00157
00158 map->RemoveFromCodeCache(index);
00159
00160 return MONOMORPHIC_PROTOTYPE_FAILURE;
00161 }
00162
00163
00164
00165
00166
00167
00168
00169 if (receiver->IsJSBuiltinsObject()) {
00170 return UNINITIALIZED;
00171 }
00172
00173 return MONOMORPHIC;
00174 }
00175
00176
00177 RelocInfo::Mode IC::ComputeMode() {
00178 Address addr = address();
00179 Code* code = Code::cast(Heap::FindCodeObject(addr));
00180 for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
00181 !it.done(); it.next()) {
00182 RelocInfo* info = it.rinfo();
00183 if (info->pc() == addr) return info->rmode();
00184 }
00185 UNREACHABLE();
00186 return RelocInfo::NONE;
00187 }
00188
00189
00190 Failure* IC::TypeError(const char* type,
00191 Handle<Object> object,
00192 Handle<String> name) {
00193 HandleScope scope;
00194 Handle<Object> args[2] = { name, object };
00195 Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2));
00196 return Top::Throw(*error);
00197 }
00198
00199
00200 Failure* IC::ReferenceError(const char* type, Handle<String> name) {
00201 HandleScope scope;
00202 Handle<Object> error =
00203 Factory::NewReferenceError(type, HandleVector(&name, 1));
00204 return Top::Throw(*error);
00205 }
00206
00207
00208 void IC::Clear(Address address) {
00209 Code* target = GetTargetAtAddress(address);
00210
00211
00212 if (target->ic_state() == DEBUG_BREAK) return;
00213
00214 switch (target->kind()) {
00215 case Code::LOAD_IC: return LoadIC::Clear(address, target);
00216 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
00217 case Code::STORE_IC: return StoreIC::Clear(address, target);
00218 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
00219 case Code::CALL_IC: return CallIC::Clear(address, target);
00220 default: UNREACHABLE();
00221 }
00222 }
00223
00224
00225 void CallIC::Clear(Address address, Code* target) {
00226 if (target->ic_state() == UNINITIALIZED) return;
00227 Code* code = StubCache::FindCallInitialize(target->arguments_count());
00228 SetTargetAtAddress(address, code);
00229 }
00230
00231
00232 void KeyedLoadIC::Clear(Address address, Code* target) {
00233 if (target->ic_state() == UNINITIALIZED) return;
00234 SetTargetAtAddress(address, initialize_stub());
00235 }
00236
00237
00238 void LoadIC::Clear(Address address, Code* target) {
00239 if (target->ic_state() == UNINITIALIZED) return;
00240 SetTargetAtAddress(address, initialize_stub());
00241 }
00242
00243
00244 void StoreIC::Clear(Address address, Code* target) {
00245 if (target->ic_state() == UNINITIALIZED) return;
00246 SetTargetAtAddress(address, initialize_stub());
00247 }
00248
00249
00250 void KeyedStoreIC::Clear(Address address, Code* target) {
00251 if (target->ic_state() == UNINITIALIZED) return;
00252 SetTargetAtAddress(address, initialize_stub());
00253 }
00254
00255
00256 Object* CallIC::TryCallAsFunction(Object* object) {
00257 HandleScope scope;
00258 Handle<Object> target(object);
00259 Handle<Object> delegate = Execution::GetFunctionDelegate(target);
00260
00261 if (delegate->IsJSFunction()) {
00262
00263
00264
00265 const int argc = this->target()->arguments_count();
00266 StackFrameLocator locator;
00267 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
00268 int index = frame->ComputeExpressionsCount() - (argc + 1);
00269 frame->SetExpression(index, *target);
00270 }
00271
00272 return *delegate;
00273 }
00274
00275
00276 Object* CallIC::LoadFunction(State state,
00277 Handle<Object> object,
00278 Handle<String> name) {
00279
00280
00281 if (object->IsUndefined() || object->IsNull()) {
00282 return TypeError("non_object_property_call", object, name);
00283 }
00284
00285 Object* result = Heap::the_hole_value();
00286
00287
00288
00289 uint32_t index;
00290 if (name->AsArrayIndex(&index)) {
00291 result = object->GetElement(index);
00292 if (result->IsJSFunction()) return result;
00293
00294
00295 result = TryCallAsFunction(result);
00296 if (result->IsJSFunction()) return result;
00297
00298
00299 }
00300
00301
00302 LookupResult lookup;
00303 object->Lookup(*name, &lookup);
00304
00305 if (!lookup.IsValid()) {
00306
00307
00308 if (is_contextual()) {
00309 return ReferenceError("not_defined", name);
00310 }
00311 return TypeError("undefined_method", object, name);
00312 }
00313
00314
00315 if (FLAG_use_ic && lookup.IsLoaded()) {
00316 UpdateCaches(&lookup, state, object, name);
00317 }
00318
00319 if (lookup.type() == INTERCEPTOR) {
00320
00321 PropertyAttributes attr;
00322 result = object->GetProperty(*name, &attr);
00323 if (result->IsFailure()) return result;
00324
00325
00326 if (attr == ABSENT) {
00327 if (is_contextual()) {
00328 return ReferenceError("not_defined", name);
00329 }
00330 return TypeError("undefined_method", object, name);
00331 }
00332 } else {
00333
00334
00335 result = object->GetProperty(*name);
00336 if (result->IsFailure()) return result;
00337 }
00338
00339 ASSERT(result != Heap::the_hole_value());
00340
00341 if (result->IsJSFunction()) {
00342
00343
00344
00345
00346 if (object->IsJSObject() && JSObject::cast(*object)->HasFastElements()) {
00347 Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object),
00348 lookup.holder(),
00349 JSFunction::cast(result));
00350 if (opt->IsJSFunction()) return opt;
00351 }
00352
00353
00354
00355 if (Debug::StepInActive() && fp() == Debug::step_in_fp()) {
00356
00357 if (JSFunction::cast(result)->context()->global() !=
00358 Top::context()->builtins()) {
00359 HandleScope scope;
00360 Handle<SharedFunctionInfo> shared(JSFunction::cast(result)->shared());
00361 Debug::FloodWithOneShot(shared);
00362 }
00363 }
00364 return result;
00365 }
00366
00367
00368 result = TryCallAsFunction(result);
00369 return result->IsJSFunction() ?
00370 result : TypeError("property_not_function", object, name);
00371 }
00372
00373
00374 void CallIC::UpdateCaches(LookupResult* lookup,
00375 State state,
00376 Handle<Object> object,
00377 Handle<String> name) {
00378 ASSERT(lookup->IsLoaded());
00379
00380 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
00381
00382
00383 int argc = target()->arguments_count();
00384 Object* code = NULL;
00385
00386 if (state == UNINITIALIZED) {
00387
00388
00389
00390 code = StubCache::ComputeCallPreMonomorphic(argc);
00391 } else if (state == MONOMORPHIC) {
00392 code = StubCache::ComputeCallMegamorphic(argc);
00393 } else {
00394
00395 switch (lookup->type()) {
00396 case FIELD: {
00397 int index = lookup->GetFieldIndex();
00398 code = StubCache::ComputeCallField(argc, *name, *object,
00399 lookup->holder(), index);
00400 break;
00401 }
00402 case CONSTANT_FUNCTION: {
00403
00404
00405
00406 JSFunction* function = lookup->GetConstantFunction();
00407 code = StubCache::ComputeCallConstant(argc, *name, *object,
00408 lookup->holder(), function);
00409 break;
00410 }
00411 case NORMAL: {
00412
00413
00414
00415
00416 if (!object->IsJSObject()) return;
00417 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
00418 if (lookup->holder() != *receiver) return;
00419 code = StubCache::ComputeCallNormal(argc, *name, *receiver);
00420 break;
00421 }
00422 case INTERCEPTOR: {
00423 code = StubCache::ComputeCallInterceptor(argc, *name, *object,
00424 lookup->holder());
00425 break;
00426 }
00427 default:
00428 return;
00429 }
00430 }
00431
00432
00433
00434 if (code->IsFailure()) return;
00435
00436
00437 if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
00438 state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
00439 set_target(Code::cast(code));
00440 }
00441
00442 #ifdef DEBUG
00443 TraceIC("CallIC", name, state, target());
00444 #endif
00445 }
00446
00447
00448 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
00449
00450
00451 if (object->IsUndefined() || object->IsNull()) {
00452 return TypeError("non_object_property_load", object, name);
00453 }
00454
00455 if (FLAG_use_ic) {
00456
00457
00458
00459
00460 if ((object->IsString() || object->IsStringWrapper()) &&
00461 name->Equals(Heap::length_symbol())) {
00462 HandleScope scope;
00463
00464 if (object->IsJSValue()) {
00465 object = Handle<Object>(Handle<JSValue>::cast(object)->value());
00466 }
00467 #ifdef DEBUG
00468 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
00469 #endif
00470 Code* target = NULL;
00471 target = Builtins::builtin(Builtins::LoadIC_StringLength);
00472 set_target(target);
00473 StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
00474 return Smi::FromInt(String::cast(*object)->length());
00475 }
00476
00477
00478 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
00479 #ifdef DEBUG
00480 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
00481 #endif
00482 Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength);
00483 set_target(target);
00484 StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
00485 return JSArray::cast(*object)->length();
00486 }
00487
00488
00489 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
00490 #ifdef DEBUG
00491 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
00492 #endif
00493 Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype);
00494 set_target(target);
00495 StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
00496 return Accessors::FunctionGetPrototype(*object, 0);
00497 }
00498 }
00499
00500
00501
00502 uint32_t index;
00503 if (name->AsArrayIndex(&index)) return object->GetElement(index);
00504
00505
00506 LookupResult lookup;
00507 object->Lookup(*name, &lookup);
00508
00509
00510 if (!lookup.IsValid()) {
00511 if (FLAG_strict || is_contextual()) {
00512 return ReferenceError("not_defined", name);
00513 }
00514 String* class_name = object->IsJSObject()
00515 ? Handle<JSObject>::cast(object)->class_name()
00516 : Heap::empty_string();
00517 LOG(SuspectReadEvent(*name, class_name));
00518 USE(class_name);
00519 }
00520
00521
00522 if (FLAG_use_ic && lookup.IsLoaded()) {
00523 UpdateCaches(&lookup, state, object, name);
00524 }
00525
00526 PropertyAttributes attr;
00527 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
00528
00529 Object* result = object->GetProperty(*object, &lookup, *name, &attr);
00530 if (result->IsFailure()) return result;
00531
00532
00533 if (attr == ABSENT && is_contextual()) {
00534 return ReferenceError("not_defined", name);
00535 }
00536 return result;
00537 }
00538
00539
00540 return object->GetProperty(*object, &lookup, *name, &attr);
00541 }
00542
00543
00544 void LoadIC::UpdateCaches(LookupResult* lookup,
00545 State state,
00546 Handle<Object> object,
00547 Handle<String> name) {
00548 ASSERT(lookup->IsLoaded());
00549
00550 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
00551
00552
00553
00554 if (!object->IsJSObject()) return;
00555 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
00556
00557
00558 Object* code = NULL;
00559 if (state == UNINITIALIZED) {
00560
00561
00562
00563 code = pre_monomorphic_stub();
00564 } else {
00565
00566 switch (lookup->type()) {
00567 case FIELD: {
00568 code = StubCache::ComputeLoadField(*name, *receiver,
00569 lookup->holder(),
00570 lookup->GetFieldIndex());
00571 break;
00572 }
00573 case CONSTANT_FUNCTION: {
00574 Object* constant = lookup->GetConstantFunction();
00575 code = StubCache::ComputeLoadConstant(*name, *receiver,
00576 lookup->holder(), constant);
00577 break;
00578 }
00579 case NORMAL: {
00580
00581
00582
00583
00584 if (lookup->holder() != *receiver) return;
00585 code = StubCache::ComputeLoadNormal(*name, *receiver);
00586 break;
00587 }
00588 case CALLBACKS: {
00589 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
00590 AccessorInfo* callback =
00591 AccessorInfo::cast(lookup->GetCallbackObject());
00592 if (v8::ToCData<Address>(callback->getter()) == 0) return;
00593 code = StubCache::ComputeLoadCallback(*name, *receiver,
00594 lookup->holder(), callback);
00595 break;
00596 }
00597 case INTERCEPTOR: {
00598 code = StubCache::ComputeLoadInterceptor(*name, *receiver,
00599 lookup->holder());
00600 break;
00601 }
00602 default:
00603 return;
00604 }
00605 }
00606
00607
00608
00609 if (code->IsFailure()) return;
00610
00611
00612 if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
00613 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
00614 set_target(Code::cast(code));
00615 } else if (state == MONOMORPHIC) {
00616 set_target(megamorphic_stub());
00617 }
00618
00619 #ifdef DEBUG
00620 TraceIC("LoadIC", name, state, target());
00621 #endif
00622 }
00623
00624
00625 Object* KeyedLoadIC::Load(State state,
00626 Handle<Object> object,
00627 Handle<Object> key) {
00628 if (key->IsSymbol()) {
00629 Handle<String> name = Handle<String>::cast(key);
00630
00631
00632
00633 if (object->IsUndefined() || object->IsNull()) {
00634 return TypeError("non_object_property_load", object, name);
00635 }
00636
00637 if (FLAG_use_ic) {
00638
00639 if (object->IsString() && name->Equals(Heap::length_symbol())) {
00640 Handle<String> string = Handle<String>::cast(object);
00641 Object* code = NULL;
00642 code = StubCache::ComputeKeyedLoadStringLength(*name, *string);
00643 if (code->IsFailure()) return code;
00644 set_target(Code::cast(code));
00645 #ifdef DEBUG
00646 TraceIC("KeyedLoadIC", name, state, target());
00647 #endif
00648 return Smi::FromInt(string->length());
00649 }
00650
00651
00652 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
00653 Handle<JSArray> array = Handle<JSArray>::cast(object);
00654 Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array);
00655 if (code->IsFailure()) return code;
00656 set_target(Code::cast(code));
00657 #ifdef DEBUG
00658 TraceIC("KeyedLoadIC", name, state, target());
00659 #endif
00660 return JSArray::cast(*object)->length();
00661 }
00662
00663
00664 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
00665 Handle<JSFunction> function = Handle<JSFunction>::cast(object);
00666 Object* code =
00667 StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function);
00668 if (code->IsFailure()) return code;
00669 set_target(Code::cast(code));
00670 #ifdef DEBUG
00671 TraceIC("KeyedLoadIC", name, state, target());
00672 #endif
00673 return Accessors::FunctionGetPrototype(*object, 0);
00674 }
00675 }
00676
00677
00678
00679 uint32_t index = 0;
00680 if (name->AsArrayIndex(&index)) {
00681 HandleScope scope;
00682
00683 if (FLAG_use_ic) set_target(generic_stub());
00684 return Runtime::GetElementOrCharAt(object, index);
00685 }
00686
00687
00688 LookupResult lookup;
00689 object->Lookup(*name, &lookup);
00690
00691
00692 if (!lookup.IsValid()) {
00693 if (FLAG_strict || is_contextual()) {
00694 return ReferenceError("not_defined", name);
00695 }
00696 }
00697
00698
00699 if (FLAG_use_ic && lookup.IsLoaded()) {
00700 UpdateCaches(&lookup, state, object, name);
00701 }
00702
00703 PropertyAttributes attr;
00704 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
00705
00706 Object* result = object->GetProperty(*object, &lookup, *name, &attr);
00707 if (result->IsFailure()) return result;
00708
00709
00710 if (attr == ABSENT && is_contextual()) {
00711 return ReferenceError("not_defined", name);
00712 }
00713 return result;
00714 }
00715
00716 return object->GetProperty(*object, &lookup, *name, &attr);
00717 }
00718
00719
00720
00721 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
00722
00723 if (use_ic) set_target(generic_stub());
00724
00725
00726 return Runtime::GetObjectProperty(object, key);
00727 }
00728
00729
00730 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
00731 Handle<Object> object, Handle<String> name) {
00732 ASSERT(lookup->IsLoaded());
00733
00734 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
00735
00736 if (!object->IsJSObject()) return;
00737 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
00738
00739
00740 Object* code = NULL;
00741
00742 if (state == UNINITIALIZED) {
00743
00744
00745
00746 code = pre_monomorphic_stub();
00747 } else {
00748
00749 switch (lookup->type()) {
00750 case FIELD: {
00751 code = StubCache::ComputeKeyedLoadField(*name, *receiver,
00752 lookup->holder(),
00753 lookup->GetFieldIndex());
00754 break;
00755 }
00756 case CONSTANT_FUNCTION: {
00757 Object* constant = lookup->GetConstantFunction();
00758 code = StubCache::ComputeKeyedLoadConstant(*name, *receiver,
00759 lookup->holder(), constant);
00760 break;
00761 }
00762 case CALLBACKS: {
00763 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
00764 AccessorInfo* callback =
00765 AccessorInfo::cast(lookup->GetCallbackObject());
00766 if (v8::ToCData<Address>(callback->getter()) == 0) return;
00767 code = StubCache::ComputeKeyedLoadCallback(*name, *receiver,
00768 lookup->holder(), callback);
00769 break;
00770 }
00771 case INTERCEPTOR: {
00772 code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver,
00773 lookup->holder());
00774 break;
00775 }
00776 default: {
00777
00778
00779 code = generic_stub();
00780 break;
00781 }
00782 }
00783 }
00784
00785
00786
00787 if (code->IsFailure()) return;
00788
00789
00790
00791 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
00792 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
00793 set_target(Code::cast(code));
00794 } else if (state == MONOMORPHIC) {
00795 set_target(megamorphic_stub());
00796 }
00797
00798 #ifdef DEBUG
00799 TraceIC("KeyedLoadIC", name, state, target());
00800 #endif
00801 }
00802
00803
00804 Object* StoreIC::Store(State state,
00805 Handle<Object> object,
00806 Handle<String> name,
00807 Handle<Object> value) {
00808
00809
00810 if (object->IsUndefined() || object->IsNull()) {
00811 return TypeError("non_object_property_store", object, name);
00812 }
00813
00814
00815 if (!object->IsJSObject()) return *value;
00816 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
00817
00818
00819 uint32_t index;
00820 if (name->AsArrayIndex(&index)) {
00821 HandleScope scope;
00822 Handle<Object> result = SetElement(receiver, index, value);
00823 if (result.is_null()) return Failure::Exception();
00824 return *value;
00825 }
00826
00827
00828 LookupResult lookup;
00829 receiver->LocalLookup(*name, &lookup);
00830
00831
00832 if (FLAG_use_ic && lookup.IsLoaded()) {
00833 UpdateCaches(&lookup, state, receiver, name, value);
00834 }
00835
00836
00837 return receiver->SetProperty(*name, *value, NONE);
00838 }
00839
00840
00841 void StoreIC::UpdateCaches(LookupResult* lookup,
00842 State state,
00843 Handle<JSObject> receiver,
00844 Handle<String> name,
00845 Handle<Object> value) {
00846 ASSERT(lookup->IsLoaded());
00847
00848 if (receiver->IsJSGlobalProxy()) return;
00849
00850
00851 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
00852
00853
00854
00855 if (lookup->IsReadOnly()) return;
00856
00857
00858
00859
00860 PropertyType type = lookup->type();
00861
00862
00863
00864
00865 Object* code = NULL;
00866 switch (type) {
00867 case FIELD: {
00868 code = StubCache::ComputeStoreField(*name, *receiver,
00869 lookup->GetFieldIndex());
00870 break;
00871 }
00872 case MAP_TRANSITION: {
00873 if (lookup->GetAttributes() != NONE) return;
00874 HandleScope scope;
00875 ASSERT(type == MAP_TRANSITION);
00876 Handle<Map> transition(lookup->GetTransitionMap());
00877 int index = transition->PropertyIndexFor(*name);
00878 code = StubCache::ComputeStoreField(*name, *receiver, index, *transition);
00879 break;
00880 }
00881 case CALLBACKS: {
00882 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
00883 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
00884 if (v8::ToCData<Address>(callback->setter()) == 0) return;
00885 code = StubCache::ComputeStoreCallback(*name, *receiver, callback);
00886 break;
00887 }
00888 case INTERCEPTOR: {
00889 code = StubCache::ComputeStoreInterceptor(*name, *receiver);
00890 break;
00891 }
00892 default:
00893 return;
00894 }
00895
00896
00897
00898 if (code->IsFailure()) return;
00899
00900
00901 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
00902 set_target(Code::cast(code));
00903 } else if (state == MONOMORPHIC) {
00904
00905 if (target() != Code::cast(code)) set_target(megamorphic_stub());
00906 }
00907
00908 #ifdef DEBUG
00909 TraceIC("StoreIC", name, state, target());
00910 #endif
00911 }
00912
00913
00914 Object* KeyedStoreIC::Store(State state,
00915 Handle<Object> object,
00916 Handle<Object> key,
00917 Handle<Object> value) {
00918 if (key->IsSymbol()) {
00919 Handle<String> name = Handle<String>::cast(key);
00920
00921
00922
00923 if (object->IsUndefined() || object->IsNull()) {
00924 return TypeError("non_object_property_store", object, name);
00925 }
00926
00927
00928 if (!object->IsJSObject()) return *value;
00929 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
00930
00931
00932 uint32_t index;
00933 if (name->AsArrayIndex(&index)) {
00934 HandleScope scope;
00935 Handle<Object> result = SetElement(receiver, index, value);
00936 if (result.is_null()) return Failure::Exception();
00937 return *value;
00938 }
00939
00940
00941 LookupResult lookup;
00942 receiver->LocalLookup(*name, &lookup);
00943
00944
00945 if (FLAG_use_ic && lookup.IsLoaded()) {
00946 UpdateCaches(&lookup, state, receiver, name, value);
00947 }
00948
00949
00950 return receiver->SetProperty(*name, *value, NONE);
00951 }
00952
00953
00954
00955 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
00956 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
00957
00958 if (use_ic) set_target(generic_stub());
00959
00960
00961 return Runtime::SetObjectProperty(object, key, value, NONE);
00962 }
00963
00964
00965 void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
00966 State state,
00967 Handle<JSObject> receiver,
00968 Handle<String> name,
00969 Handle<Object> value) {
00970 ASSERT(lookup->IsLoaded());
00971
00972
00973 if (receiver->IsJSGlobalProxy()) return;
00974
00975
00976 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
00977
00978
00979
00980 if (lookup->IsReadOnly()) return;
00981
00982
00983
00984
00985 PropertyType type = lookup->type();
00986
00987
00988
00989
00990 Object* code = NULL;
00991
00992 switch (type) {
00993 case FIELD: {
00994 code = StubCache::ComputeKeyedStoreField(*name, *receiver,
00995 lookup->GetFieldIndex());
00996 break;
00997 }
00998 case MAP_TRANSITION: {
00999 if (lookup->GetAttributes() == NONE) {
01000 HandleScope scope;
01001 ASSERT(type == MAP_TRANSITION);
01002 Handle<Map> transition(lookup->GetTransitionMap());
01003 int index = transition->PropertyIndexFor(*name);
01004 code = StubCache::ComputeKeyedStoreField(*name, *receiver,
01005 index, *transition);
01006 break;
01007 }
01008
01009 }
01010 default: {
01011
01012
01013 code = generic_stub();
01014 break;
01015 }
01016 }
01017
01018
01019
01020 if (code->IsFailure()) return;
01021
01022
01023
01024 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
01025 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
01026 set_target(Code::cast(code));
01027 } else if (state == MONOMORPHIC) {
01028 set_target(megamorphic_stub());
01029 }
01030
01031 #ifdef DEBUG
01032 TraceIC("KeyedStoreIC", name, state, target());
01033 #endif
01034 }
01035
01036
01037
01038
01039
01040
01041
01042 Object* CallIC_Miss(Arguments args) {
01043 NoHandleAllocation na;
01044 ASSERT(args.length() == 2);
01045 CallIC ic;
01046 IC::State state = IC::StateFrom(ic.target(), args[0]);
01047 return ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
01048 }
01049
01050
01051 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) {
01052 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
01053 }
01054
01055
01056 void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) {
01057 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
01058 }
01059
01060
01061 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
01062 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
01063 }
01064
01065
01066
01067 Object* LoadIC_Miss(Arguments args) {
01068 NoHandleAllocation na;
01069 ASSERT(args.length() == 2);
01070 LoadIC ic;
01071 IC::State state = IC::StateFrom(ic.target(), args[0]);
01072 return ic.Load(state, args.at<Object>(0), args.at<String>(1));
01073 }
01074
01075
01076 void LoadIC::GenerateInitialize(MacroAssembler* masm) {
01077 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
01078 }
01079
01080
01081 void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
01082 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
01083 }
01084
01085
01086
01087 Object* KeyedLoadIC_Miss(Arguments args) {
01088 NoHandleAllocation na;
01089 ASSERT(args.length() == 2);
01090 KeyedLoadIC ic;
01091 IC::State state = IC::StateFrom(ic.target(), args[0]);
01092 return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
01093 }
01094
01095
01096 void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) {
01097 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
01098 }
01099
01100
01101 void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
01102 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
01103 }
01104
01105
01106
01107 Object* StoreIC_Miss(Arguments args) {
01108 NoHandleAllocation na;
01109 ASSERT(args.length() == 3);
01110 StoreIC ic;
01111 IC::State state = IC::StateFrom(ic.target(), args[0]);
01112 return ic.Store(state, args.at<Object>(0), args.at<String>(1),
01113 args.at<Object>(2));
01114 }
01115
01116
01117
01118
01119
01120 Object* SharedStoreIC_ExtendStorage(Arguments args) {
01121 NoHandleAllocation na;
01122 ASSERT(args.length() == 3);
01123
01124
01125 JSObject* object = JSObject::cast(args[0]);
01126 Map* transition = Map::cast(args[1]);
01127 Object* value = args[2];
01128
01129
01130 ASSERT(object->HasFastProperties());
01131 ASSERT(object->map()->unused_property_fields() == 0);
01132
01133
01134 FixedArray* old_storage = object->properties();
01135 int new_unused = transition->unused_property_fields();
01136 int new_size = old_storage->length() + new_unused + 1;
01137 Object* result = old_storage->CopySize(new_size);
01138 if (result->IsFailure()) return result;
01139 FixedArray* new_storage = FixedArray::cast(result);
01140 new_storage->set(old_storage->length(), value);
01141
01142
01143 object->set_properties(new_storage);
01144 object->set_map(transition);
01145
01146
01147 return value;
01148 }
01149
01150
01151 void StoreIC::GenerateInitialize(MacroAssembler* masm) {
01152 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
01153 }
01154
01155
01156 void StoreIC::GenerateMiss(MacroAssembler* masm) {
01157 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
01158 }
01159
01160
01161
01162 Object* KeyedStoreIC_Miss(Arguments args) {
01163 NoHandleAllocation na;
01164 ASSERT(args.length() == 3);
01165 KeyedStoreIC ic;
01166 IC::State state = IC::StateFrom(ic.target(), args[0]);
01167 return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
01168 args.at<Object>(2));
01169 }
01170
01171
01172 void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) {
01173 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
01174 }
01175
01176
01177 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
01178 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
01179 }
01180
01181
01182 static Address IC_utilities[] = {
01183 #define ADDR(name) FUNCTION_ADDR(name),
01184 IC_UTIL_LIST(ADDR)
01185 NULL
01186 #undef ADDR
01187 };
01188
01189
01190 Address IC::AddressFromUtilityId(IC::UtilityId id) {
01191 return IC_utilities[id];
01192 }
01193
01194
01195 } }