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