| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 } | 54 } |
| 55 UNREACHABLE(); | 55 UNREACHABLE(); |
| 56 return 0; | 56 return 0; |
| 57 } | 57 } |
| 58 | 58 |
| 59 void IC::TraceIC(const char* type, | 59 void IC::TraceIC(const char* type, |
| 60 Handle<String> name, | 60 Handle<String> name, |
| 61 State old_state, | 61 State old_state, |
| 62 Code* new_target) { | 62 Code* new_target) { |
| 63 if (FLAG_trace_ic) { | 63 if (FLAG_trace_ic) { |
| 64 State new_state = new_target->ic_state(); | 64 State new_state = StateFrom(new_target, Heap::undefined_value()); |
| 65 PrintF("[%s (%c->%c) ", type, | 65 PrintF("[%s (%c->%c) ", type, |
| 66 TransitionMarkFromState(old_state), | 66 TransitionMarkFromState(old_state), |
| 67 TransitionMarkFromState(new_state)); | 67 TransitionMarkFromState(new_state)); |
| 68 name->Print(); | 68 name->Print(); |
| 69 PrintF("]\n"); | 69 PrintF("]\n"); |
| 70 } | 70 } |
| 71 } | 71 } |
| 72 #endif | 72 #endif |
| 73 | 73 |
| 74 | 74 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 // normally would be. | 120 // normally would be. |
| 121 Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist; | 121 Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist; |
| 122 // Return the address in the original code. This is the place where | 122 // Return the address in the original code. This is the place where |
| 123 // the call which has been overwriten by the DebugBreakXXX resides | 123 // the call which has been overwriten by the DebugBreakXXX resides |
| 124 // and the place where the inline cache system should look. | 124 // and the place where the inline cache system should look. |
| 125 int delta = original_code->instruction_start() - code->instruction_start(); | 125 int delta = original_code->instruction_start() - code->instruction_start(); |
| 126 return addr + delta; | 126 return addr + delta; |
| 127 } | 127 } |
| 128 | 128 |
| 129 | 129 |
| 130 IC::State IC::ComputeCacheState(Code* target, Object* receiver, | 130 IC::State IC::StateFrom(Code* target, Object* receiver) { |
| 131 Object* name, Object** new_target) { | 131 IC::State state = target->ic_state(); |
| 132 // Get the raw state from the target. | |
| 133 State target_state = target->ic_state(); | |
| 134 | 132 |
| 135 // Assume that no new target exists in the cache. | 133 if (state != MONOMORPHIC) return state; |
| 136 *new_target = Heap::undefined_value(); | 134 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
| 137 | |
| 138 if (target_state != MONOMORPHIC) return target_state; | |
| 139 if (receiver->IsUndefined() || receiver->IsNull()) return target_state; | |
| 140 | 135 |
| 141 Map* map = GetCodeCacheMapForObject(receiver); | 136 Map* map = GetCodeCacheMapForObject(receiver); |
| 142 | 137 |
| 143 // Decide whether the inline cache failed because of changes to the | 138 // Decide whether the inline cache failed because of changes to the |
| 144 // receiver itself or changes to one of its prototypes. | 139 // receiver itself or changes to one of its prototypes. |
| 145 // | 140 // |
| 146 // If there are changes to the receiver itself, the map of the | 141 // If there are changes to the receiver itself, the map of the |
| 147 // receiver will have changed and the current target will not be in | 142 // receiver will have changed and the current target will not be in |
| 148 // the receiver map's code cache. Therefore, if the current target | 143 // the receiver map's code cache. Therefore, if the current target |
| 149 // is in the receiver map's code cache, the inline cache failed due | 144 // is in the receiver map's code cache, the inline cache failed due |
| 150 // to prototype check failure. | 145 // to prototype check failure. |
| 151 int index = -1; | 146 int index = map->IndexInCodeCache(target); |
| 152 Object* code = NULL; | 147 if (index >= 0) { |
| 153 if (name->IsString()) { | |
| 154 code = map->FindIndexInCodeCache(String::cast(name), | |
| 155 target->flags(), | |
| 156 &index); | |
| 157 } | |
| 158 if (index >= 0 && code == target) { | |
| 159 // For keyed load/store, the most likely cause of cache failure is | 148 // For keyed load/store, the most likely cause of cache failure is |
| 160 // that the key has changed. We do not distinguish between | 149 // that the key has changed. We do not distinguish between |
| 161 // prototype and non-prototype failures for keyed access. | 150 // prototype and non-prototype failures for keyed access. |
| 162 Code::Kind kind = target->kind(); | 151 Code::Kind kind = target->kind(); |
| 163 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { | 152 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { |
| 164 return MONOMORPHIC; | 153 return MONOMORPHIC; |
| 165 } | 154 } |
| 166 | 155 |
| 167 // Remove the target from the code cache to avoid hitting the same | 156 // Remove the target from the code cache to avoid hitting the same |
| 168 // invalid stub again. | 157 // invalid stub again. |
| 169 map->RemoveFromCodeCache(index); | 158 map->RemoveFromCodeCache(index); |
| 170 | 159 |
| 171 return MONOMORPHIC_PROTOTYPE_FAILURE; | 160 return MONOMORPHIC_PROTOTYPE_FAILURE; |
| 172 } | 161 } |
| 173 | 162 |
| 174 // The builtins object is special. It only changes when JavaScript | 163 // The builtins object is special. It only changes when JavaScript |
| 175 // builtins are loaded lazily. It is important to keep inline | 164 // builtins are loaded lazily. It is important to keep inline |
| 176 // caches for the builtins object monomorphic. Therefore, if we get | 165 // caches for the builtins object monomorphic. Therefore, if we get |
| 177 // an inline cache miss for the builtins object after lazily loading | 166 // an inline cache miss for the builtins object after lazily loading |
| 178 // JavaScript builtins, we clear the code cache and return | 167 // JavaScript builtins, we clear the code cache and return |
| 179 // uninitialized as the state to force the inline cache back to | 168 // uninitialized as the state to force the inline cache back to |
| 180 // monomorphic state. | 169 // monomorphic state. |
| 181 if (receiver->IsJSBuiltinsObject()) { | 170 if (receiver->IsJSBuiltinsObject()) { |
| 182 map->ClearCodeCache(); | 171 map->ClearCodeCache(); |
| 183 return UNINITIALIZED; | 172 return UNINITIALIZED; |
| 184 } | 173 } |
| 185 | 174 |
| 186 *new_target = code; | |
| 187 return MONOMORPHIC; | 175 return MONOMORPHIC; |
| 188 } | 176 } |
| 189 | 177 |
| 190 | 178 |
| 191 RelocMode IC::ComputeMode() { | 179 RelocMode IC::ComputeMode() { |
| 192 Address addr = address(); | 180 Address addr = address(); |
| 193 Code* code = Code::cast(Heap::FindCodeObject(addr)); | 181 Code* code = Code::cast(Heap::FindCodeObject(addr)); |
| 194 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); | 182 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); |
| 195 !it.done(); it.next()) { | 183 !it.done(); it.next()) { |
| 196 RelocInfo* info = it.rinfo(); | 184 RelocInfo* info = it.rinfo(); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 StackFrameLocator locator; | 268 StackFrameLocator locator; |
| 281 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 269 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 282 int index = frame->ComputeExpressionsCount() - (argc + 1); | 270 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 283 frame->SetExpression(index, *target); | 271 frame->SetExpression(index, *target); |
| 284 } | 272 } |
| 285 | 273 |
| 286 return *delegate; | 274 return *delegate; |
| 287 } | 275 } |
| 288 | 276 |
| 289 | 277 |
| 290 Object* CallIC::LoadFunction(Handle<Object> object, | 278 Object* CallIC::LoadFunction(State state, |
| 279 Handle<Object> object, |
| 291 Handle<String> name) { | 280 Handle<String> name) { |
| 292 // If the object is undefined or null it's illegal to try to get any | 281 // If the object is undefined or null it's illegal to try to get any |
| 293 // of its properties; throw a TypeError in that case. | 282 // of its properties; throw a TypeError in that case. |
| 294 if (object->IsUndefined() || object->IsNull()) { | 283 if (object->IsUndefined() || object->IsNull()) { |
| 295 return TypeError("non_object_property_call", object, name); | 284 return TypeError("non_object_property_call", object, name); |
| 296 } | 285 } |
| 297 | 286 |
| 298 Object* result = Heap::the_hole_value(); | 287 Object* result = Heap::the_hole_value(); |
| 299 | 288 |
| 300 // Check if the name is trivially convertible to an index and get | 289 // Check if the name is trivially convertible to an index and get |
| (...skipping 18 matching lines...) Expand all Loading... |
| 319 // If the object does not have the requested property, check which | 308 // If the object does not have the requested property, check which |
| 320 // exception we need to throw. | 309 // exception we need to throw. |
| 321 if (is_contextual()) { | 310 if (is_contextual()) { |
| 322 return ReferenceError("not_defined", name); | 311 return ReferenceError("not_defined", name); |
| 323 } | 312 } |
| 324 return TypeError("undefined_method", object, name); | 313 return TypeError("undefined_method", object, name); |
| 325 } | 314 } |
| 326 | 315 |
| 327 // Lookup is valid: Update inline cache and stub cache. | 316 // Lookup is valid: Update inline cache and stub cache. |
| 328 if (FLAG_use_ic && lookup.IsLoaded()) { | 317 if (FLAG_use_ic && lookup.IsLoaded()) { |
| 329 UpdateCaches(&lookup, object, name); | 318 UpdateCaches(&lookup, state, object, name); |
| 330 } | 319 } |
| 331 | 320 |
| 332 if (lookup.type() == INTERCEPTOR) { | 321 if (lookup.type() == INTERCEPTOR) { |
| 333 // Get the property. | 322 // Get the property. |
| 334 PropertyAttributes attr; | 323 PropertyAttributes attr; |
| 335 result = object->GetProperty(*name, &attr); | 324 result = object->GetProperty(*name, &attr); |
| 336 if (result->IsFailure()) return result; | 325 if (result->IsFailure()) return result; |
| 337 // If the object does not have the requested property, check which | 326 // If the object does not have the requested property, check which |
| 338 // exception we need to throw. | 327 // exception we need to throw. |
| 339 if (attr == ABSENT) { | 328 if (attr == ABSENT) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 } | 367 } |
| 379 | 368 |
| 380 // Try to find a suitable function delegate for the object at hand. | 369 // Try to find a suitable function delegate for the object at hand. |
| 381 result = TryCallAsFunction(result); | 370 result = TryCallAsFunction(result); |
| 382 return result->IsJSFunction() ? | 371 return result->IsJSFunction() ? |
| 383 result : TypeError("property_not_function", object, name); | 372 result : TypeError("property_not_function", object, name); |
| 384 } | 373 } |
| 385 | 374 |
| 386 | 375 |
| 387 void CallIC::UpdateCaches(LookupResult* lookup, | 376 void CallIC::UpdateCaches(LookupResult* lookup, |
| 377 State state, |
| 388 Handle<Object> object, | 378 Handle<Object> object, |
| 389 Handle<String> name) { | 379 Handle<String> name) { |
| 390 ASSERT(lookup->IsLoaded()); | 380 ASSERT(lookup->IsLoaded()); |
| 391 // Bail out if we didn't find a result. | 381 // Bail out if we didn't find a result. |
| 392 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 382 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
| 393 | 383 |
| 394 // Compute the number of arguments. | 384 // Compute the number of arguments. |
| 395 int argc = target()->arguments_count(); | 385 int argc = target()->arguments_count(); |
| 386 Object* code = NULL; |
| 396 | 387 |
| 397 Object* code = Heap::undefined_value(); | 388 if (state == UNINITIALIZED) { |
| 398 State state = ComputeCacheState(target(), *object, *name, &code); | 389 // This is the first time we execute this inline cache. |
| 399 | 390 // Set the target to the pre monomorphic stub to delay |
| 400 switch (state) { | 391 // setting the monomorphic state. |
| 401 case UNINITIALIZED: | 392 code = StubCache::ComputeCallPreMonomorphic(argc); |
| 402 code = StubCache::ComputeCallPreMonomorphic(argc); | 393 } else if (state == MONOMORPHIC) { |
| 403 break; | 394 code = StubCache::ComputeCallMegamorphic(argc); |
| 404 case MONOMORPHIC: | 395 } else { |
| 405 if (code->IsUndefined()) code = StubCache::ComputeCallMegamorphic(argc); | 396 // Compute monomorphic stub. |
| 406 break; | 397 switch (lookup->type()) { |
| 407 default: | 398 case FIELD: { |
| 408 // Compute monomorphic stub. | 399 int index = lookup->GetFieldIndex(); |
| 409 switch (lookup->type()) { | 400 code = StubCache::ComputeCallField(argc, *name, *object, |
| 410 case FIELD: { | 401 lookup->holder(), index); |
| 411 int index = lookup->GetFieldIndex(); | 402 break; |
| 412 code = StubCache::ComputeCallField(argc, *name, *object, | |
| 413 lookup->holder(), index); | |
| 414 break; | |
| 415 } | |
| 416 case CONSTANT_FUNCTION: { | |
| 417 // Get the constant function and compute the code stub for this | |
| 418 // call; used for rewriting to monomorphic state and making sure | |
| 419 // that the code stub is in the stub cache. | |
| 420 JSFunction* function = lookup->GetConstantFunction(); | |
| 421 code = StubCache::ComputeCallConstant(argc, *name, *object, | |
| 422 lookup->holder(), function); | |
| 423 break; | |
| 424 } | |
| 425 case NORMAL: { | |
| 426 // There is only one shared stub for calling normalized | |
| 427 // properties. It does not traverse the prototype chain, so the | |
| 428 // property must be found in the receiver for the stub to be | |
| 429 // applicable. | |
| 430 if (!object->IsJSObject()) return; | |
| 431 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 432 if (lookup->holder() != *receiver) return; | |
| 433 code = StubCache::ComputeCallNormal(argc, *name, *receiver); | |
| 434 break; | |
| 435 } | |
| 436 case INTERCEPTOR: { | |
| 437 code = StubCache::ComputeCallInterceptor(argc, *name, *object, | |
| 438 lookup->holder()); | |
| 439 break; | |
| 440 } | |
| 441 default: | |
| 442 return; | |
| 443 } | 403 } |
| 444 break; | 404 case CONSTANT_FUNCTION: { |
| 405 // Get the constant function and compute the code stub for this |
| 406 // call; used for rewriting to monomorphic state and making sure |
| 407 // that the code stub is in the stub cache. |
| 408 JSFunction* function = lookup->GetConstantFunction(); |
| 409 code = StubCache::ComputeCallConstant(argc, *name, *object, |
| 410 lookup->holder(), function); |
| 411 break; |
| 412 } |
| 413 case NORMAL: { |
| 414 // There is only one shared stub for calling normalized |
| 415 // properties. It does not traverse the prototype chain, so the |
| 416 // property must be found in the receiver for the stub to be |
| 417 // applicable. |
| 418 if (!object->IsJSObject()) return; |
| 419 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 420 if (lookup->holder() != *receiver) return; |
| 421 code = StubCache::ComputeCallNormal(argc, *name, *receiver); |
| 422 break; |
| 423 } |
| 424 case INTERCEPTOR: { |
| 425 code = StubCache::ComputeCallInterceptor(argc, *name, *object, |
| 426 lookup->holder()); |
| 427 break; |
| 428 } |
| 429 default: |
| 430 return; |
| 431 } |
| 445 } | 432 } |
| 446 | 433 |
| 447 // If we're unable to compute the stub (not enough memory left), we | 434 // If we're unable to compute the stub (not enough memory left), we |
| 448 // simply avoid updating the caches. | 435 // simply avoid updating the caches. |
| 449 if (code->IsFailure()) return; | 436 if (code->IsFailure()) return; |
| 450 | 437 |
| 451 // Patch the call site depending on the state of the cache. | 438 // Patch the call site depending on the state of the cache. |
| 452 if (state == UNINITIALIZED || state == PREMONOMORPHIC || | 439 if (state == UNINITIALIZED || state == PREMONOMORPHIC || |
| 453 state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 440 state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 454 set_target(Code::cast(code)); | 441 set_target(Code::cast(code)); |
| 455 } | 442 } |
| 456 | 443 |
| 457 #ifdef DEBUG | 444 #ifdef DEBUG |
| 458 TraceIC("CallIC", name, state, target()); | 445 TraceIC("CallIC", name, state, target()); |
| 459 #endif | 446 #endif |
| 460 } | 447 } |
| 461 | 448 |
| 462 | 449 |
| 463 Object* LoadIC::Load(Handle<Object> object, Handle<String> name) { | 450 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { |
| 464 // If the object is undefined or null it's illegal to try to get any | 451 // If the object is undefined or null it's illegal to try to get any |
| 465 // of its properties; throw a TypeError in that case. | 452 // of its properties; throw a TypeError in that case. |
| 466 if (object->IsUndefined() || object->IsNull()) { | 453 if (object->IsUndefined() || object->IsNull()) { |
| 467 return TypeError("non_object_property_load", object, name); | 454 return TypeError("non_object_property_load", object, name); |
| 468 } | 455 } |
| 469 | 456 |
| 470 if (FLAG_use_ic) { | 457 if (FLAG_use_ic) { |
| 471 // Use specialized code for getting the length of strings. | 458 // Use specialized code for getting the length of strings. |
| 472 if (object->IsString() && name->Equals(Heap::length_symbol())) { | 459 if (object->IsString() && name->Equals(Heap::length_symbol())) { |
| 473 #ifdef DEBUG | 460 #ifdef DEBUG |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 } | 513 } |
| 527 String* class_name = object->IsJSObject() | 514 String* class_name = object->IsJSObject() |
| 528 ? Handle<JSObject>::cast(object)->class_name() | 515 ? Handle<JSObject>::cast(object)->class_name() |
| 529 : Heap::empty_string(); | 516 : Heap::empty_string(); |
| 530 LOG(SuspectReadEvent(*name, class_name)); | 517 LOG(SuspectReadEvent(*name, class_name)); |
| 531 USE(class_name); | 518 USE(class_name); |
| 532 } | 519 } |
| 533 | 520 |
| 534 // Update inline cache and stub cache. | 521 // Update inline cache and stub cache. |
| 535 if (FLAG_use_ic && lookup.IsLoaded()) { | 522 if (FLAG_use_ic && lookup.IsLoaded()) { |
| 536 UpdateCaches(&lookup, object, name); | 523 UpdateCaches(&lookup, state, object, name); |
| 537 } | 524 } |
| 538 | 525 |
| 539 PropertyAttributes attr; | 526 PropertyAttributes attr; |
| 540 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { | 527 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { |
| 541 // Get the property. | 528 // Get the property. |
| 542 Object* result = object->GetProperty(*object, &lookup, *name, &attr); | 529 Object* result = object->GetProperty(*object, &lookup, *name, &attr); |
| 543 if (result->IsFailure()) return result; | 530 if (result->IsFailure()) return result; |
| 544 // If the property is not present, check if we need to throw an | 531 // If the property is not present, check if we need to throw an |
| 545 // exception. | 532 // exception. |
| 546 if (attr == ABSENT && is_contextual()) { | 533 if (attr == ABSENT && is_contextual()) { |
| 547 return ReferenceError("not_defined", name); | 534 return ReferenceError("not_defined", name); |
| 548 } | 535 } |
| 549 return result; | 536 return result; |
| 550 } | 537 } |
| 551 | 538 |
| 552 // Get the property. | 539 // Get the property. |
| 553 return object->GetProperty(*object, &lookup, *name, &attr); | 540 return object->GetProperty(*object, &lookup, *name, &attr); |
| 554 } | 541 } |
| 555 | 542 |
| 556 | 543 |
| 557 void LoadIC::UpdateCaches(LookupResult* lookup, | 544 void LoadIC::UpdateCaches(LookupResult* lookup, |
| 545 State state, |
| 558 Handle<Object> object, | 546 Handle<Object> object, |
| 559 Handle<String> name) { | 547 Handle<String> name) { |
| 560 ASSERT(lookup->IsLoaded()); | 548 ASSERT(lookup->IsLoaded()); |
| 561 // Bail out if we didn't find a result. | 549 // Bail out if we didn't find a result. |
| 562 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 550 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
| 563 | 551 |
| 564 // Loading properties from values is not common, so don't try to | 552 // Loading properties from values is not common, so don't try to |
| 565 // deal with non-JS objects here. | 553 // deal with non-JS objects here. |
| 566 if (!object->IsJSObject()) return; | 554 if (!object->IsJSObject()) return; |
| 567 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 555 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 568 | 556 |
| 569 // Compute the code stub for this load. | 557 // Compute the code stub for this load. |
| 570 Object* code = Heap::undefined_value(); | 558 Object* code = NULL; |
| 571 State state = ComputeCacheState(target(), *object, *name, &code); | |
| 572 | |
| 573 if (state == UNINITIALIZED) { | 559 if (state == UNINITIALIZED) { |
| 574 // This is the first time we execute this inline cache. | 560 // This is the first time we execute this inline cache. |
| 575 // Set the target to the pre monomorphic stub to delay | 561 // Set the target to the pre monomorphic stub to delay |
| 576 // setting the monomorphic state. | 562 // setting the monomorphic state. |
| 577 code = pre_monomorphic_stub(); | 563 code = pre_monomorphic_stub(); |
| 578 } else if (state != MONOMORPHIC) { | 564 } else { |
| 579 // Compute monomorphic stub. | 565 // Compute monomorphic stub. |
| 580 switch (lookup->type()) { | 566 switch (lookup->type()) { |
| 581 case FIELD: { | 567 case FIELD: { |
| 582 code = StubCache::ComputeLoadField(*name, *receiver, | 568 code = StubCache::ComputeLoadField(*name, *receiver, |
| 583 lookup->holder(), | 569 lookup->holder(), |
| 584 lookup->GetFieldIndex()); | 570 lookup->GetFieldIndex()); |
| 585 break; | 571 break; |
| 586 } | 572 } |
| 587 case CONSTANT_FUNCTION: { | 573 case CONSTANT_FUNCTION: { |
| 588 Object* constant = lookup->GetConstantFunction(); | 574 Object* constant = lookup->GetConstantFunction(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 609 break; | 595 break; |
| 610 } | 596 } |
| 611 case INTERCEPTOR: { | 597 case INTERCEPTOR: { |
| 612 code = StubCache::ComputeLoadInterceptor(*name, *receiver, | 598 code = StubCache::ComputeLoadInterceptor(*name, *receiver, |
| 613 lookup->holder()); | 599 lookup->holder()); |
| 614 break; | 600 break; |
| 615 } | 601 } |
| 616 default: | 602 default: |
| 617 return; | 603 return; |
| 618 } | 604 } |
| 605 } |
| 619 | 606 |
| 620 // If we're unable to compute the stub (not enough memory left), we | 607 // If we're unable to compute the stub (not enough memory left), we |
| 621 // simply avoid updating the caches. | 608 // simply avoid updating the caches. |
| 622 if (code->IsFailure()) return; | 609 if (code->IsFailure()) return; |
| 623 } | |
| 624 | 610 |
| 625 // Patch the call site depending on the state of the cache. | 611 // Patch the call site depending on the state of the cache. |
| 626 if (state == UNINITIALIZED || state == PREMONOMORPHIC || | 612 if (state == UNINITIALIZED || state == PREMONOMORPHIC || |
| 627 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 613 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 628 set_target(Code::cast(code)); | 614 set_target(Code::cast(code)); |
| 629 } else if (state == MONOMORPHIC && code->IsUndefined()) { | 615 } else if (state == MONOMORPHIC) { |
| 630 set_target(megamorphic_stub()); | 616 set_target(megamorphic_stub()); |
| 631 } else if (state == MONOMORPHIC) { | |
| 632 set_target(Code::cast(code)); | |
| 633 } | 617 } |
| 634 | 618 |
| 635 #ifdef DEBUG | 619 #ifdef DEBUG |
| 636 TraceIC("LoadIC", name, state, target()); | 620 TraceIC("LoadIC", name, state, target()); |
| 637 #endif | 621 #endif |
| 638 } | 622 } |
| 639 | 623 |
| 640 | 624 |
| 641 Object* KeyedLoadIC::Load(Handle<Object> object, | 625 Object* KeyedLoadIC::Load(State state, |
| 626 Handle<Object> object, |
| 642 Handle<Object> key) { | 627 Handle<Object> key) { |
| 643 if (key->IsSymbol()) { | 628 if (key->IsSymbol()) { |
| 644 Handle<String> name = Handle<String>::cast(key); | 629 Handle<String> name = Handle<String>::cast(key); |
| 645 | 630 |
| 646 // If the object is undefined or null it's illegal to try to get any | 631 // If the object is undefined or null it's illegal to try to get any |
| 647 // of its properties; throw a TypeError in that case. | 632 // of its properties; throw a TypeError in that case. |
| 648 if (object->IsUndefined() || object->IsNull()) { | 633 if (object->IsUndefined() || object->IsNull()) { |
| 649 return TypeError("non_object_property_load", object, name); | 634 return TypeError("non_object_property_load", object, name); |
| 650 } | 635 } |
| 651 | 636 |
| 652 if (FLAG_use_ic) { | 637 if (FLAG_use_ic) { |
| 653 // Use specialized code for getting the length of strings. | 638 // Use specialized code for getting the length of strings. |
| 654 if (object->IsString() && name->Equals(Heap::length_symbol())) { | 639 if (object->IsString() && name->Equals(Heap::length_symbol())) { |
| 655 Handle<String> string = Handle<String>::cast(object); | 640 Handle<String> string = Handle<String>::cast(object); |
| 656 Object* code = NULL; | 641 Object* code = NULL; |
| 657 if (string->IsShortString()) { | 642 if (string->IsShortString()) { |
| 658 code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string); | 643 code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string); |
| 659 } else if (string->IsMediumString()) { | 644 } else if (string->IsMediumString()) { |
| 660 code = | 645 code = |
| 661 StubCache::ComputeKeyedLoadMediumStringLength(*name, *string); | 646 StubCache::ComputeKeyedLoadMediumStringLength(*name, *string); |
| 662 } else { | 647 } else { |
| 663 ASSERT(string->IsLongString()); | 648 ASSERT(string->IsLongString()); |
| 664 code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string); | 649 code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string); |
| 665 } | 650 } |
| 666 if (code->IsFailure()) return code; | 651 if (code->IsFailure()) return code; |
| 667 set_target(Code::cast(code)); | 652 set_target(Code::cast(code)); |
| 668 #ifdef DEBUG | 653 #ifdef DEBUG |
| 669 if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /string]\n"); | 654 TraceIC("KeyedLoadIC", name, state, target()); |
| 670 #endif | 655 #endif |
| 671 return Smi::FromInt(string->length()); | 656 return Smi::FromInt(string->length()); |
| 672 } | 657 } |
| 673 | 658 |
| 674 // Use specialized code for getting the length of arrays. | 659 // Use specialized code for getting the length of arrays. |
| 675 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { | 660 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { |
| 676 Handle<JSArray> array = Handle<JSArray>::cast(object); | 661 Handle<JSArray> array = Handle<JSArray>::cast(object); |
| 677 Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array); | 662 Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array); |
| 678 if (code->IsFailure()) return code; | 663 if (code->IsFailure()) return code; |
| 679 set_target(Code::cast(code)); | 664 set_target(Code::cast(code)); |
| 680 #ifdef DEBUG | 665 #ifdef DEBUG |
| 681 if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /array]\n"); | 666 TraceIC("KeyedLoadIC", name, state, target()); |
| 682 #endif | 667 #endif |
| 683 return JSArray::cast(*object)->length(); | 668 return JSArray::cast(*object)->length(); |
| 684 } | 669 } |
| 685 | 670 |
| 686 // Use specialized code for getting prototype of functions. | 671 // Use specialized code for getting prototype of functions. |
| 687 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) { | 672 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) { |
| 688 Handle<JSFunction> function = Handle<JSFunction>::cast(object); | 673 Handle<JSFunction> function = Handle<JSFunction>::cast(object); |
| 689 Object* code = | 674 Object* code = |
| 690 StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function); | 675 StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function); |
| 691 if (code->IsFailure()) return code; | 676 if (code->IsFailure()) return code; |
| 692 set_target(Code::cast(code)); | 677 set_target(Code::cast(code)); |
| 693 #ifdef DEBUG | 678 #ifdef DEBUG |
| 694 if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#prototype /function]\n"); | 679 TraceIC("KeyedLoadIC", name, state, target()); |
| 695 #endif | 680 #endif |
| 696 return Accessors::FunctionGetPrototype(*object, 0); | 681 return Accessors::FunctionGetPrototype(*object, 0); |
| 697 } | 682 } |
| 698 } | 683 } |
| 699 | 684 |
| 700 // Check if the name is trivially convertible to an index and get | 685 // Check if the name is trivially convertible to an index and get |
| 701 // the element or char if so. | 686 // the element or char if so. |
| 702 uint32_t index = 0; | 687 uint32_t index = 0; |
| 703 if (name->AsArrayIndex(&index)) { | 688 if (name->AsArrayIndex(&index)) { |
| 704 HandleScope scope; | 689 HandleScope scope; |
| 705 // Rewrite to the generic keyed load stub. | 690 // Rewrite to the generic keyed load stub. |
| 706 if (FLAG_use_ic) set_target(generic_stub()); | 691 if (FLAG_use_ic) set_target(generic_stub()); |
| 707 return Runtime::GetElementOrCharAt(object, index); | 692 return Runtime::GetElementOrCharAt(object, index); |
| 708 } | 693 } |
| 709 | 694 |
| 710 // Named lookup. | 695 // Named lookup. |
| 711 LookupResult lookup; | 696 LookupResult lookup; |
| 712 object->Lookup(*name, &lookup); | 697 object->Lookup(*name, &lookup); |
| 713 | 698 |
| 714 // If lookup is invalid, check if we need to throw an exception. | 699 // If lookup is invalid, check if we need to throw an exception. |
| 715 if (!lookup.IsValid()) { | 700 if (!lookup.IsValid()) { |
| 716 if (FLAG_strict || is_contextual()) { | 701 if (FLAG_strict || is_contextual()) { |
| 717 return ReferenceError("not_defined", name); | 702 return ReferenceError("not_defined", name); |
| 718 } | 703 } |
| 719 } | 704 } |
| 720 | 705 |
| 721 // Update the inline cache. | 706 // Update the inline cache. |
| 722 if (FLAG_use_ic && lookup.IsLoaded()) { | 707 if (FLAG_use_ic && lookup.IsLoaded()) { |
| 723 UpdateCaches(&lookup, object, name); | 708 UpdateCaches(&lookup, state, object, name); |
| 724 } | 709 } |
| 725 | 710 |
| 726 PropertyAttributes attr; | 711 PropertyAttributes attr; |
| 727 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { | 712 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { |
| 728 // Get the property. | 713 // Get the property. |
| 729 Object* result = object->GetProperty(*object, &lookup, *name, &attr); | 714 Object* result = object->GetProperty(*object, &lookup, *name, &attr); |
| 730 if (result->IsFailure()) return result; | 715 if (result->IsFailure()) return result; |
| 731 // If the property is not present, check if we need to throw an | 716 // If the property is not present, check if we need to throw an |
| 732 // exception. | 717 // exception. |
| 733 if (attr == ABSENT && is_contextual()) { | 718 if (attr == ABSENT && is_contextual()) { |
| 734 return ReferenceError("not_defined", name); | 719 return ReferenceError("not_defined", name); |
| 735 } | 720 } |
| 736 return result; | 721 return result; |
| 737 } | 722 } |
| 738 | 723 |
| 739 return object->GetProperty(*object, &lookup, *name, &attr); | 724 return object->GetProperty(*object, &lookup, *name, &attr); |
| 740 } | 725 } |
| 741 | 726 |
| 742 // Do not use ICs for objects that require access checks (including | 727 // Do not use ICs for objects that require access checks (including |
| 743 // the global object). | 728 // the global object). |
| 744 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 729 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 745 | 730 |
| 746 if (use_ic) set_target(generic_stub()); | 731 if (use_ic) set_target(generic_stub()); |
| 747 | 732 |
| 748 // Get the property. | 733 // Get the property. |
| 749 return Runtime::GetObjectProperty(object, key); | 734 return Runtime::GetObjectProperty(object, key); |
| 750 } | 735 } |
| 751 | 736 |
| 752 | 737 |
| 753 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, | 738 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
| 754 Handle<Object> object, | 739 Handle<Object> object, Handle<String> name) { |
| 755 Handle<String> name) { | |
| 756 ASSERT(lookup->IsLoaded()); | 740 ASSERT(lookup->IsLoaded()); |
| 757 // Bail out if we didn't find a result. | 741 // Bail out if we didn't find a result. |
| 758 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 742 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
| 759 | 743 |
| 760 if (!object->IsJSObject()) return; | 744 if (!object->IsJSObject()) return; |
| 761 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 745 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 762 | 746 |
| 763 // Compute the state of the current inline cache. | 747 // Compute the code stub for this load. |
| 764 Object* code = Heap::undefined_value(); | 748 Object* code = NULL; |
| 765 State state = ComputeCacheState(target(), *object, *name, &code); | |
| 766 | 749 |
| 767 // Compute the code stub for this load. | |
| 768 if (state == UNINITIALIZED) { | 750 if (state == UNINITIALIZED) { |
| 769 // This is the first time we execute this inline cache. | 751 // This is the first time we execute this inline cache. |
| 770 // Set the target to the pre monomorphic stub to delay | 752 // Set the target to the pre monomorphic stub to delay |
| 771 // setting the monomorphic state. | 753 // setting the monomorphic state. |
| 772 code = pre_monomorphic_stub(); | 754 code = pre_monomorphic_stub(); |
| 773 } else { | 755 } else { |
| 774 // Compute a monomorphic stub. | 756 // Compute a monomorphic stub. |
| 775 switch (lookup->type()) { | 757 switch (lookup->type()) { |
| 776 case FIELD: { | 758 case FIELD: { |
| 777 code = StubCache::ComputeKeyedLoadField(*name, *receiver, | 759 code = StubCache::ComputeKeyedLoadField(*name, *receiver, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 } else if (state == MONOMORPHIC) { | 802 } else if (state == MONOMORPHIC) { |
| 821 set_target(megamorphic_stub()); | 803 set_target(megamorphic_stub()); |
| 822 } | 804 } |
| 823 | 805 |
| 824 #ifdef DEBUG | 806 #ifdef DEBUG |
| 825 TraceIC("KeyedLoadIC", name, state, target()); | 807 TraceIC("KeyedLoadIC", name, state, target()); |
| 826 #endif | 808 #endif |
| 827 } | 809 } |
| 828 | 810 |
| 829 | 811 |
| 830 Object* StoreIC::Store(Handle<Object> object, | 812 Object* StoreIC::Store(State state, |
| 813 Handle<Object> object, |
| 831 Handle<String> name, | 814 Handle<String> name, |
| 832 Handle<Object> value) { | 815 Handle<Object> value) { |
| 833 // If the object is undefined or null it's illegal to try to set any | 816 // If the object is undefined or null it's illegal to try to set any |
| 834 // properties on it; throw a TypeError in that case. | 817 // properties on it; throw a TypeError in that case. |
| 835 if (object->IsUndefined() || object->IsNull()) { | 818 if (object->IsUndefined() || object->IsNull()) { |
| 836 return TypeError("non_object_property_store", object, name); | 819 return TypeError("non_object_property_store", object, name); |
| 837 } | 820 } |
| 838 | 821 |
| 839 // Ignore stores where the receiver is not a JSObject. | 822 // Ignore stores where the receiver is not a JSObject. |
| 840 if (!object->IsJSObject()) return *value; | 823 if (!object->IsJSObject()) return *value; |
| 841 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 824 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 842 | 825 |
| 843 // Check if the given name is an array index. | 826 // Check if the given name is an array index. |
| 844 uint32_t index; | 827 uint32_t index; |
| 845 if (name->AsArrayIndex(&index)) { | 828 if (name->AsArrayIndex(&index)) { |
| 846 HandleScope scope; | 829 HandleScope scope; |
| 847 Handle<Object> result = SetElement(receiver, index, value); | 830 Handle<Object> result = SetElement(receiver, index, value); |
| 848 if (result.is_null()) return Failure::Exception(); | 831 if (result.is_null()) return Failure::Exception(); |
| 849 return *value; | 832 return *value; |
| 850 } | 833 } |
| 851 | 834 |
| 852 // Lookup the property locally in the receiver. | 835 // Lookup the property locally in the receiver. |
| 853 LookupResult lookup; | 836 LookupResult lookup; |
| 854 receiver->LocalLookup(*name, &lookup); | 837 receiver->LocalLookup(*name, &lookup); |
| 855 | 838 |
| 856 // Update inline cache and stub cache. | 839 // Update inline cache and stub cache. |
| 857 if (FLAG_use_ic && lookup.IsLoaded()) { | 840 if (FLAG_use_ic && lookup.IsLoaded()) { |
| 858 UpdateCaches(&lookup, receiver, name, value); | 841 UpdateCaches(&lookup, state, receiver, name, value); |
| 859 } | 842 } |
| 860 | 843 |
| 861 // Set the property. | 844 // Set the property. |
| 862 return receiver->SetProperty(*name, *value, NONE); | 845 return receiver->SetProperty(*name, *value, NONE); |
| 863 } | 846 } |
| 864 | 847 |
| 865 | 848 |
| 866 void StoreIC::UpdateCaches(LookupResult* lookup, | 849 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 850 State state, |
| 867 Handle<JSObject> receiver, | 851 Handle<JSObject> receiver, |
| 868 Handle<String> name, | 852 Handle<String> name, |
| 869 Handle<Object> value) { | 853 Handle<Object> value) { |
| 870 ASSERT(lookup->IsLoaded()); | 854 ASSERT(lookup->IsLoaded()); |
| 871 // Bail out if we didn't find a result. | 855 // Bail out if we didn't find a result. |
| 872 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 856 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
| 873 | 857 |
| 874 // If the property is read-only, we leave the IC in its current | 858 // If the property is read-only, we leave the IC in its current |
| 875 // state. | 859 // state. |
| 876 if (lookup->IsReadOnly()) return; | 860 if (lookup->IsReadOnly()) return; |
| 877 | 861 |
| 878 // If the property has a non-field type allowing map transitions | 862 // If the property has a non-field type allowing map transitions |
| 879 // where there is extra room in the object, we leave the IC in its | 863 // where there is extra room in the object, we leave the IC in its |
| 880 // current state. | 864 // current state. |
| 881 PropertyType type = lookup->type(); | 865 PropertyType type = lookup->type(); |
| 882 | 866 |
| 883 // Compute the state of the current inline cache. | |
| 884 Object* code = Heap::undefined_value(); | |
| 885 State state = ComputeCacheState(target(), *receiver, *name, &code); | |
| 886 | |
| 887 // Compute the code stub for this store; used for rewriting to | 867 // Compute the code stub for this store; used for rewriting to |
| 888 // monomorphic state and making sure that the code stub is in the | 868 // monomorphic state and making sure that the code stub is in the |
| 889 // stub cache. | 869 // stub cache. |
| 870 Object* code = NULL; |
| 890 switch (type) { | 871 switch (type) { |
| 891 case FIELD: { | 872 case FIELD: { |
| 892 code = StubCache::ComputeStoreField(*name, *receiver, | 873 code = StubCache::ComputeStoreField(*name, *receiver, |
| 893 lookup->GetFieldIndex()); | 874 lookup->GetFieldIndex()); |
| 894 break; | 875 break; |
| 895 } | 876 } |
| 896 case MAP_TRANSITION: { | 877 case MAP_TRANSITION: { |
| 897 if (lookup->GetAttributes() != NONE) return; | 878 if (lookup->GetAttributes() != NONE) return; |
| 898 if (receiver->map()->unused_property_fields() == 0) return; | 879 if (receiver->map()->unused_property_fields() == 0) return; |
| 899 HandleScope scope; | 880 HandleScope scope; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 929 } else if (state == MONOMORPHIC) { | 910 } else if (state == MONOMORPHIC) { |
| 930 set_target(megamorphic_stub()); | 911 set_target(megamorphic_stub()); |
| 931 } | 912 } |
| 932 | 913 |
| 933 #ifdef DEBUG | 914 #ifdef DEBUG |
| 934 TraceIC("StoreIC", name, state, target()); | 915 TraceIC("StoreIC", name, state, target()); |
| 935 #endif | 916 #endif |
| 936 } | 917 } |
| 937 | 918 |
| 938 | 919 |
| 939 Object* KeyedStoreIC::Store(Handle<Object> object, | 920 Object* KeyedStoreIC::Store(State state, |
| 921 Handle<Object> object, |
| 940 Handle<Object> key, | 922 Handle<Object> key, |
| 941 Handle<Object> value) { | 923 Handle<Object> value) { |
| 942 if (key->IsSymbol()) { | 924 if (key->IsSymbol()) { |
| 943 Handle<String> name = Handle<String>::cast(key); | 925 Handle<String> name = Handle<String>::cast(key); |
| 944 | 926 |
| 945 // If the object is undefined or null it's illegal to try to set any | 927 // If the object is undefined or null it's illegal to try to set any |
| 946 // properties on it; throw a TypeError in that case. | 928 // properties on it; throw a TypeError in that case. |
| 947 if (object->IsUndefined() || object->IsNull()) { | 929 if (object->IsUndefined() || object->IsNull()) { |
| 948 return TypeError("non_object_property_store", object, name); | 930 return TypeError("non_object_property_store", object, name); |
| 949 } | 931 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 960 if (result.is_null()) return Failure::Exception(); | 942 if (result.is_null()) return Failure::Exception(); |
| 961 return *value; | 943 return *value; |
| 962 } | 944 } |
| 963 | 945 |
| 964 // Lookup the property locally in the receiver. | 946 // Lookup the property locally in the receiver. |
| 965 LookupResult lookup; | 947 LookupResult lookup; |
| 966 receiver->LocalLookup(*name, &lookup); | 948 receiver->LocalLookup(*name, &lookup); |
| 967 | 949 |
| 968 // Update inline cache and stub cache. | 950 // Update inline cache and stub cache. |
| 969 if (FLAG_use_ic && lookup.IsLoaded()) { | 951 if (FLAG_use_ic && lookup.IsLoaded()) { |
| 970 UpdateCaches(&lookup, receiver, name, value); | 952 UpdateCaches(&lookup, state, receiver, name, value); |
| 971 } | 953 } |
| 972 | 954 |
| 973 // Set the property. | 955 // Set the property. |
| 974 return receiver->SetProperty(*name, *value, NONE); | 956 return receiver->SetProperty(*name, *value, NONE); |
| 975 } | 957 } |
| 976 | 958 |
| 977 // Do not use ICs for objects that require access checks (including | 959 // Do not use ICs for objects that require access checks (including |
| 978 // the global object). | 960 // the global object). |
| 979 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 961 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 980 | 962 |
| 981 if (use_ic) set_target(generic_stub()); | 963 if (use_ic) set_target(generic_stub()); |
| 982 | 964 |
| 983 // Set the property. | 965 // Set the property. |
| 984 return Runtime::SetObjectProperty(object, key, value, NONE); | 966 return Runtime::SetObjectProperty(object, key, value, NONE); |
| 985 } | 967 } |
| 986 | 968 |
| 987 | 969 |
| 988 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 970 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
| 971 State state, |
| 989 Handle<JSObject> receiver, | 972 Handle<JSObject> receiver, |
| 990 Handle<String> name, | 973 Handle<String> name, |
| 991 Handle<Object> value) { | 974 Handle<Object> value) { |
| 992 ASSERT(lookup->IsLoaded()); | 975 ASSERT(lookup->IsLoaded()); |
| 993 // Bail out if we didn't find a result. | 976 // Bail out if we didn't find a result. |
| 994 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 977 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
| 995 | 978 |
| 996 // If the property is read-only, we leave the IC in its current | 979 // If the property is read-only, we leave the IC in its current |
| 997 // state. | 980 // state. |
| 998 if (lookup->IsReadOnly()) return; | 981 if (lookup->IsReadOnly()) return; |
| 999 | 982 |
| 1000 // If the property has a non-field type allowing map transitions | 983 // If the property has a non-field type allowing map transitions |
| 1001 // where there is extra room in the object, we leave the IC in its | 984 // where there is extra room in the object, we leave the IC in its |
| 1002 // current state. | 985 // current state. |
| 1003 PropertyType type = lookup->type(); | 986 PropertyType type = lookup->type(); |
| 1004 | 987 |
| 1005 // Compute the code stub for this store; used for rewriting to | 988 // Compute the code stub for this store; used for rewriting to |
| 1006 // monomorphic state and making sure that the code stub is in the | 989 // monomorphic state and making sure that the code stub is in the |
| 1007 // stub cache. | 990 // stub cache. |
| 1008 Object* code = Heap::undefined_value(); | 991 Object* code = NULL; |
| 1009 State state = ComputeCacheState(target(), *receiver, *name, &code); | |
| 1010 | 992 |
| 1011 switch (type) { | 993 switch (type) { |
| 1012 case FIELD: { | 994 case FIELD: { |
| 1013 code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 995 code = StubCache::ComputeKeyedStoreField(*name, *receiver, |
| 1014 lookup->GetFieldIndex()); | 996 lookup->GetFieldIndex()); |
| 1015 break; | 997 break; |
| 1016 } | 998 } |
| 1017 case MAP_TRANSITION: { | 999 case MAP_TRANSITION: { |
| 1018 if (lookup->GetAttributes() == NONE) { | 1000 if (lookup->GetAttributes() == NONE) { |
| 1019 if (receiver->map()->unused_property_fields() == 0) return; | 1001 if (receiver->map()->unused_property_fields() == 0) return; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 | 1039 |
| 1058 // ---------------------------------------------------------------------------- | 1040 // ---------------------------------------------------------------------------- |
| 1059 // Static IC stub generators. | 1041 // Static IC stub generators. |
| 1060 // | 1042 // |
| 1061 | 1043 |
| 1062 // Used from ic_<arch>.cc. | 1044 // Used from ic_<arch>.cc. |
| 1063 Object* CallIC_Miss(Arguments args) { | 1045 Object* CallIC_Miss(Arguments args) { |
| 1064 NoHandleAllocation na; | 1046 NoHandleAllocation na; |
| 1065 ASSERT(args.length() == 2); | 1047 ASSERT(args.length() == 2); |
| 1066 CallIC ic; | 1048 CallIC ic; |
| 1067 return ic.LoadFunction(args.at<Object>(0), args.at<String>(1)); | 1049 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1050 return ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); |
| 1068 } | 1051 } |
| 1069 | 1052 |
| 1070 | 1053 |
| 1071 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) { | 1054 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) { |
| 1072 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 1055 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
| 1073 } | 1056 } |
| 1074 | 1057 |
| 1075 | 1058 |
| 1076 void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) { | 1059 void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) { |
| 1077 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 1060 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
| 1078 } | 1061 } |
| 1079 | 1062 |
| 1080 | 1063 |
| 1081 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1064 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
| 1082 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 1065 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
| 1083 } | 1066 } |
| 1084 | 1067 |
| 1085 | 1068 |
| 1086 // Used from ic_<arch>.cc. | 1069 // Used from ic_<arch>.cc. |
| 1087 Object* LoadIC_Miss(Arguments args) { | 1070 Object* LoadIC_Miss(Arguments args) { |
| 1088 NoHandleAllocation na; | 1071 NoHandleAllocation na; |
| 1089 ASSERT(args.length() == 2); | 1072 ASSERT(args.length() == 2); |
| 1090 LoadIC ic; | 1073 LoadIC ic; |
| 1091 return ic.Load(args.at<Object>(0), args.at<String>(1)); | 1074 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1075 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
| 1092 } | 1076 } |
| 1093 | 1077 |
| 1094 | 1078 |
| 1095 void LoadIC::GenerateInitialize(MacroAssembler* masm) { | 1079 void LoadIC::GenerateInitialize(MacroAssembler* masm) { |
| 1096 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); | 1080 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); |
| 1097 } | 1081 } |
| 1098 | 1082 |
| 1099 | 1083 |
| 1100 void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { | 1084 void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { |
| 1101 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); | 1085 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); |
| 1102 } | 1086 } |
| 1103 | 1087 |
| 1104 | 1088 |
| 1105 // Used from ic_<arch>.cc | 1089 // Used from ic_<arch>.cc |
| 1106 Object* KeyedLoadIC_Miss(Arguments args) { | 1090 Object* KeyedLoadIC_Miss(Arguments args) { |
| 1107 NoHandleAllocation na; | 1091 NoHandleAllocation na; |
| 1108 ASSERT(args.length() == 2); | 1092 ASSERT(args.length() == 2); |
| 1109 KeyedLoadIC ic; | 1093 KeyedLoadIC ic; |
| 1110 return ic.Load(args.at<Object>(0), args.at<Object>(1)); | 1094 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1095 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); |
| 1111 } | 1096 } |
| 1112 | 1097 |
| 1113 | 1098 |
| 1114 void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) { | 1099 void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) { |
| 1115 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); | 1100 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); |
| 1116 } | 1101 } |
| 1117 | 1102 |
| 1118 | 1103 |
| 1119 void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { | 1104 void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { |
| 1120 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); | 1105 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); |
| 1121 } | 1106 } |
| 1122 | 1107 |
| 1123 | 1108 |
| 1124 // Used from ic_<arch>.cc. | 1109 // Used from ic_<arch>.cc. |
| 1125 Object* StoreIC_Miss(Arguments args) { | 1110 Object* StoreIC_Miss(Arguments args) { |
| 1126 NoHandleAllocation na; | 1111 NoHandleAllocation na; |
| 1127 ASSERT(args.length() == 3); | 1112 ASSERT(args.length() == 3); |
| 1128 StoreIC ic; | 1113 StoreIC ic; |
| 1129 return ic.Store(args.at<Object>(0), args.at<String>(1), args.at<Object>(2)); | 1114 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1115 return ic.Store(state, args.at<Object>(0), args.at<String>(1), |
| 1116 args.at<Object>(2)); |
| 1130 } | 1117 } |
| 1131 | 1118 |
| 1132 | 1119 |
| 1133 void StoreIC::GenerateInitialize(MacroAssembler* masm) { | 1120 void StoreIC::GenerateInitialize(MacroAssembler* masm) { |
| 1134 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); | 1121 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); |
| 1135 } | 1122 } |
| 1136 | 1123 |
| 1137 | 1124 |
| 1138 void StoreIC::GenerateMiss(MacroAssembler* masm) { | 1125 void StoreIC::GenerateMiss(MacroAssembler* masm) { |
| 1139 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); | 1126 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); |
| 1140 } | 1127 } |
| 1141 | 1128 |
| 1142 | 1129 |
| 1143 // Used from ic_<arch>.cc. | 1130 // Used from ic_<arch>.cc. |
| 1144 Object* KeyedStoreIC_Miss(Arguments args) { | 1131 Object* KeyedStoreIC_Miss(Arguments args) { |
| 1145 NoHandleAllocation na; | 1132 NoHandleAllocation na; |
| 1146 ASSERT(args.length() == 3); | 1133 ASSERT(args.length() == 3); |
| 1147 KeyedStoreIC ic; | 1134 KeyedStoreIC ic; |
| 1148 return ic.Store(args.at<Object>(0), args.at<Object>(1), args.at<Object>(2)); | 1135 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1136 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), |
| 1137 args.at<Object>(2)); |
| 1149 } | 1138 } |
| 1150 | 1139 |
| 1151 | 1140 |
| 1152 void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) { | 1141 void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) { |
| 1153 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); | 1142 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); |
| 1154 } | 1143 } |
| 1155 | 1144 |
| 1156 | 1145 |
| 1157 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 1146 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
| 1158 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); | 1147 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); |
| 1159 } | 1148 } |
| 1160 | 1149 |
| 1161 | 1150 |
| 1162 static Address IC_utilities[] = { | 1151 static Address IC_utilities[] = { |
| 1163 #define ADDR(name) FUNCTION_ADDR(name), | 1152 #define ADDR(name) FUNCTION_ADDR(name), |
| 1164 IC_UTIL_LIST(ADDR) | 1153 IC_UTIL_LIST(ADDR) |
| 1165 NULL | 1154 NULL |
| 1166 #undef ADDR | 1155 #undef ADDR |
| 1167 }; | 1156 }; |
| 1168 | 1157 |
| 1169 | 1158 |
| 1170 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 1159 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 1171 return IC_utilities[id]; | 1160 return IC_utilities[id]; |
| 1172 } | 1161 } |
| 1173 | 1162 |
| 1174 | 1163 |
| 1175 } } // namespace v8::internal | 1164 } } // namespace v8::internal |
| OLD | NEW |