OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 } | 223 } |
224 | 224 |
225 // Return and remove the on-stack parameters. | 225 // Return and remove the on-stack parameters. |
226 __ ret(3 * kPointerSize); | 226 __ ret(3 * kPointerSize); |
227 | 227 |
228 __ bind(&slow_case); | 228 __ bind(&slow_case); |
229 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 229 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
230 } | 230 } |
231 | 231 |
232 | 232 |
233 // The stub returns zero for false, and a non-zero value for true. | 233 // The stub expects its argument on the stack and returns its result in tos_: |
| 234 // zero for false, and a non-zero value for true. |
234 void ToBooleanStub::Generate(MacroAssembler* masm) { | 235 void ToBooleanStub::Generate(MacroAssembler* masm) { |
235 Label false_result, true_result, not_string; | 236 Label patch; |
| 237 const Register argument = rax; |
236 const Register map = rdx; | 238 const Register map = rdx; |
237 | 239 |
238 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 240 if (!types_.IsEmpty()) { |
| 241 __ movq(argument, Operand(rsp, 1 * kPointerSize)); |
| 242 } |
239 | 243 |
240 // undefined -> false | 244 // undefined -> false |
241 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 245 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); |
242 __ j(equal, &false_result); | |
243 | 246 |
244 // Boolean -> its value | 247 // Boolean -> its value |
245 __ CompareRoot(rax, Heap::kFalseValueRootIndex); | 248 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); |
246 __ j(equal, &false_result); | 249 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); |
247 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | |
248 __ j(equal, &true_result); | |
249 | |
250 // Smis: 0 -> false, all other -> true | |
251 __ Cmp(rax, Smi::FromInt(0)); | |
252 __ j(equal, &false_result); | |
253 __ JumpIfSmi(rax, &true_result); | |
254 | 250 |
255 // 'null' -> false. | 251 // 'null' -> false. |
256 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 252 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); |
257 __ j(equal, &false_result, Label::kNear); | |
258 | 253 |
259 // Get the map of the heap object. | 254 if (types_.Contains(SMI)) { |
260 __ movq(map, FieldOperand(rax, HeapObject::kMapOffset)); | 255 // Smis: 0 -> false, all other -> true |
| 256 Label not_smi; |
| 257 __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); |
| 258 // argument contains the correct return value already |
| 259 if (!tos_.is(argument)) { |
| 260 __ movq(tos_, argument); |
| 261 } |
| 262 __ ret(1 * kPointerSize); |
| 263 __ bind(¬_smi); |
| 264 } else if (types_.NeedsMap()) { |
| 265 // If we need a map later and have a Smi -> patch. |
| 266 __ JumpIfSmi(argument, &patch, Label::kNear); |
| 267 } |
261 | 268 |
262 // Undetectable -> false. | 269 if (types_.NeedsMap()) { |
263 __ testb(FieldOperand(map, Map::kBitFieldOffset), | 270 __ movq(map, FieldOperand(argument, HeapObject::kMapOffset)); |
264 Immediate(1 << Map::kIsUndetectable)); | |
265 __ j(not_zero, &false_result, Label::kNear); | |
266 | 271 |
267 // JavaScript object -> true. | 272 // Everything with a map could be undetectable, so check this now. |
268 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); | 273 __ testb(FieldOperand(map, Map::kBitFieldOffset), |
269 __ j(above_equal, &true_result, Label::kNear); | 274 Immediate(1 << Map::kIsUndetectable)); |
| 275 // Undetectable -> false. |
| 276 Label not_undetectable; |
| 277 __ j(zero, ¬_undetectable, Label::kNear); |
| 278 __ Set(tos_, 0); |
| 279 __ ret(1 * kPointerSize); |
| 280 __ bind(¬_undetectable); |
| 281 } |
270 | 282 |
271 // String value -> false iff empty. | 283 if (types_.Contains(SPEC_OBJECT)) { |
272 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); | 284 // spec object -> true. |
273 __ j(above_equal, ¬_string, Label::kNear); | 285 Label not_js_object; |
274 __ cmpq(FieldOperand(rax, String::kLengthOffset), Immediate(0)); | 286 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
275 __ j(zero, &false_result, Label::kNear); | 287 __ j(below, ¬_js_object, Label::kNear); |
276 __ jmp(&true_result, Label::kNear); | 288 __ Set(tos_, 1); |
| 289 __ ret(1 * kPointerSize); |
| 290 __ bind(¬_js_object); |
| 291 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 292 // We've seen a spec object for the first time -> patch. |
| 293 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 294 __ j(above_equal, &patch, Label::kNear); |
| 295 } |
277 | 296 |
278 __ bind(¬_string); | 297 if (types_.Contains(STRING)) { |
279 // HeapNumber -> false iff +0, -0, or NaN. | 298 // String value -> false iff empty. |
280 // These three cases set the zero flag when compared to zero using ucomisd. | 299 Label not_string; |
281 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); | 300 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
282 __ j(not_equal, &true_result, Label::kNear); | 301 __ j(above_equal, ¬_string, Label::kNear); |
283 __ xorps(xmm0, xmm0); | 302 __ movq(tos_, FieldOperand(argument, String::kLengthOffset)); |
284 __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | 303 __ ret(1 * kPointerSize); // the string length is OK as the return value |
285 __ j(zero, &false_result, Label::kNear); | 304 __ bind(¬_string); |
286 // Fall through to |true_result|. | 305 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 306 // We've seen a string for the first time -> patch |
| 307 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
| 308 __ j(below, &patch, Label::kNear); |
| 309 } |
287 | 310 |
288 // Return 1/0 for true/false in tos_. | 311 if (types_.Contains(HEAP_NUMBER)) { |
289 __ bind(&true_result); | 312 // heap number -> false iff +0, -0, or NaN. |
290 __ Set(tos_, 1); | 313 Label not_heap_number, false_result; |
291 __ ret(1 * kPointerSize); | 314 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
292 __ bind(&false_result); | 315 __ j(not_equal, ¬_heap_number, Label::kNear); |
293 __ Set(tos_, 0); | 316 __ xorps(xmm0, xmm0); |
294 __ ret(1 * kPointerSize); | 317 __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset)); |
| 318 __ j(zero, &false_result, Label::kNear); |
| 319 __ Set(tos_, 1); |
| 320 __ ret(1 * kPointerSize); |
| 321 __ bind(&false_result); |
| 322 __ Set(tos_, 0); |
| 323 __ ret(1 * kPointerSize); |
| 324 __ bind(¬_heap_number); |
| 325 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 326 // We've seen a heap number for the first time -> patch |
| 327 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
| 328 __ j(equal, &patch, Label::kNear); |
| 329 } |
| 330 |
| 331 if (types_.Contains(INTERNAL_OBJECT)) { |
| 332 // internal objects -> true |
| 333 __ Set(tos_, 1); |
| 334 __ ret(1 * kPointerSize); |
| 335 } |
| 336 |
| 337 if (!types_.IsAll()) { |
| 338 __ bind(&patch); |
| 339 GenerateTypeTransition(masm); |
| 340 } |
| 341 } |
| 342 |
| 343 |
| 344 void ToBooleanStub::CheckOddball(MacroAssembler* masm, |
| 345 Type type, |
| 346 Heap::RootListIndex value, |
| 347 bool result, |
| 348 Label* patch) { |
| 349 const Register argument = rax; |
| 350 if (types_.Contains(type)) { |
| 351 // If we see an expected oddball, return its ToBoolean value tos_. |
| 352 Label different_value; |
| 353 __ CompareRoot(argument, value); |
| 354 __ j(not_equal, &different_value, Label::kNear); |
| 355 __ Set(tos_, result ? 1 : 0); |
| 356 __ ret(1 * kPointerSize); |
| 357 __ bind(&different_value); |
| 358 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 359 // If we see an unexpected oddball and handle internal objects, we must |
| 360 // patch because the code for internal objects doesn't handle it explictly. |
| 361 __ CompareRoot(argument, value); |
| 362 __ j(equal, patch); |
| 363 } |
| 364 } |
| 365 |
| 366 |
| 367 void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 368 __ pop(rcx); // Get return address, operand is now on top of stack. |
| 369 __ Push(Smi::FromInt(tos_.code())); |
| 370 __ Push(Smi::FromInt(types_.ToByte())); |
| 371 __ push(rcx); // Push return address. |
| 372 // Patch the caller to an appropriate specialized stub and return the |
| 373 // operation result to the caller of the stub. |
| 374 __ TailCallExternalReference( |
| 375 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), |
| 376 3, |
| 377 1); |
295 } | 378 } |
296 | 379 |
297 | 380 |
298 class FloatingPointHelper : public AllStatic { | 381 class FloatingPointHelper : public AllStatic { |
299 public: | 382 public: |
300 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. | 383 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. |
301 // If the operands are not both numbers, jump to not_numbers. | 384 // If the operands are not both numbers, jump to not_numbers. |
302 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. | 385 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. |
303 // NumberOperands assumes both are smis or heap numbers. | 386 // NumberOperands assumes both are smis or heap numbers. |
304 static void LoadSSE2SmiOperands(MacroAssembler* masm); | 387 static void LoadSSE2SmiOperands(MacroAssembler* masm); |
(...skipping 4978 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5283 __ Drop(1); | 5366 __ Drop(1); |
5284 __ ret(2 * kPointerSize); | 5367 __ ret(2 * kPointerSize); |
5285 } | 5368 } |
5286 | 5369 |
5287 | 5370 |
5288 #undef __ | 5371 #undef __ |
5289 | 5372 |
5290 } } // namespace v8::internal | 5373 } } // namespace v8::internal |
5291 | 5374 |
5292 #endif // V8_TARGET_ARCH_X64 | 5375 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |