| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 4087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4098 // literal 'null'. If so, we optimize the code by inlining a null check | 4098 // literal 'null'. If so, we optimize the code by inlining a null check |
| 4099 // instead of calling the (very) general runtime routine for checking | 4099 // instead of calling the (very) general runtime routine for checking |
| 4100 // equality. | 4100 // equality. |
| 4101 if (op == Token::EQ || op == Token::EQ_STRICT) { | 4101 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 4102 bool left_is_null = | 4102 bool left_is_null = |
| 4103 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 4103 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 4104 bool right_is_null = | 4104 bool right_is_null = |
| 4105 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 4105 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 4106 // The 'null' value can only be equal to 'null' or 'undefined'. | 4106 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 4107 if (left_is_null || right_is_null) { | 4107 if (left_is_null || right_is_null) { |
| 4108 VirtualFrame::SpilledScope spilled_scope(this); | 4108 Load(left_is_null ? right : left); |
| 4109 LoadAndSpill(left_is_null ? right : left); | 4109 Result operand = frame_->Pop(); |
| 4110 frame_->EmitPop(eax); | 4110 operand.ToRegister(); |
| 4111 __ cmp(eax, Factory::null_value()); | 4111 __ cmp(operand.reg(), Factory::null_value()); |
| 4112 Condition cc = equal; |
| 4112 | 4113 |
| 4113 // The 'null' value is only equal to 'undefined' if using non-strict | 4114 // The 'null' value is only equal to 'undefined' if using non-strict |
| 4114 // comparisons. | 4115 // comparisons. |
| 4115 if (op != Token::EQ_STRICT) { | 4116 if (op != Token::EQ_STRICT) { |
| 4117 true_target()->Branch(cc); |
| 4118 __ cmp(operand.reg(), Factory::undefined_value()); |
| 4116 true_target()->Branch(equal); | 4119 true_target()->Branch(equal); |
| 4117 | 4120 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 4118 __ cmp(eax, Factory::undefined_value()); | |
| 4119 true_target()->Branch(equal); | |
| 4120 | |
| 4121 __ test(eax, Immediate(kSmiTagMask)); | |
| 4122 false_target()->Branch(equal); | 4121 false_target()->Branch(equal); |
| 4123 | 4122 |
| 4124 // It can be an undetectable object. | 4123 // It can be an undetectable object. |
| 4125 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 4124 // Use a scratch register in preference to spilling operand.reg(). |
| 4126 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); | 4125 Result temp = allocator()->Allocate(); |
| 4127 __ and_(eax, 1 << Map::kIsUndetectable); | 4126 ASSERT(temp.is_valid()); |
| 4128 __ cmp(eax, 1 << Map::kIsUndetectable); | 4127 __ mov(temp.reg(), |
| 4128 FieldOperand(operand.reg(), HeapObject::kMapOffset)); |
| 4129 __ movzx_b(temp.reg(), |
| 4130 FieldOperand(temp.reg(), Map::kBitFieldOffset)); |
| 4131 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); |
| 4132 cc = not_zero; |
| 4129 } | 4133 } |
| 4130 | 4134 operand.Unuse(); |
| 4131 true_target()->Branch(equal); | 4135 true_target()->Branch(cc); |
| 4132 false_target()->Jump(); | 4136 false_target()->Jump(); |
| 4133 return; | 4137 return; |
| 4134 } | 4138 } |
| 4135 } | 4139 } |
| 4136 | 4140 |
| 4137 // To make typeof testing for natives implemented in JavaScript really | 4141 // To make typeof testing for natives implemented in JavaScript really |
| 4138 // efficient, we generate special code for expressions of the form: | 4142 // efficient, we generate special code for expressions of the form: |
| 4139 // 'typeof <expression> == <string>'. | 4143 // 'typeof <expression> == <string>'. |
| 4140 UnaryOperation* operation = left->AsUnaryOperation(); | 4144 UnaryOperation* operation = left->AsUnaryOperation(); |
| 4141 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 4145 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 4142 (operation != NULL && operation->op() == Token::TYPEOF) && | 4146 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 4143 (right->AsLiteral() != NULL && | 4147 (right->AsLiteral() != NULL && |
| 4144 right->AsLiteral()->handle()->IsString())) { | 4148 right->AsLiteral()->handle()->IsString())) { |
| 4145 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 4149 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 4146 | 4150 |
| 4147 VirtualFrame::SpilledScope spilled_scope(this); | 4151 // Load the operand and move it to a register. |
| 4148 // Load the operand and move it to register edx. | 4152 { |
| 4149 LoadTypeofExpression(operation->expression()); | 4153 // TODO(toiger): Remove spill once pending change has gone in. |
| 4150 frame_->EmitPop(edx); | 4154 VirtualFrame::SpilledScope spilled_scope(this); |
| 4155 LoadTypeofExpression(operation->expression()); |
| 4156 } |
| 4157 Result answer = frame_->Pop(); |
| 4158 answer.ToRegister(); |
| 4151 | 4159 |
| 4152 if (check->Equals(Heap::number_symbol())) { | 4160 if (check->Equals(Heap::number_symbol())) { |
| 4153 __ test(edx, Immediate(kSmiTagMask)); | 4161 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 4154 true_target()->Branch(zero); | 4162 true_target()->Branch(zero); |
| 4155 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4163 frame_->Spill(answer.reg()); |
| 4156 __ cmp(edx, Factory::heap_number_map()); | 4164 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 4165 __ cmp(answer.reg(), Factory::heap_number_map()); |
| 4166 answer.Unuse(); |
| 4157 true_target()->Branch(equal); | 4167 true_target()->Branch(equal); |
| 4158 false_target()->Jump(); | 4168 false_target()->Jump(); |
| 4159 | 4169 |
| 4160 } else if (check->Equals(Heap::string_symbol())) { | 4170 } else if (check->Equals(Heap::string_symbol())) { |
| 4161 __ test(edx, Immediate(kSmiTagMask)); | 4171 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 4162 false_target()->Branch(zero); | 4172 false_target()->Branch(zero); |
| 4163 | 4173 |
| 4164 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4174 |
| 4165 | 4175 |
| 4166 // It can be an undetectable string object. | 4176 // It can be an undetectable string object. |
| 4167 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 4177 Result temp = allocator()->Allocate(); |
| 4168 __ and_(ecx, 1 << Map::kIsUndetectable); | 4178 ASSERT(temp.is_valid()); |
| 4169 __ cmp(ecx, 1 << Map::kIsUndetectable); | 4179 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 4170 false_target()->Branch(equal); | 4180 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset)); |
| 4171 | 4181 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); |
| 4172 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 4182 false_target()->Branch(not_zero); |
| 4173 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 4183 __ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 4184 __ movzx_b(temp.reg(), |
| 4185 FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
| 4186 __ cmp(temp.reg(), FIRST_NONSTRING_TYPE); |
| 4187 temp.Unuse(); |
| 4188 answer.Unuse(); |
| 4174 true_target()->Branch(less); | 4189 true_target()->Branch(less); |
| 4175 false_target()->Jump(); | 4190 false_target()->Jump(); |
| 4176 | 4191 |
| 4177 } else if (check->Equals(Heap::boolean_symbol())) { | 4192 } else if (check->Equals(Heap::boolean_symbol())) { |
| 4178 __ cmp(edx, Factory::true_value()); | 4193 __ cmp(answer.reg(), Factory::true_value()); |
| 4179 true_target()->Branch(equal); | 4194 true_target()->Branch(equal); |
| 4180 __ cmp(edx, Factory::false_value()); | 4195 __ cmp(answer.reg(), Factory::false_value()); |
| 4196 answer.Unuse(); |
| 4181 true_target()->Branch(equal); | 4197 true_target()->Branch(equal); |
| 4182 false_target()->Jump(); | 4198 false_target()->Jump(); |
| 4183 | 4199 |
| 4184 } else if (check->Equals(Heap::undefined_symbol())) { | 4200 } else if (check->Equals(Heap::undefined_symbol())) { |
| 4185 __ cmp(edx, Factory::undefined_value()); | 4201 __ cmp(answer.reg(), Factory::undefined_value()); |
| 4186 true_target()->Branch(equal); | 4202 true_target()->Branch(equal); |
| 4187 | 4203 |
| 4188 __ test(edx, Immediate(kSmiTagMask)); | 4204 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 4189 false_target()->Branch(zero); | 4205 false_target()->Branch(zero); |
| 4190 | 4206 |
| 4191 // It can be an undetectable object. | 4207 // It can be an undetectable object. |
| 4192 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4208 frame_->Spill(answer.reg()); |
| 4193 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 4209 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 4194 __ and_(ecx, 1 << Map::kIsUndetectable); | 4210 __ movzx_b(answer.reg(), |
| 4195 __ cmp(ecx, 1 << Map::kIsUndetectable); | 4211 FieldOperand(answer.reg(), Map::kBitFieldOffset)); |
| 4196 true_target()->Branch(equal); | 4212 __ test(answer.reg(), Immediate(1 << Map::kIsUndetectable)); |
| 4213 answer.Unuse(); |
| 4214 true_target()->Branch(not_zero); |
| 4197 false_target()->Jump(); | 4215 false_target()->Jump(); |
| 4198 | 4216 |
| 4199 } else if (check->Equals(Heap::function_symbol())) { | 4217 } else if (check->Equals(Heap::function_symbol())) { |
| 4200 __ test(edx, Immediate(kSmiTagMask)); | 4218 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 4201 false_target()->Branch(zero); | 4219 false_target()->Branch(zero); |
| 4202 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 4220 frame_->Spill(answer.reg()); |
| 4203 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 4221 __ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 4204 __ cmp(edx, JS_FUNCTION_TYPE); | 4222 __ movzx_b(answer.reg(), |
| 4223 FieldOperand(answer.reg(), Map::kInstanceTypeOffset)); |
| 4224 __ cmp(answer.reg(), JS_FUNCTION_TYPE); |
| 4225 answer.Unuse(); |
| 4205 true_target()->Branch(equal); | 4226 true_target()->Branch(equal); |
| 4206 false_target()->Jump(); | 4227 false_target()->Jump(); |
| 4207 | 4228 |
| 4208 } else if (check->Equals(Heap::object_symbol())) { | 4229 } else if (check->Equals(Heap::object_symbol())) { |
| 4209 __ test(edx, Immediate(kSmiTagMask)); | 4230 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 4210 false_target()->Branch(zero); | 4231 false_target()->Branch(zero); |
| 4211 | 4232 __ cmp(answer.reg(), Factory::null_value()); |
| 4212 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
| 4213 __ cmp(edx, Factory::null_value()); | |
| 4214 true_target()->Branch(equal); | 4233 true_target()->Branch(equal); |
| 4215 | 4234 |
| 4216 // It can be an undetectable object. | 4235 // It can be an undetectable object. |
| 4217 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); | 4236 Result map = allocator()->Allocate(); |
| 4218 __ and_(edx, 1 << Map::kIsUndetectable); | 4237 ASSERT(map.is_valid()); |
| 4219 __ cmp(edx, 1 << Map::kIsUndetectable); | 4238 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 4220 false_target()->Branch(equal); | 4239 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset)); |
| 4221 | 4240 __ test(map.reg(), Immediate(1 << Map::kIsUndetectable)); |
| 4222 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 4241 false_target()->Branch(not_zero); |
| 4223 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 4242 __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
| 4243 __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kInstanceTypeOffset)); |
| 4244 __ cmp(map.reg(), FIRST_JS_OBJECT_TYPE); |
| 4224 false_target()->Branch(less); | 4245 false_target()->Branch(less); |
| 4225 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 4246 __ cmp(map.reg(), LAST_JS_OBJECT_TYPE); |
| 4247 answer.Unuse(); |
| 4248 map.Unuse(); |
| 4226 true_target()->Branch(less_equal); | 4249 true_target()->Branch(less_equal); |
| 4227 false_target()->Jump(); | 4250 false_target()->Jump(); |
| 4228 | |
| 4229 } else { | 4251 } else { |
| 4230 // Uncommon case: typeof testing against a string literal that is | 4252 // Uncommon case: typeof testing against a string literal that is |
| 4231 // never returned from the typeof operator. | 4253 // never returned from the typeof operator. |
| 4254 answer.Unuse(); |
| 4232 false_target()->Jump(); | 4255 false_target()->Jump(); |
| 4233 } | 4256 } |
| 4234 return; | 4257 return; |
| 4235 } | 4258 } |
| 4236 | 4259 |
| 4237 Condition cc = no_condition; | 4260 Condition cc = no_condition; |
| 4238 bool strict = false; | 4261 bool strict = false; |
| 4239 switch (op) { | 4262 switch (op) { |
| 4240 case Token::EQ_STRICT: | 4263 case Token::EQ_STRICT: |
| 4241 strict = true; | 4264 strict = true; |
| 4242 // Fall through | 4265 // Fall through |
| 4243 case Token::EQ: | 4266 case Token::EQ: |
| 4244 cc = equal; | 4267 cc = equal; |
| 4245 break; | 4268 break; |
| 4246 case Token::LT: | 4269 case Token::LT: |
| 4247 cc = less; | 4270 cc = less; |
| 4248 break; | 4271 break; |
| 4249 case Token::GT: | 4272 case Token::GT: |
| 4250 cc = greater; | 4273 cc = greater; |
| 4251 break; | 4274 break; |
| 4252 case Token::LTE: | 4275 case Token::LTE: |
| 4253 cc = less_equal; | 4276 cc = less_equal; |
| 4254 break; | 4277 break; |
| 4255 case Token::GTE: | 4278 case Token::GTE: |
| 4256 cc = greater_equal; | 4279 cc = greater_equal; |
| 4257 break; | 4280 break; |
| 4258 case Token::IN: { | 4281 case Token::IN: { |
| 4259 Load(left); | 4282 Load(left); |
| 4260 Load(right); | 4283 Load(right); |
| 4284 // TODO(toiger): Fix once pending change is submitted. |
| 4261 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); | 4285 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); |
| 4262 frame_->Push(eax); // push the result | 4286 frame_->Push(eax); // push the result |
| 4263 return; | 4287 return; |
| 4264 } | 4288 } |
| 4265 case Token::INSTANCEOF: { | 4289 case Token::INSTANCEOF: { |
| 4266 Load(left); | 4290 Load(left); |
| 4267 Load(right); | 4291 Load(right); |
| 4268 InstanceofStub stub; | 4292 InstanceofStub stub; |
| 4269 frame_->CallStub(&stub, 2); | 4293 Result answer = frame_->CallStub(&stub, 2); |
| 4270 __ test(eax, Operand(eax)); | 4294 answer.ToRegister(); |
| 4295 __ test(answer.reg(), Operand(answer.reg())); |
| 4296 answer.Unuse(); |
| 4271 true_target()->Branch(zero); | 4297 true_target()->Branch(zero); |
| 4272 false_target()->Jump(); | 4298 false_target()->Jump(); |
| 4273 return; | 4299 return; |
| 4274 } | 4300 } |
| 4275 default: | 4301 default: |
| 4276 UNREACHABLE(); | 4302 UNREACHABLE(); |
| 4277 } | 4303 } |
| 4278 | 4304 |
| 4279 // Optimize for the case where (at least) one of the expressions | 4305 // Optimize for the case where (at least) one of the expressions |
| 4280 // is a literal small integer. | 4306 // is a literal small integer. |
| (...skipping 1803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6084 | 6110 |
| 6085 // Slow-case: Go through the JavaScript implementation. | 6111 // Slow-case: Go through the JavaScript implementation. |
| 6086 __ bind(&slow); | 6112 __ bind(&slow); |
| 6087 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6113 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6088 } | 6114 } |
| 6089 | 6115 |
| 6090 | 6116 |
| 6091 #undef __ | 6117 #undef __ |
| 6092 | 6118 |
| 6093 } } // namespace v8::internal | 6119 } } // namespace v8::internal |
| OLD | NEW |