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 |