Chromium Code Reviews| 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 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 229 } | 229 } |
| 230 | 230 |
| 231 // Return and remove the on-stack parameters. | 231 // Return and remove the on-stack parameters. |
| 232 __ ret(3 * kPointerSize); | 232 __ ret(3 * kPointerSize); |
| 233 | 233 |
| 234 __ bind(&slow_case); | 234 __ bind(&slow_case); |
| 235 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 235 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 236 } | 236 } |
| 237 | 237 |
| 238 | 238 |
| 239 // The stub returns zero for false, and a non-zero value for true. | 239 // The stub expects its argument on the stack and returns its result in tos_: |
| 240 // zero for false, and a non-zero value for true. | |
| 240 void ToBooleanStub::Generate(MacroAssembler* masm) { | 241 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 241 Label false_result, true_result, not_string; | 242 Label patch; |
| 242 Factory* factory = masm->isolate()->factory(); | 243 Factory* factory = masm->isolate()->factory(); |
| 243 const Register map = edx; | 244 const Register map = edx; |
| 244 | 245 |
| 245 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 246 if (!types_.IsEmpty()) { |
| 247 __ mov(eax, Operand(esp, 1 * kPointerSize)); | |
| 248 } | |
| 246 | 249 |
| 247 // undefined -> false | 250 // undefined -> false |
| 248 __ cmp(eax, factory->undefined_value()); | 251 CheckOddball(masm, UNDEFINED, factory->undefined_value(), false, &patch); |
| 249 __ j(equal, &false_result); | |
| 250 | 252 |
| 251 // Boolean -> its value | 253 // Boolean -> its value |
| 252 __ cmp(eax, factory->false_value()); | 254 CheckOddball(masm, BOOLEAN, factory->false_value(), false, &patch); |
| 253 __ j(equal, &false_result); | 255 CheckOddball(masm, BOOLEAN, factory->true_value(), true, &patch); |
| 254 __ cmp(eax, factory->true_value()); | |
| 255 __ j(equal, &true_result); | |
| 256 | |
| 257 // Smis: 0 -> false, all other -> true | |
| 258 __ test(eax, Operand(eax)); | |
| 259 __ j(zero, &false_result); | |
| 260 __ JumpIfSmi(eax, &true_result); | |
| 261 | 256 |
| 262 // 'null' -> false. | 257 // 'null' -> false. |
| 263 __ cmp(eax, factory->null_value()); | 258 CheckOddball(masm, NULL_TYPE, factory->null_value(), false, &patch); |
| 264 __ j(equal, &false_result, Label::kNear); | |
| 265 | 259 |
| 266 // Get the map of the heap object. | 260 bool need_map = |
| 267 __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); | 261 types_.Contains(UNDETECTABLE) | |
| 262 types_.Contains(SPEC_OBJECT) | | |
| 263 types_.Contains(STRING) | | |
| 264 types_.Contains(HEAP_NUMBER) | | |
| 265 types_.Contains(INTERNAL_OBJECT); | |
| 268 | 266 |
| 269 // Undetectable -> false. | 267 if (types_.Contains(SMI)) { |
| 270 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | 268 // Smis: 0 -> false, all other -> true |
| 271 1 << Map::kIsUndetectable); | 269 Label not_smi; |
| 272 __ j(not_zero, &false_result, Label::kNear); | 270 __ JumpIfNotSmi(eax, ¬_smi, Label::kNear); |
| 271 __ ret(1 * kPointerSize); // eax contains the correct value already | |
| 272 __ bind(¬_smi); | |
| 273 } else if (need_map) { | |
| 274 // If we need a map later and have a Smi -> patch. | |
| 275 __ JumpIfSmi(eax, &patch, Label::kNear); | |
| 276 } | |
| 273 | 277 |
| 274 // JavaScript object -> true. | 278 if (need_map) { |
| 275 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); | 279 __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); |
| 276 __ j(above_equal, &true_result, Label::kNear); | |
| 277 | 280 |
| 278 // String value -> false iff empty. | 281 // Everything with a map could be undetectable, so check this now. |
| 279 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); | 282 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
| 280 __ j(above_equal, ¬_string, Label::kNear); | 283 1 << Map::kIsUndetectable); |
| 281 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); | 284 if (types_.Contains(UNDETECTABLE)) { |
| 282 __ j(zero, &false_result, Label::kNear); | 285 // Undetectable -> false. |
| 283 __ jmp(&true_result, Label::kNear); | 286 Label not_undetectable; |
| 287 __ j(zero, ¬_undetectable, Label::kNear); | |
| 288 __ xor_(tos_, Operand(tos_)); | |
|
Vitaly Repeshko
2011/07/21 13:17:23
The macro assembler has Set macro that emits the o
Sven Panne
2011/07/21 13:49:28
I didn't know that one, thanks. :-)
| |
| 289 __ ret(1 * kPointerSize); | |
| 290 __ bind(¬_undetectable); | |
| 291 } else { | |
| 292 // We've seen an undetectable value for the first time -> patch. | |
| 293 __ j(not_zero, &patch, Label::kNear); | |
| 294 } | |
| 295 } | |
| 284 | 296 |
| 285 __ bind(¬_string); | 297 if (types_.Contains(SPEC_OBJECT)) { |
| 286 // HeapNumber -> false iff +0, -0, or NaN. | 298 // spec object -> true. |
| 287 __ cmp(map, factory->heap_number_map()); | 299 Label not_js_object; |
| 288 __ j(not_equal, &true_result, Label::kNear); | 300 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 289 __ fldz(); | 301 __ j(below, ¬_js_object, Label::kNear); |
| 290 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 302 __ mov(tos_, 1); |
| 291 __ FCmp(); | 303 __ ret(1 * kPointerSize); |
| 292 __ j(zero, &false_result, Label::kNear); | 304 __ bind(¬_js_object); |
| 293 // Fall through to |true_result|. | 305 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 306 // We've seen a spec object for the first time -> patch. | |
| 307 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); | |
| 308 __ j(above_equal, &patch, Label::kNear); | |
| 309 } | |
| 294 | 310 |
| 295 // Return 1/0 for true/false in tos_. | 311 if (types_.Contains(STRING)) { |
| 296 __ bind(&true_result); | 312 // String value -> false iff empty. |
| 297 __ mov(tos_, 1); | 313 Label not_string; |
| 298 __ ret(1 * kPointerSize); | 314 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
| 299 __ bind(&false_result); | 315 __ j(above_equal, ¬_string, Label::kNear); |
| 300 __ mov(tos_, 0); | 316 __ mov(eax, FieldOperand(eax, String::kLengthOffset)); |
|
danno
2011/07/21 12:39:07
eax -> tos_?
Sven Panne
2011/07/21 13:49:28
Ooops, fixed, same for Smi part above.
| |
| 301 __ ret(1 * kPointerSize); | 317 __ ret(1 * kPointerSize); // the string length is OK as the return value |
| 318 __ bind(¬_string); | |
| 319 } else if (types_.Contains(INTERNAL_OBJECT)) { | |
| 320 // We've seen a string for the first time -> patch | |
| 321 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); | |
| 322 __ j(below, &patch, Label::kNear); | |
| 323 } | |
| 324 | |
| 325 if (types_.Contains(HEAP_NUMBER)) { | |
| 326 // heap number -> false iff +0, -0, or NaN. | |
| 327 Label not_heap_number, false_result; | |
| 328 __ cmp(map, factory->heap_number_map()); | |
| 329 __ j(not_equal, ¬_heap_number, Label::kNear); | |
| 330 __ fldz(); | |
| 331 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 332 __ FCmp(); | |
| 333 __ j(zero, &false_result, Label::kNear); | |
| 334 __ mov(tos_, 1); | |
| 335 __ ret(1 * kPointerSize); | |
| 336 __ bind(&false_result); | |
| 337 __ xor_(tos_, Operand(tos_)); | |
| 338 __ ret(1 * kPointerSize); | |
| 339 __ bind(¬_heap_number); | |
| 340 } else if (types_.Contains(INTERNAL_OBJECT)) { | |
| 341 // We've seen a heap number for the first time -> patch | |
| 342 __ cmp(map, factory->heap_number_map()); | |
| 343 __ j(equal, &patch, Label::kNear); | |
| 344 } | |
| 345 | |
| 346 if (types_.Contains(INTERNAL_OBJECT)) { | |
|
fschneider
2011/07/21 13:16:44
Can you explain why we need the INTERNAL_OBJECT ca
Sven Panne
2011/07/21 13:49:28
While we probably can't encounter internal objects
| |
| 347 // internal objects -> true | |
| 348 __ mov(tos_, 1); | |
| 349 __ ret(1 * kPointerSize); | |
| 350 } | |
| 351 | |
| 352 __ bind(&patch); | |
| 353 GenerateTypeTransition(masm); | |
| 354 } | |
| 355 | |
| 356 | |
| 357 void ToBooleanStub::CheckOddball(MacroAssembler* masm, | |
| 358 Type type, | |
| 359 Handle<Object> value, | |
| 360 bool result, | |
| 361 Label* patch) { | |
| 362 __ cmp(eax, value); | |
|
danno
2011/07/21 12:39:07
This should be duplicated in the two if branches s
Sven Panne
2011/07/21 13:49:28
Done.
| |
| 363 if (types_.Contains(type)) { | |
| 364 // If we see an expected oddball, return its ToBoolean value tos_. | |
| 365 Label different_value; | |
| 366 __ j(not_equal, &different_value, Label::kNear); | |
| 367 if (result) { | |
| 368 __ mov(tos_, 1); | |
| 369 } else { | |
| 370 __ xor_(tos_, Operand(tos_)); | |
| 371 } | |
| 372 __ ret(1 * kPointerSize); | |
| 373 __ bind(&different_value); | |
| 374 } else if (types_.Contains(INTERNAL_OBJECT)) { | |
| 375 // If we see an unexpected oddball and handle internal objects, we must | |
| 376 // patch because the code for internal objects doesn't handle it explictly. | |
| 377 __ j(equal, patch); | |
| 378 } | |
| 379 } | |
| 380 | |
| 381 | |
| 382 void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { | |
| 383 __ pop(ecx); // Get return address, operand is now on top of stack. | |
| 384 __ push(Immediate(Smi::FromInt(tos_.code()))); | |
| 385 __ push(Immediate(Smi::FromInt(types_.ToInt()))); | |
| 386 __ push(ecx); // Push return address. | |
| 387 // Patch the caller to an appropriate specialized stub and return the | |
| 388 // operation result to the caller of the stub. | |
| 389 __ TailCallExternalReference( | |
| 390 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), | |
| 391 3, | |
| 392 1); | |
| 302 } | 393 } |
| 303 | 394 |
| 304 | 395 |
| 305 class FloatingPointHelper : public AllStatic { | 396 class FloatingPointHelper : public AllStatic { |
| 306 public: | 397 public: |
| 307 enum ArgLocation { | 398 enum ArgLocation { |
| 308 ARGS_ON_STACK, | 399 ARGS_ON_STACK, |
| 309 ARGS_IN_REGISTERS | 400 ARGS_IN_REGISTERS |
| 310 }; | 401 }; |
| 311 | 402 |
| (...skipping 5981 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6293 __ Drop(1); | 6384 __ Drop(1); |
| 6294 __ ret(2 * kPointerSize); | 6385 __ ret(2 * kPointerSize); |
| 6295 } | 6386 } |
| 6296 | 6387 |
| 6297 | 6388 |
| 6298 #undef __ | 6389 #undef __ |
| 6299 | 6390 |
| 6300 } } // namespace v8::internal | 6391 } } // namespace v8::internal |
| 6301 | 6392 |
| 6302 #endif // V8_TARGET_ARCH_IA32 | 6393 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |