| 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 } |
| 295 } | 341 } |
| 296 | 342 |
| 297 | 343 |
| 298 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 344 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 299 __ PushCallerSaved(save_doubles_); | 345 __ PushCallerSaved(save_doubles_); |
| 300 const int argument_count = 1; | 346 const int argument_count = 1; |
| 301 __ PrepareCallCFunction(argument_count); | 347 __ PrepareCallCFunction(argument_count); |
| 302 #ifdef _WIN64 | 348 #ifdef _WIN64 |
| 303 __ LoadAddress(rcx, ExternalReference::isolate_address()); | 349 __ LoadAddress(rcx, ExternalReference::isolate_address()); |
| 304 #else | 350 #else |
| 305 __ LoadAddress(rdi, ExternalReference::isolate_address()); | 351 __ LoadAddress(rdi, ExternalReference::isolate_address()); |
| 306 #endif | 352 #endif |
| 307 __ CallCFunction( | 353 __ CallCFunction( |
| 308 ExternalReference::store_buffer_overflow_function(masm->isolate()), | 354 ExternalReference::store_buffer_overflow_function(masm->isolate()), |
| 309 argument_count); | 355 argument_count); |
| 310 __ PopCallerSaved(save_doubles_); | 356 __ PopCallerSaved(save_doubles_); |
| 311 __ ret(0); | 357 __ ret(0); |
| 312 } | 358 } |
| 313 | 359 |
| 314 | 360 |
| 361 void ToBooleanStub::CheckOddball(MacroAssembler* masm, |
| 362 Type type, |
| 363 Heap::RootListIndex value, |
| 364 bool result, |
| 365 Label* patch) { |
| 366 const Register argument = rax; |
| 367 if (types_.Contains(type)) { |
| 368 // If we see an expected oddball, return its ToBoolean value tos_. |
| 369 Label different_value; |
| 370 __ CompareRoot(argument, value); |
| 371 __ j(not_equal, &different_value, Label::kNear); |
| 372 __ Set(tos_, result ? 1 : 0); |
| 373 __ ret(1 * kPointerSize); |
| 374 __ bind(&different_value); |
| 375 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 376 // If we see an unexpected oddball and handle internal objects, we must |
| 377 // patch because the code for internal objects doesn't handle it explictly. |
| 378 __ CompareRoot(argument, value); |
| 379 __ j(equal, patch); |
| 380 } |
| 381 } |
| 382 |
| 383 |
| 384 void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 385 __ pop(rcx); // Get return address, operand is now on top of stack. |
| 386 __ Push(Smi::FromInt(tos_.code())); |
| 387 __ Push(Smi::FromInt(types_.ToByte())); |
| 388 __ push(rcx); // Push return address. |
| 389 // Patch the caller to an appropriate specialized stub and return the |
| 390 // operation result to the caller of the stub. |
| 391 __ TailCallExternalReference( |
| 392 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), |
| 393 3, |
| 394 1); |
| 395 } |
| 396 |
| 397 |
| 315 class FloatingPointHelper : public AllStatic { | 398 class FloatingPointHelper : public AllStatic { |
| 316 public: | 399 public: |
| 317 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. | 400 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. |
| 318 // If the operands are not both numbers, jump to not_numbers. | 401 // If the operands are not both numbers, jump to not_numbers. |
| 319 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. | 402 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. |
| 320 // NumberOperands assumes both are smis or heap numbers. | 403 // NumberOperands assumes both are smis or heap numbers. |
| 321 static void LoadSSE2SmiOperands(MacroAssembler* masm); | 404 static void LoadSSE2SmiOperands(MacroAssembler* masm); |
| 322 static void LoadSSE2NumberOperands(MacroAssembler* masm); | 405 static void LoadSSE2NumberOperands(MacroAssembler* masm); |
| 323 static void LoadSSE2UnknownOperands(MacroAssembler* masm, | 406 static void LoadSSE2UnknownOperands(MacroAssembler* masm, |
| 324 Label* not_numbers); | 407 Label* not_numbers); |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 break; | 735 break; |
| 653 case Token::BIT_NOT: | 736 case Token::BIT_NOT: |
| 654 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | 737 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
| 655 break; | 738 break; |
| 656 default: | 739 default: |
| 657 UNREACHABLE(); | 740 UNREACHABLE(); |
| 658 } | 741 } |
| 659 } | 742 } |
| 660 | 743 |
| 661 | 744 |
| 662 const char* UnaryOpStub::GetName() { | 745 void UnaryOpStub::PrintName(StringStream* stream) { |
| 663 if (name_ != NULL) return name_; | |
| 664 const int kMaxNameLength = 100; | |
| 665 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | |
| 666 kMaxNameLength); | |
| 667 if (name_ == NULL) return "OOM"; | |
| 668 const char* op_name = Token::Name(op_); | 746 const char* op_name = Token::Name(op_); |
| 669 const char* overwrite_name = NULL; // Make g++ happy. | 747 const char* overwrite_name = NULL; // Make g++ happy. |
| 670 switch (mode_) { | 748 switch (mode_) { |
| 671 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 749 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 672 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; | 750 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; |
| 673 } | 751 } |
| 674 | 752 stream->Add("UnaryOpStub_%s_%s_%s", |
| 675 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 753 op_name, |
| 676 "UnaryOpStub_%s_%s_%s", | 754 overwrite_name, |
| 677 op_name, | 755 UnaryOpIC::GetName(operand_type_)); |
| 678 overwrite_name, | |
| 679 UnaryOpIC::GetName(operand_type_)); | |
| 680 return name_; | |
| 681 } | 756 } |
| 682 | 757 |
| 683 | 758 |
| 684 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 759 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 685 __ pop(rcx); // Save return address. | 760 __ pop(rcx); // Save return address. |
| 686 __ push(rdx); | 761 __ push(rdx); |
| 687 __ push(rax); | 762 __ push(rax); |
| 688 // Left and right arguments are now on top. | 763 // Left and right arguments are now on top. |
| 689 // Push this stub's key. Although the operation and the type info are | 764 // Push this stub's key. Although the operation and the type info are |
| 690 // encoded into the key, the encoding is opaque, so push them too. | 765 // encoded into the key, the encoding is opaque, so push them too. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 break; | 806 break; |
| 732 case BinaryOpIC::GENERIC: | 807 case BinaryOpIC::GENERIC: |
| 733 GenerateGeneric(masm); | 808 GenerateGeneric(masm); |
| 734 break; | 809 break; |
| 735 default: | 810 default: |
| 736 UNREACHABLE(); | 811 UNREACHABLE(); |
| 737 } | 812 } |
| 738 } | 813 } |
| 739 | 814 |
| 740 | 815 |
| 741 const char* BinaryOpStub::GetName() { | 816 void BinaryOpStub::PrintName(StringStream* stream) { |
| 742 if (name_ != NULL) return name_; | |
| 743 const int kMaxNameLength = 100; | |
| 744 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | |
| 745 kMaxNameLength); | |
| 746 if (name_ == NULL) return "OOM"; | |
| 747 const char* op_name = Token::Name(op_); | 817 const char* op_name = Token::Name(op_); |
| 748 const char* overwrite_name; | 818 const char* overwrite_name; |
| 749 switch (mode_) { | 819 switch (mode_) { |
| 750 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 820 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 751 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 821 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 752 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 822 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 753 default: overwrite_name = "UnknownOverwrite"; break; | 823 default: overwrite_name = "UnknownOverwrite"; break; |
| 754 } | 824 } |
| 755 | 825 stream->Add("BinaryOpStub_%s_%s_%s", |
| 756 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 826 op_name, |
| 757 "BinaryOpStub_%s_%s_%s", | 827 overwrite_name, |
| 758 op_name, | 828 BinaryOpIC::GetName(operands_type_)); |
| 759 overwrite_name, | |
| 760 BinaryOpIC::GetName(operands_type_)); | |
| 761 return name_; | |
| 762 } | 829 } |
| 763 | 830 |
| 764 | 831 |
| 765 void BinaryOpStub::GenerateSmiCode( | 832 void BinaryOpStub::GenerateSmiCode( |
| 766 MacroAssembler* masm, | 833 MacroAssembler* masm, |
| 767 Label* slow, | 834 Label* slow, |
| 768 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { | 835 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { |
| 769 | 836 |
| 770 // Arguments to BinaryOpStub are in rdx and rax. | 837 // Arguments to BinaryOpStub are in rdx and rax. |
| 771 Register left = rdx; | 838 Register left = rdx; |
| (...skipping 1783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2555 __ bind(&setup_rest); | 2622 __ bind(&setup_rest); |
| 2556 // Argument 2: Previous index. | 2623 // Argument 2: Previous index. |
| 2557 __ movq(arg2, rbx); | 2624 __ movq(arg2, rbx); |
| 2558 | 2625 |
| 2559 // Argument 1: Subject string. | 2626 // Argument 1: Subject string. |
| 2560 #ifdef _WIN64 | 2627 #ifdef _WIN64 |
| 2561 __ movq(arg1, rdi); | 2628 __ movq(arg1, rdi); |
| 2562 #else | 2629 #else |
| 2563 // Already there in AMD64 calling convention. | 2630 // Already there in AMD64 calling convention. |
| 2564 ASSERT(arg1.is(rdi)); | 2631 ASSERT(arg1.is(rdi)); |
| 2632 USE(arg1); |
| 2565 #endif | 2633 #endif |
| 2566 | 2634 |
| 2567 // Locate the code entry and call it. | 2635 // Locate the code entry and call it. |
| 2568 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 2636 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 2569 __ call(r11); | 2637 __ call(r11); |
| 2570 | 2638 |
| 2571 __ LeaveApiExitFrame(); | 2639 __ LeaveApiExitFrame(); |
| 2572 | 2640 |
| 2573 // Check the result. | 2641 // Check the result. |
| 2574 Label success; | 2642 Label success; |
| (...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3230 // Slow-case: Non-function called. | 3298 // Slow-case: Non-function called. |
| 3231 __ bind(&slow); | 3299 __ bind(&slow); |
| 3232 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | 3300 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 3233 // of the original receiver from the call site). | 3301 // of the original receiver from the call site). |
| 3234 __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi); | 3302 __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi); |
| 3235 __ Set(rax, argc_); | 3303 __ Set(rax, argc_); |
| 3236 __ Set(rbx, 0); | 3304 __ Set(rbx, 0); |
| 3237 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); | 3305 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
| 3238 Handle<Code> adaptor = | 3306 Handle<Code> adaptor = |
| 3239 Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline(); | 3307 Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline(); |
| 3308 __ SetCallKind(rcx, CALL_AS_METHOD); |
| 3240 __ Jump(adaptor, RelocInfo::CODE_TARGET); | 3309 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
| 3241 } | 3310 } |
| 3242 | 3311 |
| 3243 | 3312 |
| 3244 bool CEntryStub::NeedsImmovableCode() { | 3313 bool CEntryStub::NeedsImmovableCode() { |
| 3245 return false; | 3314 return false; |
| 3246 } | 3315 } |
| 3247 | 3316 |
| 3248 | 3317 |
| 3249 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 3318 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3466 __ bind(&throw_termination_exception); | 3535 __ bind(&throw_termination_exception); |
| 3467 GenerateThrowUncatchable(masm, TERMINATION); | 3536 GenerateThrowUncatchable(masm, TERMINATION); |
| 3468 | 3537 |
| 3469 __ bind(&throw_normal_exception); | 3538 __ bind(&throw_normal_exception); |
| 3470 GenerateThrowTOS(masm); | 3539 GenerateThrowTOS(masm); |
| 3471 } | 3540 } |
| 3472 | 3541 |
| 3473 | 3542 |
| 3474 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { | 3543 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |
| 3475 Label invoke, exit; | 3544 Label invoke, exit; |
| 3476 #ifdef ENABLE_LOGGING_AND_PROFILING | |
| 3477 Label not_outermost_js, not_outermost_js_2; | 3545 Label not_outermost_js, not_outermost_js_2; |
| 3478 #endif | |
| 3479 { // NOLINT. Scope block confuses linter. | 3546 { // NOLINT. Scope block confuses linter. |
| 3480 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); | 3547 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); |
| 3481 // Setup frame. | 3548 // Setup frame. |
| 3482 __ push(rbp); | 3549 __ push(rbp); |
| 3483 __ movq(rbp, rsp); | 3550 __ movq(rbp, rsp); |
| 3484 | 3551 |
| 3485 // Push the stack frame type marker twice. | 3552 // Push the stack frame type marker twice. |
| 3486 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; | 3553 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |
| 3487 // Scratch register is neither callee-save, nor an argument register on any | 3554 // Scratch register is neither callee-save, nor an argument register on any |
| 3488 // platform. It's free to use at this point. | 3555 // platform. It's free to use at this point. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3513 | 3580 |
| 3514 Isolate* isolate = masm->isolate(); | 3581 Isolate* isolate = masm->isolate(); |
| 3515 | 3582 |
| 3516 // Save copies of the top frame descriptor on the stack. | 3583 // Save copies of the top frame descriptor on the stack. |
| 3517 ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, isolate); | 3584 ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, isolate); |
| 3518 { | 3585 { |
| 3519 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); | 3586 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); |
| 3520 __ push(c_entry_fp_operand); | 3587 __ push(c_entry_fp_operand); |
| 3521 } | 3588 } |
| 3522 | 3589 |
| 3523 #ifdef ENABLE_LOGGING_AND_PROFILING | |
| 3524 // If this is the outermost JS call, set js_entry_sp value. | 3590 // If this is the outermost JS call, set js_entry_sp value. |
| 3525 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate); | 3591 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate); |
| 3526 __ Load(rax, js_entry_sp); | 3592 __ Load(rax, js_entry_sp); |
| 3527 __ testq(rax, rax); | 3593 __ testq(rax, rax); |
| 3528 __ j(not_zero, ¬_outermost_js); | 3594 __ j(not_zero, ¬_outermost_js); |
| 3529 __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); | 3595 __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| 3530 __ movq(rax, rbp); | 3596 __ movq(rax, rbp); |
| 3531 __ Store(js_entry_sp, rax); | 3597 __ Store(js_entry_sp, rax); |
| 3532 Label cont; | 3598 Label cont; |
| 3533 __ jmp(&cont); | 3599 __ jmp(&cont); |
| 3534 __ bind(¬_outermost_js); | 3600 __ bind(¬_outermost_js); |
| 3535 __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); | 3601 __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); |
| 3536 __ bind(&cont); | 3602 __ bind(&cont); |
| 3537 #endif | |
| 3538 | 3603 |
| 3539 // Call a faked try-block that does the invoke. | 3604 // Call a faked try-block that does the invoke. |
| 3540 __ call(&invoke); | 3605 __ call(&invoke); |
| 3541 | 3606 |
| 3542 // Caught exception: Store result (exception) in the pending | 3607 // Caught exception: Store result (exception) in the pending |
| 3543 // exception field in the JSEnv and return a failure sentinel. | 3608 // exception field in the JSEnv and return a failure sentinel. |
| 3544 ExternalReference pending_exception(Isolate::k_pending_exception_address, | 3609 ExternalReference pending_exception(Isolate::k_pending_exception_address, |
| 3545 isolate); | 3610 isolate); |
| 3546 __ Store(pending_exception, rax); | 3611 __ Store(pending_exception, rax); |
| 3547 __ movq(rax, Failure::Exception(), RelocInfo::NONE); | 3612 __ movq(rax, Failure::Exception(), RelocInfo::NONE); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3571 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate); | 3636 ExternalReference entry(Builtins::kJSEntryTrampoline, isolate); |
| 3572 __ Load(rax, entry); | 3637 __ Load(rax, entry); |
| 3573 } | 3638 } |
| 3574 __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize)); | 3639 __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize)); |
| 3575 __ call(kScratchRegister); | 3640 __ call(kScratchRegister); |
| 3576 | 3641 |
| 3577 // Unlink this frame from the handler chain. | 3642 // Unlink this frame from the handler chain. |
| 3578 __ PopTryHandler(); | 3643 __ PopTryHandler(); |
| 3579 | 3644 |
| 3580 __ bind(&exit); | 3645 __ bind(&exit); |
| 3581 #ifdef ENABLE_LOGGING_AND_PROFILING | |
| 3582 // Check if the current stack frame is marked as the outermost JS frame. | 3646 // Check if the current stack frame is marked as the outermost JS frame. |
| 3583 __ pop(rbx); | 3647 __ pop(rbx); |
| 3584 __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); | 3648 __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| 3585 __ j(not_equal, ¬_outermost_js_2); | 3649 __ j(not_equal, ¬_outermost_js_2); |
| 3586 __ movq(kScratchRegister, js_entry_sp); | 3650 __ movq(kScratchRegister, js_entry_sp); |
| 3587 __ movq(Operand(kScratchRegister, 0), Immediate(0)); | 3651 __ movq(Operand(kScratchRegister, 0), Immediate(0)); |
| 3588 __ bind(¬_outermost_js_2); | 3652 __ bind(¬_outermost_js_2); |
| 3589 #endif | |
| 3590 | 3653 |
| 3591 // Restore the top frame descriptor from the stack. | 3654 // Restore the top frame descriptor from the stack. |
| 3592 { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); | 3655 { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); |
| 3593 __ pop(c_entry_fp_operand); | 3656 __ pop(c_entry_fp_operand); |
| 3594 } | 3657 } |
| 3595 | 3658 |
| 3596 // Restore callee-saved registers (X64 conventions). | 3659 // Restore callee-saved registers (X64 conventions). |
| 3597 __ pop(rbx); | 3660 __ pop(rbx); |
| 3598 #ifdef _WIN64 | 3661 #ifdef _WIN64 |
| 3599 // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI. | 3662 // Callee save on in Win64 ABI, arguments/volatile in AMD64 ABI. |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3793 | RegisterField::encode(false) // lhs_ and rhs_ are not used | 3856 | RegisterField::encode(false) // lhs_ and rhs_ are not used |
| 3794 | StrictField::encode(strict_) | 3857 | StrictField::encode(strict_) |
| 3795 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) | 3858 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) |
| 3796 | IncludeNumberCompareField::encode(include_number_compare_) | 3859 | IncludeNumberCompareField::encode(include_number_compare_) |
| 3797 | IncludeSmiCompareField::encode(include_smi_compare_); | 3860 | IncludeSmiCompareField::encode(include_smi_compare_); |
| 3798 } | 3861 } |
| 3799 | 3862 |
| 3800 | 3863 |
| 3801 // Unfortunately you have to run without snapshots to see most of these | 3864 // Unfortunately you have to run without snapshots to see most of these |
| 3802 // names in the profile since most compare stubs end up in the snapshot. | 3865 // names in the profile since most compare stubs end up in the snapshot. |
| 3803 const char* CompareStub::GetName() { | 3866 void CompareStub::PrintName(StringStream* stream) { |
| 3804 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 3867 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |
| 3805 | |
| 3806 if (name_ != NULL) return name_; | |
| 3807 const int kMaxNameLength = 100; | |
| 3808 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | |
| 3809 kMaxNameLength); | |
| 3810 if (name_ == NULL) return "OOM"; | |
| 3811 | |
| 3812 const char* cc_name; | 3868 const char* cc_name; |
| 3813 switch (cc_) { | 3869 switch (cc_) { |
| 3814 case less: cc_name = "LT"; break; | 3870 case less: cc_name = "LT"; break; |
| 3815 case greater: cc_name = "GT"; break; | 3871 case greater: cc_name = "GT"; break; |
| 3816 case less_equal: cc_name = "LE"; break; | 3872 case less_equal: cc_name = "LE"; break; |
| 3817 case greater_equal: cc_name = "GE"; break; | 3873 case greater_equal: cc_name = "GE"; break; |
| 3818 case equal: cc_name = "EQ"; break; | 3874 case equal: cc_name = "EQ"; break; |
| 3819 case not_equal: cc_name = "NE"; break; | 3875 case not_equal: cc_name = "NE"; break; |
| 3820 default: cc_name = "UnknownCondition"; break; | 3876 default: cc_name = "UnknownCondition"; break; |
| 3821 } | 3877 } |
| 3822 | 3878 bool is_equality = cc_ == equal || cc_ == not_equal; |
| 3823 const char* strict_name = ""; | 3879 stream->Add("CompareStub_%s", cc_name); |
| 3824 if (strict_ && (cc_ == equal || cc_ == not_equal)) { | 3880 if (strict_ && is_equality) stream->Add("_STRICT"); |
| 3825 strict_name = "_STRICT"; | 3881 if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); |
| 3826 } | 3882 if (!include_number_compare_) stream->Add("_NO_NUMBER"); |
| 3827 | 3883 if (!include_smi_compare_) stream->Add("_NO_SMI"); |
| 3828 const char* never_nan_nan_name = ""; | |
| 3829 if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) { | |
| 3830 never_nan_nan_name = "_NO_NAN"; | |
| 3831 } | |
| 3832 | |
| 3833 const char* include_number_compare_name = ""; | |
| 3834 if (!include_number_compare_) { | |
| 3835 include_number_compare_name = "_NO_NUMBER"; | |
| 3836 } | |
| 3837 | |
| 3838 const char* include_smi_compare_name = ""; | |
| 3839 if (!include_smi_compare_) { | |
| 3840 include_smi_compare_name = "_NO_SMI"; | |
| 3841 } | |
| 3842 | |
| 3843 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | |
| 3844 "CompareStub_%s%s%s%s", | |
| 3845 cc_name, | |
| 3846 strict_name, | |
| 3847 never_nan_nan_name, | |
| 3848 include_number_compare_name, | |
| 3849 include_smi_compare_name); | |
| 3850 return name_; | |
| 3851 } | 3884 } |
| 3852 | 3885 |
| 3853 | 3886 |
| 3854 // ------------------------------------------------------------------------- | 3887 // ------------------------------------------------------------------------- |
| 3855 // StringCharCodeAtGenerator | 3888 // StringCharCodeAtGenerator |
| 3856 | 3889 |
| 3857 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3890 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 3858 Label flat_string; | 3891 Label flat_string; |
| 3859 Label ascii_string; | 3892 Label ascii_string; |
| 3860 Label got_char_code; | 3893 Label got_char_code; |
| (...skipping 1647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5508 // TODO(gc): Add call to EnsureNotWhite here. | 5541 // TODO(gc): Add call to EnsureNotWhite here. |
| 5509 // Fall through when we need to inform the incremental marker. | 5542 // Fall through when we need to inform the incremental marker. |
| 5510 } | 5543 } |
| 5511 | 5544 |
| 5512 | 5545 |
| 5513 #undef __ | 5546 #undef __ |
| 5514 | 5547 |
| 5515 } } // namespace v8::internal | 5548 } } // namespace v8::internal |
| 5516 | 5549 |
| 5517 #endif // V8_TARGET_ARCH_X64 | 5550 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |