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 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 void ToBooleanStub::Generate(MacroAssembler* masm) { | 235 void ToBooleanStub::Generate(MacroAssembler* masm) { |
236 Label patch; | 236 Label patch; |
237 const Register argument = rax; | 237 const Register argument = rax; |
238 const Register map = rdx; | 238 const Register map = rdx; |
239 | 239 |
240 if (!types_.IsEmpty()) { | 240 if (!types_.IsEmpty()) { |
241 __ movq(argument, Operand(rsp, 1 * kPointerSize)); | 241 __ movq(argument, Operand(rsp, 1 * kPointerSize)); |
242 } | 242 } |
243 | 243 |
244 // undefined -> false | 244 // undefined -> false |
245 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); | 245 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); |
246 | 246 |
247 // Boolean -> its value | 247 // Boolean -> its value |
248 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); | 248 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); |
249 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); | 249 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); |
250 | 250 |
251 // 'null' -> false. | 251 // 'null' -> false. |
252 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); | 252 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); |
253 | 253 |
254 if (types_.Contains(SMI)) { | 254 if (types_.Contains(SMI)) { |
255 // Smis: 0 -> false, all other -> true | 255 // Smis: 0 -> false, all other -> true |
256 Label not_smi; | 256 Label not_smi; |
257 __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); | 257 __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); |
258 // argument contains the correct return value already | 258 // argument contains the correct return value already |
259 if (!tos_.is(argument)) { | 259 if (!tos_.is(argument)) { |
260 __ movq(tos_, argument); | 260 __ movq(tos_, argument); |
261 } | 261 } |
262 __ ret(1 * kPointerSize); | 262 __ ret(1 * kPointerSize); |
263 __ bind(¬_smi); | 263 __ bind(¬_smi); |
264 } else if (types_.NeedsMap()) { | 264 } else if (types_.NeedsMap()) { |
265 // If we need a map later and have a Smi -> patch. | 265 // If we need a map later and have a Smi -> patch. |
266 __ JumpIfSmi(argument, &patch, Label::kNear); | 266 __ JumpIfSmi(argument, &patch, Label::kNear); |
267 } | 267 } |
268 | 268 |
269 if (types_.NeedsMap()) { | 269 if (types_.NeedsMap()) { |
270 __ movq(map, FieldOperand(argument, HeapObject::kMapOffset)); | 270 __ movq(map, FieldOperand(argument, HeapObject::kMapOffset)); |
271 | 271 |
272 // Everything with a map could be undetectable, so check this now. | 272 if (types_.CanBeUndetectable()) { |
273 __ testb(FieldOperand(map, Map::kBitFieldOffset), | 273 __ testb(FieldOperand(map, Map::kBitFieldOffset), |
274 Immediate(1 << Map::kIsUndetectable)); | 274 Immediate(1 << Map::kIsUndetectable)); |
275 // Undetectable -> false. | 275 // Undetectable -> false. |
276 Label not_undetectable; | 276 Label not_undetectable; |
277 __ j(zero, ¬_undetectable, Label::kNear); | 277 __ j(zero, ¬_undetectable, Label::kNear); |
278 __ Set(tos_, 0); | 278 __ Set(tos_, 0); |
279 __ ret(1 * kPointerSize); | 279 __ ret(1 * kPointerSize); |
280 __ bind(¬_undetectable); | 280 __ bind(¬_undetectable); |
| 281 } |
281 } | 282 } |
282 | 283 |
283 if (types_.Contains(SPEC_OBJECT)) { | 284 if (types_.Contains(SPEC_OBJECT)) { |
284 // spec object -> true. | 285 // spec object -> true. |
285 Label not_js_object; | 286 Label not_js_object; |
286 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); | 287 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
287 __ j(below, ¬_js_object, Label::kNear); | 288 __ j(below, ¬_js_object, Label::kNear); |
288 __ Set(tos_, 1); | 289 // argument contains the correct return value already. |
| 290 if (!tos_.is(argument)) { |
| 291 __ Set(tos_, 1); |
| 292 } |
289 __ ret(1 * kPointerSize); | 293 __ ret(1 * kPointerSize); |
290 __ bind(¬_js_object); | 294 __ 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 } | 295 } |
296 | 296 |
297 if (types_.Contains(STRING)) { | 297 if (types_.Contains(STRING)) { |
298 // String value -> false iff empty. | 298 // String value -> false iff empty. |
299 Label not_string; | 299 Label not_string; |
300 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); | 300 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
301 __ j(above_equal, ¬_string, Label::kNear); | 301 __ j(above_equal, ¬_string, Label::kNear); |
302 __ movq(tos_, FieldOperand(argument, String::kLengthOffset)); | 302 __ movq(tos_, FieldOperand(argument, String::kLengthOffset)); |
303 __ ret(1 * kPointerSize); // the string length is OK as the return value | 303 __ ret(1 * kPointerSize); // the string length is OK as the return value |
304 __ bind(¬_string); | 304 __ bind(¬_string); |
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 } | 305 } |
310 | 306 |
311 if (types_.Contains(HEAP_NUMBER)) { | 307 if (types_.Contains(HEAP_NUMBER)) { |
312 // heap number -> false iff +0, -0, or NaN. | 308 // heap number -> false iff +0, -0, or NaN. |
313 Label not_heap_number, false_result; | 309 Label not_heap_number, false_result; |
314 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); | 310 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
315 __ j(not_equal, ¬_heap_number, Label::kNear); | 311 __ j(not_equal, ¬_heap_number, Label::kNear); |
316 __ xorps(xmm0, xmm0); | 312 __ xorps(xmm0, xmm0); |
317 __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset)); | 313 __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset)); |
318 __ j(zero, &false_result, Label::kNear); | 314 __ j(zero, &false_result, Label::kNear); |
319 __ Set(tos_, 1); | 315 // argument contains the correct return value already. |
| 316 if (!tos_.is(argument)) { |
| 317 __ Set(tos_, 1); |
| 318 } |
320 __ ret(1 * kPointerSize); | 319 __ ret(1 * kPointerSize); |
321 __ bind(&false_result); | 320 __ bind(&false_result); |
322 __ Set(tos_, 0); | 321 __ Set(tos_, 0); |
323 __ ret(1 * kPointerSize); | 322 __ ret(1 * kPointerSize); |
324 __ bind(¬_heap_number); | 323 __ 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 } | 324 } |
330 | 325 |
331 if (types_.Contains(INTERNAL_OBJECT)) { | 326 __ bind(&patch); |
332 // internal objects -> true | 327 GenerateTypeTransition(masm); |
333 __ Set(tos_, 1); | |
334 __ ret(1 * kPointerSize); | |
335 } | |
336 | |
337 if (!types_.IsAll()) { | |
338 __ bind(&patch); | |
339 GenerateTypeTransition(masm); | |
340 } | |
341 } | 328 } |
342 | 329 |
343 | 330 |
344 void ToBooleanStub::CheckOddball(MacroAssembler* masm, | 331 void ToBooleanStub::CheckOddball(MacroAssembler* masm, |
345 Type type, | 332 Type type, |
346 Heap::RootListIndex value, | 333 Heap::RootListIndex value, |
347 bool result, | 334 bool result) { |
348 Label* patch) { | |
349 const Register argument = rax; | 335 const Register argument = rax; |
350 if (types_.Contains(type)) { | 336 if (types_.Contains(type)) { |
351 // If we see an expected oddball, return its ToBoolean value tos_. | 337 // If we see an expected oddball, return its ToBoolean value tos_. |
352 Label different_value; | 338 Label different_value; |
353 __ CompareRoot(argument, value); | 339 __ CompareRoot(argument, value); |
354 __ j(not_equal, &different_value, Label::kNear); | 340 __ j(not_equal, &different_value, Label::kNear); |
355 __ Set(tos_, result ? 1 : 0); | 341 if (!result) { |
| 342 // If we have to return zero, there is no way around clearing tos_. |
| 343 __ Set(tos_, 0); |
| 344 } else if (!tos_.is(argument)) { |
| 345 // If we have to return non-zero, we can re-use the argument if it is the |
| 346 // same register as the result, because we never see Smi-zero here. |
| 347 __ Set(tos_, 1); |
| 348 } |
356 __ ret(1 * kPointerSize); | 349 __ ret(1 * kPointerSize); |
357 __ bind(&different_value); | 350 __ 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 } | 351 } |
364 } | 352 } |
365 | 353 |
366 | 354 |
367 void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { | 355 void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { |
368 __ pop(rcx); // Get return address, operand is now on top of stack. | 356 __ pop(rcx); // Get return address, operand is now on top of stack. |
369 __ Push(Smi::FromInt(tos_.code())); | 357 __ Push(Smi::FromInt(tos_.code())); |
370 __ Push(Smi::FromInt(types_.ToByte())); | 358 __ Push(Smi::FromInt(types_.ToByte())); |
371 __ push(rcx); // Push return address. | 359 __ push(rcx); // Push return address. |
372 // Patch the caller to an appropriate specialized stub and return the | 360 // Patch the caller to an appropriate specialized stub and return the |
(...skipping 4993 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5366 __ Drop(1); | 5354 __ Drop(1); |
5367 __ ret(2 * kPointerSize); | 5355 __ ret(2 * kPointerSize); |
5368 } | 5356 } |
5369 | 5357 |
5370 | 5358 |
5371 #undef __ | 5359 #undef __ |
5372 | 5360 |
5373 } } // namespace v8::internal | 5361 } } // namespace v8::internal |
5374 | 5362 |
5375 #endif // V8_TARGET_ARCH_X64 | 5363 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |