| 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 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 __ push(receiver); | 398 __ push(receiver); |
| 399 __ push(holder); | 399 __ push(holder); |
| 400 } | 400 } |
| 401 | 401 |
| 402 | 402 |
| 403 static void CompileCallLoadPropertyWithInterceptor( | 403 static void CompileCallLoadPropertyWithInterceptor( |
| 404 MacroAssembler* masm, | 404 MacroAssembler* masm, |
| 405 Register receiver, | 405 Register receiver, |
| 406 Register holder, | 406 Register holder, |
| 407 Register name, | 407 Register name, |
| 408 Handle<JSObject> holder_obj) { | 408 Handle<JSObject> holder_obj, |
| 409 IC::UtilityId id) { |
| 409 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 410 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
| 410 __ CallExternalReference( | 411 __ CallExternalReference( |
| 411 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), | 412 ExternalReference(IC_Utility(id), masm->isolate()), |
| 412 masm->isolate()), | |
| 413 StubCache::kInterceptorArgsLength); | 413 StubCache::kInterceptorArgsLength); |
| 414 } | 414 } |
| 415 | 415 |
| 416 | 416 |
| 417 // Number of pointers to be reserved on stack for fast API call. | 417 // Number of pointers to be reserved on stack for fast API call. |
| 418 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; | 418 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; |
| 419 | 419 |
| 420 | 420 |
| 421 // Reserves space for the extra arguments to API function in the | 421 // Reserves space for the extra arguments to API function in the |
| 422 // caller's frame. | 422 // caller's frame. |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 ApiParameterOperand(1), | 638 ApiParameterOperand(1), |
| 639 argc + kFastApiCallArguments + 1, | 639 argc + kFastApiCallArguments + 1, |
| 640 return_value_operand, | 640 return_value_operand, |
| 641 restore_context ? | 641 restore_context ? |
| 642 &context_restore_operand : NULL); | 642 &context_restore_operand : NULL); |
| 643 } | 643 } |
| 644 | 644 |
| 645 | 645 |
| 646 class CallInterceptorCompiler BASE_EMBEDDED { | 646 class CallInterceptorCompiler BASE_EMBEDDED { |
| 647 public: | 647 public: |
| 648 CallInterceptorCompiler(StubCompiler* stub_compiler, | 648 CallInterceptorCompiler(CallStubCompiler* stub_compiler, |
| 649 const ParameterCount& arguments, | 649 const ParameterCount& arguments, |
| 650 Register name, | 650 Register name) |
| 651 Code::ExtraICState extra_state) | |
| 652 : stub_compiler_(stub_compiler), | 651 : stub_compiler_(stub_compiler), |
| 653 arguments_(arguments), | 652 arguments_(arguments), |
| 654 name_(name), | 653 name_(name) {} |
| 655 extra_state_(extra_state) {} | |
| 656 | 654 |
| 657 void Compile(MacroAssembler* masm, | 655 void Compile(MacroAssembler* masm, |
| 658 Handle<JSObject> object, | 656 Handle<JSObject> object, |
| 659 Handle<JSObject> holder, | 657 Handle<JSObject> holder, |
| 660 Handle<Name> name, | 658 Handle<Name> name, |
| 661 LookupResult* lookup, | 659 LookupResult* lookup, |
| 662 Register receiver, | 660 Register receiver, |
| 663 Register scratch1, | 661 Register scratch1, |
| 664 Register scratch2, | 662 Register scratch2, |
| 665 Register scratch3, | 663 Register scratch3, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 if (can_do_fast_api_call) { | 714 if (can_do_fast_api_call) { |
| 717 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); | 715 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); |
| 718 ReserveSpaceForFastApiCall(masm, scratch1); | 716 ReserveSpaceForFastApiCall(masm, scratch1); |
| 719 } | 717 } |
| 720 | 718 |
| 721 // Check that the maps from receiver to interceptor's holder | 719 // Check that the maps from receiver to interceptor's holder |
| 722 // haven't changed and thus we can invoke interceptor. | 720 // haven't changed and thus we can invoke interceptor. |
| 723 Label miss_cleanup; | 721 Label miss_cleanup; |
| 724 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | 722 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
| 725 Register holder = | 723 Register holder = |
| 726 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, | 724 stub_compiler_->CheckPrototypes( |
| 727 scratch1, scratch2, scratch3, | 725 IC::CurrentTypeOf(object, masm->isolate()), receiver, |
| 728 name, depth1, miss); | 726 interceptor_holder, scratch1, scratch2, scratch3, |
| 727 name, depth1, miss); |
| 729 | 728 |
| 730 // Invoke an interceptor and if it provides a value, | 729 // Invoke an interceptor and if it provides a value, |
| 731 // branch to |regular_invoke|. | 730 // branch to |regular_invoke|. |
| 732 Label regular_invoke; | 731 Label regular_invoke; |
| 733 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | 732 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
| 734 ®ular_invoke); | 733 ®ular_invoke); |
| 735 | 734 |
| 736 // Interceptor returned nothing for this property. Try to use cached | 735 // Interceptor returned nothing for this property. Try to use cached |
| 737 // constant function. | 736 // constant function. |
| 738 | 737 |
| 739 // Check that the maps from interceptor's holder to constant function's | 738 // Check that the maps from interceptor's holder to constant function's |
| 740 // holder haven't changed and thus we can use cached constant function. | 739 // holder haven't changed and thus we can use cached constant function. |
| 741 if (*interceptor_holder != lookup->holder()) { | 740 if (*interceptor_holder != lookup->holder()) { |
| 742 stub_compiler_->CheckPrototypes(interceptor_holder, receiver, | 741 stub_compiler_->CheckPrototypes( |
| 743 Handle<JSObject>(lookup->holder()), | 742 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, |
| 744 scratch1, scratch2, scratch3, | 743 handle(lookup->holder()), scratch1, scratch2, scratch3, |
| 745 name, depth2, miss); | 744 name, depth2, miss); |
| 746 } else { | 745 } else { |
| 747 // CheckPrototypes has a side effect of fetching a 'holder' | 746 // CheckPrototypes has a side effect of fetching a 'holder' |
| 748 // for API (object which is instanceof for the signature). It's | 747 // for API (object which is instanceof for the signature). It's |
| 749 // safe to omit it here, as if present, it should be fetched | 748 // safe to omit it here, as if present, it should be fetched |
| 750 // by the previous CheckPrototypes. | 749 // by the previous CheckPrototypes. |
| 751 ASSERT(depth2 == kInvalidProtoDepth); | 750 ASSERT(depth2 == kInvalidProtoDepth); |
| 752 } | 751 } |
| 753 | 752 |
| 754 // Invoke function. | 753 // Invoke function. |
| 755 if (can_do_fast_api_call) { | 754 if (can_do_fast_api_call) { |
| 756 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 755 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
| 757 } else { | 756 } else { |
| 758 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 757 Handle<JSFunction> fun = optimization.constant_function(); |
| 759 ? CALL_AS_FUNCTION | 758 stub_compiler_->GenerateJumpFunction(object, fun); |
| 760 : CALL_AS_METHOD; | |
| 761 Handle<JSFunction> function = optimization.constant_function(); | |
| 762 ParameterCount expected(function); | |
| 763 __ InvokeFunction(function, expected, arguments_, | |
| 764 JUMP_FUNCTION, NullCallWrapper(), call_kind); | |
| 765 } | 759 } |
| 766 | 760 |
| 767 // Deferred code for fast API call case---clean preallocated space. | 761 // Deferred code for fast API call case---clean preallocated space. |
| 768 if (can_do_fast_api_call) { | 762 if (can_do_fast_api_call) { |
| 769 __ bind(&miss_cleanup); | 763 __ bind(&miss_cleanup); |
| 770 FreeSpaceForFastApiCall(masm, scratch1); | 764 FreeSpaceForFastApiCall(masm, scratch1); |
| 771 __ jmp(miss_label); | 765 __ jmp(miss_label); |
| 772 } | 766 } |
| 773 | 767 |
| 774 // Invoke a regular function. | 768 // Invoke a regular function. |
| 775 __ bind(®ular_invoke); | 769 __ bind(®ular_invoke); |
| 776 if (can_do_fast_api_call) { | 770 if (can_do_fast_api_call) { |
| 777 FreeSpaceForFastApiCall(masm, scratch1); | 771 FreeSpaceForFastApiCall(masm, scratch1); |
| 778 } | 772 } |
| 779 } | 773 } |
| 780 | 774 |
| 781 void CompileRegular(MacroAssembler* masm, | 775 void CompileRegular(MacroAssembler* masm, |
| 782 Handle<JSObject> object, | 776 Handle<JSObject> object, |
| 783 Register receiver, | 777 Register receiver, |
| 784 Register scratch1, | 778 Register scratch1, |
| 785 Register scratch2, | 779 Register scratch2, |
| 786 Register scratch3, | 780 Register scratch3, |
| 787 Handle<Name> name, | 781 Handle<Name> name, |
| 788 Handle<JSObject> interceptor_holder, | 782 Handle<JSObject> interceptor_holder, |
| 789 Label* miss_label) { | 783 Label* miss_label) { |
| 790 Register holder = | 784 Register holder = |
| 791 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, | 785 stub_compiler_->CheckPrototypes( |
| 792 scratch1, scratch2, scratch3, | 786 IC::CurrentTypeOf(object, masm->isolate()), receiver, |
| 793 name, miss_label); | 787 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label); |
| 794 | 788 |
| 795 FrameScope scope(masm, StackFrame::INTERNAL); | 789 FrameScope scope(masm, StackFrame::INTERNAL); |
| 796 // Save the name_ register across the call. | 790 // Save the name_ register across the call. |
| 797 __ push(name_); | 791 __ push(name_); |
| 798 | 792 |
| 799 PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); | 793 CompileCallLoadPropertyWithInterceptor( |
| 800 | 794 masm, receiver, holder, name_, interceptor_holder, |
| 801 __ CallExternalReference( | 795 IC::kLoadPropertyWithInterceptorForCall); |
| 802 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), | |
| 803 masm->isolate()), | |
| 804 StubCache::kInterceptorArgsLength); | |
| 805 | 796 |
| 806 // Restore the name_ register. | 797 // Restore the name_ register. |
| 807 __ pop(name_); | 798 __ pop(name_); |
| 808 | 799 |
| 809 // Leave the internal frame. | 800 // Leave the internal frame. |
| 810 } | 801 } |
| 811 | 802 |
| 812 void LoadWithInterceptor(MacroAssembler* masm, | 803 void LoadWithInterceptor(MacroAssembler* masm, |
| 813 Register receiver, | 804 Register receiver, |
| 814 Register holder, | 805 Register holder, |
| 815 Handle<JSObject> holder_obj, | 806 Handle<JSObject> holder_obj, |
| 816 Label* interceptor_succeeded) { | 807 Label* interceptor_succeeded) { |
| 817 { | 808 { |
| 818 FrameScope scope(masm, StackFrame::INTERNAL); | 809 FrameScope scope(masm, StackFrame::INTERNAL); |
| 819 __ push(holder); // Save the holder. | 810 __ push(receiver); |
| 820 __ push(name_); // Save the name. | 811 __ push(holder); |
| 812 __ push(name_); |
| 821 | 813 |
| 822 CompileCallLoadPropertyWithInterceptor(masm, | 814 CompileCallLoadPropertyWithInterceptor( |
| 823 receiver, | 815 masm, receiver, holder, name_, holder_obj, |
| 824 holder, | 816 IC::kLoadPropertyWithInterceptorOnly); |
| 825 name_, | |
| 826 holder_obj); | |
| 827 | 817 |
| 828 __ pop(name_); // Restore the name. | 818 __ pop(name_); |
| 829 __ pop(receiver); // Restore the holder. | 819 __ pop(holder); |
| 820 __ pop(receiver); |
| 830 // Leave the internal frame. | 821 // Leave the internal frame. |
| 831 } | 822 } |
| 832 | 823 |
| 833 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); | 824 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); |
| 834 __ j(not_equal, interceptor_succeeded); | 825 __ j(not_equal, interceptor_succeeded); |
| 835 } | 826 } |
| 836 | 827 |
| 837 StubCompiler* stub_compiler_; | 828 CallStubCompiler* stub_compiler_; |
| 838 const ParameterCount& arguments_; | 829 const ParameterCount& arguments_; |
| 839 Register name_; | 830 Register name_; |
| 840 Code::ExtraICState extra_state_; | |
| 841 }; | 831 }; |
| 842 | 832 |
| 843 | 833 |
| 844 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, | 834 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm, |
| 845 Label* label, | 835 Label* label, |
| 846 Handle<Name> name) { | 836 Handle<Name> name) { |
| 847 if (!label->is_unused()) { | 837 if (!label->is_unused()) { |
| 848 __ bind(label); | 838 __ bind(label); |
| 849 __ mov(this->name(), Immediate(name)); | 839 __ mov(this->name(), Immediate(name)); |
| 850 } | 840 } |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1177 smi_check); | 1167 smi_check); |
| 1178 } | 1168 } |
| 1179 } | 1169 } |
| 1180 | 1170 |
| 1181 // Return the value (register eax). | 1171 // Return the value (register eax). |
| 1182 ASSERT(value_reg.is(eax)); | 1172 ASSERT(value_reg.is(eax)); |
| 1183 __ ret(0); | 1173 __ ret(0); |
| 1184 } | 1174 } |
| 1185 | 1175 |
| 1186 | 1176 |
| 1187 void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm, | |
| 1188 Handle<JSObject> object, | |
| 1189 Handle<JSObject> holder, | |
| 1190 Handle<Name> name, | |
| 1191 Register scratch, | |
| 1192 Label* miss) { | |
| 1193 Handle<JSObject> current = object; | |
| 1194 while (!current.is_identical_to(holder)) { | |
| 1195 if (current->IsJSGlobalObject()) { | |
| 1196 GenerateCheckPropertyCell(masm, | |
| 1197 Handle<JSGlobalObject>::cast(current), | |
| 1198 name, | |
| 1199 scratch, | |
| 1200 miss); | |
| 1201 } | |
| 1202 current = Handle<JSObject>(JSObject::cast(current->GetPrototype())); | |
| 1203 } | |
| 1204 } | |
| 1205 | |
| 1206 | |
| 1207 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 1177 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
| 1208 __ jmp(code, RelocInfo::CODE_TARGET); | 1178 __ jmp(code, RelocInfo::CODE_TARGET); |
| 1209 } | 1179 } |
| 1210 | 1180 |
| 1211 | 1181 |
| 1212 #undef __ | 1182 #undef __ |
| 1213 #define __ ACCESS_MASM(masm()) | 1183 #define __ ACCESS_MASM(masm()) |
| 1214 | 1184 |
| 1215 | 1185 |
| 1216 Register StubCompiler::CheckPrototypes(Handle<JSObject> object, | 1186 Register StubCompiler::CheckPrototypes(Handle<Type> type, |
| 1217 Register object_reg, | 1187 Register object_reg, |
| 1218 Handle<JSObject> holder, | 1188 Handle<JSObject> holder, |
| 1219 Register holder_reg, | 1189 Register holder_reg, |
| 1220 Register scratch1, | 1190 Register scratch1, |
| 1221 Register scratch2, | 1191 Register scratch2, |
| 1222 Handle<Name> name, | 1192 Handle<Name> name, |
| 1223 int save_at_depth, | 1193 int save_at_depth, |
| 1224 Label* miss, | 1194 Label* miss, |
| 1225 PrototypeCheckType check) { | 1195 PrototypeCheckType check) { |
| 1226 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1; | 1196 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); |
| 1227 // Make sure that the type feedback oracle harvests the receiver map. | 1197 // Make sure that the type feedback oracle harvests the receiver map. |
| 1228 // TODO(svenpanne) Remove this hack when all ICs are reworked. | 1198 // TODO(svenpanne) Remove this hack when all ICs are reworked. |
| 1229 __ mov(scratch1, Handle<Map>(object->map())); | 1199 __ mov(scratch1, receiver_map); |
| 1230 | 1200 |
| 1231 Handle<JSObject> first = object; | |
| 1232 // Make sure there's no overlap between holder and object registers. | 1201 // Make sure there's no overlap between holder and object registers. |
| 1233 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 1202 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 1234 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 1203 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 1235 && !scratch2.is(scratch1)); | 1204 && !scratch2.is(scratch1)); |
| 1236 | 1205 |
| 1237 // Keep track of the current object in register reg. | 1206 // Keep track of the current object in register reg. |
| 1238 Register reg = object_reg; | 1207 Register reg = object_reg; |
| 1239 Handle<JSObject> current = object; | |
| 1240 int depth = 0; | 1208 int depth = 0; |
| 1241 | 1209 |
| 1210 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1; |
| 1242 if (save_at_depth == depth) { | 1211 if (save_at_depth == depth) { |
| 1243 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); | 1212 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); |
| 1244 } | 1213 } |
| 1245 | 1214 |
| 1215 Handle<JSObject> current = Handle<JSObject>::null(); |
| 1216 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); |
| 1217 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 1218 Handle<Map> current_map = receiver_map; |
| 1219 Handle<Map> holder_map(holder->map()); |
| 1246 // Traverse the prototype chain and check the maps in the prototype chain for | 1220 // Traverse the prototype chain and check the maps in the prototype chain for |
| 1247 // fast and global objects or do negative lookup for normal objects. | 1221 // fast and global objects or do negative lookup for normal objects. |
| 1248 while (!current.is_identical_to(holder)) { | 1222 while (!current_map.is_identical_to(holder_map)) { |
| 1249 ++depth; | 1223 ++depth; |
| 1250 | 1224 |
| 1251 // Only global objects and objects that do not require access | 1225 // Only global objects and objects that do not require access |
| 1252 // checks are allowed in stubs. | 1226 // checks are allowed in stubs. |
| 1253 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); | 1227 ASSERT(current_map->IsJSGlobalProxyMap() || |
| 1228 !current_map->is_access_check_needed()); |
| 1254 | 1229 |
| 1255 Handle<JSObject> prototype(JSObject::cast(current->GetPrototype())); | 1230 prototype = handle(JSObject::cast(current_map->prototype())); |
| 1256 if (!current->HasFastProperties() && | 1231 if (current_map->is_dictionary_map() && |
| 1257 !current->IsJSGlobalObject() && | 1232 !current_map->IsJSGlobalObjectMap() && |
| 1258 !current->IsJSGlobalProxy()) { | 1233 !current_map->IsJSGlobalProxyMap()) { |
| 1259 if (!name->IsUniqueName()) { | 1234 if (!name->IsUniqueName()) { |
| 1260 ASSERT(name->IsString()); | 1235 ASSERT(name->IsString()); |
| 1261 name = factory()->InternalizeString(Handle<String>::cast(name)); | 1236 name = factory()->InternalizeString(Handle<String>::cast(name)); |
| 1262 } | 1237 } |
| 1263 ASSERT(current->property_dictionary()->FindEntry(*name) == | 1238 ASSERT(current.is_null() || |
| 1239 current->property_dictionary()->FindEntry(*name) == |
| 1264 NameDictionary::kNotFound); | 1240 NameDictionary::kNotFound); |
| 1265 | 1241 |
| 1266 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, | 1242 GenerateDictionaryNegativeLookup(masm(), miss, reg, name, |
| 1267 scratch1, scratch2); | 1243 scratch1, scratch2); |
| 1268 | 1244 |
| 1269 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 1245 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 1270 reg = holder_reg; // From now on the object will be in holder_reg. | 1246 reg = holder_reg; // From now on the object will be in holder_reg. |
| 1271 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 1247 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 1272 } else { | 1248 } else { |
| 1273 bool in_new_space = heap()->InNewSpace(*prototype); | 1249 bool in_new_space = heap()->InNewSpace(*prototype); |
| 1274 Handle<Map> current_map(current->map()); | 1250 if (depth != 1 || check == CHECK_ALL_MAPS) { |
| 1275 if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) { | |
| 1276 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); | 1251 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); |
| 1277 } | 1252 } |
| 1278 | 1253 |
| 1279 // Check access rights to the global object. This has to happen after | 1254 // Check access rights to the global object. This has to happen after |
| 1280 // the map check so that we know that the object is actually a global | 1255 // the map check so that we know that the object is actually a global |
| 1281 // object. | 1256 // object. |
| 1282 if (current->IsJSGlobalProxy()) { | 1257 if (current_map->IsJSGlobalProxyMap()) { |
| 1283 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); | 1258 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); |
| 1259 } else if (current_map->IsJSGlobalObjectMap()) { |
| 1260 GenerateCheckPropertyCell( |
| 1261 masm(), Handle<JSGlobalObject>::cast(current), name, |
| 1262 scratch2, miss); |
| 1284 } | 1263 } |
| 1285 | 1264 |
| 1286 if (in_new_space) { | 1265 if (in_new_space) { |
| 1287 // Save the map in scratch1 for later. | 1266 // Save the map in scratch1 for later. |
| 1288 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 1267 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 1289 } | 1268 } |
| 1290 | 1269 |
| 1291 reg = holder_reg; // From now on the object will be in holder_reg. | 1270 reg = holder_reg; // From now on the object will be in holder_reg. |
| 1292 | 1271 |
| 1293 if (in_new_space) { | 1272 if (in_new_space) { |
| 1294 // The prototype is in new space; we cannot store a reference to it | 1273 // The prototype is in new space; we cannot store a reference to it |
| 1295 // in the code. Load it from the map. | 1274 // in the code. Load it from the map. |
| 1296 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 1275 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 1297 } else { | 1276 } else { |
| 1298 // The prototype is in old space; load it directly. | 1277 // The prototype is in old space; load it directly. |
| 1299 __ mov(reg, prototype); | 1278 __ mov(reg, prototype); |
| 1300 } | 1279 } |
| 1301 } | 1280 } |
| 1302 | 1281 |
| 1303 if (save_at_depth == depth) { | 1282 if (save_at_depth == depth) { |
| 1304 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); | 1283 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); |
| 1305 } | 1284 } |
| 1306 | 1285 |
| 1307 // Go to the next object in the prototype chain. | 1286 // Go to the next object in the prototype chain. |
| 1308 current = prototype; | 1287 current = prototype; |
| 1288 current_map = handle(current->map()); |
| 1309 } | 1289 } |
| 1310 ASSERT(current.is_identical_to(holder)); | |
| 1311 | 1290 |
| 1312 // Log the check depth. | 1291 // Log the check depth. |
| 1313 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 1292 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 1314 | 1293 |
| 1315 if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) { | 1294 if (depth != 0 || check == CHECK_ALL_MAPS) { |
| 1316 // Check the holder map. | 1295 // Check the holder map. |
| 1317 __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK); | 1296 __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); |
| 1318 } | 1297 } |
| 1319 | 1298 |
| 1320 // Perform security check for access to the global object. | 1299 // Perform security check for access to the global object. |
| 1321 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 1300 ASSERT(current_map->IsJSGlobalProxyMap() || |
| 1322 if (holder->IsJSGlobalProxy()) { | 1301 !current_map->is_access_check_needed()); |
| 1302 if (current_map->IsJSGlobalProxyMap()) { |
| 1323 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); | 1303 __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); |
| 1324 } | 1304 } |
| 1325 | 1305 |
| 1326 // If we've skipped any global objects, it's not enough to verify that | |
| 1327 // their maps haven't changed. We also need to check that the property | |
| 1328 // cell for the property is still empty. | |
| 1329 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); | |
| 1330 | |
| 1331 // Return the register containing the holder. | 1306 // Return the register containing the holder. |
| 1332 return reg; | 1307 return reg; |
| 1333 } | 1308 } |
| 1334 | 1309 |
| 1335 | 1310 |
| 1336 void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) { | 1311 void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) { |
| 1337 if (!miss->is_unused()) { | 1312 if (!miss->is_unused()) { |
| 1338 Label success; | 1313 Label success; |
| 1339 __ jmp(&success); | 1314 __ jmp(&success); |
| 1340 __ bind(miss); | 1315 __ bind(miss); |
| 1341 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1316 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1342 __ bind(&success); | 1317 __ bind(&success); |
| 1343 } | 1318 } |
| 1344 } | 1319 } |
| 1345 | 1320 |
| 1346 | 1321 |
| 1347 void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) { | 1322 void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) { |
| 1348 if (!miss->is_unused()) { | 1323 if (!miss->is_unused()) { |
| 1349 Label success; | 1324 Label success; |
| 1350 __ jmp(&success); | 1325 __ jmp(&success); |
| 1351 GenerateRestoreName(masm(), miss, name); | 1326 GenerateRestoreName(masm(), miss, name); |
| 1352 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1327 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1353 __ bind(&success); | 1328 __ bind(&success); |
| 1354 } | 1329 } |
| 1355 } | 1330 } |
| 1356 | 1331 |
| 1357 | 1332 |
| 1358 Register LoadStubCompiler::CallbackHandlerFrontend( | 1333 Register LoadStubCompiler::CallbackHandlerFrontend( |
| 1359 Handle<Object> object, | 1334 Handle<Type> type, |
| 1360 Register object_reg, | 1335 Register object_reg, |
| 1361 Handle<JSObject> holder, | 1336 Handle<JSObject> holder, |
| 1362 Handle<Name> name, | 1337 Handle<Name> name, |
| 1363 Handle<Object> callback) { | 1338 Handle<Object> callback) { |
| 1364 Label miss; | 1339 Label miss; |
| 1365 | 1340 |
| 1366 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); | 1341 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); |
| 1367 | 1342 |
| 1368 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | 1343 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 1369 ASSERT(!reg.is(scratch2())); | 1344 ASSERT(!reg.is(scratch2())); |
| 1370 ASSERT(!reg.is(scratch3())); | 1345 ASSERT(!reg.is(scratch3())); |
| 1371 Register dictionary = scratch1(); | 1346 Register dictionary = scratch1(); |
| 1372 bool must_preserve_dictionary_reg = reg.is(dictionary); | 1347 bool must_preserve_dictionary_reg = reg.is(dictionary); |
| 1373 | 1348 |
| 1374 // Load the properties dictionary. | 1349 // Load the properties dictionary. |
| 1375 if (must_preserve_dictionary_reg) { | 1350 if (must_preserve_dictionary_reg) { |
| 1376 __ push(dictionary); | 1351 __ push(dictionary); |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1560 | 1535 |
| 1561 if (must_preserve_receiver_reg) { | 1536 if (must_preserve_receiver_reg) { |
| 1562 __ push(receiver()); | 1537 __ push(receiver()); |
| 1563 } | 1538 } |
| 1564 __ push(holder_reg); | 1539 __ push(holder_reg); |
| 1565 __ push(this->name()); | 1540 __ push(this->name()); |
| 1566 | 1541 |
| 1567 // Invoke an interceptor. Note: map checks from receiver to | 1542 // Invoke an interceptor. Note: map checks from receiver to |
| 1568 // interceptor's holder has been compiled before (see a caller | 1543 // interceptor's holder has been compiled before (see a caller |
| 1569 // of this method.) | 1544 // of this method.) |
| 1570 CompileCallLoadPropertyWithInterceptor(masm(), | 1545 CompileCallLoadPropertyWithInterceptor( |
| 1571 receiver(), | 1546 masm(), receiver(), holder_reg, this->name(), interceptor_holder, |
| 1572 holder_reg, | 1547 IC::kLoadPropertyWithInterceptorOnly); |
| 1573 this->name(), | |
| 1574 interceptor_holder); | |
| 1575 | 1548 |
| 1576 // Check if interceptor provided a value for property. If it's | 1549 // Check if interceptor provided a value for property. If it's |
| 1577 // the case, return immediately. | 1550 // the case, return immediately. |
| 1578 Label interceptor_failed; | 1551 Label interceptor_failed; |
| 1579 __ cmp(eax, factory()->no_interceptor_result_sentinel()); | 1552 __ cmp(eax, factory()->no_interceptor_result_sentinel()); |
| 1580 __ j(equal, &interceptor_failed); | 1553 __ j(equal, &interceptor_failed); |
| 1581 frame_scope.GenerateLeaveFrame(); | 1554 frame_scope.GenerateLeaveFrame(); |
| 1582 __ ret(0); | 1555 __ ret(0); |
| 1583 | 1556 |
| 1584 // Clobber registers when generating debug-code to provoke errors. | 1557 // Clobber registers when generating debug-code to provoke errors. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1616 | 1589 |
| 1617 | 1590 |
| 1618 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { | 1591 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { |
| 1619 if (kind_ == Code::KEYED_CALL_IC) { | 1592 if (kind_ == Code::KEYED_CALL_IC) { |
| 1620 __ cmp(ecx, Immediate(name)); | 1593 __ cmp(ecx, Immediate(name)); |
| 1621 __ j(not_equal, miss); | 1594 __ j(not_equal, miss); |
| 1622 } | 1595 } |
| 1623 } | 1596 } |
| 1624 | 1597 |
| 1625 | 1598 |
| 1626 void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object, | 1599 void CallStubCompiler::GenerateFunctionCheck(Register function, |
| 1627 Handle<JSObject> holder, | 1600 Register scratch, |
| 1628 Handle<Name> name, | 1601 Label* miss) { |
| 1629 Label* miss) { | 1602 __ JumpIfSmi(function, miss); |
| 1630 ASSERT(holder->IsGlobalObject()); | 1603 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); |
| 1631 | 1604 __ j(not_equal, miss); |
| 1632 // Get the number of arguments. | |
| 1633 const int argc = arguments().immediate(); | |
| 1634 | |
| 1635 // Get the receiver from the stack. | |
| 1636 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1637 | |
| 1638 | |
| 1639 // Check that the maps haven't changed. | |
| 1640 __ JumpIfSmi(edx, miss); | |
| 1641 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss); | |
| 1642 } | 1605 } |
| 1643 | 1606 |
| 1644 | 1607 |
| 1645 void CallStubCompiler::GenerateLoadFunctionFromCell( | 1608 void CallStubCompiler::GenerateLoadFunctionFromCell( |
| 1646 Handle<Cell> cell, | 1609 Handle<Cell> cell, |
| 1647 Handle<JSFunction> function, | 1610 Handle<JSFunction> function, |
| 1648 Label* miss) { | 1611 Label* miss) { |
| 1649 // Get the value from the cell. | 1612 // Get the value from the cell. |
| 1650 if (Serializer::enabled()) { | 1613 if (Serializer::enabled()) { |
| 1651 __ mov(edi, Immediate(cell)); | 1614 __ mov(edi, Immediate(cell)); |
| 1652 __ mov(edi, FieldOperand(edi, Cell::kValueOffset)); | 1615 __ mov(edi, FieldOperand(edi, Cell::kValueOffset)); |
| 1653 } else { | 1616 } else { |
| 1654 __ mov(edi, Operand::ForCell(cell)); | 1617 __ mov(edi, Operand::ForCell(cell)); |
| 1655 } | 1618 } |
| 1656 | 1619 |
| 1657 // Check that the cell contains the same function. | 1620 // Check that the cell contains the same function. |
| 1658 if (isolate()->heap()->InNewSpace(*function)) { | 1621 if (isolate()->heap()->InNewSpace(*function)) { |
| 1659 // We can't embed a pointer to a function in new space so we have | 1622 // We can't embed a pointer to a function in new space so we have |
| 1660 // to verify that the shared function info is unchanged. This has | 1623 // to verify that the shared function info is unchanged. This has |
| 1661 // the nice side effect that multiple closures based on the same | 1624 // the nice side effect that multiple closures based on the same |
| 1662 // function can all use this call IC. Before we load through the | 1625 // function can all use this call IC. Before we load through the |
| 1663 // function, we have to verify that it still is a function. | 1626 // function, we have to verify that it still is a function. |
| 1664 __ JumpIfSmi(edi, miss); | 1627 GenerateFunctionCheck(edi, ebx, miss); |
| 1665 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | |
| 1666 __ j(not_equal, miss); | |
| 1667 | 1628 |
| 1668 // Check the shared function info. Make sure it hasn't changed. | 1629 // Check the shared function info. Make sure it hasn't changed. |
| 1669 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | 1630 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), |
| 1670 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | 1631 Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
| 1671 } else { | 1632 } else { |
| 1672 __ cmp(edi, Immediate(function)); | 1633 __ cmp(edi, Immediate(function)); |
| 1673 } | 1634 } |
| 1674 __ j(not_equal, miss); | 1635 __ j(not_equal, miss); |
| 1675 } | 1636 } |
| 1676 | 1637 |
| 1677 | 1638 |
| 1678 void CallStubCompiler::GenerateMissBranch() { | 1639 void CallStubCompiler::GenerateMissBranch() { |
| 1679 Handle<Code> code = | 1640 Handle<Code> code = |
| 1680 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | 1641 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), |
| 1681 kind_, | 1642 kind_, |
| 1682 extra_state_); | 1643 extra_state()); |
| 1683 __ jmp(code, RelocInfo::CODE_TARGET); | 1644 __ jmp(code, RelocInfo::CODE_TARGET); |
| 1684 } | 1645 } |
| 1685 | 1646 |
| 1686 | 1647 |
| 1687 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | 1648 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, |
| 1688 Handle<JSObject> holder, | 1649 Handle<JSObject> holder, |
| 1689 PropertyIndex index, | 1650 PropertyIndex index, |
| 1690 Handle<Name> name) { | 1651 Handle<Name> name) { |
| 1691 // ----------- S t a t e ------------- | |
| 1692 // -- ecx : name | |
| 1693 // -- esp[0] : return address | |
| 1694 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 1695 // -- ... | |
| 1696 // -- esp[(argc + 1) * 4] : receiver | |
| 1697 // ----------------------------------- | |
| 1698 Label miss; | 1652 Label miss; |
| 1699 | 1653 |
| 1700 GenerateNameCheck(name, &miss); | 1654 Register reg = HandlerFrontendHeader( |
| 1701 | 1655 object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 1702 // Get the receiver from the stack. | |
| 1703 const int argc = arguments().immediate(); | |
| 1704 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1705 | |
| 1706 // Check that the receiver isn't a smi. | |
| 1707 __ JumpIfSmi(edx, &miss); | |
| 1708 | |
| 1709 // Do the right check and compute the holder register. | |
| 1710 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi, | |
| 1711 name, &miss); | |
| 1712 | 1656 |
| 1713 GenerateFastPropertyLoad( | 1657 GenerateFastPropertyLoad( |
| 1714 masm(), edi, reg, index.is_inobject(holder), | 1658 masm(), edi, reg, index.is_inobject(holder), |
| 1715 index.translate(holder), Representation::Tagged()); | 1659 index.translate(holder), Representation::Tagged()); |
| 1660 GenerateJumpFunction(object, edi, &miss); |
| 1716 | 1661 |
| 1717 // Check that the function really is a function. | 1662 HandlerFrontendFooter(&miss); |
| 1718 __ JumpIfSmi(edi, &miss); | |
| 1719 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | |
| 1720 __ j(not_equal, &miss); | |
| 1721 | |
| 1722 // Patch the receiver on the stack with the global proxy if | |
| 1723 // necessary. | |
| 1724 if (object->IsGlobalObject()) { | |
| 1725 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | |
| 1726 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | |
| 1727 } | |
| 1728 | |
| 1729 // Invoke the function. | |
| 1730 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | |
| 1731 ? CALL_AS_FUNCTION | |
| 1732 : CALL_AS_METHOD; | |
| 1733 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, | |
| 1734 NullCallWrapper(), call_kind); | |
| 1735 | |
| 1736 // Handle call cache miss. | |
| 1737 __ bind(&miss); | |
| 1738 GenerateMissBranch(); | |
| 1739 | 1663 |
| 1740 // Return the generated code. | 1664 // Return the generated code. |
| 1741 return GetCode(Code::FAST, name); | 1665 return GetCode(Code::FAST, name); |
| 1742 } | 1666 } |
| 1743 | 1667 |
| 1744 | 1668 |
| 1745 Handle<Code> CallStubCompiler::CompileArrayCodeCall( | 1669 Handle<Code> CallStubCompiler::CompileArrayCodeCall( |
| 1746 Handle<Object> object, | 1670 Handle<Object> object, |
| 1747 Handle<JSObject> holder, | 1671 Handle<JSObject> holder, |
| 1748 Handle<Cell> cell, | 1672 Handle<Cell> cell, |
| 1749 Handle<JSFunction> function, | 1673 Handle<JSFunction> function, |
| 1750 Handle<String> name, | 1674 Handle<String> name, |
| 1751 Code::StubType type) { | 1675 Code::StubType type) { |
| 1752 Label miss; | 1676 Label miss; |
| 1753 | 1677 |
| 1754 // Check that function is still array | 1678 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 1755 const int argc = arguments().immediate(); | 1679 if (!cell.is_null()) { |
| 1756 GenerateNameCheck(name, &miss); | |
| 1757 | |
| 1758 if (cell.is_null()) { | |
| 1759 // Get the receiver from the stack. | |
| 1760 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1761 | |
| 1762 // Check that the receiver isn't a smi. | |
| 1763 __ JumpIfSmi(edx, &miss); | |
| 1764 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, | |
| 1765 name, &miss); | |
| 1766 } else { | |
| 1767 ASSERT(cell->value() == *function); | 1680 ASSERT(cell->value() == *function); |
| 1768 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, | |
| 1769 &miss); | |
| 1770 GenerateLoadFunctionFromCell(cell, function, &miss); | 1681 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 1771 } | 1682 } |
| 1772 | 1683 |
| 1773 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); | 1684 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); |
| 1774 site->SetElementsKind(GetInitialFastElementsKind()); | 1685 site->SetElementsKind(GetInitialFastElementsKind()); |
| 1775 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); | 1686 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); |
| 1687 const int argc = arguments().immediate(); |
| 1776 __ mov(eax, Immediate(argc)); | 1688 __ mov(eax, Immediate(argc)); |
| 1777 __ mov(ebx, site_feedback_cell); | 1689 __ mov(ebx, site_feedback_cell); |
| 1778 __ mov(edi, function); | 1690 __ mov(edi, function); |
| 1779 | 1691 |
| 1780 ArrayConstructorStub stub(isolate()); | 1692 ArrayConstructorStub stub(isolate()); |
| 1781 __ TailCallStub(&stub); | 1693 __ TailCallStub(&stub); |
| 1782 | 1694 |
| 1783 __ bind(&miss); | 1695 HandlerFrontendFooter(&miss); |
| 1784 GenerateMissBranch(); | |
| 1785 | 1696 |
| 1786 // Return the generated code. | 1697 // Return the generated code. |
| 1787 return GetCode(type, name); | 1698 return GetCode(type, name); |
| 1788 } | 1699 } |
| 1789 | 1700 |
| 1790 | 1701 |
| 1791 Handle<Code> CallStubCompiler::CompileArrayPushCall( | 1702 Handle<Code> CallStubCompiler::CompileArrayPushCall( |
| 1792 Handle<Object> object, | 1703 Handle<Object> object, |
| 1793 Handle<JSObject> holder, | 1704 Handle<JSObject> holder, |
| 1794 Handle<Cell> cell, | 1705 Handle<Cell> cell, |
| 1795 Handle<JSFunction> function, | 1706 Handle<JSFunction> function, |
| 1796 Handle<String> name, | 1707 Handle<String> name, |
| 1797 Code::StubType type) { | 1708 Code::StubType type) { |
| 1798 // ----------- S t a t e ------------- | 1709 // If object is not an array or is observed or sealed, bail out to regular |
| 1799 // -- ecx : name | 1710 // call. |
| 1800 // -- esp[0] : return address | |
| 1801 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 1802 // -- ... | |
| 1803 // -- esp[(argc + 1) * 4] : receiver | |
| 1804 // ----------------------------------- | |
| 1805 | |
| 1806 // If object is not an array or is observed, bail out to regular call. | |
| 1807 if (!object->IsJSArray() || | 1711 if (!object->IsJSArray() || |
| 1808 !cell.is_null() || | 1712 !cell.is_null() || |
| 1809 Handle<JSArray>::cast(object)->map()->is_observed()) { | 1713 Handle<JSArray>::cast(object)->map()->is_observed() || |
| 1714 !Handle<JSArray>::cast(object)->map()->is_extensible()) { |
| 1810 return Handle<Code>::null(); | 1715 return Handle<Code>::null(); |
| 1811 } | 1716 } |
| 1812 | 1717 |
| 1813 Label miss; | 1718 Label miss; |
| 1814 | 1719 |
| 1815 GenerateNameCheck(name, &miss); | 1720 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 1816 | 1721 |
| 1817 // Get the receiver from the stack. | |
| 1818 const int argc = arguments().immediate(); | 1722 const int argc = arguments().immediate(); |
| 1819 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1820 | |
| 1821 // Check that the receiver isn't a smi. | |
| 1822 __ JumpIfSmi(edx, &miss); | |
| 1823 | |
| 1824 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, | |
| 1825 name, &miss); | |
| 1826 | |
| 1827 if (argc == 0) { | 1723 if (argc == 0) { |
| 1828 // Noop, return the length. | 1724 // Noop, return the length. |
| 1829 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | 1725 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1830 __ ret((argc + 1) * kPointerSize); | 1726 __ ret((argc + 1) * kPointerSize); |
| 1831 } else { | 1727 } else { |
| 1832 Label call_builtin; | 1728 Label call_builtin; |
| 1833 | 1729 |
| 1834 if (argc == 1) { // Otherwise fall through to call builtin. | 1730 if (argc == 1) { // Otherwise fall through to call builtin. |
| 1835 Label attempt_to_grow_elements, with_write_barrier, check_double; | 1731 Label attempt_to_grow_elements, with_write_barrier, check_double; |
| 1836 | 1732 |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2034 __ ret((argc + 1) * kPointerSize); | 1930 __ ret((argc + 1) * kPointerSize); |
| 2035 } | 1931 } |
| 2036 | 1932 |
| 2037 __ bind(&call_builtin); | 1933 __ bind(&call_builtin); |
| 2038 __ TailCallExternalReference( | 1934 __ TailCallExternalReference( |
| 2039 ExternalReference(Builtins::c_ArrayPush, isolate()), | 1935 ExternalReference(Builtins::c_ArrayPush, isolate()), |
| 2040 argc + 1, | 1936 argc + 1, |
| 2041 1); | 1937 1); |
| 2042 } | 1938 } |
| 2043 | 1939 |
| 2044 __ bind(&miss); | 1940 HandlerFrontendFooter(&miss); |
| 2045 GenerateMissBranch(); | |
| 2046 | 1941 |
| 2047 // Return the generated code. | 1942 // Return the generated code. |
| 2048 return GetCode(type, name); | 1943 return GetCode(type, name); |
| 2049 } | 1944 } |
| 2050 | 1945 |
| 2051 | 1946 |
| 2052 Handle<Code> CallStubCompiler::CompileArrayPopCall( | 1947 Handle<Code> CallStubCompiler::CompileArrayPopCall( |
| 2053 Handle<Object> object, | 1948 Handle<Object> object, |
| 2054 Handle<JSObject> holder, | 1949 Handle<JSObject> holder, |
| 2055 Handle<Cell> cell, | 1950 Handle<Cell> cell, |
| 2056 Handle<JSFunction> function, | 1951 Handle<JSFunction> function, |
| 2057 Handle<String> name, | 1952 Handle<String> name, |
| 2058 Code::StubType type) { | 1953 Code::StubType type) { |
| 2059 // ----------- S t a t e ------------- | 1954 // If object is not an array or is observed or sealed, bail out to regular |
| 2060 // -- ecx : name | 1955 // call. |
| 2061 // -- esp[0] : return address | |
| 2062 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2063 // -- ... | |
| 2064 // -- esp[(argc + 1) * 4] : receiver | |
| 2065 // ----------------------------------- | |
| 2066 | |
| 2067 // If object is not an array or is observed, bail out to regular call. | |
| 2068 if (!object->IsJSArray() || | 1956 if (!object->IsJSArray() || |
| 2069 !cell.is_null() || | 1957 !cell.is_null() || |
| 2070 Handle<JSArray>::cast(object)->map()->is_observed()) { | 1958 Handle<JSArray>::cast(object)->map()->is_observed() || |
| 1959 !Handle<JSArray>::cast(object)->map()->is_extensible()) { |
| 2071 return Handle<Code>::null(); | 1960 return Handle<Code>::null(); |
| 2072 } | 1961 } |
| 2073 | 1962 |
| 2074 Label miss, return_undefined, call_builtin; | 1963 Label miss, return_undefined, call_builtin; |
| 2075 | 1964 |
| 2076 GenerateNameCheck(name, &miss); | 1965 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 2077 | |
| 2078 // Get the receiver from the stack. | |
| 2079 const int argc = arguments().immediate(); | |
| 2080 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 2081 | |
| 2082 // Check that the receiver isn't a smi. | |
| 2083 __ JumpIfSmi(edx, &miss); | |
| 2084 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, | |
| 2085 name, &miss); | |
| 2086 | 1966 |
| 2087 // Get the elements array of the object. | 1967 // Get the elements array of the object. |
| 2088 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1968 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 2089 | 1969 |
| 2090 // Check that the elements are in fast mode and writable. | 1970 // Check that the elements are in fast mode and writable. |
| 2091 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1971 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 2092 Immediate(factory()->fixed_array_map())); | 1972 Immediate(factory()->fixed_array_map())); |
| 2093 __ j(not_equal, &call_builtin); | 1973 __ j(not_equal, &call_builtin); |
| 2094 | 1974 |
| 2095 // Get the array's length into ecx and calculate new length. | 1975 // Get the array's length into ecx and calculate new length. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2107 __ j(equal, &call_builtin); | 1987 __ j(equal, &call_builtin); |
| 2108 | 1988 |
| 2109 // Set the array's length. | 1989 // Set the array's length. |
| 2110 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); | 1990 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); |
| 2111 | 1991 |
| 2112 // Fill with the hole. | 1992 // Fill with the hole. |
| 2113 __ mov(FieldOperand(ebx, | 1993 __ mov(FieldOperand(ebx, |
| 2114 ecx, times_half_pointer_size, | 1994 ecx, times_half_pointer_size, |
| 2115 FixedArray::kHeaderSize), | 1995 FixedArray::kHeaderSize), |
| 2116 Immediate(factory()->the_hole_value())); | 1996 Immediate(factory()->the_hole_value())); |
| 1997 const int argc = arguments().immediate(); |
| 2117 __ ret((argc + 1) * kPointerSize); | 1998 __ ret((argc + 1) * kPointerSize); |
| 2118 | 1999 |
| 2119 __ bind(&return_undefined); | 2000 __ bind(&return_undefined); |
| 2120 __ mov(eax, Immediate(factory()->undefined_value())); | 2001 __ mov(eax, Immediate(factory()->undefined_value())); |
| 2121 __ ret((argc + 1) * kPointerSize); | 2002 __ ret((argc + 1) * kPointerSize); |
| 2122 | 2003 |
| 2123 __ bind(&call_builtin); | 2004 __ bind(&call_builtin); |
| 2124 __ TailCallExternalReference( | 2005 __ TailCallExternalReference( |
| 2125 ExternalReference(Builtins::c_ArrayPop, isolate()), | 2006 ExternalReference(Builtins::c_ArrayPop, isolate()), |
| 2126 argc + 1, | 2007 argc + 1, |
| 2127 1); | 2008 1); |
| 2128 | 2009 |
| 2129 __ bind(&miss); | 2010 HandlerFrontendFooter(&miss); |
| 2130 GenerateMissBranch(); | |
| 2131 | 2011 |
| 2132 // Return the generated code. | 2012 // Return the generated code. |
| 2133 return GetCode(type, name); | 2013 return GetCode(type, name); |
| 2134 } | 2014 } |
| 2135 | 2015 |
| 2136 | 2016 |
| 2137 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( | 2017 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( |
| 2138 Handle<Object> object, | 2018 Handle<Object> object, |
| 2139 Handle<JSObject> holder, | 2019 Handle<JSObject> holder, |
| 2140 Handle<Cell> cell, | 2020 Handle<Cell> cell, |
| 2141 Handle<JSFunction> function, | 2021 Handle<JSFunction> function, |
| 2142 Handle<String> name, | 2022 Handle<String> name, |
| 2143 Code::StubType type) { | 2023 Code::StubType type) { |
| 2144 // ----------- S t a t e ------------- | |
| 2145 // -- ecx : function name | |
| 2146 // -- esp[0] : return address | |
| 2147 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2148 // -- ... | |
| 2149 // -- esp[(argc + 1) * 4] : receiver | |
| 2150 // ----------------------------------- | |
| 2151 | |
| 2152 // If object is not a string, bail out to regular call. | 2024 // If object is not a string, bail out to regular call. |
| 2153 if (!object->IsString() || !cell.is_null()) { | 2025 if (!object->IsString() || !cell.is_null()) { |
| 2154 return Handle<Code>::null(); | 2026 return Handle<Code>::null(); |
| 2155 } | 2027 } |
| 2156 | 2028 |
| 2157 const int argc = arguments().immediate(); | 2029 const int argc = arguments().immediate(); |
| 2158 | 2030 |
| 2159 Label miss; | 2031 Label miss; |
| 2160 Label name_miss; | 2032 Label name_miss; |
| 2161 Label index_out_of_range; | 2033 Label index_out_of_range; |
| 2162 Label* index_out_of_range_label = &index_out_of_range; | 2034 Label* index_out_of_range_label = &index_out_of_range; |
| 2163 | 2035 |
| 2164 if (kind_ == Code::CALL_IC && | 2036 if (kind_ == Code::CALL_IC && |
| 2165 (CallICBase::StringStubState::decode(extra_state_) == | 2037 (CallICBase::StringStubState::decode(extra_state()) == |
| 2166 DEFAULT_STRING_STUB)) { | 2038 DEFAULT_STRING_STUB)) { |
| 2167 index_out_of_range_label = &miss; | 2039 index_out_of_range_label = &miss; |
| 2168 } | 2040 } |
| 2169 | 2041 |
| 2170 GenerateNameCheck(name, &name_miss); | 2042 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); |
| 2171 | |
| 2172 // Check that the maps starting from the prototype haven't changed. | |
| 2173 GenerateDirectLoadGlobalFunctionPrototype(masm(), | |
| 2174 Context::STRING_FUNCTION_INDEX, | |
| 2175 eax, | |
| 2176 &miss); | |
| 2177 ASSERT(!object.is_identical_to(holder)); | |
| 2178 CheckPrototypes( | |
| 2179 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), | |
| 2180 eax, holder, ebx, edx, edi, name, &miss); | |
| 2181 | 2043 |
| 2182 Register receiver = ebx; | 2044 Register receiver = ebx; |
| 2183 Register index = edi; | 2045 Register index = edi; |
| 2184 Register result = eax; | 2046 Register result = eax; |
| 2185 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 2047 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 2186 if (argc > 0) { | 2048 if (argc > 0) { |
| 2187 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 2049 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 2188 } else { | 2050 } else { |
| 2189 __ Set(index, Immediate(factory()->undefined_value())); | 2051 __ Set(index, Immediate(factory()->undefined_value())); |
| 2190 } | 2052 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2204 | 2066 |
| 2205 if (index_out_of_range.is_linked()) { | 2067 if (index_out_of_range.is_linked()) { |
| 2206 __ bind(&index_out_of_range); | 2068 __ bind(&index_out_of_range); |
| 2207 __ Set(eax, Immediate(factory()->nan_value())); | 2069 __ Set(eax, Immediate(factory()->nan_value())); |
| 2208 __ ret((argc + 1) * kPointerSize); | 2070 __ ret((argc + 1) * kPointerSize); |
| 2209 } | 2071 } |
| 2210 | 2072 |
| 2211 __ bind(&miss); | 2073 __ bind(&miss); |
| 2212 // Restore function name in ecx. | 2074 // Restore function name in ecx. |
| 2213 __ Set(ecx, Immediate(name)); | 2075 __ Set(ecx, Immediate(name)); |
| 2214 __ bind(&name_miss); | 2076 HandlerFrontendFooter(&name_miss); |
| 2215 GenerateMissBranch(); | |
| 2216 | 2077 |
| 2217 // Return the generated code. | 2078 // Return the generated code. |
| 2218 return GetCode(type, name); | 2079 return GetCode(type, name); |
| 2219 } | 2080 } |
| 2220 | 2081 |
| 2221 | 2082 |
| 2222 Handle<Code> CallStubCompiler::CompileStringCharAtCall( | 2083 Handle<Code> CallStubCompiler::CompileStringCharAtCall( |
| 2223 Handle<Object> object, | 2084 Handle<Object> object, |
| 2224 Handle<JSObject> holder, | 2085 Handle<JSObject> holder, |
| 2225 Handle<Cell> cell, | 2086 Handle<Cell> cell, |
| 2226 Handle<JSFunction> function, | 2087 Handle<JSFunction> function, |
| 2227 Handle<String> name, | 2088 Handle<String> name, |
| 2228 Code::StubType type) { | 2089 Code::StubType type) { |
| 2229 // ----------- S t a t e ------------- | |
| 2230 // -- ecx : function name | |
| 2231 // -- esp[0] : return address | |
| 2232 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2233 // -- ... | |
| 2234 // -- esp[(argc + 1) * 4] : receiver | |
| 2235 // ----------------------------------- | |
| 2236 | |
| 2237 // If object is not a string, bail out to regular call. | 2090 // If object is not a string, bail out to regular call. |
| 2238 if (!object->IsString() || !cell.is_null()) { | 2091 if (!object->IsString() || !cell.is_null()) { |
| 2239 return Handle<Code>::null(); | 2092 return Handle<Code>::null(); |
| 2240 } | 2093 } |
| 2241 | 2094 |
| 2242 const int argc = arguments().immediate(); | 2095 const int argc = arguments().immediate(); |
| 2243 | 2096 |
| 2244 Label miss; | 2097 Label miss; |
| 2245 Label name_miss; | 2098 Label name_miss; |
| 2246 Label index_out_of_range; | 2099 Label index_out_of_range; |
| 2247 Label* index_out_of_range_label = &index_out_of_range; | 2100 Label* index_out_of_range_label = &index_out_of_range; |
| 2248 | 2101 |
| 2249 if (kind_ == Code::CALL_IC && | 2102 if (kind_ == Code::CALL_IC && |
| 2250 (CallICBase::StringStubState::decode(extra_state_) == | 2103 (CallICBase::StringStubState::decode(extra_state()) == |
| 2251 DEFAULT_STRING_STUB)) { | 2104 DEFAULT_STRING_STUB)) { |
| 2252 index_out_of_range_label = &miss; | 2105 index_out_of_range_label = &miss; |
| 2253 } | 2106 } |
| 2254 | 2107 |
| 2255 GenerateNameCheck(name, &name_miss); | 2108 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); |
| 2256 | |
| 2257 // Check that the maps starting from the prototype haven't changed. | |
| 2258 GenerateDirectLoadGlobalFunctionPrototype(masm(), | |
| 2259 Context::STRING_FUNCTION_INDEX, | |
| 2260 eax, | |
| 2261 &miss); | |
| 2262 ASSERT(!object.is_identical_to(holder)); | |
| 2263 CheckPrototypes( | |
| 2264 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), | |
| 2265 eax, holder, ebx, edx, edi, name, &miss); | |
| 2266 | 2109 |
| 2267 Register receiver = eax; | 2110 Register receiver = eax; |
| 2268 Register index = edi; | 2111 Register index = edi; |
| 2269 Register scratch = edx; | 2112 Register scratch = edx; |
| 2270 Register result = eax; | 2113 Register result = eax; |
| 2271 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 2114 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 2272 if (argc > 0) { | 2115 if (argc > 0) { |
| 2273 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 2116 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 2274 } else { | 2117 } else { |
| 2275 __ Set(index, Immediate(factory()->undefined_value())); | 2118 __ Set(index, Immediate(factory()->undefined_value())); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2291 | 2134 |
| 2292 if (index_out_of_range.is_linked()) { | 2135 if (index_out_of_range.is_linked()) { |
| 2293 __ bind(&index_out_of_range); | 2136 __ bind(&index_out_of_range); |
| 2294 __ Set(eax, Immediate(factory()->empty_string())); | 2137 __ Set(eax, Immediate(factory()->empty_string())); |
| 2295 __ ret((argc + 1) * kPointerSize); | 2138 __ ret((argc + 1) * kPointerSize); |
| 2296 } | 2139 } |
| 2297 | 2140 |
| 2298 __ bind(&miss); | 2141 __ bind(&miss); |
| 2299 // Restore function name in ecx. | 2142 // Restore function name in ecx. |
| 2300 __ Set(ecx, Immediate(name)); | 2143 __ Set(ecx, Immediate(name)); |
| 2301 __ bind(&name_miss); | 2144 HandlerFrontendFooter(&name_miss); |
| 2302 GenerateMissBranch(); | |
| 2303 | 2145 |
| 2304 // Return the generated code. | 2146 // Return the generated code. |
| 2305 return GetCode(type, name); | 2147 return GetCode(type, name); |
| 2306 } | 2148 } |
| 2307 | 2149 |
| 2308 | 2150 |
| 2309 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( | 2151 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( |
| 2310 Handle<Object> object, | 2152 Handle<Object> object, |
| 2311 Handle<JSObject> holder, | 2153 Handle<JSObject> holder, |
| 2312 Handle<Cell> cell, | 2154 Handle<Cell> cell, |
| 2313 Handle<JSFunction> function, | 2155 Handle<JSFunction> function, |
| 2314 Handle<String> name, | 2156 Handle<String> name, |
| 2315 Code::StubType type) { | 2157 Code::StubType type) { |
| 2316 // ----------- S t a t e ------------- | |
| 2317 // -- ecx : function name | |
| 2318 // -- esp[0] : return address | |
| 2319 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2320 // -- ... | |
| 2321 // -- esp[(argc + 1) * 4] : receiver | |
| 2322 // ----------------------------------- | |
| 2323 | |
| 2324 const int argc = arguments().immediate(); | 2158 const int argc = arguments().immediate(); |
| 2325 | 2159 |
| 2326 // If the object is not a JSObject or we got an unexpected number of | 2160 // If the object is not a JSObject or we got an unexpected number of |
| 2327 // arguments, bail out to the regular call. | 2161 // arguments, bail out to the regular call. |
| 2328 if (!object->IsJSObject() || argc != 1) { | 2162 if (!object->IsJSObject() || argc != 1) { |
| 2329 return Handle<Code>::null(); | 2163 return Handle<Code>::null(); |
| 2330 } | 2164 } |
| 2331 | 2165 |
| 2332 Label miss; | 2166 Label miss; |
| 2333 GenerateNameCheck(name, &miss); | |
| 2334 | 2167 |
| 2335 if (cell.is_null()) { | 2168 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 2336 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 2169 if (!cell.is_null()) { |
| 2337 STATIC_ASSERT(kSmiTag == 0); | |
| 2338 __ JumpIfSmi(edx, &miss); | |
| 2339 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, | |
| 2340 name, &miss); | |
| 2341 } else { | |
| 2342 ASSERT(cell->value() == *function); | 2170 ASSERT(cell->value() == *function); |
| 2343 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, | |
| 2344 &miss); | |
| 2345 GenerateLoadFunctionFromCell(cell, function, &miss); | 2171 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2346 } | 2172 } |
| 2347 | 2173 |
| 2348 // Load the char code argument. | 2174 // Load the char code argument. |
| 2349 Register code = ebx; | 2175 Register code = ebx; |
| 2350 __ mov(code, Operand(esp, 1 * kPointerSize)); | 2176 __ mov(code, Operand(esp, 1 * kPointerSize)); |
| 2351 | 2177 |
| 2352 // Check the code is a smi. | 2178 // Check the code is a smi. |
| 2353 Label slow; | 2179 Label slow; |
| 2354 STATIC_ASSERT(kSmiTag == 0); | 2180 STATIC_ASSERT(kSmiTag == 0); |
| 2355 __ JumpIfNotSmi(code, &slow); | 2181 __ JumpIfNotSmi(code, &slow); |
| 2356 | 2182 |
| 2357 // Convert the smi code to uint16. | 2183 // Convert the smi code to uint16. |
| 2358 __ and_(code, Immediate(Smi::FromInt(0xffff))); | 2184 __ and_(code, Immediate(Smi::FromInt(0xffff))); |
| 2359 | 2185 |
| 2360 StringCharFromCodeGenerator generator(code, eax); | 2186 StringCharFromCodeGenerator generator(code, eax); |
| 2361 generator.GenerateFast(masm()); | 2187 generator.GenerateFast(masm()); |
| 2362 __ ret(2 * kPointerSize); | 2188 __ ret(2 * kPointerSize); |
| 2363 | 2189 |
| 2364 StubRuntimeCallHelper call_helper; | 2190 StubRuntimeCallHelper call_helper; |
| 2365 generator.GenerateSlow(masm(), call_helper); | 2191 generator.GenerateSlow(masm(), call_helper); |
| 2366 | 2192 |
| 2367 // Tail call the full function. We do not have to patch the receiver | |
| 2368 // because the function makes no use of it. | |
| 2369 __ bind(&slow); | 2193 __ bind(&slow); |
| 2370 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 2194 // We do not have to patch the receiver because the function makes no use of |
| 2371 ? CALL_AS_FUNCTION | 2195 // it. |
| 2372 : CALL_AS_METHOD; | 2196 GenerateJumpFunctionIgnoreReceiver(function); |
| 2373 ParameterCount expected(function); | |
| 2374 __ InvokeFunction(function, expected, arguments(), | |
| 2375 JUMP_FUNCTION, NullCallWrapper(), call_kind); | |
| 2376 | 2197 |
| 2377 __ bind(&miss); | 2198 HandlerFrontendFooter(&miss); |
| 2378 // ecx: function name. | |
| 2379 GenerateMissBranch(); | |
| 2380 | 2199 |
| 2381 // Return the generated code. | 2200 // Return the generated code. |
| 2382 return GetCode(type, name); | 2201 return GetCode(type, name); |
| 2383 } | 2202 } |
| 2384 | 2203 |
| 2385 | 2204 |
| 2386 Handle<Code> CallStubCompiler::CompileMathFloorCall( | 2205 Handle<Code> CallStubCompiler::CompileMathFloorCall( |
| 2387 Handle<Object> object, | 2206 Handle<Object> object, |
| 2388 Handle<JSObject> holder, | 2207 Handle<JSObject> holder, |
| 2389 Handle<Cell> cell, | 2208 Handle<Cell> cell, |
| 2390 Handle<JSFunction> function, | 2209 Handle<JSFunction> function, |
| 2391 Handle<String> name, | 2210 Handle<String> name, |
| 2392 Code::StubType type) { | 2211 Code::StubType type) { |
| 2393 // ----------- S t a t e ------------- | |
| 2394 // -- ecx : name | |
| 2395 // -- esp[0] : return address | |
| 2396 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2397 // -- ... | |
| 2398 // -- esp[(argc + 1) * 4] : receiver | |
| 2399 // ----------------------------------- | |
| 2400 | |
| 2401 if (!CpuFeatures::IsSupported(SSE2)) { | 2212 if (!CpuFeatures::IsSupported(SSE2)) { |
| 2402 return Handle<Code>::null(); | 2213 return Handle<Code>::null(); |
| 2403 } | 2214 } |
| 2404 | 2215 |
| 2405 CpuFeatureScope use_sse2(masm(), SSE2); | 2216 CpuFeatureScope use_sse2(masm(), SSE2); |
| 2406 | 2217 |
| 2407 const int argc = arguments().immediate(); | 2218 const int argc = arguments().immediate(); |
| 2408 | 2219 |
| 2409 // If the object is not a JSObject or we got an unexpected number of | 2220 // If the object is not a JSObject or we got an unexpected number of |
| 2410 // arguments, bail out to the regular call. | 2221 // arguments, bail out to the regular call. |
| 2411 if (!object->IsJSObject() || argc != 1) { | 2222 if (!object->IsJSObject() || argc != 1) { |
| 2412 return Handle<Code>::null(); | 2223 return Handle<Code>::null(); |
| 2413 } | 2224 } |
| 2414 | 2225 |
| 2415 Label miss; | 2226 Label miss; |
| 2416 GenerateNameCheck(name, &miss); | |
| 2417 | 2227 |
| 2418 if (cell.is_null()) { | 2228 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 2419 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 2229 if (!cell.is_null()) { |
| 2420 | |
| 2421 STATIC_ASSERT(kSmiTag == 0); | |
| 2422 __ JumpIfSmi(edx, &miss); | |
| 2423 | |
| 2424 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, | |
| 2425 name, &miss); | |
| 2426 } else { | |
| 2427 ASSERT(cell->value() == *function); | 2230 ASSERT(cell->value() == *function); |
| 2428 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, | |
| 2429 &miss); | |
| 2430 GenerateLoadFunctionFromCell(cell, function, &miss); | 2231 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2431 } | 2232 } |
| 2432 | 2233 |
| 2433 // Load the (only) argument into eax. | 2234 // Load the (only) argument into eax. |
| 2434 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2235 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2435 | 2236 |
| 2436 // Check if the argument is a smi. | 2237 // Check if the argument is a smi. |
| 2437 Label smi; | 2238 Label smi; |
| 2438 STATIC_ASSERT(kSmiTag == 0); | 2239 STATIC_ASSERT(kSmiTag == 0); |
| 2439 __ JumpIfSmi(eax, &smi); | 2240 __ JumpIfSmi(eax, &smi); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2492 // Return a new heap number. | 2293 // Return a new heap number. |
| 2493 __ AllocateHeapNumber(eax, ebx, edx, &slow); | 2294 __ AllocateHeapNumber(eax, ebx, edx, &slow); |
| 2494 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 2295 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 2495 __ ret(2 * kPointerSize); | 2296 __ ret(2 * kPointerSize); |
| 2496 | 2297 |
| 2497 // Return the argument (when it's an already round heap number). | 2298 // Return the argument (when it's an already round heap number). |
| 2498 __ bind(&already_round); | 2299 __ bind(&already_round); |
| 2499 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2300 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2500 __ ret(2 * kPointerSize); | 2301 __ ret(2 * kPointerSize); |
| 2501 | 2302 |
| 2502 // Tail call the full function. We do not have to patch the receiver | |
| 2503 // because the function makes no use of it. | |
| 2504 __ bind(&slow); | 2303 __ bind(&slow); |
| 2505 ParameterCount expected(function); | 2304 // We do not have to patch the receiver because the function makes no use of |
| 2506 __ InvokeFunction(function, expected, arguments(), | 2305 // it. |
| 2507 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); | 2306 GenerateJumpFunctionIgnoreReceiver(function); |
| 2508 | 2307 |
| 2509 __ bind(&miss); | 2308 HandlerFrontendFooter(&miss); |
| 2510 // ecx: function name. | |
| 2511 GenerateMissBranch(); | |
| 2512 | 2309 |
| 2513 // Return the generated code. | 2310 // Return the generated code. |
| 2514 return GetCode(type, name); | 2311 return GetCode(type, name); |
| 2515 } | 2312 } |
| 2516 | 2313 |
| 2517 | 2314 |
| 2518 Handle<Code> CallStubCompiler::CompileMathAbsCall( | 2315 Handle<Code> CallStubCompiler::CompileMathAbsCall( |
| 2519 Handle<Object> object, | 2316 Handle<Object> object, |
| 2520 Handle<JSObject> holder, | 2317 Handle<JSObject> holder, |
| 2521 Handle<Cell> cell, | 2318 Handle<Cell> cell, |
| 2522 Handle<JSFunction> function, | 2319 Handle<JSFunction> function, |
| 2523 Handle<String> name, | 2320 Handle<String> name, |
| 2524 Code::StubType type) { | 2321 Code::StubType type) { |
| 2525 // ----------- S t a t e ------------- | |
| 2526 // -- ecx : name | |
| 2527 // -- esp[0] : return address | |
| 2528 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2529 // -- ... | |
| 2530 // -- esp[(argc + 1) * 4] : receiver | |
| 2531 // ----------------------------------- | |
| 2532 | |
| 2533 const int argc = arguments().immediate(); | 2322 const int argc = arguments().immediate(); |
| 2534 | 2323 |
| 2535 // If the object is not a JSObject or we got an unexpected number of | 2324 // If the object is not a JSObject or we got an unexpected number of |
| 2536 // arguments, bail out to the regular call. | 2325 // arguments, bail out to the regular call. |
| 2537 if (!object->IsJSObject() || argc != 1) { | 2326 if (!object->IsJSObject() || argc != 1) { |
| 2538 return Handle<Code>::null(); | 2327 return Handle<Code>::null(); |
| 2539 } | 2328 } |
| 2540 | 2329 |
| 2541 Label miss; | 2330 Label miss; |
| 2542 GenerateNameCheck(name, &miss); | |
| 2543 | 2331 |
| 2544 if (cell.is_null()) { | 2332 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 2545 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 2333 if (!cell.is_null()) { |
| 2546 | |
| 2547 STATIC_ASSERT(kSmiTag == 0); | |
| 2548 __ JumpIfSmi(edx, &miss); | |
| 2549 | |
| 2550 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, | |
| 2551 name, &miss); | |
| 2552 } else { | |
| 2553 ASSERT(cell->value() == *function); | 2334 ASSERT(cell->value() == *function); |
| 2554 GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, | |
| 2555 &miss); | |
| 2556 GenerateLoadFunctionFromCell(cell, function, &miss); | 2335 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2557 } | 2336 } |
| 2558 | 2337 |
| 2559 // Load the (only) argument into eax. | 2338 // Load the (only) argument into eax. |
| 2560 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2339 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2561 | 2340 |
| 2562 // Check if the argument is a smi. | 2341 // Check if the argument is a smi. |
| 2563 Label not_smi; | 2342 Label not_smi; |
| 2564 STATIC_ASSERT(kSmiTag == 0); | 2343 STATIC_ASSERT(kSmiTag == 0); |
| 2565 __ JumpIfNotSmi(eax, ¬_smi); | 2344 __ JumpIfNotSmi(eax, ¬_smi); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2601 // If the argument is negative, clear the sign, and return a new | 2380 // If the argument is negative, clear the sign, and return a new |
| 2602 // number. | 2381 // number. |
| 2603 __ bind(&negative_sign); | 2382 __ bind(&negative_sign); |
| 2604 __ and_(ebx, ~HeapNumber::kSignMask); | 2383 __ and_(ebx, ~HeapNumber::kSignMask); |
| 2605 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset)); | 2384 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset)); |
| 2606 __ AllocateHeapNumber(eax, edi, edx, &slow); | 2385 __ AllocateHeapNumber(eax, edi, edx, &slow); |
| 2607 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx); | 2386 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx); |
| 2608 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); | 2387 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); |
| 2609 __ ret(2 * kPointerSize); | 2388 __ ret(2 * kPointerSize); |
| 2610 | 2389 |
| 2611 // Tail call the full function. We do not have to patch the receiver | |
| 2612 // because the function makes no use of it. | |
| 2613 __ bind(&slow); | 2390 __ bind(&slow); |
| 2614 ParameterCount expected(function); | 2391 // We do not have to patch the receiver because the function makes no use of |
| 2615 __ InvokeFunction(function, expected, arguments(), | 2392 // it. |
| 2616 JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); | 2393 GenerateJumpFunctionIgnoreReceiver(function); |
| 2617 | 2394 |
| 2618 __ bind(&miss); | 2395 HandlerFrontendFooter(&miss); |
| 2619 // ecx: function name. | |
| 2620 GenerateMissBranch(); | |
| 2621 | 2396 |
| 2622 // Return the generated code. | 2397 // Return the generated code. |
| 2623 return GetCode(type, name); | 2398 return GetCode(type, name); |
| 2624 } | 2399 } |
| 2625 | 2400 |
| 2626 | 2401 |
| 2627 Handle<Code> CallStubCompiler::CompileFastApiCall( | 2402 Handle<Code> CallStubCompiler::CompileFastApiCall( |
| 2628 const CallOptimization& optimization, | 2403 const CallOptimization& optimization, |
| 2629 Handle<Object> object, | 2404 Handle<Object> object, |
| 2630 Handle<JSObject> holder, | 2405 Handle<JSObject> holder, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2654 | 2429 |
| 2655 Counters* counters = isolate()->counters(); | 2430 Counters* counters = isolate()->counters(); |
| 2656 __ IncrementCounter(counters->call_const(), 1); | 2431 __ IncrementCounter(counters->call_const(), 1); |
| 2657 __ IncrementCounter(counters->call_const_fast_api(), 1); | 2432 __ IncrementCounter(counters->call_const_fast_api(), 1); |
| 2658 | 2433 |
| 2659 // Allocate space for v8::Arguments implicit values. Must be initialized | 2434 // Allocate space for v8::Arguments implicit values. Must be initialized |
| 2660 // before calling any runtime function. | 2435 // before calling any runtime function. |
| 2661 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); | 2436 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
| 2662 | 2437 |
| 2663 // Check that the maps haven't changed and find a Holder as a side effect. | 2438 // Check that the maps haven't changed and find a Holder as a side effect. |
| 2664 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi, | 2439 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, |
| 2665 name, depth, &miss); | 2440 ebx, eax, edi, name, depth, &miss); |
| 2666 | 2441 |
| 2667 // Move the return address on top of the stack. | 2442 // Move the return address on top of the stack. |
| 2668 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); | 2443 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); |
| 2669 __ mov(Operand(esp, 0 * kPointerSize), eax); | 2444 __ mov(Operand(esp, 0 * kPointerSize), eax); |
| 2670 | 2445 |
| 2671 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains | 2446 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains |
| 2672 // duplicate of return address and will be overwritten. | 2447 // duplicate of return address and will be overwritten. |
| 2673 GenerateFastApiCall(masm(), optimization, argc); | 2448 GenerateFastApiCall(masm(), optimization, argc); |
| 2674 | 2449 |
| 2675 __ bind(&miss); | 2450 __ bind(&miss); |
| 2676 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); | 2451 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
| 2677 | 2452 |
| 2678 __ bind(&miss_before_stack_reserved); | 2453 HandlerFrontendFooter(&miss_before_stack_reserved); |
| 2679 GenerateMissBranch(); | |
| 2680 | 2454 |
| 2681 // Return the generated code. | 2455 // Return the generated code. |
| 2682 return GetCode(function); | 2456 return GetCode(function); |
| 2683 } | 2457 } |
| 2684 | 2458 |
| 2685 | 2459 |
| 2686 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 2460 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 2687 Label success; | 2461 Label success; |
| 2688 // Check that the object is a boolean. | 2462 // Check that the object is a boolean. |
| 2689 __ cmp(object, factory()->true_value()); | 2463 __ cmp(object, factory()->true_value()); |
| 2690 __ j(equal, &success); | 2464 __ j(equal, &success); |
| 2691 __ cmp(object, factory()->false_value()); | 2465 __ cmp(object, factory()->false_value()); |
| 2692 __ j(not_equal, miss); | 2466 __ j(not_equal, miss); |
| 2693 __ bind(&success); | 2467 __ bind(&success); |
| 2694 } | 2468 } |
| 2695 | 2469 |
| 2696 | 2470 |
| 2697 void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object, | 2471 void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) { |
| 2698 Handle<JSObject> holder, | 2472 if (object->IsGlobalObject()) { |
| 2699 Handle<Name> name, | 2473 const int argc = arguments().immediate(); |
| 2700 CheckType check) { | 2474 const int receiver_offset = (argc + 1) * kPointerSize; |
| 2701 // ----------- S t a t e ------------- | 2475 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2702 // -- ecx : name | 2476 __ mov(Operand(esp, receiver_offset), edx); |
| 2703 // -- esp[0] : return address | 2477 } |
| 2704 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 2478 } |
| 2705 // -- ... | |
| 2706 // -- esp[(argc + 1) * 4] : receiver | |
| 2707 // ----------------------------------- | |
| 2708 Label miss; | |
| 2709 GenerateNameCheck(name, &miss); | |
| 2710 | 2479 |
| 2711 // Get the receiver from the stack. | 2480 |
| 2481 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, |
| 2482 Handle<JSObject> holder, |
| 2483 Handle<Name> name, |
| 2484 CheckType check, |
| 2485 Label* miss) { |
| 2486 GenerateNameCheck(name, miss); |
| 2487 |
| 2488 Register reg = edx; |
| 2489 |
| 2712 const int argc = arguments().immediate(); | 2490 const int argc = arguments().immediate(); |
| 2713 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2491 const int receiver_offset = (argc + 1) * kPointerSize; |
| 2492 __ mov(reg, Operand(esp, receiver_offset)); |
| 2714 | 2493 |
| 2715 // Check that the receiver isn't a smi. | 2494 // Check that the receiver isn't a smi. |
| 2716 if (check != NUMBER_CHECK) { | 2495 if (check != NUMBER_CHECK) { |
| 2717 __ JumpIfSmi(edx, &miss); | 2496 __ JumpIfSmi(reg, miss); |
| 2718 } | 2497 } |
| 2719 | 2498 |
| 2720 // Make sure that it's okay not to patch the on stack receiver | 2499 // Make sure that it's okay not to patch the on stack receiver |
| 2721 // unless we're doing a receiver map check. | 2500 // unless we're doing a receiver map check. |
| 2722 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 2501 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
| 2723 switch (check) { | 2502 switch (check) { |
| 2724 case RECEIVER_MAP_CHECK: | 2503 case RECEIVER_MAP_CHECK: |
| 2725 __ IncrementCounter(isolate()->counters()->call_const(), 1); | 2504 __ IncrementCounter(isolate()->counters()->call_const(), 1); |
| 2726 | 2505 |
| 2727 // Check that the maps haven't changed. | 2506 // Check that the maps haven't changed. |
| 2728 CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, | 2507 reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), reg, holder, |
| 2729 edi, name, &miss); | 2508 ebx, eax, edi, name, miss); |
| 2730 | 2509 |
| 2731 // Patch the receiver on the stack with the global proxy if | |
| 2732 // necessary. | |
| 2733 if (object->IsGlobalObject()) { | |
| 2734 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | |
| 2735 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | |
| 2736 } | |
| 2737 break; | 2510 break; |
| 2738 | 2511 |
| 2739 case STRING_CHECK: | 2512 case STRING_CHECK: { |
| 2740 // Check that the object is a string. | 2513 // Check that the object is a string. |
| 2741 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); | 2514 __ CmpObjectType(reg, FIRST_NONSTRING_TYPE, eax); |
| 2742 __ j(above_equal, &miss); | 2515 __ j(above_equal, miss); |
| 2743 // Check that the maps starting from the prototype haven't changed. | 2516 // Check that the maps starting from the prototype haven't changed. |
| 2744 GenerateDirectLoadGlobalFunctionPrototype( | 2517 GenerateDirectLoadGlobalFunctionPrototype( |
| 2745 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); | 2518 masm(), Context::STRING_FUNCTION_INDEX, eax, miss); |
| 2746 CheckPrototypes( | |
| 2747 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), | |
| 2748 eax, holder, ebx, edx, edi, name, &miss); | |
| 2749 break; | 2519 break; |
| 2750 | 2520 } |
| 2751 case SYMBOL_CHECK: | 2521 case SYMBOL_CHECK: { |
| 2752 // Check that the object is a symbol. | 2522 // Check that the object is a symbol. |
| 2753 __ CmpObjectType(edx, SYMBOL_TYPE, eax); | 2523 __ CmpObjectType(reg, SYMBOL_TYPE, eax); |
| 2754 __ j(not_equal, &miss); | 2524 __ j(not_equal, miss); |
| 2755 // Check that the maps starting from the prototype haven't changed. | 2525 // Check that the maps starting from the prototype haven't changed. |
| 2756 GenerateDirectLoadGlobalFunctionPrototype( | 2526 GenerateDirectLoadGlobalFunctionPrototype( |
| 2757 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss); | 2527 masm(), Context::SYMBOL_FUNCTION_INDEX, eax, miss); |
| 2758 CheckPrototypes( | |
| 2759 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), | |
| 2760 eax, holder, ebx, edx, edi, name, &miss); | |
| 2761 break; | 2528 break; |
| 2762 | 2529 } |
| 2763 case NUMBER_CHECK: { | 2530 case NUMBER_CHECK: { |
| 2764 Label fast; | 2531 Label fast; |
| 2765 // Check that the object is a smi or a heap number. | 2532 // Check that the object is a smi or a heap number. |
| 2766 __ JumpIfSmi(edx, &fast); | 2533 __ JumpIfSmi(reg, &fast); |
| 2767 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); | 2534 __ CmpObjectType(reg, HEAP_NUMBER_TYPE, eax); |
| 2768 __ j(not_equal, &miss); | 2535 __ j(not_equal, miss); |
| 2769 __ bind(&fast); | 2536 __ bind(&fast); |
| 2770 // Check that the maps starting from the prototype haven't changed. | 2537 // Check that the maps starting from the prototype haven't changed. |
| 2771 GenerateDirectLoadGlobalFunctionPrototype( | 2538 GenerateDirectLoadGlobalFunctionPrototype( |
| 2772 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); | 2539 masm(), Context::NUMBER_FUNCTION_INDEX, eax, miss); |
| 2773 CheckPrototypes( | |
| 2774 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), | |
| 2775 eax, holder, ebx, edx, edi, name, &miss); | |
| 2776 break; | 2540 break; |
| 2777 } | 2541 } |
| 2778 case BOOLEAN_CHECK: { | 2542 case BOOLEAN_CHECK: { |
| 2779 GenerateBooleanCheck(edx, &miss); | 2543 GenerateBooleanCheck(reg, miss); |
| 2780 // Check that the maps starting from the prototype haven't changed. | 2544 // Check that the maps starting from the prototype haven't changed. |
| 2781 GenerateDirectLoadGlobalFunctionPrototype( | 2545 GenerateDirectLoadGlobalFunctionPrototype( |
| 2782 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); | 2546 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, miss); |
| 2783 CheckPrototypes( | |
| 2784 Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))), | |
| 2785 eax, holder, ebx, edx, edi, name, &miss); | |
| 2786 break; | 2547 break; |
| 2787 } | 2548 } |
| 2788 } | 2549 } |
| 2789 | 2550 |
| 2790 Label success; | 2551 if (check != RECEIVER_MAP_CHECK) { |
| 2791 __ jmp(&success); | 2552 Handle<Object> prototype(object->GetPrototype(isolate()), isolate()); |
| 2553 reg = CheckPrototypes( |
| 2554 IC::CurrentTypeOf(prototype, isolate()), |
| 2555 eax, holder, ebx, edx, edi, name, miss); |
| 2556 } |
| 2792 | 2557 |
| 2793 // Handle call cache miss. | 2558 return reg; |
| 2794 __ bind(&miss); | |
| 2795 GenerateMissBranch(); | |
| 2796 | |
| 2797 __ bind(&success); | |
| 2798 } | 2559 } |
| 2799 | 2560 |
| 2800 | 2561 |
| 2801 void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) { | 2562 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, |
| 2802 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | 2563 Register function, |
| 2803 ? CALL_AS_FUNCTION | 2564 Label* miss) { |
| 2804 : CALL_AS_METHOD; | 2565 // Check that the function really is a function. |
| 2805 ParameterCount expected(function); | 2566 GenerateFunctionCheck(function, ebx, miss); |
| 2806 __ InvokeFunction(function, expected, arguments(), | |
| 2807 JUMP_FUNCTION, NullCallWrapper(), call_kind); | |
| 2808 } | |
| 2809 | 2567 |
| 2568 if (!function.is(edi)) __ mov(edi, function); |
| 2569 PatchGlobalProxy(object); |
| 2810 | 2570 |
| 2811 Handle<Code> CallStubCompiler::CompileCallConstant( | 2571 // Invoke the function. |
| 2812 Handle<Object> object, | 2572 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, |
| 2813 Handle<JSObject> holder, | 2573 NullCallWrapper(), call_kind()); |
| 2814 Handle<Name> name, | |
| 2815 CheckType check, | |
| 2816 Handle<JSFunction> function) { | |
| 2817 | |
| 2818 if (HasCustomCallGenerator(function)) { | |
| 2819 Handle<Code> code = CompileCustomCall(object, holder, | |
| 2820 Handle<Cell>::null(), | |
| 2821 function, Handle<String>::cast(name), | |
| 2822 Code::FAST); | |
| 2823 // A null handle means bail out to the regular compiler code below. | |
| 2824 if (!code.is_null()) return code; | |
| 2825 } | |
| 2826 | |
| 2827 CompileHandlerFrontend(object, holder, name, check); | |
| 2828 CompileHandlerBackend(function); | |
| 2829 | |
| 2830 // Return the generated code. | |
| 2831 return GetCode(function); | |
| 2832 } | 2574 } |
| 2833 | 2575 |
| 2834 | 2576 |
| 2835 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, | 2577 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, |
| 2836 Handle<JSObject> holder, | 2578 Handle<JSObject> holder, |
| 2837 Handle<Name> name) { | 2579 Handle<Name> name) { |
| 2838 // ----------- S t a t e ------------- | |
| 2839 // -- ecx : name | |
| 2840 // -- esp[0] : return address | |
| 2841 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2842 // -- ... | |
| 2843 // -- esp[(argc + 1) * 4] : receiver | |
| 2844 // ----------------------------------- | |
| 2845 Label miss; | 2580 Label miss; |
| 2846 | 2581 |
| 2847 GenerateNameCheck(name, &miss); | 2582 GenerateNameCheck(name, &miss); |
| 2848 | 2583 |
| 2849 // Get the number of arguments. | 2584 // Get the number of arguments. |
| 2850 const int argc = arguments().immediate(); | 2585 const int argc = arguments().immediate(); |
| 2851 | 2586 |
| 2852 LookupResult lookup(isolate()); | 2587 LookupResult lookup(isolate()); |
| 2853 LookupPostInterceptor(holder, name, &lookup); | 2588 LookupPostInterceptor(holder, name, &lookup); |
| 2854 | 2589 |
| 2855 // Get the receiver from the stack. | 2590 // Get the receiver from the stack. |
| 2856 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2591 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2857 | 2592 |
| 2858 CallInterceptorCompiler compiler(this, arguments(), ecx, extra_state_); | 2593 CallInterceptorCompiler compiler(this, arguments(), ecx); |
| 2859 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax, | 2594 compiler.Compile(masm(), object, holder, name, &lookup, edx, ebx, edi, eax, |
| 2860 &miss); | 2595 &miss); |
| 2861 | 2596 |
| 2862 // Restore receiver. | 2597 // Restore receiver. |
| 2863 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2598 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2864 | 2599 |
| 2865 // Check that the function really is a function. | 2600 GenerateJumpFunction(object, eax, &miss); |
| 2866 __ JumpIfSmi(eax, &miss); | |
| 2867 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | |
| 2868 __ j(not_equal, &miss); | |
| 2869 | 2601 |
| 2870 // Patch the receiver on the stack with the global proxy if | 2602 HandlerFrontendFooter(&miss); |
| 2871 // necessary. | |
| 2872 if (object->IsGlobalObject()) { | |
| 2873 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | |
| 2874 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | |
| 2875 } | |
| 2876 | |
| 2877 // Invoke the function. | |
| 2878 __ mov(edi, eax); | |
| 2879 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | |
| 2880 ? CALL_AS_FUNCTION | |
| 2881 : CALL_AS_METHOD; | |
| 2882 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION, | |
| 2883 NullCallWrapper(), call_kind); | |
| 2884 | |
| 2885 // Handle load cache miss. | |
| 2886 __ bind(&miss); | |
| 2887 GenerateMissBranch(); | |
| 2888 | 2603 |
| 2889 // Return the generated code. | 2604 // Return the generated code. |
| 2890 return GetCode(Code::FAST, name); | 2605 return GetCode(Code::FAST, name); |
| 2891 } | 2606 } |
| 2892 | 2607 |
| 2893 | 2608 |
| 2894 Handle<Code> CallStubCompiler::CompileCallGlobal( | 2609 Handle<Code> CallStubCompiler::CompileCallGlobal( |
| 2895 Handle<JSObject> object, | 2610 Handle<JSObject> object, |
| 2896 Handle<GlobalObject> holder, | 2611 Handle<GlobalObject> holder, |
| 2897 Handle<PropertyCell> cell, | 2612 Handle<PropertyCell> cell, |
| 2898 Handle<JSFunction> function, | 2613 Handle<JSFunction> function, |
| 2899 Handle<Name> name) { | 2614 Handle<Name> name) { |
| 2900 // ----------- S t a t e ------------- | |
| 2901 // -- ecx : name | |
| 2902 // -- esp[0] : return address | |
| 2903 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
| 2904 // -- ... | |
| 2905 // -- esp[(argc + 1) * 4] : receiver | |
| 2906 // ----------------------------------- | |
| 2907 | |
| 2908 if (HasCustomCallGenerator(function)) { | 2615 if (HasCustomCallGenerator(function)) { |
| 2909 Handle<Code> code = CompileCustomCall( | 2616 Handle<Code> code = CompileCustomCall( |
| 2910 object, holder, cell, function, Handle<String>::cast(name), | 2617 object, holder, cell, function, Handle<String>::cast(name), |
| 2911 Code::NORMAL); | 2618 Code::NORMAL); |
| 2912 // A null handle means bail out to the regular compiler code below. | 2619 // A null handle means bail out to the regular compiler code below. |
| 2913 if (!code.is_null()) return code; | 2620 if (!code.is_null()) return code; |
| 2914 } | 2621 } |
| 2915 | 2622 |
| 2916 Label miss; | 2623 Label miss; |
| 2917 GenerateNameCheck(name, &miss); | 2624 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); |
| 2625 // Potentially loads a closure that matches the shared function info of the |
| 2626 // function, rather than function. |
| 2627 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2628 GenerateJumpFunction(object, edi, function); |
| 2918 | 2629 |
| 2919 // Get the number of arguments. | 2630 HandlerFrontendFooter(&miss); |
| 2920 const int argc = arguments().immediate(); | |
| 2921 GenerateGlobalReceiverCheck(object, holder, name, &miss); | |
| 2922 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2923 | |
| 2924 // Patch the receiver on the stack with the global proxy. | |
| 2925 if (object->IsGlobalObject()) { | |
| 2926 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | |
| 2927 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | |
| 2928 } | |
| 2929 | |
| 2930 // Set up the context (function already in edi). | |
| 2931 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
| 2932 | |
| 2933 // Jump to the cached code (tail call). | |
| 2934 Counters* counters = isolate()->counters(); | |
| 2935 __ IncrementCounter(counters->call_global_inline(), 1); | |
| 2936 ParameterCount expected(function->shared()->formal_parameter_count()); | |
| 2937 CallKind call_kind = CallICBase::Contextual::decode(extra_state_) | |
| 2938 ? CALL_AS_FUNCTION | |
| 2939 : CALL_AS_METHOD; | |
| 2940 // We call indirectly through the code field in the function to | |
| 2941 // allow recompilation to take effect without changing any of the | |
| 2942 // call sites. | |
| 2943 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), | |
| 2944 expected, arguments(), JUMP_FUNCTION, | |
| 2945 NullCallWrapper(), call_kind); | |
| 2946 | |
| 2947 // Handle call cache miss. | |
| 2948 __ bind(&miss); | |
| 2949 __ IncrementCounter(counters->call_global_inline_miss(), 1); | |
| 2950 GenerateMissBranch(); | |
| 2951 | 2631 |
| 2952 // Return the generated code. | 2632 // Return the generated code. |
| 2953 return GetCode(Code::NORMAL, name); | 2633 return GetCode(Code::NORMAL, name); |
| 2954 } | 2634 } |
| 2955 | 2635 |
| 2956 | 2636 |
| 2957 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 2637 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2958 Handle<JSObject> object, | 2638 Handle<JSObject> object, |
| 2959 Handle<JSObject> holder, | 2639 Handle<JSObject> holder, |
| 2960 Handle<Name> name, | 2640 Handle<Name> name, |
| 2961 Handle<ExecutableAccessorInfo> callback) { | 2641 Handle<ExecutableAccessorInfo> callback) { |
| 2962 HandlerFrontend(object, receiver(), holder, name); | 2642 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), |
| 2643 receiver(), holder, name); |
| 2963 | 2644 |
| 2964 __ pop(scratch1()); // remove the return address | 2645 __ pop(scratch1()); // remove the return address |
| 2965 __ push(receiver()); | 2646 __ push(receiver()); |
| 2966 __ Push(callback); | 2647 __ Push(callback); |
| 2967 __ Push(name); | 2648 __ Push(name); |
| 2968 __ push(value()); | 2649 __ push(value()); |
| 2969 __ push(scratch1()); // restore return address | 2650 __ push(scratch1()); // restore return address |
| 2970 | 2651 |
| 2971 // Do tail-call to the runtime system. | 2652 // Do tail-call to the runtime system. |
| 2972 ExternalReference store_callback_property = | 2653 ExternalReference store_callback_property = |
| 2973 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); | 2654 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |
| 2974 __ TailCallExternalReference(store_callback_property, 4, 1); | 2655 __ TailCallExternalReference(store_callback_property, 4, 1); |
| 2975 | 2656 |
| 2976 // Return the generated code. | 2657 // Return the generated code. |
| 2977 return GetCode(kind(), Code::FAST, name); | 2658 return GetCode(kind(), Code::FAST, name); |
| 2978 } | 2659 } |
| 2979 | 2660 |
| 2980 | 2661 |
| 2981 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 2662 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2982 Handle<JSObject> object, | 2663 Handle<JSObject> object, |
| 2983 Handle<JSObject> holder, | 2664 Handle<JSObject> holder, |
| 2984 Handle<Name> name, | 2665 Handle<Name> name, |
| 2985 const CallOptimization& call_optimization) { | 2666 const CallOptimization& call_optimization) { |
| 2986 HandlerFrontend(object, receiver(), holder, name); | 2667 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), |
| 2668 receiver(), holder, name); |
| 2987 | 2669 |
| 2988 Register values[] = { value() }; | 2670 Register values[] = { value() }; |
| 2989 GenerateFastApiCall( | 2671 GenerateFastApiCall( |
| 2990 masm(), call_optimization, receiver(), scratch1(), | 2672 masm(), call_optimization, receiver(), scratch1(), |
| 2991 scratch2(), this->name(), 1, values); | 2673 scratch2(), this->name(), 1, values); |
| 2992 | 2674 |
| 2993 // Return the generated code. | 2675 // Return the generated code. |
| 2994 return GetCode(kind(), Code::FAST, name); | 2676 return GetCode(kind(), Code::FAST, name); |
| 2995 } | 2677 } |
| 2996 | 2678 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3042 #define __ ACCESS_MASM(masm()) | 2724 #define __ ACCESS_MASM(masm()) |
| 3043 | 2725 |
| 3044 | 2726 |
| 3045 Handle<Code> StoreStubCompiler::CompileStoreInterceptor( | 2727 Handle<Code> StoreStubCompiler::CompileStoreInterceptor( |
| 3046 Handle<JSObject> object, | 2728 Handle<JSObject> object, |
| 3047 Handle<Name> name) { | 2729 Handle<Name> name) { |
| 3048 __ pop(scratch1()); // remove the return address | 2730 __ pop(scratch1()); // remove the return address |
| 3049 __ push(receiver()); | 2731 __ push(receiver()); |
| 3050 __ push(this->name()); | 2732 __ push(this->name()); |
| 3051 __ push(value()); | 2733 __ push(value()); |
| 3052 __ push(Immediate(Smi::FromInt(strict_mode()))); | |
| 3053 __ push(scratch1()); // restore return address | 2734 __ push(scratch1()); // restore return address |
| 3054 | 2735 |
| 3055 // Do tail-call to the runtime system. | 2736 // Do tail-call to the runtime system. |
| 3056 ExternalReference store_ic_property = | 2737 ExternalReference store_ic_property = |
| 3057 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate()); | 2738 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate()); |
| 3058 __ TailCallExternalReference(store_ic_property, 4, 1); | 2739 __ TailCallExternalReference(store_ic_property, 3, 1); |
| 3059 | 2740 |
| 3060 // Return the generated code. | 2741 // Return the generated code. |
| 3061 return GetCode(kind(), Code::FAST, name); | 2742 return GetCode(kind(), Code::FAST, name); |
| 3062 } | 2743 } |
| 3063 | 2744 |
| 3064 | 2745 |
| 3065 Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic( | 2746 Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic( |
| 3066 MapHandleList* receiver_maps, | 2747 MapHandleList* receiver_maps, |
| 3067 CodeHandleList* handler_stubs, | 2748 CodeHandleList* handler_stubs, |
| 3068 MapHandleList* transitioned_maps) { | 2749 MapHandleList* transitioned_maps) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3083 } | 2764 } |
| 3084 __ bind(&miss); | 2765 __ bind(&miss); |
| 3085 TailCallBuiltin(masm(), MissBuiltin(kind())); | 2766 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 3086 | 2767 |
| 3087 // Return the generated code. | 2768 // Return the generated code. |
| 3088 return GetICCode( | 2769 return GetICCode( |
| 3089 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); | 2770 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); |
| 3090 } | 2771 } |
| 3091 | 2772 |
| 3092 | 2773 |
| 3093 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( | 2774 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type, |
| 3094 Handle<Object> object, | 2775 Handle<JSObject> last, |
| 3095 Handle<JSObject> last, | 2776 Handle<Name> name) { |
| 3096 Handle<Name> name, | 2777 NonexistentHandlerFrontend(type, last, name); |
| 3097 Handle<JSGlobalObject> global) { | |
| 3098 NonexistentHandlerFrontend(object, last, name, global); | |
| 3099 | 2778 |
| 3100 // Return undefined if maps of the full prototype chain are still the | 2779 // Return undefined if maps of the full prototype chain are still the |
| 3101 // same and no global property with this name contains a value. | 2780 // same and no global property with this name contains a value. |
| 3102 __ mov(eax, isolate()->factory()->undefined_value()); | 2781 __ mov(eax, isolate()->factory()->undefined_value()); |
| 3103 __ ret(0); | 2782 __ ret(0); |
| 3104 | 2783 |
| 3105 // Return the generated code. | 2784 // Return the generated code. |
| 3106 return GetCode(kind(), Code::FAST, name); | 2785 return GetCode(kind(), Code::FAST, name); |
| 3107 } | 2786 } |
| 3108 | 2787 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3179 } | 2858 } |
| 3180 __ ret(0); | 2859 __ ret(0); |
| 3181 } | 2860 } |
| 3182 | 2861 |
| 3183 | 2862 |
| 3184 #undef __ | 2863 #undef __ |
| 3185 #define __ ACCESS_MASM(masm()) | 2864 #define __ ACCESS_MASM(masm()) |
| 3186 | 2865 |
| 3187 | 2866 |
| 3188 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2867 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 3189 Handle<Object> object, | 2868 Handle<Type> type, |
| 3190 Handle<GlobalObject> global, | 2869 Handle<GlobalObject> global, |
| 3191 Handle<PropertyCell> cell, | 2870 Handle<PropertyCell> cell, |
| 3192 Handle<Name> name, | 2871 Handle<Name> name, |
| 3193 bool is_dont_delete) { | 2872 bool is_dont_delete) { |
| 3194 Label miss; | 2873 Label miss; |
| 3195 | 2874 |
| 3196 HandlerFrontendHeader(object, receiver(), global, name, &miss); | 2875 HandlerFrontendHeader(type, receiver(), global, name, &miss); |
| 3197 // Get the value from the cell. | 2876 // Get the value from the cell. |
| 3198 if (Serializer::enabled()) { | 2877 if (Serializer::enabled()) { |
| 3199 __ mov(eax, Immediate(cell)); | 2878 __ mov(eax, Immediate(cell)); |
| 3200 __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset)); | 2879 __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset)); |
| 3201 } else { | 2880 } else { |
| 3202 __ mov(eax, Operand::ForCell(cell)); | 2881 __ mov(eax, Operand::ForCell(cell)); |
| 3203 } | 2882 } |
| 3204 | 2883 |
| 3205 // Check for deleted property if property can actually be deleted. | 2884 // Check for deleted property if property can actually be deleted. |
| 3206 if (!is_dont_delete) { | 2885 if (!is_dont_delete) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3314 // ----------------------------------- | 2993 // ----------------------------------- |
| 3315 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2994 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 3316 } | 2995 } |
| 3317 | 2996 |
| 3318 | 2997 |
| 3319 #undef __ | 2998 #undef __ |
| 3320 | 2999 |
| 3321 } } // namespace v8::internal | 3000 } } // namespace v8::internal |
| 3322 | 3001 |
| 3323 #endif // V8_TARGET_ARCH_IA32 | 3002 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |