| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 // Load the prototype from the initial map. | 264 // Load the prototype from the initial map. |
| 265 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 265 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 266 } | 266 } |
| 267 | 267 |
| 268 | 268 |
| 269 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( | 269 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( |
| 270 MacroAssembler* masm, | 270 MacroAssembler* masm, |
| 271 int index, | 271 int index, |
| 272 Register prototype, | 272 Register prototype, |
| 273 Label* miss) { | 273 Label* miss) { |
| 274 // Check we're still in the same context. | |
| 275 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)), | |
| 276 masm->isolate()->global_object()); | |
| 277 __ j(not_equal, miss); | |
| 278 // Get the global function with the given index. | 274 // Get the global function with the given index. |
| 279 Handle<JSFunction> function( | 275 Handle<JSFunction> function( |
| 280 JSFunction::cast(masm->isolate()->native_context()->get(index))); | 276 JSFunction::cast(masm->isolate()->native_context()->get(index))); |
| 277 // Check we're still in the same context. |
| 278 Register scratch = prototype; |
| 279 const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); |
| 280 __ mov(scratch, Operand(esi, offset)); |
| 281 __ mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset)); |
| 282 __ cmp(Operand(scratch, Context::SlotOffset(index)), function); |
| 283 __ j(not_equal, miss); |
| 284 |
| 281 // Load its initial map. The global functions all have initial maps. | 285 // Load its initial map. The global functions all have initial maps. |
| 282 __ Set(prototype, Immediate(Handle<Map>(function->initial_map()))); | 286 __ Set(prototype, Immediate(Handle<Map>(function->initial_map()))); |
| 283 // Load the prototype from the initial map. | 287 // Load the prototype from the initial map. |
| 284 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 288 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 285 } | 289 } |
| 286 | 290 |
| 287 | 291 |
| 288 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, | 292 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, |
| 289 Register receiver, | 293 Register receiver, |
| 290 Register scratch, | 294 Register scratch, |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 // Put api_function_address in place. | 459 // Put api_function_address in place. |
| 456 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 460 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
| 457 __ mov(api_function_address, Immediate(function_address)); | 461 __ mov(api_function_address, Immediate(function_address)); |
| 458 | 462 |
| 459 // Jump to stub. | 463 // Jump to stub. |
| 460 CallApiFunctionStub stub(restore_context, call_data_undefined, argc); | 464 CallApiFunctionStub stub(restore_context, call_data_undefined, argc); |
| 461 __ TailCallStub(&stub); | 465 __ TailCallStub(&stub); |
| 462 } | 466 } |
| 463 | 467 |
| 464 | 468 |
| 465 // Generates call to API function. | |
| 466 static void GenerateFastApiCall(MacroAssembler* masm, | |
| 467 const CallOptimization& optimization, | |
| 468 int argc, | |
| 469 Handle<Map> map_to_holder, | |
| 470 CallOptimization::HolderLookup holder_lookup) { | |
| 471 Counters* counters = masm->isolate()->counters(); | |
| 472 __ IncrementCounter(counters->call_const_fast_api(), 1); | |
| 473 | |
| 474 // Move holder to a register | |
| 475 Register holder_reg = ecx; | |
| 476 switch (holder_lookup) { | |
| 477 case CallOptimization::kHolderIsReceiver: | |
| 478 { | |
| 479 ASSERT(map_to_holder.is_null()); | |
| 480 __ mov(holder_reg, Operand(esp, (argc + 1)* kPointerSize)); | |
| 481 } | |
| 482 break; | |
| 483 case CallOptimization::kHolderIsPrototypeOfMap: | |
| 484 { | |
| 485 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); | |
| 486 if (!masm->isolate()->heap()->InNewSpace(*holder)) { | |
| 487 __ mov(holder_reg, holder); | |
| 488 } else { | |
| 489 __ mov(holder_reg, map_to_holder); | |
| 490 __ mov(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset)); | |
| 491 } | |
| 492 } | |
| 493 break; | |
| 494 case CallOptimization::kHolderNotFound: | |
| 495 UNREACHABLE(); | |
| 496 } | |
| 497 GenerateFastApiCallBody(masm, | |
| 498 optimization, | |
| 499 argc, | |
| 500 holder_reg, | |
| 501 false); | |
| 502 } | |
| 503 | |
| 504 | |
| 505 // Generate call to api function. | 469 // Generate call to api function. |
| 506 // This function uses push() to generate smaller, faster code than | 470 // This function uses push() to generate smaller, faster code than |
| 507 // the version above. It is an optimization that should will be removed | 471 // the version above. It is an optimization that should will be removed |
| 508 // when api call ICs are generated in hydrogen. | 472 // when api call ICs are generated in hydrogen. |
| 509 static void GenerateFastApiCall(MacroAssembler* masm, | 473 static void GenerateFastApiCall(MacroAssembler* masm, |
| 510 const CallOptimization& optimization, | 474 const CallOptimization& optimization, |
| 511 Register receiver, | 475 Register receiver, |
| 512 Register scratch1, | 476 Register scratch1, |
| 513 int argc, | 477 int argc, |
| 514 Register* values) { | 478 Register* values) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 526 __ push(scratch1); | 490 __ push(scratch1); |
| 527 // Stack now matches JSFunction abi. | 491 // Stack now matches JSFunction abi. |
| 528 GenerateFastApiCallBody(masm, | 492 GenerateFastApiCallBody(masm, |
| 529 optimization, | 493 optimization, |
| 530 argc, | 494 argc, |
| 531 receiver, | 495 receiver, |
| 532 true); | 496 true); |
| 533 } | 497 } |
| 534 | 498 |
| 535 | 499 |
| 536 class CallInterceptorCompiler BASE_EMBEDDED { | |
| 537 public: | |
| 538 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | |
| 539 const ParameterCount& arguments, | |
| 540 Register name) | |
| 541 : stub_compiler_(stub_compiler), | |
| 542 arguments_(arguments), | |
| 543 name_(name) {} | |
| 544 | |
| 545 void Compile(MacroAssembler* masm, | |
| 546 Handle<JSObject> object, | |
| 547 Handle<JSObject> holder, | |
| 548 Handle<Name> name, | |
| 549 LookupResult* lookup, | |
| 550 Register receiver, | |
| 551 Register scratch1, | |
| 552 Register scratch2, | |
| 553 Register scratch3, | |
| 554 Label* miss) { | |
| 555 ASSERT(holder->HasNamedInterceptor()); | |
| 556 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
| 557 | |
| 558 // Check that the receiver isn't a smi. | |
| 559 __ JumpIfSmi(receiver, miss); | |
| 560 | |
| 561 CallOptimization optimization(lookup); | |
| 562 if (optimization.is_constant_call()) { | |
| 563 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 564 holder, lookup, name, optimization, miss); | |
| 565 } else { | |
| 566 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 567 name, holder, miss); | |
| 568 } | |
| 569 } | |
| 570 | |
| 571 private: | |
| 572 void CompileCacheable(MacroAssembler* masm, | |
| 573 Handle<JSObject> object, | |
| 574 Register receiver, | |
| 575 Register scratch1, | |
| 576 Register scratch2, | |
| 577 Register scratch3, | |
| 578 Handle<JSObject> interceptor_holder, | |
| 579 LookupResult* lookup, | |
| 580 Handle<Name> name, | |
| 581 const CallOptimization& optimization, | |
| 582 Label* miss_label) { | |
| 583 ASSERT(optimization.is_constant_call()); | |
| 584 ASSERT(!lookup->holder()->IsGlobalObject()); | |
| 585 | |
| 586 Counters* counters = masm->isolate()->counters(); | |
| 587 __ IncrementCounter(counters->call_const_interceptor(), 1); | |
| 588 | |
| 589 // Check that the maps from receiver to interceptor's holder | |
| 590 // haven't changed and thus we can invoke interceptor. | |
| 591 Register holder = | |
| 592 stub_compiler_->CheckPrototypes( | |
| 593 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 594 interceptor_holder, scratch1, scratch2, scratch3, | |
| 595 name, miss_label); | |
| 596 | |
| 597 // Invoke an interceptor and if it provides a value, | |
| 598 // branch to |regular_invoke|. | |
| 599 Label regular_invoke; | |
| 600 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | |
| 601 ®ular_invoke); | |
| 602 | |
| 603 // Interceptor returned nothing for this property. Try to use cached | |
| 604 // constant function. | |
| 605 | |
| 606 // Check that the maps from interceptor's holder to constant function's | |
| 607 // holder haven't changed and thus we can use cached constant function. | |
| 608 if (*interceptor_holder != lookup->holder()) { | |
| 609 stub_compiler_->CheckPrototypes( | |
| 610 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | |
| 611 handle(lookup->holder()), scratch1, scratch2, scratch3, | |
| 612 name, miss_label); | |
| 613 } | |
| 614 | |
| 615 Handle<Map> lookup_map; | |
| 616 CallOptimization::HolderLookup holder_lookup = | |
| 617 CallOptimization::kHolderNotFound; | |
| 618 if (optimization.is_simple_api_call() && | |
| 619 !lookup->holder()->IsGlobalObject()) { | |
| 620 lookup_map = optimization.LookupHolderOfExpectedType( | |
| 621 object, object, interceptor_holder, &holder_lookup); | |
| 622 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 623 lookup_map = | |
| 624 optimization.LookupHolderOfExpectedType( | |
| 625 object, | |
| 626 interceptor_holder, | |
| 627 Handle<JSObject>(lookup->holder()), | |
| 628 &holder_lookup); | |
| 629 } | |
| 630 } | |
| 631 | |
| 632 // Invoke function. | |
| 633 if (holder_lookup != CallOptimization::kHolderNotFound) { | |
| 634 int argc = arguments_.immediate(); | |
| 635 GenerateFastApiCall(masm, | |
| 636 optimization, | |
| 637 argc, | |
| 638 lookup_map, | |
| 639 holder_lookup); | |
| 640 } else { | |
| 641 Handle<JSFunction> fun = optimization.constant_function(); | |
| 642 stub_compiler_->GenerateJumpFunction(object, fun); | |
| 643 } | |
| 644 | |
| 645 // Invoke a regular function. | |
| 646 __ bind(®ular_invoke); | |
| 647 } | |
| 648 | |
| 649 void CompileRegular(MacroAssembler* masm, | |
| 650 Handle<JSObject> object, | |
| 651 Register receiver, | |
| 652 Register scratch1, | |
| 653 Register scratch2, | |
| 654 Register scratch3, | |
| 655 Handle<Name> name, | |
| 656 Handle<JSObject> interceptor_holder, | |
| 657 Label* miss_label) { | |
| 658 Register holder = | |
| 659 stub_compiler_->CheckPrototypes( | |
| 660 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 661 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label); | |
| 662 | |
| 663 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 664 // Save the name_ register across the call. | |
| 665 __ push(name_); | |
| 666 | |
| 667 CompileCallLoadPropertyWithInterceptor( | |
| 668 masm, receiver, holder, name_, interceptor_holder, | |
| 669 IC::kLoadPropertyWithInterceptorForCall); | |
| 670 | |
| 671 // Restore the name_ register. | |
| 672 __ pop(name_); | |
| 673 | |
| 674 // Leave the internal frame. | |
| 675 } | |
| 676 | |
| 677 void LoadWithInterceptor(MacroAssembler* masm, | |
| 678 Register receiver, | |
| 679 Register holder, | |
| 680 Handle<JSObject> holder_obj, | |
| 681 Label* interceptor_succeeded) { | |
| 682 { | |
| 683 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 684 __ push(receiver); | |
| 685 __ push(holder); | |
| 686 __ push(name_); | |
| 687 | |
| 688 CompileCallLoadPropertyWithInterceptor( | |
| 689 masm, receiver, holder, name_, holder_obj, | |
| 690 IC::kLoadPropertyWithInterceptorOnly); | |
| 691 | |
| 692 __ pop(name_); | |
| 693 __ pop(holder); | |
| 694 __ pop(receiver); | |
| 695 // Leave the internal frame. | |
| 696 } | |
| 697 | |
| 698 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); | |
| 699 __ j(not_equal, interceptor_succeeded); | |
| 700 } | |
| 701 | |
| 702 CallStubCompiler* stub_compiler_; | |
| 703 const ParameterCount& arguments_; | |
| 704 Register name_; | |
| 705 }; | |
| 706 | |
| 707 | |
| 708 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, | 500 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, |
| 709 Label* label, | 501 Label* label, |
| 710 Handle<Name> name) { | 502 Handle<Name> name) { |
| 711 if (!label->is_unused()) { | 503 if (!label->is_unused()) { |
| 712 __ bind(label); | 504 __ bind(label); |
| 713 __ mov(this->name(), Immediate(name)); | 505 __ mov(this->name(), Immediate(name)); |
| 714 } | 506 } |
| 715 } | 507 } |
| 716 | 508 |
| 717 | 509 |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1306 // ReturnValue default value | 1098 // ReturnValue default value |
| 1307 __ push(Immediate(isolate()->factory()->undefined_value())); | 1099 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 1308 __ push(Immediate(reinterpret_cast<int>(isolate()))); | 1100 __ push(Immediate(reinterpret_cast<int>(isolate()))); |
| 1309 __ push(reg); // holder | 1101 __ push(reg); // holder |
| 1310 | 1102 |
| 1311 // Save a pointer to where we pushed the arguments. This will be | 1103 // Save a pointer to where we pushed the arguments. This will be |
| 1312 // passed as the const PropertyAccessorInfo& to the C++ callback. | 1104 // passed as the const PropertyAccessorInfo& to the C++ callback. |
| 1313 __ push(esp); | 1105 __ push(esp); |
| 1314 | 1106 |
| 1315 __ push(name()); // name | 1107 __ push(name()); // name |
| 1316 __ mov(ebx, esp); // esp points to reference to name (handler). | |
| 1317 | 1108 |
| 1318 __ push(scratch3()); // Restore return address. | 1109 __ push(scratch3()); // Restore return address. |
| 1319 | 1110 |
| 1320 // array for v8::Arguments::values_, handler for name and pointer | 1111 // Abi for CallApiGetter |
| 1321 // to the values (it considered as smi in GC). | |
| 1322 const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2; | |
| 1323 // Allocate space for opional callback address parameter in case | |
| 1324 // CPU profiler is active. | |
| 1325 const int kApiArgc = 2 + 1; | |
| 1326 | |
| 1327 __ PrepareCallApiFunction(kApiArgc); | |
| 1328 __ mov(ApiParameterOperand(0), ebx); // name. | |
| 1329 __ add(ebx, Immediate(kPointerSize)); | |
| 1330 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. | |
| 1331 | |
| 1332 // Emitting a stub call may try to allocate (if the code is not | |
| 1333 // already generated). Do not allow the assembler to perform a | |
| 1334 // garbage collection but instead return the allocation failure | |
| 1335 // object. | |
| 1336 | |
| 1337 Register getter_address = edx; | 1112 Register getter_address = edx; |
| 1338 Address function_address = v8::ToCData<Address>(callback->getter()); | 1113 Address function_address = v8::ToCData<Address>(callback->getter()); |
| 1339 __ mov(getter_address, Immediate(function_address)); | 1114 __ mov(getter_address, Immediate(function_address)); |
| 1340 | 1115 |
| 1341 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback); | 1116 CallApiGetterStub stub; |
| 1342 | 1117 __ TailCallStub(&stub); |
| 1343 __ CallApiFunctionAndReturn(getter_address, | |
| 1344 thunk_address, | |
| 1345 ApiParameterOperand(2), | |
| 1346 kStackSpace, | |
| 1347 Operand(ebp, 7 * kPointerSize), | |
| 1348 NULL); | |
| 1349 } | 1118 } |
| 1350 | 1119 |
| 1351 | 1120 |
| 1352 void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) { | 1121 void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) { |
| 1353 // Return the constant value. | 1122 // Return the constant value. |
| 1354 __ LoadObject(eax, value); | 1123 __ LoadObject(eax, value); |
| 1355 __ ret(0); | 1124 __ ret(0); |
| 1356 } | 1125 } |
| 1357 | 1126 |
| 1358 | 1127 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1448 __ push(scratch2()); // restore old return address | 1217 __ push(scratch2()); // restore old return address |
| 1449 | 1218 |
| 1450 ExternalReference ref = | 1219 ExternalReference ref = |
| 1451 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1220 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
| 1452 isolate()); | 1221 isolate()); |
| 1453 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); | 1222 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); |
| 1454 } | 1223 } |
| 1455 } | 1224 } |
| 1456 | 1225 |
| 1457 | 1226 |
| 1458 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { | |
| 1459 if (kind_ == Code::KEYED_CALL_IC) { | |
| 1460 __ cmp(ecx, Immediate(name)); | |
| 1461 __ j(not_equal, miss); | |
| 1462 } | |
| 1463 } | |
| 1464 | |
| 1465 | |
| 1466 void CallStubCompiler::GenerateFunctionCheck(Register function, | |
| 1467 Register scratch, | |
| 1468 Label* miss) { | |
| 1469 __ JumpIfSmi(function, miss); | |
| 1470 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); | |
| 1471 __ j(not_equal, miss); | |
| 1472 } | |
| 1473 | |
| 1474 | |
| 1475 void CallStubCompiler::GenerateLoadFunctionFromCell( | |
| 1476 Handle<Cell> cell, | |
| 1477 Handle<JSFunction> function, | |
| 1478 Label* miss) { | |
| 1479 // Get the value from the cell. | |
| 1480 if (Serializer::enabled()) { | |
| 1481 __ mov(edi, Immediate(cell)); | |
| 1482 __ mov(edi, FieldOperand(edi, Cell::kValueOffset)); | |
| 1483 } else { | |
| 1484 __ mov(edi, Operand::ForCell(cell)); | |
| 1485 } | |
| 1486 | |
| 1487 // Check that the cell contains the same function. | |
| 1488 if (isolate()->heap()->InNewSpace(*function)) { | |
| 1489 // We can't embed a pointer to a function in new space so we have | |
| 1490 // to verify that the shared function info is unchanged. This has | |
| 1491 // the nice side effect that multiple closures based on the same | |
| 1492 // function can all use this call IC. Before we load through the | |
| 1493 // function, we have to verify that it still is a function. | |
| 1494 GenerateFunctionCheck(edi, ebx, miss); | |
| 1495 | |
| 1496 // Check the shared function info. Make sure it hasn't changed. | |
| 1497 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | |
| 1498 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | |
| 1499 } else { | |
| 1500 __ cmp(edi, Immediate(function)); | |
| 1501 } | |
| 1502 __ j(not_equal, miss); | |
| 1503 } | |
| 1504 | |
| 1505 | |
| 1506 void CallStubCompiler::GenerateMissBranch() { | |
| 1507 Handle<Code> code = | |
| 1508 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | |
| 1509 kind_, | |
| 1510 extra_state()); | |
| 1511 __ jmp(code, RelocInfo::CODE_TARGET); | |
| 1512 } | |
| 1513 | |
| 1514 | |
| 1515 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | |
| 1516 Handle<JSObject> holder, | |
| 1517 PropertyIndex index, | |
| 1518 Handle<Name> name) { | |
| 1519 Label miss; | |
| 1520 | |
| 1521 Register reg = HandlerFrontendHeader( | |
| 1522 object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1523 | |
| 1524 GenerateFastPropertyLoad( | |
| 1525 masm(), edi, reg, index.is_inobject(holder), | |
| 1526 index.translate(holder), Representation::Tagged()); | |
| 1527 GenerateJumpFunction(object, edi, &miss); | |
| 1528 | |
| 1529 HandlerFrontendFooter(&miss); | |
| 1530 | |
| 1531 // Return the generated code. | |
| 1532 return GetCode(Code::FAST, name); | |
| 1533 } | |
| 1534 | |
| 1535 | |
| 1536 Handle<Code> CallStubCompiler::CompileFastApiCall( | |
| 1537 const CallOptimization& optimization, | |
| 1538 Handle<Object> object, | |
| 1539 Handle<JSObject> holder, | |
| 1540 Handle<Cell> cell, | |
| 1541 Handle<JSFunction> function, | |
| 1542 Handle<String> name) { | |
| 1543 ASSERT(optimization.is_simple_api_call()); | |
| 1544 // Bail out if object is a global object as we don't want to | |
| 1545 // repatch it to global receiver. | |
| 1546 if (object->IsGlobalObject()) return Handle<Code>::null(); | |
| 1547 if (!cell.is_null()) return Handle<Code>::null(); | |
| 1548 if (!object->IsJSObject()) return Handle<Code>::null(); | |
| 1549 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 1550 CallOptimization::HolderLookup holder_lookup = | |
| 1551 CallOptimization::kHolderNotFound; | |
| 1552 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType( | |
| 1553 receiver, receiver, holder, &holder_lookup); | |
| 1554 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 1555 return Handle<Code>::null(); | |
| 1556 } | |
| 1557 | |
| 1558 Label miss; | |
| 1559 GenerateNameCheck(name, &miss); | |
| 1560 | |
| 1561 // Get the receiver from the stack. | |
| 1562 const int argc = arguments().immediate(); | |
| 1563 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1564 | |
| 1565 // Check that the receiver isn't a smi. | |
| 1566 __ JumpIfSmi(edx, &miss); | |
| 1567 | |
| 1568 Counters* counters = isolate()->counters(); | |
| 1569 __ IncrementCounter(counters->call_const(), 1); | |
| 1570 | |
| 1571 // Check that the maps haven't changed and find a Holder as a side effect. | |
| 1572 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, | |
| 1573 ebx, eax, edi, name, &miss); | |
| 1574 | |
| 1575 GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); | |
| 1576 | |
| 1577 HandlerFrontendFooter(&miss); | |
| 1578 | |
| 1579 // Return the generated code. | |
| 1580 return GetCode(function); | |
| 1581 } | |
| 1582 | |
| 1583 | |
| 1584 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1227 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 1585 Label success; | 1228 Label success; |
| 1586 // Check that the object is a boolean. | 1229 // Check that the object is a boolean. |
| 1587 __ cmp(object, factory()->true_value()); | 1230 __ cmp(object, factory()->true_value()); |
| 1588 __ j(equal, &success); | 1231 __ j(equal, &success); |
| 1589 __ cmp(object, factory()->false_value()); | 1232 __ cmp(object, factory()->false_value()); |
| 1590 __ j(not_equal, miss); | 1233 __ j(not_equal, miss); |
| 1591 __ bind(&success); | 1234 __ bind(&success); |
| 1592 } | 1235 } |
| 1593 | 1236 |
| 1594 | 1237 |
| 1595 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) { | |
| 1596 if (object->IsGlobalObject()) { | |
| 1597 const int argc = arguments().immediate(); | |
| 1598 const int receiver_offset = (argc + 1) * kPointerSize; | |
| 1599 __ mov(Operand(esp, receiver_offset), | |
| 1600 isolate()->factory()->undefined_value()); | |
| 1601 } | |
| 1602 } | |
| 1603 | |
| 1604 | |
| 1605 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, | |
| 1606 Handle<JSObject> holder, | |
| 1607 Handle<Name> name, | |
| 1608 CheckType check, | |
| 1609 Label* miss) { | |
| 1610 GenerateNameCheck(name, miss); | |
| 1611 | |
| 1612 Register reg = edx; | |
| 1613 | |
| 1614 const int argc = arguments().immediate(); | |
| 1615 const int receiver_offset = (argc + 1) * kPointerSize; | |
| 1616 __ mov(reg, Operand(esp, receiver_offset)); | |
| 1617 | |
| 1618 // Check that the receiver isn't a smi. | |
| 1619 if (check != NUMBER_CHECK) { | |
| 1620 __ JumpIfSmi(reg, miss); | |
| 1621 } | |
| 1622 | |
| 1623 // Make sure that it's okay not to patch the on stack receiver | |
| 1624 // unless we're doing a receiver map check. | |
| 1625 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | |
| 1626 switch (check) { | |
| 1627 case RECEIVER_MAP_CHECK: | |
| 1628 __ IncrementCounter(isolate()->counters()->call_const(), 1); | |
| 1629 | |
| 1630 // Check that the maps haven't changed. | |
| 1631 reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), reg, holder, | |
| 1632 ebx, eax, edi, name, miss); | |
| 1633 | |
| 1634 break; | |
| 1635 | |
| 1636 case STRING_CHECK: { | |
| 1637 // Check that the object is a string. | |
| 1638 __ CmpObjectType(reg, FIRST_NONSTRING_TYPE, eax); | |
| 1639 __ j(above_equal, miss); | |
| 1640 // Check that the maps starting from the prototype haven't changed. | |
| 1641 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1642 masm(), Context::STRING_FUNCTION_INDEX, eax, miss); | |
| 1643 break; | |
| 1644 } | |
| 1645 case SYMBOL_CHECK: { | |
| 1646 // Check that the object is a symbol. | |
| 1647 __ CmpObjectType(reg, SYMBOL_TYPE, eax); | |
| 1648 __ j(not_equal, miss); | |
| 1649 // Check that the maps starting from the prototype haven't changed. | |
| 1650 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1651 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, miss); | |
| 1652 break; | |
| 1653 } | |
| 1654 case NUMBER_CHECK: { | |
| 1655 Label fast; | |
| 1656 // Check that the object is a smi or a heap number. | |
| 1657 __ JumpIfSmi(reg, &fast); | |
| 1658 __ CmpObjectType(reg, HEAP_NUMBER_TYPE, eax); | |
| 1659 __ j(not_equal, miss); | |
| 1660 __ bind(&fast); | |
| 1661 // Check that the maps starting from the prototype haven't changed. | |
| 1662 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1663 masm(), Context::NUMBER_FUNCTION_INDEX, eax, miss); | |
| 1664 break; | |
| 1665 } | |
| 1666 case BOOLEAN_CHECK: { | |
| 1667 GenerateBooleanCheck(reg, miss); | |
| 1668 // Check that the maps starting from the prototype haven't changed. | |
| 1669 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1670 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, miss); | |
| 1671 break; | |
| 1672 } | |
| 1673 } | |
| 1674 | |
| 1675 if (check != RECEIVER_MAP_CHECK) { | |
| 1676 Handle<Object> prototype(object->GetPrototype(isolate()), isolate()); | |
| 1677 reg = CheckPrototypes( | |
| 1678 IC::CurrentTypeOf(prototype, isolate()), | |
| 1679 eax, holder, ebx, edx, edi, name, miss); | |
| 1680 } | |
| 1681 | |
| 1682 return reg; | |
| 1683 } | |
| 1684 | |
| 1685 | |
| 1686 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, | |
| 1687 Register function, | |
| 1688 Label* miss) { | |
| 1689 // Check that the function really is a function. | |
| 1690 GenerateFunctionCheck(function, ebx, miss); | |
| 1691 | |
| 1692 if (!function.is(edi)) __ mov(edi, function); | |
| 1693 PatchImplicitReceiver(object); | |
| 1694 | |
| 1695 // Invoke the function. | |
| 1696 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, NullCallWrapper()); | |
| 1697 } | |
| 1698 | |
| 1699 | |
| 1700 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, | |
| 1701 Handle<JSObject> holder, | |
| 1702 Handle<Name> name) { | |
| 1703 Label miss; | |
| 1704 | |
| 1705 GenerateNameCheck(name, &miss); | |
| 1706 | |
| 1707 // Get the number of arguments. | |
| 1708 const int argc = arguments().immediate(); | |
| 1709 | |
| 1710 LookupResult lookup(isolate()); | |
| 1711 LookupPostInterceptor(holder, name, &lookup); | |
| 1712 | |
| 1713 // Get the receiver from the stack. | |
| 1714 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1715 | |
| 1716 CallInterceptorCompiler compiler(this, arguments(), ecx); | |
| 1717 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax, | |
| 1718 &miss); | |
| 1719 | |
| 1720 // Restore receiver. | |
| 1721 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1722 | |
| 1723 GenerateJumpFunction(object, eax, &miss); | |
| 1724 | |
| 1725 HandlerFrontendFooter(&miss); | |
| 1726 | |
| 1727 // Return the generated code. | |
| 1728 return GetCode(Code::FAST, name); | |
| 1729 } | |
| 1730 | |
| 1731 | |
| 1732 Handle<Code> CallStubCompiler::CompileCallGlobal( | |
| 1733 Handle<JSObject> object, | |
| 1734 Handle<GlobalObject> holder, | |
| 1735 Handle<PropertyCell> cell, | |
| 1736 Handle<JSFunction> function, | |
| 1737 Handle<Name> name) { | |
| 1738 if (HasCustomCallGenerator(function)) { | |
| 1739 Handle<Code> code = CompileCustomCall( | |
| 1740 object, holder, cell, function, Handle<String>::cast(name), | |
| 1741 Code::NORMAL); | |
| 1742 // A null handle means bail out to the regular compiler code below. | |
| 1743 if (!code.is_null()) return code; | |
| 1744 } | |
| 1745 | |
| 1746 Label miss; | |
| 1747 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1748 // Potentially loads a closure that matches the shared function info of the | |
| 1749 // function, rather than function. | |
| 1750 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 1751 GenerateJumpFunction(object, edi, function); | |
| 1752 | |
| 1753 HandlerFrontendFooter(&miss); | |
| 1754 | |
| 1755 // Return the generated code. | |
| 1756 return GetCode(Code::NORMAL, name); | |
| 1757 } | |
| 1758 | |
| 1759 | |
| 1760 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1238 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 1761 Handle<JSObject> object, | 1239 Handle<JSObject> object, |
| 1762 Handle<JSObject> holder, | 1240 Handle<JSObject> holder, |
| 1763 Handle<Name> name, | 1241 Handle<Name> name, |
| 1764 Handle<ExecutableAccessorInfo> callback) { | 1242 Handle<ExecutableAccessorInfo> callback) { |
| 1765 Register holder_reg = HandlerFrontend( | 1243 Register holder_reg = HandlerFrontend( |
| 1766 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); | 1244 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
| 1767 | 1245 |
| 1768 __ pop(scratch1()); // remove the return address | 1246 __ pop(scratch1()); // remove the return address |
| 1769 __ push(receiver()); | 1247 __ push(receiver()); |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1991 | 1469 |
| 1992 // Check for deleted property if property can actually be deleted. | 1470 // Check for deleted property if property can actually be deleted. |
| 1993 if (!is_dont_delete) { | 1471 if (!is_dont_delete) { |
| 1994 __ cmp(eax, factory()->the_hole_value()); | 1472 __ cmp(eax, factory()->the_hole_value()); |
| 1995 __ j(equal, &miss); | 1473 __ j(equal, &miss); |
| 1996 } else if (FLAG_debug_code) { | 1474 } else if (FLAG_debug_code) { |
| 1997 __ cmp(eax, factory()->the_hole_value()); | 1475 __ cmp(eax, factory()->the_hole_value()); |
| 1998 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); | 1476 __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); |
| 1999 } | 1477 } |
| 2000 | 1478 |
| 2001 HandlerFrontendFooter(name, &miss); | |
| 2002 | |
| 2003 Counters* counters = isolate()->counters(); | 1479 Counters* counters = isolate()->counters(); |
| 2004 __ IncrementCounter(counters->named_load_global_stub(), 1); | 1480 __ IncrementCounter(counters->named_load_global_stub(), 1); |
| 2005 // The code above already loads the result into the return register. | 1481 // The code above already loads the result into the return register. |
| 2006 __ ret(0); | 1482 __ ret(0); |
| 2007 | 1483 |
| 1484 HandlerFrontendFooter(name, &miss); |
| 1485 |
| 2008 // Return the generated code. | 1486 // Return the generated code. |
| 2009 return GetCode(kind(), Code::NORMAL, name); | 1487 return GetCode(kind(), Code::NORMAL, name); |
| 2010 } | 1488 } |
| 2011 | 1489 |
| 2012 | 1490 |
| 2013 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 1491 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 2014 TypeHandleList* types, | 1492 TypeHandleList* types, |
| 2015 CodeHandleList* handlers, | 1493 CodeHandleList* handlers, |
| 2016 Handle<Name> name, | 1494 Handle<Name> name, |
| 2017 Code::StubType type, | 1495 Code::StubType type, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2103 // ----------------------------------- | 1581 // ----------------------------------- |
| 2104 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1582 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2105 } | 1583 } |
| 2106 | 1584 |
| 2107 | 1585 |
| 2108 #undef __ | 1586 #undef __ |
| 2109 | 1587 |
| 2110 } } // namespace v8::internal | 1588 } } // namespace v8::internal |
| 2111 | 1589 |
| 2112 #endif // V8_TARGET_ARCH_IA32 | 1590 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |