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 4955 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4966 __ pop(esi); | 4966 __ pop(esi); |
4967 __ pop(edi); | 4967 __ pop(edi); |
4968 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers | 4968 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers |
4969 | 4969 |
4970 // Restore frame pointer and return. | 4970 // Restore frame pointer and return. |
4971 __ pop(ebp); | 4971 __ pop(ebp); |
4972 __ ret(0); | 4972 __ ret(0); |
4973 } | 4973 } |
4974 | 4974 |
4975 | 4975 |
4976 // Generate stub code for instanceof. | |
4977 // This code can patch an call site inlined cache of the instance of check, | |
Mads Ager (chromium)
2011/01/04 17:25:58
an call site -> a call site
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
4978 // which looks like this. | |
4979 // cmp edi, <the hole, patched to a map> | |
4980 // jne <some label> | |
4981 // mov eax, <the hole, patched to either true or false> | |
4982 // If that patching is requested the stack will have the delte from the return | |
4983 // address to the cmp instruction just just below the return address. | |
Mads Ager (chromium)
2011/01/04 17:25:58
just just -> just
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
4984 // esp[0] : return address | |
4985 // esp[4] : delta from return address to cmp instruction | |
Mads Ager (chromium)
2011/01/04 17:25:58
You should add to this comment that call site patc
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
4986 // This also means that for the call site patching the args have to be in | |
4987 // registers and not on the stack. | |
4976 void InstanceofStub::Generate(MacroAssembler* masm) { | 4988 void InstanceofStub::Generate(MacroAssembler* masm) { |
4977 // Fixed register usage throughout the stub. | 4989 // Fixed register usage throughout the stub. |
4978 Register object = eax; // Object (lhs). | 4990 Register object = eax; // Object (lhs). |
4979 Register map = ebx; // Map of the object. | 4991 Register map = ebx; // Map of the object. |
4980 Register function = edx; // Function (rhs). | 4992 Register function = edx; // Function (rhs). |
4981 Register prototype = edi; // Prototype of the function. | 4993 Register prototype = edi; // Prototype of the function. |
4982 Register scratch = ecx; | 4994 Register scratch = ecx; |
4983 | 4995 |
4996 ExternalReference roots_address = ExternalReference::roots_address(); | |
4997 | |
4998 ASSERT_EQ(object.code(), InstanceofStub::left().code()); | |
4999 ASSERT_EQ(function.code(), InstanceofStub::right().code()); | |
5000 | |
4984 // Get the object and function - they are always both needed. | 5001 // Get the object and function - they are always both needed. |
4985 Label slow, not_js_object; | 5002 Label slow, not_js_object; |
4986 if (!args_in_registers()) { | 5003 if (!HasArgsInRegisters()) { |
4987 __ mov(object, Operand(esp, 2 * kPointerSize)); | 5004 __ mov(object, Operand(esp, 2 * kPointerSize)); |
4988 __ mov(function, Operand(esp, 1 * kPointerSize)); | 5005 __ mov(function, Operand(esp, 1 * kPointerSize)); |
4989 } | 5006 } |
4990 | 5007 |
4991 // Check that the left hand is a JS object. | 5008 // Check that the left hand is a JS object. |
4992 __ test(object, Immediate(kSmiTagMask)); | 5009 __ test(object, Immediate(kSmiTagMask)); |
4993 __ j(zero, ¬_js_object, not_taken); | 5010 __ j(zero, ¬_js_object, not_taken); |
4994 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); | 5011 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); |
4995 | 5012 |
4996 // Look up the function and the map in the instanceof cache. | 5013 // If there is a call site cache don't look in the global cache, but do the |
4997 NearLabel miss; | 5014 // real lookup and update the call site cache. |
4998 ExternalReference roots_address = ExternalReference::roots_address(); | 5015 if (!HasCallSiteInlineCheck()) { |
4999 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 5016 // Look up the function and the map in the instanceof cache. |
5000 __ cmp(function, | 5017 NearLabel miss; |
5001 Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 5018 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
5002 __ j(not_equal, &miss); | 5019 __ cmp(function, |
5003 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 5020 Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
5004 __ cmp(map, Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 5021 __ j(not_equal, &miss); |
5005 __ j(not_equal, &miss); | 5022 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
5006 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5023 __ cmp(map, Operand::StaticArray( |
5007 __ mov(eax, Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 5024 scratch, times_pointer_size, roots_address)); |
5008 __ IncrementCounter(&Counters::instance_of_cache, 1); | 5025 __ j(not_equal, &miss); |
5009 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); | 5026 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
5027 __ mov(eax, Operand::StaticArray( | |
5028 scratch, times_pointer_size, roots_address)); | |
5029 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | |
5030 __ bind(&miss); | |
5031 } | |
5010 | 5032 |
5011 __ bind(&miss); | |
5012 // Get the prototype of the function. | 5033 // Get the prototype of the function. |
5013 __ TryGetFunctionPrototype(function, prototype, scratch, &slow); | 5034 __ TryGetFunctionPrototype(function, prototype, scratch, &slow); |
5014 | 5035 |
5015 // Check that the function prototype is a JS object. | 5036 // Check that the function prototype is a JS object. |
5016 __ test(prototype, Immediate(kSmiTagMask)); | 5037 __ test(prototype, Immediate(kSmiTagMask)); |
5017 __ j(zero, &slow, not_taken); | 5038 __ j(zero, &slow, not_taken); |
5018 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); | 5039 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); |
5019 | 5040 |
5020 // Update the golbal instanceof cache with the current map and function. The | 5041 // Update the global instanceof cache with the current map and function. The |
Mads Ager (chromium)
2011/01/04 17:25:58
global -> global or inlined?
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5021 // cached answer will be set when it is known. | 5042 // cached answer will be set when it is known. |
5043 if (!HasCallSiteInlineCheck()) { | |
5022 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 5044 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
5023 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); | 5045 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); |
5024 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 5046 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
5025 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), | 5047 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), |
5026 function); | 5048 function); |
5049 } else { | |
5050 // The constatns in for the code patching are based on no push instructions | |
Mads Ager (chromium)
2011/01/04 17:25:58
constatns in for -> constants for
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5051 // at the call site. | |
5052 ASSERT(HasArgsInRegisters()); | |
5053 // Get return address and delta to inlined map check. | |
5054 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | |
5055 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | |
5056 __ add(Operand(scratch), Immediate(2)); | |
Mads Ager (chromium)
2011/01/04 17:25:58
Named constant? Also, can't this be part of the op
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5057 __ mov(Operand(scratch, 0), map); | |
5058 } | |
5027 | 5059 |
5028 // Loop through the prototype chain of the object looking for the function | 5060 // Loop through the prototype chain of the object looking for the function |
5029 // prototype. | 5061 // prototype. |
5030 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); | 5062 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); |
5031 NearLabel loop, is_instance, is_not_instance; | 5063 NearLabel loop, is_instance, is_not_instance; |
5032 __ bind(&loop); | 5064 __ bind(&loop); |
5033 __ cmp(scratch, Operand(prototype)); | 5065 __ cmp(scratch, Operand(prototype)); |
5034 __ j(equal, &is_instance); | 5066 __ j(equal, &is_instance); |
5035 __ cmp(Operand(scratch), Immediate(Factory::null_value())); | 5067 __ cmp(Operand(scratch), Immediate(Factory::null_value())); |
5036 __ j(equal, &is_not_instance); | 5068 __ j(equal, &is_not_instance); |
5037 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 5069 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
5038 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); | 5070 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); |
5039 __ jmp(&loop); | 5071 __ jmp(&loop); |
5040 | 5072 |
5041 __ bind(&is_instance); | 5073 __ bind(&is_instance); |
5042 __ IncrementCounter(&Counters::instance_of_stub_true, 1); | 5074 if (!HasCallSiteInlineCheck()) { |
5043 __ Set(eax, Immediate(0)); | 5075 __ Set(eax, Immediate(0)); |
5044 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5076 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
5045 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax); | 5077 __ mov(Operand::StaticArray(scratch, |
5046 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); | 5078 times_pointer_size, roots_address), eax); |
5079 } else { | |
5080 // Get return address and delte to inlined map check. | |
5081 __ mov(eax, Factory::true_value()); | |
5082 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | |
5083 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | |
5084 __ add(Operand(scratch), Immediate(13)); | |
Mads Ager (chromium)
2011/01/04 17:25:58
Named constant? Combine with move?
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5085 __ mov(Operand(scratch, 0), eax); | |
5086 if (!ReturnTrueFalseObject()) { | |
5087 __ Set(eax, Immediate(0)); | |
5088 } | |
5089 } | |
5090 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | |
5047 | 5091 |
5048 __ bind(&is_not_instance); | 5092 __ bind(&is_not_instance); |
5049 __ IncrementCounter(&Counters::instance_of_stub_false, 1); | 5093 if (!HasCallSiteInlineCheck()) { |
5050 __ Set(eax, Immediate(Smi::FromInt(1))); | 5094 __ Set(eax, Immediate(Smi::FromInt(1))); |
5051 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5095 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
5052 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), eax); | 5096 __ mov(Operand::StaticArray( |
5053 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); | 5097 scratch, times_pointer_size, roots_address), eax); |
5098 } else { | |
5099 // Get return address and delte to inlined map check. | |
5100 __ mov(eax, Factory::false_value()); | |
5101 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | |
5102 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | |
5103 __ add(Operand(scratch), Immediate(13)); | |
Mads Ager (chromium)
2011/01/04 17:25:58
Same here.
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5104 __ mov(Operand(scratch, 0), eax); | |
5105 if (!ReturnTrueFalseObject()) { | |
5106 __ Set(eax, Immediate(Smi::FromInt(1))); | |
5107 } | |
5108 } | |
5109 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | |
5054 | 5110 |
5055 Label object_not_null, object_not_null_or_smi; | 5111 Label object_not_null, object_not_null_or_smi; |
5056 __ bind(¬_js_object); | 5112 __ bind(¬_js_object); |
5057 // Before null, smi and string value checks, check that the rhs is a function | 5113 // Before null, smi and string value checks, check that the rhs is a function |
5058 // as for a non-function rhs an exception needs to be thrown. | 5114 // as for a non-function rhs an exception needs to be thrown. |
5059 __ test(function, Immediate(kSmiTagMask)); | 5115 __ test(function, Immediate(kSmiTagMask)); |
5060 __ j(zero, &slow, not_taken); | 5116 __ j(zero, &slow, not_taken); |
5061 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); | 5117 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); |
5062 __ j(not_equal, &slow, not_taken); | 5118 __ j(not_equal, &slow, not_taken); |
5063 | 5119 |
5064 // Null is not instance of anything. | 5120 // Null is not instance of anything. |
5065 __ cmp(object, Factory::null_value()); | 5121 __ cmp(object, Factory::null_value()); |
5066 __ j(not_equal, &object_not_null); | 5122 __ j(not_equal, &object_not_null); |
5067 __ IncrementCounter(&Counters::instance_of_stub_false_null, 1); | |
5068 __ Set(eax, Immediate(Smi::FromInt(1))); | 5123 __ Set(eax, Immediate(Smi::FromInt(1))); |
5069 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); | 5124 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
5070 | 5125 |
5071 __ bind(&object_not_null); | 5126 __ bind(&object_not_null); |
5072 // Smi values is not instance of anything. | 5127 // Smi values is not instance of anything. |
5073 __ test(object, Immediate(kSmiTagMask)); | 5128 __ test(object, Immediate(kSmiTagMask)); |
5074 __ j(not_zero, &object_not_null_or_smi, not_taken); | 5129 __ j(not_zero, &object_not_null_or_smi, not_taken); |
5075 __ Set(eax, Immediate(Smi::FromInt(1))); | 5130 __ Set(eax, Immediate(Smi::FromInt(1))); |
5076 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); | 5131 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
5077 | 5132 |
5078 __ bind(&object_not_null_or_smi); | 5133 __ bind(&object_not_null_or_smi); |
5079 // String values is not instance of anything. | 5134 // String values is not instance of anything. |
5080 Condition is_string = masm->IsObjectStringType(object, scratch, scratch); | 5135 Condition is_string = masm->IsObjectStringType(object, scratch, scratch); |
5081 __ j(NegateCondition(is_string), &slow); | 5136 __ j(NegateCondition(is_string), &slow); |
5082 __ IncrementCounter(&Counters::instance_of_stub_false_string, 1); | |
5083 __ Set(eax, Immediate(Smi::FromInt(1))); | 5137 __ Set(eax, Immediate(Smi::FromInt(1))); |
5084 __ ret((args_in_registers() ? 0 : 2) * kPointerSize); | 5138 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
5085 | 5139 |
5086 // Slow-case: Go through the JavaScript implementation. | 5140 // Slow-case: Go through the JavaScript implementation. |
5087 __ bind(&slow); | 5141 __ bind(&slow); |
5088 if (args_in_registers()) { | 5142 if (HasArgsInRegisters()) { |
5089 // Push arguments below return address. | 5143 // Push arguments below return address. |
5090 __ pop(scratch); | 5144 __ pop(scratch); |
5091 __ push(object); | 5145 __ push(object); |
5092 __ push(function); | 5146 __ push(function); |
5093 __ push(scratch); | 5147 __ push(scratch); |
5094 } | 5148 } |
5095 __ IncrementCounter(&Counters::instance_of_slow, 1); | |
5096 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5149 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
5097 } | 5150 } |
5098 | 5151 |
5099 | 5152 |
5153 Register InstanceofStub::left() { return eax; } | |
5154 | |
Mads Ager (chromium)
2011/01/04 17:25:58
two blank lines between functions
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5155 Register InstanceofStub::right() { return edx; } | |
5156 | |
Mads Ager (chromium)
2011/01/04 17:25:58
Two blanks.
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5157 const char* InstanceofStub::GetName() { | |
5158 if (name_ != NULL) return name_; | |
5159 const int kMaxNameLength = 100; | |
5160 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); | |
5161 if (name_ == NULL) return "OOM"; | |
5162 | |
5163 const char* args = ""; | |
5164 if (HasArgsInRegisters()) { | |
5165 args = "_REGS"; | |
5166 } | |
5167 | |
5168 const char* inline_check = ""; | |
5169 if (HasCallSiteInlineCheck()) { | |
5170 inline_check = "_INLINE"; | |
5171 } | |
5172 | |
5173 const char* return_true_false_object = ""; | |
5174 if (ReturnTrueFalseObject()) { | |
5175 return_true_false_object = "_TRUEFALSE"; | |
5176 } | |
5177 | |
5178 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | |
5179 "InstanceofStub%s%s", | |
Mads Ager (chromium)
2011/01/04 17:25:58
Isn't there a %s missing here?
Søren Thygesen Gjesse
2011/01/05 09:28:00
Done.
| |
5180 args, | |
5181 inline_check, | |
5182 return_true_false_object); | |
5183 return name_; | |
5184 } | |
5185 | |
5186 | |
5100 int CompareStub::MinorKey() { | 5187 int CompareStub::MinorKey() { |
5101 // Encode the three parameters in a unique 16 bit value. To avoid duplicate | 5188 // Encode the three parameters in a unique 16 bit value. To avoid duplicate |
5102 // stubs the never NaN NaN condition is only taken into account if the | 5189 // stubs the never NaN NaN condition is only taken into account if the |
5103 // condition is equals. | 5190 // condition is equals. |
5104 ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); | 5191 ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); |
5105 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 5192 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |
5106 return ConditionField::encode(static_cast<unsigned>(cc_)) | 5193 return ConditionField::encode(static_cast<unsigned>(cc_)) |
5107 | RegisterField::encode(false) // lhs_ and rhs_ are not used | 5194 | RegisterField::encode(false) // lhs_ and rhs_ are not used |
5108 | StrictField::encode(strict_) | 5195 | StrictField::encode(strict_) |
5109 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) | 5196 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) |
(...skipping 1295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6405 // Do a tail call to the rewritten stub. | 6492 // Do a tail call to the rewritten stub. |
6406 __ jmp(Operand(edi)); | 6493 __ jmp(Operand(edi)); |
6407 } | 6494 } |
6408 | 6495 |
6409 | 6496 |
6410 #undef __ | 6497 #undef __ |
6411 | 6498 |
6412 } } // namespace v8::internal | 6499 } } // namespace v8::internal |
6413 | 6500 |
6414 #endif // V8_TARGET_ARCH_IA32 | 6501 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |