| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 // Decide whether the inline cache failed because of changes to the | 145 // Decide whether the inline cache failed because of changes to the |
| 146 // receiver itself or changes to one of its prototypes. | 146 // receiver itself or changes to one of its prototypes. |
| 147 // | 147 // |
| 148 // If there are changes to the receiver itself, the map of the | 148 // If there are changes to the receiver itself, the map of the |
| 149 // receiver will have changed and the current target will not be in | 149 // receiver will have changed and the current target will not be in |
| 150 // the receiver map's code cache. Therefore, if the current target | 150 // the receiver map's code cache. Therefore, if the current target |
| 151 // is in the receiver map's code cache, the inline cache failed due | 151 // is in the receiver map's code cache, the inline cache failed due |
| 152 // to prototype check failure. | 152 // to prototype check failure. |
| 153 int index = map->IndexInCodeCache(name, target); | 153 int index = map->IndexInCodeCache(name, target); |
| 154 if (index >= 0) { | 154 if (index >= 0) { |
| 155 // For keyed load/store, the most likely cause of cache failure is | 155 // For keyed load/store/call, the most likely cause of cache failure is |
| 156 // that the key has changed. We do not distinguish between | 156 // that the key has changed. We do not distinguish between |
| 157 // prototype and non-prototype failures for keyed access. | 157 // prototype and non-prototype failures for keyed access. |
| 158 Code::Kind kind = target->kind(); | 158 Code::Kind kind = target->kind(); |
| 159 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { | 159 if (kind == Code::KEYED_LOAD_IC || |
| 160 kind == Code::KEYED_STORE_IC || |
| 161 kind == Code::KEYED_CALL_IC) { |
| 160 return MONOMORPHIC; | 162 return MONOMORPHIC; |
| 161 } | 163 } |
| 162 | 164 |
| 163 // Remove the target from the code cache to avoid hitting the same | 165 // Remove the target from the code cache to avoid hitting the same |
| 164 // invalid stub again. | 166 // invalid stub again. |
| 165 map->RemoveFromCodeCache(String::cast(name), target, index); | 167 map->RemoveFromCodeCache(String::cast(name), target, index); |
| 166 | 168 |
| 167 return MONOMORPHIC_PROTOTYPE_FAILURE; | 169 return MONOMORPHIC_PROTOTYPE_FAILURE; |
| 168 } | 170 } |
| 169 | 171 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 189 RelocInfo* info = it.rinfo(); | 191 RelocInfo* info = it.rinfo(); |
| 190 if (info->pc() == addr) return info->rmode(); | 192 if (info->pc() == addr) return info->rmode(); |
| 191 } | 193 } |
| 192 UNREACHABLE(); | 194 UNREACHABLE(); |
| 193 return RelocInfo::NONE; | 195 return RelocInfo::NONE; |
| 194 } | 196 } |
| 195 | 197 |
| 196 | 198 |
| 197 Failure* IC::TypeError(const char* type, | 199 Failure* IC::TypeError(const char* type, |
| 198 Handle<Object> object, | 200 Handle<Object> object, |
| 199 Handle<String> name) { | 201 Handle<Object> key) { |
| 200 HandleScope scope; | 202 HandleScope scope; |
| 201 Handle<Object> args[2] = { name, object }; | 203 Handle<Object> args[2] = { key, object }; |
| 202 Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2)); | 204 Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2)); |
| 203 return Top::Throw(*error); | 205 return Top::Throw(*error); |
| 204 } | 206 } |
| 205 | 207 |
| 206 | 208 |
| 207 Failure* IC::ReferenceError(const char* type, Handle<String> name) { | 209 Failure* IC::ReferenceError(const char* type, Handle<String> name) { |
| 208 HandleScope scope; | 210 HandleScope scope; |
| 209 Handle<Object> error = | 211 Handle<Object> error = |
| 210 Factory::NewReferenceError(type, HandleVector(&name, 1)); | 212 Factory::NewReferenceError(type, HandleVector(&name, 1)); |
| 211 return Top::Throw(*error); | 213 return Top::Throw(*error); |
| 212 } | 214 } |
| 213 | 215 |
| 214 | 216 |
| 215 void IC::Clear(Address address) { | 217 void IC::Clear(Address address) { |
| 216 Code* target = GetTargetAtAddress(address); | 218 Code* target = GetTargetAtAddress(address); |
| 217 | 219 |
| 218 // Don't clear debug break inline cache as it will remove the break point. | 220 // Don't clear debug break inline cache as it will remove the break point. |
| 219 if (target->ic_state() == DEBUG_BREAK) return; | 221 if (target->ic_state() == DEBUG_BREAK) return; |
| 220 | 222 |
| 221 switch (target->kind()) { | 223 switch (target->kind()) { |
| 222 case Code::LOAD_IC: return LoadIC::Clear(address, target); | 224 case Code::LOAD_IC: return LoadIC::Clear(address, target); |
| 223 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); | 225 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); |
| 224 case Code::STORE_IC: return StoreIC::Clear(address, target); | 226 case Code::STORE_IC: return StoreIC::Clear(address, target); |
| 225 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); | 227 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); |
| 226 case Code::CALL_IC: return CallIC::Clear(address, target); | 228 case Code::CALL_IC: return CallIC::Clear(address, target); |
| 229 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); |
| 227 case Code::BINARY_OP_IC: return; // Clearing these is tricky and does not | 230 case Code::BINARY_OP_IC: return; // Clearing these is tricky and does not |
| 228 // make any performance difference. | 231 // make any performance difference. |
| 229 default: UNREACHABLE(); | 232 default: UNREACHABLE(); |
| 230 } | 233 } |
| 231 } | 234 } |
| 232 | 235 |
| 233 | 236 |
| 234 void CallIC::Clear(Address address, Code* target) { | 237 void CallICBase::Clear(Address address, Code* target) { |
| 235 State state = target->ic_state(); | 238 State state = target->ic_state(); |
| 236 InLoopFlag in_loop = target->ic_in_loop(); | |
| 237 if (state == UNINITIALIZED) return; | 239 if (state == UNINITIALIZED) return; |
| 238 Code* code = | 240 Code* code = |
| 239 StubCache::FindCallInitialize(target->arguments_count(), in_loop); | 241 StubCache::FindCallInitialize(target->arguments_count(), |
| 242 target->ic_in_loop(), |
| 243 target->kind()); |
| 240 SetTargetAtAddress(address, code); | 244 SetTargetAtAddress(address, code); |
| 241 } | 245 } |
| 242 | 246 |
| 243 | 247 |
| 244 void KeyedLoadIC::Clear(Address address, Code* target) { | 248 void KeyedLoadIC::Clear(Address address, Code* target) { |
| 245 if (target->ic_state() == UNINITIALIZED) return; | 249 if (target->ic_state() == UNINITIALIZED) return; |
| 246 // Make sure to also clear the map used in inline fast cases. If we | 250 // Make sure to also clear the map used in inline fast cases. If we |
| 247 // do not clear these maps, cached code can keep objects alive | 251 // do not clear these maps, cached code can keep objects alive |
| 248 // through the embedded maps. | 252 // through the embedded maps. |
| 249 ClearInlinedVersion(address); | 253 ClearInlinedVersion(address); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 if (proto->IsNull()) { | 361 if (proto->IsNull()) { |
| 358 lookup->NotFound(); | 362 lookup->NotFound(); |
| 359 return; | 363 return; |
| 360 } | 364 } |
| 361 | 365 |
| 362 object = proto; | 366 object = proto; |
| 363 } | 367 } |
| 364 } | 368 } |
| 365 | 369 |
| 366 | 370 |
| 367 Object* CallIC::TryCallAsFunction(Object* object) { | 371 Object* CallICBase::TryCallAsFunction(Object* object) { |
| 368 HandleScope scope; | 372 HandleScope scope; |
| 369 Handle<Object> target(object); | 373 Handle<Object> target(object); |
| 370 Handle<Object> delegate = Execution::GetFunctionDelegate(target); | 374 Handle<Object> delegate = Execution::GetFunctionDelegate(target); |
| 371 | 375 |
| 372 if (delegate->IsJSFunction()) { | 376 if (delegate->IsJSFunction()) { |
| 373 // Patch the receiver and use the delegate as the function to | 377 // Patch the receiver and use the delegate as the function to |
| 374 // invoke. This is used for invoking objects as if they were | 378 // invoke. This is used for invoking objects as if they were |
| 375 // functions. | 379 // functions. |
| 376 const int argc = this->target()->arguments_count(); | 380 const int argc = this->target()->arguments_count(); |
| 377 StackFrameLocator locator; | 381 StackFrameLocator locator; |
| 378 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 382 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 379 int index = frame->ComputeExpressionsCount() - (argc + 1); | 383 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 380 frame->SetExpression(index, *target); | 384 frame->SetExpression(index, *target); |
| 381 } | 385 } |
| 382 | 386 |
| 383 return *delegate; | 387 return *delegate; |
| 384 } | 388 } |
| 385 | 389 |
| 386 void CallIC::ReceiverToObject(Handle<Object> object) { | 390 void CallICBase::ReceiverToObject(Handle<Object> object) { |
| 387 HandleScope scope; | 391 HandleScope scope; |
| 388 Handle<Object> receiver(object); | 392 Handle<Object> receiver(object); |
| 389 | 393 |
| 390 // Change the receiver to the result of calling ToObject on it. | 394 // Change the receiver to the result of calling ToObject on it. |
| 391 const int argc = this->target()->arguments_count(); | 395 const int argc = this->target()->arguments_count(); |
| 392 StackFrameLocator locator; | 396 StackFrameLocator locator; |
| 393 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 397 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
| 394 int index = frame->ComputeExpressionsCount() - (argc + 1); | 398 int index = frame->ComputeExpressionsCount() - (argc + 1); |
| 395 frame->SetExpression(index, *Factory::ToObject(object)); | 399 frame->SetExpression(index, *Factory::ToObject(object)); |
| 396 } | 400 } |
| 397 | 401 |
| 398 | 402 |
| 399 Object* CallIC::LoadFunction(State state, | 403 Object* CallICBase::LoadFunction(State state, |
| 400 Handle<Object> object, | 404 Handle<Object> object, |
| 401 Handle<String> name) { | 405 Handle<String> name) { |
| 402 // If the object is undefined or null it's illegal to try to get any | 406 // If the object is undefined or null it's illegal to try to get any |
| 403 // of its properties; throw a TypeError in that case. | 407 // of its properties; throw a TypeError in that case. |
| 404 if (object->IsUndefined() || object->IsNull()) { | 408 if (object->IsUndefined() || object->IsNull()) { |
| 405 return TypeError("non_object_property_call", object, name); | 409 return TypeError("non_object_property_call", object, name); |
| 406 } | 410 } |
| 407 | 411 |
| 408 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { | 412 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 409 ReceiverToObject(object); | 413 ReceiverToObject(object); |
| 410 } | 414 } |
| 411 | 415 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 return result; | 478 return result; |
| 475 } | 479 } |
| 476 | 480 |
| 477 // Try to find a suitable function delegate for the object at hand. | 481 // Try to find a suitable function delegate for the object at hand. |
| 478 result = TryCallAsFunction(result); | 482 result = TryCallAsFunction(result); |
| 479 return result->IsJSFunction() ? | 483 return result->IsJSFunction() ? |
| 480 result : TypeError("property_not_function", object, name); | 484 result : TypeError("property_not_function", object, name); |
| 481 } | 485 } |
| 482 | 486 |
| 483 | 487 |
| 484 void CallIC::UpdateCaches(LookupResult* lookup, | 488 void CallICBase::UpdateCaches(LookupResult* lookup, |
| 485 State state, | 489 State state, |
| 486 Handle<Object> object, | 490 Handle<Object> object, |
| 487 Handle<String> name) { | 491 Handle<String> name) { |
| 488 // Bail out if we didn't find a result. | 492 // Bail out if we didn't find a result. |
| 489 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; | 493 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
| 490 | 494 |
| 491 // Compute the number of arguments. | 495 // Compute the number of arguments. |
| 492 int argc = target()->arguments_count(); | 496 int argc = target()->arguments_count(); |
| 493 InLoopFlag in_loop = target()->ic_in_loop(); | 497 InLoopFlag in_loop = target()->ic_in_loop(); |
| 494 Object* code = NULL; | 498 Object* code = NULL; |
| 495 | 499 |
| 496 if (state == UNINITIALIZED) { | 500 if (state == UNINITIALIZED) { |
| 497 // This is the first time we execute this inline cache. | 501 // This is the first time we execute this inline cache. |
| 498 // Set the target to the pre monomorphic stub to delay | 502 // Set the target to the pre monomorphic stub to delay |
| 499 // setting the monomorphic state. | 503 // setting the monomorphic state. |
| 500 code = StubCache::ComputeCallPreMonomorphic(argc, in_loop); | 504 code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); |
| 501 } else if (state == MONOMORPHIC) { | 505 } else if (state == MONOMORPHIC) { |
| 502 code = StubCache::ComputeCallMegamorphic(argc, in_loop); | 506 code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); |
| 503 } else { | 507 } else { |
| 504 // Compute monomorphic stub. | 508 // Compute monomorphic stub. |
| 505 switch (lookup->type()) { | 509 switch (lookup->type()) { |
| 506 case FIELD: { | 510 case FIELD: { |
| 507 int index = lookup->GetFieldIndex(); | 511 int index = lookup->GetFieldIndex(); |
| 508 code = StubCache::ComputeCallField(argc, in_loop, *name, *object, | 512 code = StubCache::ComputeCallField(argc, |
| 509 lookup->holder(), index); | 513 in_loop, |
| 514 kind_, |
| 515 *name, |
| 516 *object, |
| 517 lookup->holder(), |
| 518 index); |
| 510 break; | 519 break; |
| 511 } | 520 } |
| 512 case CONSTANT_FUNCTION: { | 521 case CONSTANT_FUNCTION: { |
| 513 // Get the constant function and compute the code stub for this | 522 // Get the constant function and compute the code stub for this |
| 514 // call; used for rewriting to monomorphic state and making sure | 523 // call; used for rewriting to monomorphic state and making sure |
| 515 // that the code stub is in the stub cache. | 524 // that the code stub is in the stub cache. |
| 516 JSFunction* function = lookup->GetConstantFunction(); | 525 JSFunction* function = lookup->GetConstantFunction(); |
| 517 code = StubCache::ComputeCallConstant(argc, in_loop, *name, *object, | 526 code = StubCache::ComputeCallConstant(argc, |
| 518 lookup->holder(), function); | 527 in_loop, |
| 528 kind_, |
| 529 *name, |
| 530 *object, |
| 531 lookup->holder(), |
| 532 function); |
| 519 break; | 533 break; |
| 520 } | 534 } |
| 521 case NORMAL: { | 535 case NORMAL: { |
| 522 if (!object->IsJSObject()) return; | 536 if (!object->IsJSObject()) return; |
| 523 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 537 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 524 | 538 |
| 525 if (lookup->holder()->IsGlobalObject()) { | 539 if (lookup->holder()->IsGlobalObject()) { |
| 526 GlobalObject* global = GlobalObject::cast(lookup->holder()); | 540 GlobalObject* global = GlobalObject::cast(lookup->holder()); |
| 527 JSGlobalPropertyCell* cell = | 541 JSGlobalPropertyCell* cell = |
| 528 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 542 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 529 if (!cell->value()->IsJSFunction()) return; | 543 if (!cell->value()->IsJSFunction()) return; |
| 530 JSFunction* function = JSFunction::cast(cell->value()); | 544 JSFunction* function = JSFunction::cast(cell->value()); |
| 531 code = StubCache::ComputeCallGlobal(argc, | 545 code = StubCache::ComputeCallGlobal(argc, |
| 532 in_loop, | 546 in_loop, |
| 547 kind_, |
| 533 *name, | 548 *name, |
| 534 *receiver, | 549 *receiver, |
| 535 global, | 550 global, |
| 536 cell, | 551 cell, |
| 537 function); | 552 function); |
| 538 } else { | 553 } else { |
| 539 // There is only one shared stub for calling normalized | 554 // There is only one shared stub for calling normalized |
| 540 // properties. It does not traverse the prototype chain, so the | 555 // properties. It does not traverse the prototype chain, so the |
| 541 // property must be found in the receiver for the stub to be | 556 // property must be found in the receiver for the stub to be |
| 542 // applicable. | 557 // applicable. |
| 543 if (lookup->holder() != *receiver) return; | 558 if (lookup->holder() != *receiver) return; |
| 544 code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); | 559 code = StubCache::ComputeCallNormal(argc, |
| 560 in_loop, |
| 561 kind_, |
| 562 *name, |
| 563 *receiver); |
| 545 } | 564 } |
| 546 break; | 565 break; |
| 547 } | 566 } |
| 548 case INTERCEPTOR: { | 567 case INTERCEPTOR: { |
| 549 ASSERT(HasInterceptorGetter(lookup->holder())); | 568 ASSERT(HasInterceptorGetter(lookup->holder())); |
| 550 code = StubCache::ComputeCallInterceptor(argc, *name, *object, | 569 code = StubCache::ComputeCallInterceptor(argc, |
| 570 kind_, |
| 571 *name, |
| 572 *object, |
| 551 lookup->holder()); | 573 lookup->holder()); |
| 552 break; | 574 break; |
| 553 } | 575 } |
| 554 default: | 576 default: |
| 555 return; | 577 return; |
| 556 } | 578 } |
| 557 } | 579 } |
| 558 | 580 |
| 559 // If we're unable to compute the stub (not enough memory left), we | 581 // If we're unable to compute the stub (not enough memory left), we |
| 560 // simply avoid updating the caches. | 582 // simply avoid updating the caches. |
| 561 if (code == NULL || code->IsFailure()) return; | 583 if (code == NULL || code->IsFailure()) return; |
| 562 | 584 |
| 563 // Patch the call site depending on the state of the cache. | 585 // Patch the call site depending on the state of the cache. |
| 564 if (state == UNINITIALIZED || | 586 if (state == UNINITIALIZED || |
| 565 state == PREMONOMORPHIC || | 587 state == PREMONOMORPHIC || |
| 566 state == MONOMORPHIC || | 588 state == MONOMORPHIC || |
| 567 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 589 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 568 set_target(Code::cast(code)); | 590 set_target(Code::cast(code)); |
| 569 } | 591 } |
| 570 | 592 |
| 571 #ifdef DEBUG | 593 #ifdef DEBUG |
| 572 TraceIC("CallIC", name, state, target(), in_loop ? " (in-loop)" : ""); | 594 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", |
| 595 name, state, target(), in_loop ? " (in-loop)" : ""); |
| 573 #endif | 596 #endif |
| 574 } | 597 } |
| 575 | 598 |
| 576 | 599 |
| 600 Object* KeyedCallIC::LoadFunction(State state, |
| 601 Handle<Object> object, |
| 602 Handle<Object> key) { |
| 603 if (key->IsSymbol()) { |
| 604 return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); |
| 605 } |
| 606 |
| 607 if (object->IsUndefined() || object->IsNull()) { |
| 608 return TypeError("non_object_property_call", object, key); |
| 609 } |
| 610 |
| 611 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
| 612 ReceiverToObject(object); |
| 613 } else { |
| 614 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { |
| 615 int argc = target()->arguments_count(); |
| 616 InLoopFlag in_loop = target()->ic_in_loop(); |
| 617 Object* code = StubCache::ComputeCallMegamorphic( |
| 618 argc, in_loop, Code::KEYED_CALL_IC); |
| 619 if (!code->IsFailure()) { |
| 620 set_target(Code::cast(code)); |
| 621 } |
| 622 } |
| 623 } |
| 624 Object* result = Runtime::GetObjectProperty(object, key); |
| 625 if (result->IsJSFunction()) return result; |
| 626 result = TryCallAsFunction(result); |
| 627 return result->IsJSFunction() ? |
| 628 result : TypeError("property_not_function", object, key); |
| 629 } |
| 630 |
| 631 |
| 577 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { | 632 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { |
| 578 // If the object is undefined or null it's illegal to try to get any | 633 // If the object is undefined or null it's illegal to try to get any |
| 579 // of its properties; throw a TypeError in that case. | 634 // of its properties; throw a TypeError in that case. |
| 580 if (object->IsUndefined() || object->IsNull()) { | 635 if (object->IsUndefined() || object->IsNull()) { |
| 581 return TypeError("non_object_property_load", object, name); | 636 return TypeError("non_object_property_load", object, name); |
| 582 } | 637 } |
| 583 | 638 |
| 584 if (FLAG_use_ic) { | 639 if (FLAG_use_ic) { |
| 585 // Use specialized code for getting the length of strings and | 640 // Use specialized code for getting the length of strings and |
| 586 // string wrapper objects. The length property of string wrapper | 641 // string wrapper objects. The length property of string wrapper |
| (...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1286 #ifdef DEBUG | 1341 #ifdef DEBUG |
| 1287 TraceIC("KeyedStoreIC", name, state, target()); | 1342 TraceIC("KeyedStoreIC", name, state, target()); |
| 1288 #endif | 1343 #endif |
| 1289 } | 1344 } |
| 1290 | 1345 |
| 1291 | 1346 |
| 1292 // ---------------------------------------------------------------------------- | 1347 // ---------------------------------------------------------------------------- |
| 1293 // Static IC stub generators. | 1348 // Static IC stub generators. |
| 1294 // | 1349 // |
| 1295 | 1350 |
| 1296 // Used from ic_<arch>.cc. | 1351 static Object* CompileFunction(Object* result, |
| 1352 Handle<Object> object, |
| 1353 InLoopFlag in_loop) { |
| 1354 // Compile now with optimization. |
| 1355 HandleScope scope; |
| 1356 Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); |
| 1357 if (in_loop == IN_LOOP) { |
| 1358 CompileLazyInLoop(function, object, CLEAR_EXCEPTION); |
| 1359 } else { |
| 1360 CompileLazy(function, object, CLEAR_EXCEPTION); |
| 1361 } |
| 1362 return *function; |
| 1363 } |
| 1364 |
| 1365 |
| 1366 // Used from ic-<arch>.cc. |
| 1297 Object* CallIC_Miss(Arguments args) { | 1367 Object* CallIC_Miss(Arguments args) { |
| 1298 NoHandleAllocation na; | 1368 NoHandleAllocation na; |
| 1299 ASSERT(args.length() == 2); | 1369 ASSERT(args.length() == 2); |
| 1300 CallIC ic; | 1370 CallIC ic; |
| 1301 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1371 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1302 Object* result = | 1372 Object* result = |
| 1303 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); | 1373 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); |
| 1304 | 1374 |
| 1305 // The first time the inline cache is updated may be the first time the | 1375 // The first time the inline cache is updated may be the first time the |
| 1306 // function it references gets called. If the function was lazily compiled | 1376 // function it references gets called. If the function was lazily compiled |
| 1307 // then the first call will trigger a compilation. We check for this case | 1377 // then the first call will trigger a compilation. We check for this case |
| 1308 // and we do the compilation immediately, instead of waiting for the stub | 1378 // and we do the compilation immediately, instead of waiting for the stub |
| 1309 // currently attached to the JSFunction object to trigger compilation. We | 1379 // currently attached to the JSFunction object to trigger compilation. We |
| 1310 // do this in the case where we know that the inline cache is inside a loop, | 1380 // do this in the case where we know that the inline cache is inside a loop, |
| 1311 // because then we know that we want to optimize the function. | 1381 // because then we know that we want to optimize the function. |
| 1312 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { | 1382 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
| 1313 return result; | 1383 return result; |
| 1314 } | 1384 } |
| 1315 | 1385 return CompileFunction(result, args.at<Object>(0), ic.target()->ic_in_loop()); |
| 1316 // Compile now with optimization. | |
| 1317 HandleScope scope; | |
| 1318 Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); | |
| 1319 InLoopFlag in_loop = ic.target()->ic_in_loop(); | |
| 1320 if (in_loop == IN_LOOP) { | |
| 1321 CompileLazyInLoop(function, args.at<Object>(0), CLEAR_EXCEPTION); | |
| 1322 } else { | |
| 1323 CompileLazy(function, args.at<Object>(0), CLEAR_EXCEPTION); | |
| 1324 } | |
| 1325 return *function; | |
| 1326 } | 1386 } |
| 1327 | 1387 |
| 1328 | 1388 |
| 1329 // Used from ic_<arch>.cc. | 1389 // Used from ic-<arch>.cc. |
| 1390 Object* KeyedCallIC_Miss(Arguments args) { |
| 1391 NoHandleAllocation na; |
| 1392 ASSERT(args.length() == 2); |
| 1393 KeyedCallIC ic; |
| 1394 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1395 Object* result = |
| 1396 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); |
| 1397 |
| 1398 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
| 1399 return result; |
| 1400 } |
| 1401 return CompileFunction(result, args.at<Object>(0), ic.target()->ic_in_loop()); |
| 1402 } |
| 1403 |
| 1404 |
| 1405 // Used from ic-<arch>.cc. |
| 1330 Object* LoadIC_Miss(Arguments args) { | 1406 Object* LoadIC_Miss(Arguments args) { |
| 1331 NoHandleAllocation na; | 1407 NoHandleAllocation na; |
| 1332 ASSERT(args.length() == 2); | 1408 ASSERT(args.length() == 2); |
| 1333 LoadIC ic; | 1409 LoadIC ic; |
| 1334 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1410 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1335 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); | 1411 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
| 1336 } | 1412 } |
| 1337 | 1413 |
| 1338 | 1414 |
| 1339 // Used from ic_<arch>.cc | 1415 // Used from ic-<arch>.cc |
| 1340 Object* KeyedLoadIC_Miss(Arguments args) { | 1416 Object* KeyedLoadIC_Miss(Arguments args) { |
| 1341 NoHandleAllocation na; | 1417 NoHandleAllocation na; |
| 1342 ASSERT(args.length() == 2); | 1418 ASSERT(args.length() == 2); |
| 1343 KeyedLoadIC ic; | 1419 KeyedLoadIC ic; |
| 1344 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1420 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1345 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); | 1421 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); |
| 1346 } | 1422 } |
| 1347 | 1423 |
| 1348 | 1424 |
| 1349 // Used from ic_<arch>.cc. | 1425 // Used from ic-<arch>.cc. |
| 1350 Object* StoreIC_Miss(Arguments args) { | 1426 Object* StoreIC_Miss(Arguments args) { |
| 1351 NoHandleAllocation na; | 1427 NoHandleAllocation na; |
| 1352 ASSERT(args.length() == 3); | 1428 ASSERT(args.length() == 3); |
| 1353 StoreIC ic; | 1429 StoreIC ic; |
| 1354 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1430 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1355 return ic.Store(state, args.at<Object>(0), args.at<String>(1), | 1431 return ic.Store(state, args.at<Object>(0), args.at<String>(1), |
| 1356 args.at<Object>(2)); | 1432 args.at<Object>(2)); |
| 1357 } | 1433 } |
| 1358 | 1434 |
| 1359 | 1435 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1397 | 1473 |
| 1398 // Set the new property value and do the map transition. | 1474 // Set the new property value and do the map transition. |
| 1399 object->set_properties(new_storage); | 1475 object->set_properties(new_storage); |
| 1400 object->set_map(transition); | 1476 object->set_map(transition); |
| 1401 | 1477 |
| 1402 // Return the stored value. | 1478 // Return the stored value. |
| 1403 return value; | 1479 return value; |
| 1404 } | 1480 } |
| 1405 | 1481 |
| 1406 | 1482 |
| 1407 // Used from ic_<arch>.cc. | 1483 // Used from ic-<arch>.cc. |
| 1408 Object* KeyedStoreIC_Miss(Arguments args) { | 1484 Object* KeyedStoreIC_Miss(Arguments args) { |
| 1409 NoHandleAllocation na; | 1485 NoHandleAllocation na; |
| 1410 ASSERT(args.length() == 3); | 1486 ASSERT(args.length() == 3); |
| 1411 KeyedStoreIC ic; | 1487 KeyedStoreIC ic; |
| 1412 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1488 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1413 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), | 1489 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), |
| 1414 args.at<Object>(2)); | 1490 args.at<Object>(2)); |
| 1415 } | 1491 } |
| 1416 | 1492 |
| 1417 | 1493 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1510 #undef ADDR | 1586 #undef ADDR |
| 1511 }; | 1587 }; |
| 1512 | 1588 |
| 1513 | 1589 |
| 1514 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 1590 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 1515 return IC_utilities[id]; | 1591 return IC_utilities[id]; |
| 1516 } | 1592 } |
| 1517 | 1593 |
| 1518 | 1594 |
| 1519 } } // namespace v8::internal | 1595 } } // namespace v8::internal |
| OLD | NEW |