OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 5022 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5033 __ pop(edi); | 5033 __ pop(edi); |
5034 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers | 5034 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers |
5035 | 5035 |
5036 // Restore frame pointer and return. | 5036 // Restore frame pointer and return. |
5037 __ pop(ebp); | 5037 __ pop(ebp); |
5038 __ ret(0); | 5038 __ ret(0); |
5039 } | 5039 } |
5040 | 5040 |
5041 | 5041 |
5042 void InstanceofStub::Generate(MacroAssembler* masm) { | 5042 void InstanceofStub::Generate(MacroAssembler* masm) { |
5043 // Get the object - go slow case if it's a smi. | 5043 // Fixed register usage throughout the stub. |
5044 Label slow; | 5044 Register object = eax; // Object (lhs). |
5045 __ mov(eax, Operand(esp, 2 * kPointerSize)); // 2 ~ return address, function | 5045 Register map = ebx; // Map of the object. |
5046 __ test(eax, Immediate(kSmiTagMask)); | 5046 Register function = edx; // Function (rhs). |
5047 __ j(zero, &slow, not_taken); | 5047 Register prototype = edi; // Prototype of the function. |
| 5048 Register scratch = ecx; |
| 5049 |
| 5050 // Get the object and function - they are always both needed. |
| 5051 Label slow, not_js_object; |
| 5052 if (!args_in_registers()) { |
| 5053 __ mov(object, Operand(esp, 2 * kPointerSize)); |
| 5054 __ mov(function, Operand(esp, 1 * kPointerSize)); |
| 5055 } |
5048 | 5056 |
5049 // Check that the left hand is a JS object. | 5057 // Check that the left hand is a JS object. |
5050 __ IsObjectJSObjectType(eax, eax, edx, &slow); | 5058 __ test(object, Immediate(kSmiTagMask)); |
5051 | 5059 __ j(zero, ¬_js_object, not_taken); |
5052 // Get the prototype of the function. | 5060 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); |
5053 __ mov(edx, Operand(esp, 1 * kPointerSize)); // 1 ~ return address | |
5054 // edx is function, eax is map. | |
5055 | 5061 |
5056 // Look up the function and the map in the instanceof cache. | 5062 // Look up the function and the map in the instanceof cache. |
5057 NearLabel miss; | 5063 NearLabel miss; |
5058 ExternalReference roots_address = ExternalReference::roots_address(); | 5064 ExternalReference roots_address = ExternalReference::roots_address(); |
5059 __ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 5065 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
5060 __ cmp(edx, Operand::StaticArray(ecx, times_pointer_size, roots_address)); | 5066 __ cmp(function, |
| 5067 Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
5061 __ j(not_equal, &miss); | 5068 __ j(not_equal, &miss); |
5062 __ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 5069 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
5063 __ cmp(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address)); | 5070 __ cmp(map, Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
5064 __ j(not_equal, &miss); | 5071 __ j(not_equal, &miss); |
5065 __ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5072 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
5066 __ mov(eax, Operand::StaticArray(ecx, times_pointer_size, roots_address)); | 5073 __ mov(eax, Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
5067 __ ret(2 * kPointerSize); | 5074 __ IncrementCounter(&Counters::instance_of_cache, 1); |
| 5075 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
5068 | 5076 |
5069 __ bind(&miss); | 5077 __ bind(&miss); |
5070 __ TryGetFunctionPrototype(edx, ebx, ecx, &slow); | 5078 // Get the prototype of the function. |
| 5079 __ TryGetFunctionPrototype(function, prototype, scratch, &slow); |
5071 | 5080 |
5072 // Check that the function prototype is a JS object. | 5081 // Check that the function prototype is a JS object. |
5073 __ test(ebx, Immediate(kSmiTagMask)); | 5082 __ test(prototype, Immediate(kSmiTagMask)); |
5074 __ j(zero, &slow, not_taken); | 5083 __ j(zero, &slow, not_taken); |
5075 __ IsObjectJSObjectType(ebx, ecx, ecx, &slow); | 5084 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); |
5076 | 5085 |
5077 // Register mapping: | 5086 // Update the golbal instanceof cache with the current map and function. The |
5078 // eax is object map. | 5087 // cached answer will be set when it is known. |
5079 // edx is function. | 5088 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
5080 // ebx is function prototype. | 5089 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); |
5081 __ mov(ecx, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 5090 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
5082 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax); | 5091 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), |
5083 __ mov(ecx, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 5092 function); |
5084 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), edx); | |
5085 | 5093 |
5086 __ mov(ecx, FieldOperand(eax, Map::kPrototypeOffset)); | 5094 // Loop through the prototype chain of the object looking for the function |
5087 | 5095 // prototype. |
5088 // Loop through the prototype chain looking for the function prototype. | 5096 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); |
5089 NearLabel loop, is_instance, is_not_instance; | 5097 NearLabel loop, is_instance, is_not_instance; |
5090 __ bind(&loop); | 5098 __ bind(&loop); |
5091 __ cmp(ecx, Operand(ebx)); | 5099 __ cmp(scratch, Operand(prototype)); |
5092 __ j(equal, &is_instance); | 5100 __ j(equal, &is_instance); |
5093 __ cmp(Operand(ecx), Immediate(Factory::null_value())); | 5101 __ cmp(Operand(scratch), Immediate(Factory::null_value())); |
5094 __ j(equal, &is_not_instance); | 5102 __ j(equal, &is_not_instance); |
5095 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); | 5103 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
5096 __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset)); | 5104 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); |
5097 __ jmp(&loop); | 5105 __ jmp(&loop); |
5098 | 5106 |
5099 __ bind(&is_instance); | 5107 __ bind(&is_instance); |
| 5108 __ IncrementCounter(&Counters::instance_of_stub_true, 1); |
5100 __ Set(eax, Immediate(0)); | 5109 __ Set(eax, Immediate(0)); |
5101 __ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5110 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
5102 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax); | 5111 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax); |
5103 __ ret(2 * kPointerSize); | 5112 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
5104 | 5113 |
5105 __ bind(&is_not_instance); | 5114 __ bind(&is_not_instance); |
| 5115 __ IncrementCounter(&Counters::instance_of_stub_false, 1); |
5106 __ Set(eax, Immediate(Smi::FromInt(1))); | 5116 __ Set(eax, Immediate(Smi::FromInt(1))); |
5107 __ mov(ecx, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5117 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
5108 __ mov(Operand::StaticArray(ecx, times_pointer_size, roots_address), eax); | 5118 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax); |
5109 __ ret(2 * kPointerSize); | 5119 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| 5120 |
| 5121 Label object_not_null, object_not_null_or_smi; |
| 5122 __ bind(¬_js_object); |
| 5123 // Before null, smi and string value checks, check that the rhs is a function |
| 5124 // as for a non-function rhs an exception needs to be thrown. |
| 5125 __ test(function, Immediate(kSmiTagMask)); |
| 5126 __ j(zero, &slow, not_taken); |
| 5127 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); |
| 5128 __ j(not_equal, &slow, not_taken); |
| 5129 |
| 5130 // Null is not instance of anything. |
| 5131 __ cmp(object, Factory::null_value()); |
| 5132 __ j(not_equal, &object_not_null); |
| 5133 __ IncrementCounter(&Counters::instance_of_stub_false_null, 1); |
| 5134 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 5135 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| 5136 |
| 5137 __ bind(&object_not_null); |
| 5138 // Smi values is not instance of anything. |
| 5139 __ test(object, Immediate(kSmiTagMask)); |
| 5140 __ j(not_zero, &object_not_null_or_smi, not_taken); |
| 5141 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 5142 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
| 5143 |
| 5144 __ bind(&object_not_null_or_smi); |
| 5145 // String values is not instance of anything. |
| 5146 Condition is_string = masm->IsObjectStringType(object, scratch, scratch); |
| 5147 __ j(NegateCondition(is_string), &slow); |
| 5148 __ IncrementCounter(&Counters::instance_of_stub_false_string, 1); |
| 5149 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 5150 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); |
5110 | 5151 |
5111 // Slow-case: Go through the JavaScript implementation. | 5152 // Slow-case: Go through the JavaScript implementation. |
5112 __ bind(&slow); | 5153 __ bind(&slow); |
| 5154 if (args_in_registers()) { |
| 5155 // Push arguments below return address. |
| 5156 __ pop(scratch); |
| 5157 __ push(object); |
| 5158 __ push(function); |
| 5159 __ push(scratch); |
| 5160 } |
| 5161 __ IncrementCounter(&Counters::instance_of_slow, 1); |
5113 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5162 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
5114 } | 5163 } |
5115 | 5164 |
5116 | 5165 |
5117 int CompareStub::MinorKey() { | 5166 int CompareStub::MinorKey() { |
5118 // Encode the three parameters in a unique 16 bit value. To avoid duplicate | 5167 // Encode the three parameters in a unique 16 bit value. To avoid duplicate |
5119 // stubs the never NaN NaN condition is only taken into account if the | 5168 // stubs the never NaN NaN condition is only taken into account if the |
5120 // condition is equals. | 5169 // condition is equals. |
5121 ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); | 5170 ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); |
5122 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 5171 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |
(...skipping 1299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6422 // Do a tail call to the rewritten stub. | 6471 // Do a tail call to the rewritten stub. |
6423 __ jmp(Operand(edi)); | 6472 __ jmp(Operand(edi)); |
6424 } | 6473 } |
6425 | 6474 |
6426 | 6475 |
6427 #undef __ | 6476 #undef __ |
6428 | 6477 |
6429 } } // namespace v8::internal | 6478 } } // namespace v8::internal |
6430 | 6479 |
6431 #endif // V8_TARGET_ARCH_IA32 | 6480 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |