| 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 25 matching lines...) Expand all Loading... |
| 36 #include "regexp-macro-assembler.h" | 36 #include "regexp-macro-assembler.h" |
| 37 | 37 |
| 38 namespace v8 { | 38 namespace v8 { |
| 39 namespace internal { | 39 namespace internal { |
| 40 | 40 |
| 41 #define __ ACCESS_MASM(masm) | 41 #define __ ACCESS_MASM(masm) |
| 42 | 42 |
| 43 void ToNumberStub::Generate(MacroAssembler* masm) { | 43 void ToNumberStub::Generate(MacroAssembler* masm) { |
| 44 // The ToNumber stub takes one argument in eax. | 44 // The ToNumber stub takes one argument in eax. |
| 45 Label check_heap_number, call_builtin; | 45 Label check_heap_number, call_builtin; |
| 46 __ test(eax, Immediate(kSmiTagMask)); | 46 __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); |
| 47 __ j(not_zero, &check_heap_number, Label::kNear); | |
| 48 __ ret(0); | 47 __ ret(0); |
| 49 | 48 |
| 50 __ bind(&check_heap_number); | 49 __ bind(&check_heap_number); |
| 51 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 50 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 52 Factory* factory = masm->isolate()->factory(); | 51 Factory* factory = masm->isolate()->factory(); |
| 53 __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); | 52 __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); |
| 54 __ j(not_equal, &call_builtin, Label::kNear); | 53 __ j(not_equal, &call_builtin, Label::kNear); |
| 55 __ ret(0); | 54 __ ret(0); |
| 56 | 55 |
| 57 __ bind(&call_builtin); | 56 __ bind(&call_builtin); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 Label gc; | 121 Label gc; |
| 123 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 122 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 124 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, | 123 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, |
| 125 eax, ebx, ecx, &gc, TAG_OBJECT); | 124 eax, ebx, ecx, &gc, TAG_OBJECT); |
| 126 | 125 |
| 127 // Get the function from the stack. | 126 // Get the function from the stack. |
| 128 __ mov(ecx, Operand(esp, 1 * kPointerSize)); | 127 __ mov(ecx, Operand(esp, 1 * kPointerSize)); |
| 129 | 128 |
| 130 // Setup the object header. | 129 // Setup the object header. |
| 131 Factory* factory = masm->isolate()->factory(); | 130 Factory* factory = masm->isolate()->factory(); |
| 132 __ mov(FieldOperand(eax, HeapObject::kMapOffset), factory->context_map()); | 131 __ mov(FieldOperand(eax, HeapObject::kMapOffset), |
| 132 factory->function_context_map()); |
| 133 __ mov(FieldOperand(eax, Context::kLengthOffset), | 133 __ mov(FieldOperand(eax, Context::kLengthOffset), |
| 134 Immediate(Smi::FromInt(length))); | 134 Immediate(Smi::FromInt(length))); |
| 135 | 135 |
| 136 // Setup the fixed slots. | 136 // Setup the fixed slots. |
| 137 __ Set(ebx, Immediate(0)); // Set to NULL. | 137 __ Set(ebx, Immediate(0)); // Set to NULL. |
| 138 __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); | 138 __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); |
| 139 __ mov(Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)), eax); | 139 __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi); |
| 140 __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), ebx); | |
| 141 __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); | 140 __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); |
| 142 | 141 |
| 143 // Copy the global object from the surrounding context. We go through the | 142 // Copy the global object from the previous context. |
| 144 // context in the function (ecx) to match the allocation behavior we have | 143 __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 145 // in the runtime system (see Heap::AllocateFunctionContext). | |
| 146 __ mov(ebx, FieldOperand(ecx, JSFunction::kContextOffset)); | |
| 147 __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::GLOBAL_INDEX))); | |
| 148 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); | 144 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); |
| 149 | 145 |
| 150 // Initialize the rest of the slots to undefined. | 146 // Initialize the rest of the slots to undefined. |
| 151 __ mov(ebx, factory->undefined_value()); | 147 __ mov(ebx, factory->undefined_value()); |
| 152 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 148 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |
| 153 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); | 149 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); |
| 154 } | 150 } |
| 155 | 151 |
| 156 // Return and remove the on-stack parameter. | 152 // Return and remove the on-stack parameter. |
| 157 __ mov(esi, Operand(eax)); | 153 __ mov(esi, Operand(eax)); |
| 158 __ ret(1 * kPointerSize); | 154 __ ret(1 * kPointerSize); |
| 159 | 155 |
| 160 // Need to collect. Call into runtime system. | 156 // Need to collect. Call into runtime system. |
| 161 __ bind(&gc); | 157 __ bind(&gc); |
| 162 __ TailCallRuntime(Runtime::kNewContext, 1, 1); | 158 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); |
| 163 } | 159 } |
| 164 | 160 |
| 165 | 161 |
| 166 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 162 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 167 // Stack layout on entry: | 163 // Stack layout on entry: |
| 168 // | 164 // |
| 169 // [esp + kPointerSize]: constant elements. | 165 // [esp + kPointerSize]: constant elements. |
| 170 // [esp + (2 * kPointerSize)]: literal index. | 166 // [esp + (2 * kPointerSize)]: literal index. |
| 171 // [esp + (3 * kPointerSize)]: literals array. | 167 // [esp + (3 * kPointerSize)]: literals array. |
| 172 | 168 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 } | 229 } |
| 234 | 230 |
| 235 // Return and remove the on-stack parameters. | 231 // Return and remove the on-stack parameters. |
| 236 __ ret(3 * kPointerSize); | 232 __ ret(3 * kPointerSize); |
| 237 | 233 |
| 238 __ bind(&slow_case); | 234 __ bind(&slow_case); |
| 239 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 235 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 240 } | 236 } |
| 241 | 237 |
| 242 | 238 |
| 243 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). | 239 // The stub returns zero for false, and a non-zero value for true. |
| 244 void ToBooleanStub::Generate(MacroAssembler* masm) { | 240 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 245 Label false_result, true_result, not_string; | 241 Label false_result, true_result, not_string; |
| 242 Factory* factory = masm->isolate()->factory(); |
| 243 const Register map = edx; |
| 244 |
| 246 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 245 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 247 Factory* factory = masm->isolate()->factory(); | |
| 248 | 246 |
| 249 // undefined -> false | 247 // undefined -> false |
| 250 __ cmp(eax, factory->undefined_value()); | 248 __ cmp(eax, factory->undefined_value()); |
| 251 __ j(equal, &false_result); | 249 __ j(equal, &false_result); |
| 252 | 250 |
| 253 // Boolean -> its value | 251 // Boolean -> its value |
| 252 __ cmp(eax, factory->false_value()); |
| 253 __ j(equal, &false_result); |
| 254 __ cmp(eax, factory->true_value()); | 254 __ cmp(eax, factory->true_value()); |
| 255 __ j(equal, &true_result); | 255 __ j(equal, &true_result); |
| 256 __ cmp(eax, factory->false_value()); | |
| 257 __ j(equal, &false_result); | |
| 258 | 256 |
| 259 // Smis: 0 -> false, all other -> true | 257 // Smis: 0 -> false, all other -> true |
| 260 __ test(eax, Operand(eax)); | 258 __ test(eax, Operand(eax)); |
| 261 __ j(zero, &false_result); | 259 __ j(zero, &false_result); |
| 262 __ test(eax, Immediate(kSmiTagMask)); | 260 __ JumpIfSmi(eax, &true_result); |
| 263 __ j(zero, &true_result); | |
| 264 | 261 |
| 265 // 'null' => false. | 262 // 'null' -> false. |
| 266 __ cmp(eax, factory->null_value()); | 263 __ cmp(eax, factory->null_value()); |
| 267 __ j(equal, &false_result, Label::kNear); | 264 __ j(equal, &false_result, Label::kNear); |
| 268 | 265 |
| 269 // Get the map and type of the heap object. | 266 // Get the map of the heap object. |
| 270 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 267 __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); |
| 271 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | |
| 272 | 268 |
| 273 // Undetectable => false. | 269 // Undetectable -> false. |
| 274 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 270 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
| 275 1 << Map::kIsUndetectable); | 271 1 << Map::kIsUndetectable); |
| 276 __ j(not_zero, &false_result, Label::kNear); | 272 __ j(not_zero, &false_result, Label::kNear); |
| 277 | 273 |
| 278 // JavaScript object => true. | 274 // JavaScript object -> true. |
| 279 __ CmpInstanceType(edx, FIRST_JS_OBJECT_TYPE); | 275 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 280 __ j(above_equal, &true_result, Label::kNear); | 276 __ j(above_equal, &true_result, Label::kNear); |
| 281 | 277 |
| 282 // String value => false iff empty. | 278 // String value -> false iff empty. |
| 283 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); | 279 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
| 284 __ j(above_equal, ¬_string, Label::kNear); | 280 __ j(above_equal, ¬_string, Label::kNear); |
| 285 STATIC_ASSERT(kSmiTag == 0); | |
| 286 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); | 281 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); |
| 287 __ j(zero, &false_result, Label::kNear); | 282 __ j(zero, &false_result, Label::kNear); |
| 288 __ jmp(&true_result, Label::kNear); | 283 __ jmp(&true_result, Label::kNear); |
| 289 | 284 |
| 290 __ bind(¬_string); | 285 __ bind(¬_string); |
| 291 // HeapNumber => false iff +0, -0, or NaN. | 286 // HeapNumber -> false iff +0, -0, or NaN. |
| 292 __ cmp(edx, factory->heap_number_map()); | 287 __ cmp(map, factory->heap_number_map()); |
| 293 __ j(not_equal, &true_result, Label::kNear); | 288 __ j(not_equal, &true_result, Label::kNear); |
| 294 __ fldz(); | 289 __ fldz(); |
| 295 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 290 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 296 __ FCmp(); | 291 __ FCmp(); |
| 297 __ j(zero, &false_result, Label::kNear); | 292 __ j(zero, &false_result, Label::kNear); |
| 298 // Fall through to |true_result|. | 293 // Fall through to |true_result|. |
| 299 | 294 |
| 300 // Return 1/0 for true/false in eax. | 295 // Return 1/0 for true/false in tos_. |
| 301 __ bind(&true_result); | 296 __ bind(&true_result); |
| 302 __ mov(eax, 1); | 297 __ mov(tos_, 1); |
| 303 __ ret(1 * kPointerSize); | 298 __ ret(1 * kPointerSize); |
| 304 __ bind(&false_result); | 299 __ bind(&false_result); |
| 305 __ mov(eax, 0); | 300 __ mov(tos_, 0); |
| 306 __ ret(1 * kPointerSize); | 301 __ ret(1 * kPointerSize); |
| 307 } | 302 } |
| 308 | 303 |
| 309 | 304 |
| 310 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 305 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 311 // We don't allow a GC during a store buffer overflow so there is no need to | 306 // We don't allow a GC during a store buffer overflow so there is no need to |
| 312 // store the registers in any particular way, but we do have to store and | 307 // store the registers in any particular way, but we do have to store and |
| 313 // restore them. | 308 // restore them. |
| 314 __ pushad(); | 309 __ pushad(); |
| 315 if (save_doubles_ == kSaveFPRegs) { | 310 if (save_doubles_ == kSaveFPRegs) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 335 } | 330 } |
| 336 __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 331 __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 337 } | 332 } |
| 338 __ popad(); | 333 __ popad(); |
| 339 __ ret(0); | 334 __ ret(0); |
| 340 } | 335 } |
| 341 | 336 |
| 342 | 337 |
| 343 class FloatingPointHelper : public AllStatic { | 338 class FloatingPointHelper : public AllStatic { |
| 344 public: | 339 public: |
| 345 | |
| 346 enum ArgLocation { | 340 enum ArgLocation { |
| 347 ARGS_ON_STACK, | 341 ARGS_ON_STACK, |
| 348 ARGS_IN_REGISTERS | 342 ARGS_IN_REGISTERS |
| 349 }; | 343 }; |
| 350 | 344 |
| 351 // Code pattern for loading a floating point value. Input value must | 345 // Code pattern for loading a floating point value. Input value must |
| 352 // be either a smi or a heap number object (fp value). Requirements: | 346 // be either a smi or a heap number object (fp value). Requirements: |
| 353 // operand in register number. Returns operand as floating point number | 347 // operand in register number. Returns operand as floating point number |
| 354 // on FPU stack. | 348 // on FPU stack. |
| 355 static void LoadFloatOperand(MacroAssembler* masm, Register number); | 349 static void LoadFloatOperand(MacroAssembler* masm, Register number); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 __ j(greater, &negative, Label::kNear); | 537 __ j(greater, &negative, Label::kNear); |
| 544 __ mov(ecx, scratch2); | 538 __ mov(ecx, scratch2); |
| 545 __ jmp(&done, Label::kNear); | 539 __ jmp(&done, Label::kNear); |
| 546 __ bind(&negative); | 540 __ bind(&negative); |
| 547 __ sub(ecx, Operand(scratch2)); | 541 __ sub(ecx, Operand(scratch2)); |
| 548 __ bind(&done); | 542 __ bind(&done); |
| 549 } | 543 } |
| 550 } | 544 } |
| 551 | 545 |
| 552 | 546 |
| 553 Handle<Code> GetUnaryOpStub(int key, UnaryOpIC::TypeInfo type_info) { | |
| 554 UnaryOpStub stub(key, type_info); | |
| 555 return stub.GetCode(); | |
| 556 } | |
| 557 | |
| 558 | |
| 559 const char* UnaryOpStub::GetName() { | 547 const char* UnaryOpStub::GetName() { |
| 560 if (name_ != NULL) return name_; | 548 if (name_ != NULL) return name_; |
| 561 const int kMaxNameLength = 100; | 549 const int kMaxNameLength = 100; |
| 562 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | 550 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 563 kMaxNameLength); | 551 kMaxNameLength); |
| 564 if (name_ == NULL) return "OOM"; | 552 if (name_ == NULL) return "OOM"; |
| 565 const char* op_name = Token::Name(op_); | 553 const char* op_name = Token::Name(op_); |
| 566 const char* overwrite_name = NULL; // Make g++ happy. | 554 const char* overwrite_name = NULL; // Make g++ happy. |
| 567 switch (mode_) { | 555 switch (mode_) { |
| 568 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 556 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 592 break; | 580 break; |
| 593 case UnaryOpIC::GENERIC: | 581 case UnaryOpIC::GENERIC: |
| 594 GenerateGenericStub(masm); | 582 GenerateGenericStub(masm); |
| 595 break; | 583 break; |
| 596 } | 584 } |
| 597 } | 585 } |
| 598 | 586 |
| 599 | 587 |
| 600 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 588 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 601 __ pop(ecx); // Save return address. | 589 __ pop(ecx); // Save return address. |
| 602 __ push(eax); | 590 |
| 603 // the argument is now on top. | 591 __ push(eax); // the operand |
| 604 // Push this stub's key. Although the operation and the type info are | |
| 605 // encoded into the key, the encoding is opaque, so push them too. | |
| 606 __ push(Immediate(Smi::FromInt(MinorKey()))); | |
| 607 __ push(Immediate(Smi::FromInt(op_))); | 592 __ push(Immediate(Smi::FromInt(op_))); |
| 593 __ push(Immediate(Smi::FromInt(mode_))); |
| 608 __ push(Immediate(Smi::FromInt(operand_type_))); | 594 __ push(Immediate(Smi::FromInt(operand_type_))); |
| 609 | 595 |
| 610 __ push(ecx); // Push return address. | 596 __ push(ecx); // Push return address. |
| 611 | 597 |
| 612 // Patch the caller to an appropriate specialized stub and return the | 598 // Patch the caller to an appropriate specialized stub and return the |
| 613 // operation result to the caller of the stub. | 599 // operation result to the caller of the stub. |
| 614 __ TailCallExternalReference( | 600 __ TailCallExternalReference( |
| 615 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), | 601 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); |
| 616 masm->isolate()), 4, 1); | |
| 617 } | 602 } |
| 618 | 603 |
| 619 | 604 |
| 620 // TODO(svenpanne): Use virtual functions instead of switch. | 605 // TODO(svenpanne): Use virtual functions instead of switch. |
| 621 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 606 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 622 switch (op_) { | 607 switch (op_) { |
| 623 case Token::SUB: | 608 case Token::SUB: |
| 624 GenerateSmiStubSub(masm); | 609 GenerateSmiStubSub(masm); |
| 625 break; | 610 break; |
| 626 case Token::BIT_NOT: | 611 case Token::BIT_NOT: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 653 | 638 |
| 654 | 639 |
| 655 void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, | 640 void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, |
| 656 Label* non_smi, | 641 Label* non_smi, |
| 657 Label* undo, | 642 Label* undo, |
| 658 Label* slow, | 643 Label* slow, |
| 659 Label::Distance non_smi_near, | 644 Label::Distance non_smi_near, |
| 660 Label::Distance undo_near, | 645 Label::Distance undo_near, |
| 661 Label::Distance slow_near) { | 646 Label::Distance slow_near) { |
| 662 // Check whether the value is a smi. | 647 // Check whether the value is a smi. |
| 663 __ test(eax, Immediate(kSmiTagMask)); | 648 __ JumpIfNotSmi(eax, non_smi, non_smi_near); |
| 664 __ j(not_zero, non_smi, non_smi_near); | |
| 665 | 649 |
| 666 // We can't handle -0 with smis, so use a type transition for that case. | 650 // We can't handle -0 with smis, so use a type transition for that case. |
| 667 __ test(eax, Operand(eax)); | 651 __ test(eax, Operand(eax)); |
| 668 __ j(zero, slow, slow_near); | 652 __ j(zero, slow, slow_near); |
| 669 | 653 |
| 670 // Try optimistic subtraction '0 - value', saving operand in eax for undo. | 654 // Try optimistic subtraction '0 - value', saving operand in eax for undo. |
| 671 __ mov(edx, Operand(eax)); | 655 __ mov(edx, Operand(eax)); |
| 672 __ Set(eax, Immediate(0)); | 656 __ Set(eax, Immediate(0)); |
| 673 __ sub(eax, Operand(edx)); | 657 __ sub(eax, Operand(edx)); |
| 674 __ j(overflow, undo, undo_near); | 658 __ j(overflow, undo, undo_near); |
| 675 __ ret(0); | 659 __ ret(0); |
| 676 } | 660 } |
| 677 | 661 |
| 678 | 662 |
| 679 void UnaryOpStub::GenerateSmiCodeBitNot( | 663 void UnaryOpStub::GenerateSmiCodeBitNot( |
| 680 MacroAssembler* masm, | 664 MacroAssembler* masm, |
| 681 Label* non_smi, | 665 Label* non_smi, |
| 682 Label::Distance non_smi_near) { | 666 Label::Distance non_smi_near) { |
| 683 // Check whether the value is a smi. | 667 // Check whether the value is a smi. |
| 684 __ test(eax, Immediate(kSmiTagMask)); | 668 __ JumpIfNotSmi(eax, non_smi, non_smi_near); |
| 685 __ j(not_zero, non_smi, non_smi_near); | |
| 686 | 669 |
| 687 // Flip bits and revert inverted smi-tag. | 670 // Flip bits and revert inverted smi-tag. |
| 688 __ not_(eax); | 671 __ not_(eax); |
| 689 __ and_(eax, ~kSmiTagMask); | 672 __ and_(eax, ~kSmiTagMask); |
| 690 __ ret(0); | 673 __ ret(0); |
| 691 } | 674 } |
| 692 | 675 |
| 693 | 676 |
| 694 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { | 677 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { |
| 695 __ mov(eax, Operand(edx)); | 678 __ mov(eax, Operand(edx)); |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 879 break; | 862 break; |
| 880 case Token::BIT_NOT: | 863 case Token::BIT_NOT: |
| 881 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | 864 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
| 882 break; | 865 break; |
| 883 default: | 866 default: |
| 884 UNREACHABLE(); | 867 UNREACHABLE(); |
| 885 } | 868 } |
| 886 } | 869 } |
| 887 | 870 |
| 888 | 871 |
| 889 Handle<Code> GetBinaryOpStub(int key, | |
| 890 BinaryOpIC::TypeInfo type_info, | |
| 891 BinaryOpIC::TypeInfo result_type_info) { | |
| 892 BinaryOpStub stub(key, type_info, result_type_info); | |
| 893 return stub.GetCode(); | |
| 894 } | |
| 895 | |
| 896 | |
| 897 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 872 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 898 __ pop(ecx); // Save return address. | 873 __ pop(ecx); // Save return address. |
| 899 __ push(edx); | 874 __ push(edx); |
| 900 __ push(eax); | 875 __ push(eax); |
| 901 // Left and right arguments are now on top. | 876 // Left and right arguments are now on top. |
| 902 // Push this stub's key. Although the operation and the type info are | 877 // Push this stub's key. Although the operation and the type info are |
| 903 // encoded into the key, the encoding is opaque, so push them too. | 878 // encoded into the key, the encoding is opaque, so push them too. |
| 904 __ push(Immediate(Smi::FromInt(MinorKey()))); | 879 __ push(Immediate(Smi::FromInt(MinorKey()))); |
| 905 __ push(Immediate(Smi::FromInt(op_))); | 880 __ push(Immediate(Smi::FromInt(op_))); |
| 906 __ push(Immediate(Smi::FromInt(operands_type_))); | 881 __ push(Immediate(Smi::FromInt(operands_type_))); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1049 __ or_(right, Operand(left)); | 1024 __ or_(right, Operand(left)); |
| 1050 combined = right; | 1025 combined = right; |
| 1051 break; | 1026 break; |
| 1052 | 1027 |
| 1053 default: | 1028 default: |
| 1054 break; | 1029 break; |
| 1055 } | 1030 } |
| 1056 | 1031 |
| 1057 // 3. Perform the smi check of the operands. | 1032 // 3. Perform the smi check of the operands. |
| 1058 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. | 1033 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. |
| 1059 __ test(combined, Immediate(kSmiTagMask)); | 1034 __ JumpIfNotSmi(combined, ¬_smis); |
| 1060 __ j(not_zero, ¬_smis); | |
| 1061 | 1035 |
| 1062 // 4. Operands are both smis, perform the operation leaving the result in | 1036 // 4. Operands are both smis, perform the operation leaving the result in |
| 1063 // eax and check the result if necessary. | 1037 // eax and check the result if necessary. |
| 1064 Comment perform_smi(masm, "-- Perform smi operation"); | 1038 Comment perform_smi(masm, "-- Perform smi operation"); |
| 1065 Label use_fp_on_smis; | 1039 Label use_fp_on_smis; |
| 1066 switch (op_) { | 1040 switch (op_) { |
| 1067 case Token::BIT_OR: | 1041 case Token::BIT_OR: |
| 1068 // Nothing to do. | 1042 // Nothing to do. |
| 1069 break; | 1043 break; |
| 1070 | 1044 |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1438 ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); | 1412 ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); |
| 1439 ASSERT(op_ == Token::ADD); | 1413 ASSERT(op_ == Token::ADD); |
| 1440 // If both arguments are strings, call the string add stub. | 1414 // If both arguments are strings, call the string add stub. |
| 1441 // Otherwise, do a transition. | 1415 // Otherwise, do a transition. |
| 1442 | 1416 |
| 1443 // Registers containing left and right operands respectively. | 1417 // Registers containing left and right operands respectively. |
| 1444 Register left = edx; | 1418 Register left = edx; |
| 1445 Register right = eax; | 1419 Register right = eax; |
| 1446 | 1420 |
| 1447 // Test if left operand is a string. | 1421 // Test if left operand is a string. |
| 1448 __ test(left, Immediate(kSmiTagMask)); | 1422 __ JumpIfSmi(left, &call_runtime); |
| 1449 __ j(zero, &call_runtime); | |
| 1450 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); | 1423 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); |
| 1451 __ j(above_equal, &call_runtime); | 1424 __ j(above_equal, &call_runtime); |
| 1452 | 1425 |
| 1453 // Test if right operand is a string. | 1426 // Test if right operand is a string. |
| 1454 __ test(right, Immediate(kSmiTagMask)); | 1427 __ JumpIfSmi(right, &call_runtime); |
| 1455 __ j(zero, &call_runtime); | |
| 1456 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); | 1428 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); |
| 1457 __ j(above_equal, &call_runtime); | 1429 __ j(above_equal, &call_runtime); |
| 1458 | 1430 |
| 1459 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); | 1431 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); |
| 1460 GenerateRegisterArgsPush(masm); | 1432 GenerateRegisterArgsPush(masm); |
| 1461 __ TailCallStub(&string_add_stub); | 1433 __ TailCallStub(&string_add_stub); |
| 1462 | 1434 |
| 1463 __ bind(&call_runtime); | 1435 __ bind(&call_runtime); |
| 1464 GenerateTypeTransition(masm); | 1436 GenerateTypeTransition(masm); |
| 1465 } | 1437 } |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1581 // Allocate a heap number if needed. | 1553 // Allocate a heap number if needed. |
| 1582 __ mov(ebx, Operand(eax)); // ebx: result | 1554 __ mov(ebx, Operand(eax)); // ebx: result |
| 1583 Label skip_allocation; | 1555 Label skip_allocation; |
| 1584 switch (mode_) { | 1556 switch (mode_) { |
| 1585 case OVERWRITE_LEFT: | 1557 case OVERWRITE_LEFT: |
| 1586 case OVERWRITE_RIGHT: | 1558 case OVERWRITE_RIGHT: |
| 1587 // If the operand was an object, we skip the | 1559 // If the operand was an object, we skip the |
| 1588 // allocation of a heap number. | 1560 // allocation of a heap number. |
| 1589 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | 1561 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
| 1590 1 * kPointerSize : 2 * kPointerSize)); | 1562 1 * kPointerSize : 2 * kPointerSize)); |
| 1591 __ test(eax, Immediate(kSmiTagMask)); | 1563 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
| 1592 __ j(not_zero, &skip_allocation, Label::kNear); | |
| 1593 // Fall through! | 1564 // Fall through! |
| 1594 case NO_OVERWRITE: | 1565 case NO_OVERWRITE: |
| 1595 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 1566 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 1596 __ bind(&skip_allocation); | 1567 __ bind(&skip_allocation); |
| 1597 break; | 1568 break; |
| 1598 default: UNREACHABLE(); | 1569 default: UNREACHABLE(); |
| 1599 } | 1570 } |
| 1600 // Store the result in the HeapNumber and return. | 1571 // Store the result in the HeapNumber and return. |
| 1601 if (CpuFeatures::IsSupported(SSE2)) { | 1572 if (CpuFeatures::IsSupported(SSE2)) { |
| 1602 CpuFeatures::Scope use_sse2(SSE2); | 1573 CpuFeatures::Scope use_sse2(SSE2); |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1796 // Allocate a heap number if needed. | 1767 // Allocate a heap number if needed. |
| 1797 __ mov(ebx, Operand(eax)); // ebx: result | 1768 __ mov(ebx, Operand(eax)); // ebx: result |
| 1798 Label skip_allocation; | 1769 Label skip_allocation; |
| 1799 switch (mode_) { | 1770 switch (mode_) { |
| 1800 case OVERWRITE_LEFT: | 1771 case OVERWRITE_LEFT: |
| 1801 case OVERWRITE_RIGHT: | 1772 case OVERWRITE_RIGHT: |
| 1802 // If the operand was an object, we skip the | 1773 // If the operand was an object, we skip the |
| 1803 // allocation of a heap number. | 1774 // allocation of a heap number. |
| 1804 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | 1775 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
| 1805 1 * kPointerSize : 2 * kPointerSize)); | 1776 1 * kPointerSize : 2 * kPointerSize)); |
| 1806 __ test(eax, Immediate(kSmiTagMask)); | 1777 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
| 1807 __ j(not_zero, &skip_allocation, Label::kNear); | |
| 1808 // Fall through! | 1778 // Fall through! |
| 1809 case NO_OVERWRITE: | 1779 case NO_OVERWRITE: |
| 1810 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 1780 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 1811 __ bind(&skip_allocation); | 1781 __ bind(&skip_allocation); |
| 1812 break; | 1782 break; |
| 1813 default: UNREACHABLE(); | 1783 default: UNREACHABLE(); |
| 1814 } | 1784 } |
| 1815 // Store the result in the HeapNumber and return. | 1785 // Store the result in the HeapNumber and return. |
| 1816 if (CpuFeatures::IsSupported(SSE2)) { | 1786 if (CpuFeatures::IsSupported(SSE2)) { |
| 1817 CpuFeatures::Scope use_sse2(SSE2); | 1787 CpuFeatures::Scope use_sse2(SSE2); |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1996 // Allocate a heap number if needed. | 1966 // Allocate a heap number if needed. |
| 1997 __ mov(ebx, Operand(eax)); // ebx: result | 1967 __ mov(ebx, Operand(eax)); // ebx: result |
| 1998 Label skip_allocation; | 1968 Label skip_allocation; |
| 1999 switch (mode_) { | 1969 switch (mode_) { |
| 2000 case OVERWRITE_LEFT: | 1970 case OVERWRITE_LEFT: |
| 2001 case OVERWRITE_RIGHT: | 1971 case OVERWRITE_RIGHT: |
| 2002 // If the operand was an object, we skip the | 1972 // If the operand was an object, we skip the |
| 2003 // allocation of a heap number. | 1973 // allocation of a heap number. |
| 2004 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | 1974 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
| 2005 1 * kPointerSize : 2 * kPointerSize)); | 1975 1 * kPointerSize : 2 * kPointerSize)); |
| 2006 __ test(eax, Immediate(kSmiTagMask)); | 1976 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
| 2007 __ j(not_zero, &skip_allocation, Label::kNear); | |
| 2008 // Fall through! | 1977 // Fall through! |
| 2009 case NO_OVERWRITE: | 1978 case NO_OVERWRITE: |
| 2010 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 1979 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 2011 __ bind(&skip_allocation); | 1980 __ bind(&skip_allocation); |
| 2012 break; | 1981 break; |
| 2013 default: UNREACHABLE(); | 1982 default: UNREACHABLE(); |
| 2014 } | 1983 } |
| 2015 // Store the result in the HeapNumber and return. | 1984 // Store the result in the HeapNumber and return. |
| 2016 if (CpuFeatures::IsSupported(SSE2)) { | 1985 if (CpuFeatures::IsSupported(SSE2)) { |
| 2017 CpuFeatures::Scope use_sse2(SSE2); | 1986 CpuFeatures::Scope use_sse2(SSE2); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2080 | 2049 |
| 2081 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { | 2050 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { |
| 2082 ASSERT(op_ == Token::ADD); | 2051 ASSERT(op_ == Token::ADD); |
| 2083 Label left_not_string, call_runtime; | 2052 Label left_not_string, call_runtime; |
| 2084 | 2053 |
| 2085 // Registers containing left and right operands respectively. | 2054 // Registers containing left and right operands respectively. |
| 2086 Register left = edx; | 2055 Register left = edx; |
| 2087 Register right = eax; | 2056 Register right = eax; |
| 2088 | 2057 |
| 2089 // Test if left operand is a string. | 2058 // Test if left operand is a string. |
| 2090 __ test(left, Immediate(kSmiTagMask)); | 2059 __ JumpIfSmi(left, &left_not_string, Label::kNear); |
| 2091 __ j(zero, &left_not_string, Label::kNear); | |
| 2092 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); | 2060 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); |
| 2093 __ j(above_equal, &left_not_string, Label::kNear); | 2061 __ j(above_equal, &left_not_string, Label::kNear); |
| 2094 | 2062 |
| 2095 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); | 2063 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); |
| 2096 GenerateRegisterArgsPush(masm); | 2064 GenerateRegisterArgsPush(masm); |
| 2097 __ TailCallStub(&string_add_left_stub); | 2065 __ TailCallStub(&string_add_left_stub); |
| 2098 | 2066 |
| 2099 // Left operand is not a string, test right. | 2067 // Left operand is not a string, test right. |
| 2100 __ bind(&left_not_string); | 2068 __ bind(&left_not_string); |
| 2101 __ test(right, Immediate(kSmiTagMask)); | 2069 __ JumpIfSmi(right, &call_runtime, Label::kNear); |
| 2102 __ j(zero, &call_runtime, Label::kNear); | |
| 2103 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); | 2070 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); |
| 2104 __ j(above_equal, &call_runtime, Label::kNear); | 2071 __ j(above_equal, &call_runtime, Label::kNear); |
| 2105 | 2072 |
| 2106 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); | 2073 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); |
| 2107 GenerateRegisterArgsPush(masm); | 2074 GenerateRegisterArgsPush(masm); |
| 2108 __ TailCallStub(&string_add_right_stub); | 2075 __ TailCallStub(&string_add_right_stub); |
| 2109 | 2076 |
| 2110 // Neither argument is a string. | 2077 // Neither argument is a string. |
| 2111 __ bind(&call_runtime); | 2078 __ bind(&call_runtime); |
| 2112 } | 2079 } |
| 2113 | 2080 |
| 2114 | 2081 |
| 2115 void BinaryOpStub::GenerateHeapResultAllocation( | 2082 void BinaryOpStub::GenerateHeapResultAllocation( |
| 2116 MacroAssembler* masm, | 2083 MacroAssembler* masm, |
| 2117 Label* alloc_failure) { | 2084 Label* alloc_failure) { |
| 2118 Label skip_allocation; | 2085 Label skip_allocation; |
| 2119 OverwriteMode mode = mode_; | 2086 OverwriteMode mode = mode_; |
| 2120 switch (mode) { | 2087 switch (mode) { |
| 2121 case OVERWRITE_LEFT: { | 2088 case OVERWRITE_LEFT: { |
| 2122 // If the argument in edx is already an object, we skip the | 2089 // If the argument in edx is already an object, we skip the |
| 2123 // allocation of a heap number. | 2090 // allocation of a heap number. |
| 2124 __ test(edx, Immediate(kSmiTagMask)); | 2091 __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); |
| 2125 __ j(not_zero, &skip_allocation); | |
| 2126 // Allocate a heap number for the result. Keep eax and edx intact | 2092 // Allocate a heap number for the result. Keep eax and edx intact |
| 2127 // for the possible runtime call. | 2093 // for the possible runtime call. |
| 2128 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); | 2094 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |
| 2129 // Now edx can be overwritten losing one of the arguments as we are | 2095 // Now edx can be overwritten losing one of the arguments as we are |
| 2130 // now done and will not need it any more. | 2096 // now done and will not need it any more. |
| 2131 __ mov(edx, Operand(ebx)); | 2097 __ mov(edx, Operand(ebx)); |
| 2132 __ bind(&skip_allocation); | 2098 __ bind(&skip_allocation); |
| 2133 // Use object in edx as a result holder | 2099 // Use object in edx as a result holder |
| 2134 __ mov(eax, Operand(edx)); | 2100 __ mov(eax, Operand(edx)); |
| 2135 break; | 2101 break; |
| 2136 } | 2102 } |
| 2137 case OVERWRITE_RIGHT: | 2103 case OVERWRITE_RIGHT: |
| 2138 // If the argument in eax is already an object, we skip the | 2104 // If the argument in eax is already an object, we skip the |
| 2139 // allocation of a heap number. | 2105 // allocation of a heap number. |
| 2140 __ test(eax, Immediate(kSmiTagMask)); | 2106 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
| 2141 __ j(not_zero, &skip_allocation); | |
| 2142 // Fall through! | 2107 // Fall through! |
| 2143 case NO_OVERWRITE: | 2108 case NO_OVERWRITE: |
| 2144 // Allocate a heap number for the result. Keep eax and edx intact | 2109 // Allocate a heap number for the result. Keep eax and edx intact |
| 2145 // for the possible runtime call. | 2110 // for the possible runtime call. |
| 2146 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); | 2111 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |
| 2147 // Now eax can be overwritten losing one of the arguments as we are | 2112 // Now eax can be overwritten losing one of the arguments as we are |
| 2148 // now done and will not need it any more. | 2113 // now done and will not need it any more. |
| 2149 __ mov(eax, ebx); | 2114 __ mov(eax, ebx); |
| 2150 __ bind(&skip_allocation); | 2115 __ bind(&skip_allocation); |
| 2151 break; | 2116 break; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2178 | 2143 |
| 2179 Label runtime_call; | 2144 Label runtime_call; |
| 2180 Label runtime_call_clear_stack; | 2145 Label runtime_call_clear_stack; |
| 2181 Label skip_cache; | 2146 Label skip_cache; |
| 2182 const bool tagged = (argument_type_ == TAGGED); | 2147 const bool tagged = (argument_type_ == TAGGED); |
| 2183 if (tagged) { | 2148 if (tagged) { |
| 2184 // Test that eax is a number. | 2149 // Test that eax is a number. |
| 2185 Label input_not_smi; | 2150 Label input_not_smi; |
| 2186 Label loaded; | 2151 Label loaded; |
| 2187 __ mov(eax, Operand(esp, kPointerSize)); | 2152 __ mov(eax, Operand(esp, kPointerSize)); |
| 2188 __ test(eax, Immediate(kSmiTagMask)); | 2153 __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); |
| 2189 __ j(not_zero, &input_not_smi, Label::kNear); | |
| 2190 // Input is a smi. Untag and load it onto the FPU stack. | 2154 // Input is a smi. Untag and load it onto the FPU stack. |
| 2191 // Then load the low and high words of the double into ebx, edx. | 2155 // Then load the low and high words of the double into ebx, edx. |
| 2192 STATIC_ASSERT(kSmiTagSize == 1); | 2156 STATIC_ASSERT(kSmiTagSize == 1); |
| 2193 __ sar(eax, 1); | 2157 __ sar(eax, 1); |
| 2194 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 2158 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 2195 __ mov(Operand(esp, 0), eax); | 2159 __ mov(Operand(esp, 0), eax); |
| 2196 __ fild_s(Operand(esp, 0)); | 2160 __ fild_s(Operand(esp, 0)); |
| 2197 __ fst_d(Operand(esp, 0)); | 2161 __ fst_d(Operand(esp, 0)); |
| 2198 __ pop(edx); | 2162 __ pop(edx); |
| 2199 __ pop(ebx); | 2163 __ pop(ebx); |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2457 // Output: eax, ecx are left and right integers for a bit op. | 2421 // Output: eax, ecx are left and right integers for a bit op. |
| 2458 void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, | 2422 void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, |
| 2459 bool use_sse3, | 2423 bool use_sse3, |
| 2460 Label* conversion_failure) { | 2424 Label* conversion_failure) { |
| 2461 // Check float operands. | 2425 // Check float operands. |
| 2462 Label arg1_is_object, check_undefined_arg1; | 2426 Label arg1_is_object, check_undefined_arg1; |
| 2463 Label arg2_is_object, check_undefined_arg2; | 2427 Label arg2_is_object, check_undefined_arg2; |
| 2464 Label load_arg2, done; | 2428 Label load_arg2, done; |
| 2465 | 2429 |
| 2466 // Test if arg1 is a Smi. | 2430 // Test if arg1 is a Smi. |
| 2467 __ test(edx, Immediate(kSmiTagMask)); | 2431 __ JumpIfNotSmi(edx, &arg1_is_object); |
| 2468 __ j(not_zero, &arg1_is_object); | |
| 2469 | 2432 |
| 2470 __ SmiUntag(edx); | 2433 __ SmiUntag(edx); |
| 2471 __ jmp(&load_arg2); | 2434 __ jmp(&load_arg2); |
| 2472 | 2435 |
| 2473 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 2436 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
| 2474 __ bind(&check_undefined_arg1); | 2437 __ bind(&check_undefined_arg1); |
| 2475 Factory* factory = masm->isolate()->factory(); | 2438 Factory* factory = masm->isolate()->factory(); |
| 2476 __ cmp(edx, factory->undefined_value()); | 2439 __ cmp(edx, factory->undefined_value()); |
| 2477 __ j(not_equal, conversion_failure); | 2440 __ j(not_equal, conversion_failure); |
| 2478 __ mov(edx, Immediate(0)); | 2441 __ mov(edx, Immediate(0)); |
| 2479 __ jmp(&load_arg2); | 2442 __ jmp(&load_arg2); |
| 2480 | 2443 |
| 2481 __ bind(&arg1_is_object); | 2444 __ bind(&arg1_is_object); |
| 2482 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 2445 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 2483 __ cmp(ebx, factory->heap_number_map()); | 2446 __ cmp(ebx, factory->heap_number_map()); |
| 2484 __ j(not_equal, &check_undefined_arg1); | 2447 __ j(not_equal, &check_undefined_arg1); |
| 2485 | 2448 |
| 2486 // Get the untagged integer version of the edx heap number in ecx. | 2449 // Get the untagged integer version of the edx heap number in ecx. |
| 2487 IntegerConvert(masm, edx, use_sse3, conversion_failure); | 2450 IntegerConvert(masm, edx, use_sse3, conversion_failure); |
| 2488 __ mov(edx, ecx); | 2451 __ mov(edx, ecx); |
| 2489 | 2452 |
| 2490 // Here edx has the untagged integer, eax has a Smi or a heap number. | 2453 // Here edx has the untagged integer, eax has a Smi or a heap number. |
| 2491 __ bind(&load_arg2); | 2454 __ bind(&load_arg2); |
| 2492 | 2455 |
| 2493 // Test if arg2 is a Smi. | 2456 // Test if arg2 is a Smi. |
| 2494 __ test(eax, Immediate(kSmiTagMask)); | 2457 __ JumpIfNotSmi(eax, &arg2_is_object); |
| 2495 __ j(not_zero, &arg2_is_object); | |
| 2496 | 2458 |
| 2497 __ SmiUntag(eax); | 2459 __ SmiUntag(eax); |
| 2498 __ mov(ecx, eax); | 2460 __ mov(ecx, eax); |
| 2499 __ jmp(&done); | 2461 __ jmp(&done); |
| 2500 | 2462 |
| 2501 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 2463 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
| 2502 __ bind(&check_undefined_arg2); | 2464 __ bind(&check_undefined_arg2); |
| 2503 __ cmp(eax, factory->undefined_value()); | 2465 __ cmp(eax, factory->undefined_value()); |
| 2504 __ j(not_equal, conversion_failure); | 2466 __ j(not_equal, conversion_failure); |
| 2505 __ mov(ecx, Immediate(0)); | 2467 __ mov(ecx, Immediate(0)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2521 bool use_sse3, | 2483 bool use_sse3, |
| 2522 Label* not_int32) { | 2484 Label* not_int32) { |
| 2523 return; | 2485 return; |
| 2524 } | 2486 } |
| 2525 | 2487 |
| 2526 | 2488 |
| 2527 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 2489 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
| 2528 Register number) { | 2490 Register number) { |
| 2529 Label load_smi, done; | 2491 Label load_smi, done; |
| 2530 | 2492 |
| 2531 __ test(number, Immediate(kSmiTagMask)); | 2493 __ JumpIfSmi(number, &load_smi, Label::kNear); |
| 2532 __ j(zero, &load_smi, Label::kNear); | |
| 2533 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); | 2494 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); |
| 2534 __ jmp(&done, Label::kNear); | 2495 __ jmp(&done, Label::kNear); |
| 2535 | 2496 |
| 2536 __ bind(&load_smi); | 2497 __ bind(&load_smi); |
| 2537 __ SmiUntag(number); | 2498 __ SmiUntag(number); |
| 2538 __ push(number); | 2499 __ push(number); |
| 2539 __ fild_s(Operand(esp, 0)); | 2500 __ fild_s(Operand(esp, 0)); |
| 2540 __ pop(number); | 2501 __ pop(number); |
| 2541 | 2502 |
| 2542 __ bind(&done); | 2503 __ bind(&done); |
| 2543 } | 2504 } |
| 2544 | 2505 |
| 2545 | 2506 |
| 2546 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) { | 2507 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) { |
| 2547 Label load_smi_edx, load_eax, load_smi_eax, done; | 2508 Label load_smi_edx, load_eax, load_smi_eax, done; |
| 2548 // Load operand in edx into xmm0. | 2509 // Load operand in edx into xmm0. |
| 2549 __ test(edx, Immediate(kSmiTagMask)); | 2510 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); |
| 2550 // Argument in edx is a smi. | |
| 2551 __ j(zero, &load_smi_edx, Label::kNear); | |
| 2552 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 2511 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 2553 | 2512 |
| 2554 __ bind(&load_eax); | 2513 __ bind(&load_eax); |
| 2555 // Load operand in eax into xmm1. | 2514 // Load operand in eax into xmm1. |
| 2556 __ test(eax, Immediate(kSmiTagMask)); | 2515 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); |
| 2557 // Argument in eax is a smi. | |
| 2558 __ j(zero, &load_smi_eax, Label::kNear); | |
| 2559 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 2516 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 2560 __ jmp(&done, Label::kNear); | 2517 __ jmp(&done, Label::kNear); |
| 2561 | 2518 |
| 2562 __ bind(&load_smi_edx); | 2519 __ bind(&load_smi_edx); |
| 2563 __ SmiUntag(edx); // Untag smi before converting to float. | 2520 __ SmiUntag(edx); // Untag smi before converting to float. |
| 2564 __ cvtsi2sd(xmm0, Operand(edx)); | 2521 __ cvtsi2sd(xmm0, Operand(edx)); |
| 2565 __ SmiTag(edx); // Retag smi for heap number overwriting test. | 2522 __ SmiTag(edx); // Retag smi for heap number overwriting test. |
| 2566 __ jmp(&load_eax); | 2523 __ jmp(&load_eax); |
| 2567 | 2524 |
| 2568 __ bind(&load_smi_eax); | 2525 __ bind(&load_smi_eax); |
| 2569 __ SmiUntag(eax); // Untag smi before converting to float. | 2526 __ SmiUntag(eax); // Untag smi before converting to float. |
| 2570 __ cvtsi2sd(xmm1, Operand(eax)); | 2527 __ cvtsi2sd(xmm1, Operand(eax)); |
| 2571 __ SmiTag(eax); // Retag smi for heap number overwriting test. | 2528 __ SmiTag(eax); // Retag smi for heap number overwriting test. |
| 2572 | 2529 |
| 2573 __ bind(&done); | 2530 __ bind(&done); |
| 2574 } | 2531 } |
| 2575 | 2532 |
| 2576 | 2533 |
| 2577 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, | 2534 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, |
| 2578 Label* not_numbers) { | 2535 Label* not_numbers) { |
| 2579 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; | 2536 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; |
| 2580 // Load operand in edx into xmm0, or branch to not_numbers. | 2537 // Load operand in edx into xmm0, or branch to not_numbers. |
| 2581 __ test(edx, Immediate(kSmiTagMask)); | 2538 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); |
| 2582 // Argument in edx is a smi. | |
| 2583 __ j(zero, &load_smi_edx, Label::kNear); | |
| 2584 Factory* factory = masm->isolate()->factory(); | 2539 Factory* factory = masm->isolate()->factory(); |
| 2585 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); | 2540 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); |
| 2586 __ j(not_equal, not_numbers); // Argument in edx is not a number. | 2541 __ j(not_equal, not_numbers); // Argument in edx is not a number. |
| 2587 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 2542 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 2588 __ bind(&load_eax); | 2543 __ bind(&load_eax); |
| 2589 // Load operand in eax into xmm1, or branch to not_numbers. | 2544 // Load operand in eax into xmm1, or branch to not_numbers. |
| 2590 __ test(eax, Immediate(kSmiTagMask)); | 2545 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); |
| 2591 // Argument in eax is a smi. | |
| 2592 __ j(zero, &load_smi_eax, Label::kNear); | |
| 2593 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); | 2546 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); |
| 2594 __ j(equal, &load_float_eax, Label::kNear); | 2547 __ j(equal, &load_float_eax, Label::kNear); |
| 2595 __ jmp(not_numbers); // Argument in eax is not a number. | 2548 __ jmp(not_numbers); // Argument in eax is not a number. |
| 2596 __ bind(&load_smi_edx); | 2549 __ bind(&load_smi_edx); |
| 2597 __ SmiUntag(edx); // Untag smi before converting to float. | 2550 __ SmiUntag(edx); // Untag smi before converting to float. |
| 2598 __ cvtsi2sd(xmm0, Operand(edx)); | 2551 __ cvtsi2sd(xmm0, Operand(edx)); |
| 2599 __ SmiTag(edx); // Retag smi for heap number overwriting test. | 2552 __ SmiTag(edx); // Retag smi for heap number overwriting test. |
| 2600 __ jmp(&load_eax); | 2553 __ jmp(&load_eax); |
| 2601 __ bind(&load_smi_eax); | 2554 __ bind(&load_smi_eax); |
| 2602 __ SmiUntag(eax); // Untag smi before converting to float. | 2555 __ SmiUntag(eax); // Untag smi before converting to float. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2642 | 2595 |
| 2643 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 2596 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
| 2644 Register scratch, | 2597 Register scratch, |
| 2645 ArgLocation arg_location) { | 2598 ArgLocation arg_location) { |
| 2646 Label load_smi_1, load_smi_2, done_load_1, done; | 2599 Label load_smi_1, load_smi_2, done_load_1, done; |
| 2647 if (arg_location == ARGS_IN_REGISTERS) { | 2600 if (arg_location == ARGS_IN_REGISTERS) { |
| 2648 __ mov(scratch, edx); | 2601 __ mov(scratch, edx); |
| 2649 } else { | 2602 } else { |
| 2650 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | 2603 __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| 2651 } | 2604 } |
| 2652 __ test(scratch, Immediate(kSmiTagMask)); | 2605 __ JumpIfSmi(scratch, &load_smi_1, Label::kNear); |
| 2653 __ j(zero, &load_smi_1, Label::kNear); | |
| 2654 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); | 2606 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); |
| 2655 __ bind(&done_load_1); | 2607 __ bind(&done_load_1); |
| 2656 | 2608 |
| 2657 if (arg_location == ARGS_IN_REGISTERS) { | 2609 if (arg_location == ARGS_IN_REGISTERS) { |
| 2658 __ mov(scratch, eax); | 2610 __ mov(scratch, eax); |
| 2659 } else { | 2611 } else { |
| 2660 __ mov(scratch, Operand(esp, 1 * kPointerSize)); | 2612 __ mov(scratch, Operand(esp, 1 * kPointerSize)); |
| 2661 } | 2613 } |
| 2662 __ test(scratch, Immediate(kSmiTagMask)); | 2614 __ JumpIfSmi(scratch, &load_smi_2, Label::kNear); |
| 2663 __ j(zero, &load_smi_2, Label::kNear); | |
| 2664 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); | 2615 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); |
| 2665 __ jmp(&done, Label::kNear); | 2616 __ jmp(&done, Label::kNear); |
| 2666 | 2617 |
| 2667 __ bind(&load_smi_1); | 2618 __ bind(&load_smi_1); |
| 2668 __ SmiUntag(scratch); | 2619 __ SmiUntag(scratch); |
| 2669 __ push(scratch); | 2620 __ push(scratch); |
| 2670 __ fild_s(Operand(esp, 0)); | 2621 __ fild_s(Operand(esp, 0)); |
| 2671 __ pop(scratch); | 2622 __ pop(scratch); |
| 2672 __ jmp(&done_load_1); | 2623 __ jmp(&done_load_1); |
| 2673 | 2624 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2698 __ pop(scratch); | 2649 __ pop(scratch); |
| 2699 } | 2650 } |
| 2700 | 2651 |
| 2701 | 2652 |
| 2702 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, | 2653 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, |
| 2703 Label* non_float, | 2654 Label* non_float, |
| 2704 Register scratch) { | 2655 Register scratch) { |
| 2705 Label test_other, done; | 2656 Label test_other, done; |
| 2706 // Test if both operands are floats or smi -> scratch=k_is_float; | 2657 // Test if both operands are floats or smi -> scratch=k_is_float; |
| 2707 // Otherwise scratch = k_not_float. | 2658 // Otherwise scratch = k_not_float. |
| 2708 __ test(edx, Immediate(kSmiTagMask)); | 2659 __ JumpIfSmi(edx, &test_other, Label::kNear); |
| 2709 __ j(zero, &test_other, Label::kNear); // argument in edx is OK | |
| 2710 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); | 2660 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); |
| 2711 Factory* factory = masm->isolate()->factory(); | 2661 Factory* factory = masm->isolate()->factory(); |
| 2712 __ cmp(scratch, factory->heap_number_map()); | 2662 __ cmp(scratch, factory->heap_number_map()); |
| 2713 __ j(not_equal, non_float); // argument in edx is not a number -> NaN | 2663 __ j(not_equal, non_float); // argument in edx is not a number -> NaN |
| 2714 | 2664 |
| 2715 __ bind(&test_other); | 2665 __ bind(&test_other); |
| 2716 __ test(eax, Immediate(kSmiTagMask)); | 2666 __ JumpIfSmi(eax, &done, Label::kNear); |
| 2717 __ j(zero, &done, Label::kNear); // argument in eax is OK | |
| 2718 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); | 2667 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2719 __ cmp(scratch, factory->heap_number_map()); | 2668 __ cmp(scratch, factory->heap_number_map()); |
| 2720 __ j(not_equal, non_float); // argument in eax is not a number -> NaN | 2669 __ j(not_equal, non_float); // argument in eax is not a number -> NaN |
| 2721 | 2670 |
| 2722 // Fall-through: Both operands are numbers. | 2671 // Fall-through: Both operands are numbers. |
| 2723 __ bind(&done); | 2672 __ bind(&done); |
| 2724 } | 2673 } |
| 2725 | 2674 |
| 2726 | 2675 |
| 2727 void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, | 2676 void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2743 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 2692 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 2744 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2693 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2745 | 2694 |
| 2746 // Save 1 in xmm3 - we need this several times later on. | 2695 // Save 1 in xmm3 - we need this several times later on. |
| 2747 __ mov(ecx, Immediate(1)); | 2696 __ mov(ecx, Immediate(1)); |
| 2748 __ cvtsi2sd(xmm3, Operand(ecx)); | 2697 __ cvtsi2sd(xmm3, Operand(ecx)); |
| 2749 | 2698 |
| 2750 Label exponent_nonsmi; | 2699 Label exponent_nonsmi; |
| 2751 Label base_nonsmi; | 2700 Label base_nonsmi; |
| 2752 // If the exponent is a heap number go to that specific case. | 2701 // If the exponent is a heap number go to that specific case. |
| 2753 __ test(eax, Immediate(kSmiTagMask)); | 2702 __ JumpIfNotSmi(eax, &exponent_nonsmi); |
| 2754 __ j(not_zero, &exponent_nonsmi); | 2703 __ JumpIfNotSmi(edx, &base_nonsmi); |
| 2755 __ test(edx, Immediate(kSmiTagMask)); | |
| 2756 __ j(not_zero, &base_nonsmi); | |
| 2757 | 2704 |
| 2758 // Optimized version when both exponent and base are smis. | 2705 // Optimized version when both exponent and base are smis. |
| 2759 Label powi; | 2706 Label powi; |
| 2760 __ SmiUntag(edx); | 2707 __ SmiUntag(edx); |
| 2761 __ cvtsi2sd(xmm0, Operand(edx)); | 2708 __ cvtsi2sd(xmm0, Operand(edx)); |
| 2762 __ jmp(&powi); | 2709 __ jmp(&powi); |
| 2763 // exponent is smi and base is a heapnumber. | 2710 // exponent is smi and base is a heapnumber. |
| 2764 __ bind(&base_nonsmi); | 2711 __ bind(&base_nonsmi); |
| 2765 Factory* factory = masm->isolate()->factory(); | 2712 Factory* factory = masm->isolate()->factory(); |
| 2766 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2713 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2818 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 2765 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 2819 factory->heap_number_map()); | 2766 factory->heap_number_map()); |
| 2820 __ j(not_equal, &call_runtime); | 2767 __ j(not_equal, &call_runtime); |
| 2821 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 2768 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 2822 // Test if exponent is nan. | 2769 // Test if exponent is nan. |
| 2823 __ ucomisd(xmm1, xmm1); | 2770 __ ucomisd(xmm1, xmm1); |
| 2824 __ j(parity_even, &call_runtime); | 2771 __ j(parity_even, &call_runtime); |
| 2825 | 2772 |
| 2826 Label base_not_smi; | 2773 Label base_not_smi; |
| 2827 Label handle_special_cases; | 2774 Label handle_special_cases; |
| 2828 __ test(edx, Immediate(kSmiTagMask)); | 2775 __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); |
| 2829 __ j(not_zero, &base_not_smi, Label::kNear); | |
| 2830 __ SmiUntag(edx); | 2776 __ SmiUntag(edx); |
| 2831 __ cvtsi2sd(xmm0, Operand(edx)); | 2777 __ cvtsi2sd(xmm0, Operand(edx)); |
| 2832 __ jmp(&handle_special_cases, Label::kNear); | 2778 __ jmp(&handle_special_cases, Label::kNear); |
| 2833 | 2779 |
| 2834 __ bind(&base_not_smi); | 2780 __ bind(&base_not_smi); |
| 2835 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2781 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2836 factory->heap_number_map()); | 2782 factory->heap_number_map()); |
| 2837 __ j(not_equal, &call_runtime); | 2783 __ j(not_equal, &call_runtime); |
| 2838 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 2784 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
| 2839 __ and_(ecx, HeapNumber::kExponentMask); | 2785 __ and_(ecx, HeapNumber::kExponentMask); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2891 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { | 2837 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
| 2892 // The key is in edx and the parameter count is in eax. | 2838 // The key is in edx and the parameter count is in eax. |
| 2893 | 2839 |
| 2894 // The displacement is used for skipping the frame pointer on the | 2840 // The displacement is used for skipping the frame pointer on the |
| 2895 // stack. It is the offset of the last parameter (if any) relative | 2841 // stack. It is the offset of the last parameter (if any) relative |
| 2896 // to the frame pointer. | 2842 // to the frame pointer. |
| 2897 static const int kDisplacement = 1 * kPointerSize; | 2843 static const int kDisplacement = 1 * kPointerSize; |
| 2898 | 2844 |
| 2899 // Check that the key is a smi. | 2845 // Check that the key is a smi. |
| 2900 Label slow; | 2846 Label slow; |
| 2901 __ test(edx, Immediate(kSmiTagMask)); | 2847 __ JumpIfNotSmi(edx, &slow); |
| 2902 __ j(not_zero, &slow); | |
| 2903 | 2848 |
| 2904 // Check if the calling frame is an arguments adaptor frame. | 2849 // Check if the calling frame is an arguments adaptor frame. |
| 2905 Label adaptor; | 2850 Label adaptor; |
| 2906 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 2851 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2907 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); | 2852 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); |
| 2908 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2853 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2909 __ j(equal, &adaptor, Label::kNear); | 2854 __ j(equal, &adaptor, Label::kNear); |
| 2910 | 2855 |
| 2911 // Check index against formal parameters count limit passed in | 2856 // Check index against formal parameters count limit passed in |
| 2912 // through register eax. Use unsigned comparison to get negative | 2857 // through register eax. Use unsigned comparison to get negative |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2941 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 2886 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 2942 // by calling the runtime system. | 2887 // by calling the runtime system. |
| 2943 __ bind(&slow); | 2888 __ bind(&slow); |
| 2944 __ pop(ebx); // Return address. | 2889 __ pop(ebx); // Return address. |
| 2945 __ push(edx); | 2890 __ push(edx); |
| 2946 __ push(ebx); | 2891 __ push(ebx); |
| 2947 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); | 2892 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 2948 } | 2893 } |
| 2949 | 2894 |
| 2950 | 2895 |
| 2951 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { | 2896 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { |
| 2952 // esp[0] : return address | 2897 // esp[0] : return address |
| 2953 // esp[4] : number of parameters | 2898 // esp[4] : number of parameters |
| 2954 // esp[8] : receiver displacement | 2899 // esp[8] : receiver displacement |
| 2955 // esp[16] : function | 2900 // esp[12] : function |
| 2956 | 2901 |
| 2957 // The displacement is used for skipping the return address and the | 2902 // Check if the calling frame is an arguments adaptor frame. |
| 2958 // frame pointer on the stack. It is the offset of the last | 2903 Label runtime; |
| 2959 // parameter (if any) relative to the frame pointer. | 2904 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2960 static const int kDisplacement = 2 * kPointerSize; | 2905 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |
| 2906 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2907 __ j(not_equal, &runtime, Label::kNear); |
| 2908 |
| 2909 // Patch the arguments.length and the parameters pointer. |
| 2910 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2911 __ mov(Operand(esp, 1 * kPointerSize), ecx); |
| 2912 __ lea(edx, Operand(edx, ecx, times_2, |
| 2913 StandardFrameConstants::kCallerSPOffset)); |
| 2914 __ mov(Operand(esp, 2 * kPointerSize), edx); |
| 2915 |
| 2916 __ bind(&runtime); |
| 2917 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 2918 } |
| 2919 |
| 2920 |
| 2921 void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { |
| 2922 // esp[0] : return address |
| 2923 // esp[4] : number of parameters (tagged) |
| 2924 // esp[8] : receiver displacement |
| 2925 // esp[12] : function |
| 2926 |
| 2927 // ebx = parameter count (tagged) |
| 2928 __ mov(ebx, Operand(esp, 1 * kPointerSize)); |
| 2929 |
| 2930 // Check if the calling frame is an arguments adaptor frame. |
| 2931 // TODO(rossberg): Factor out some of the bits that are shared with the other |
| 2932 // Generate* functions. |
| 2933 Label runtime; |
| 2934 Label adaptor_frame, try_allocate; |
| 2935 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2936 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |
| 2937 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2938 __ j(equal, &adaptor_frame, Label::kNear); |
| 2939 |
| 2940 // No adaptor, parameter count = argument count. |
| 2941 __ mov(ecx, ebx); |
| 2942 __ jmp(&try_allocate, Label::kNear); |
| 2943 |
| 2944 // We have an adaptor frame. Patch the parameters pointer. |
| 2945 __ bind(&adaptor_frame); |
| 2946 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2947 __ lea(edx, Operand(edx, ecx, times_2, |
| 2948 StandardFrameConstants::kCallerSPOffset)); |
| 2949 __ mov(Operand(esp, 2 * kPointerSize), edx); |
| 2950 |
| 2951 // ebx = parameter count (tagged) |
| 2952 // ecx = argument count (tagged) |
| 2953 // esp[4] = parameter count (tagged) |
| 2954 // esp[8] = address of receiver argument |
| 2955 // Compute the mapped parameter count = min(ebx, ecx) in ebx. |
| 2956 __ cmp(ebx, Operand(ecx)); |
| 2957 __ j(less_equal, &try_allocate, Label::kNear); |
| 2958 __ mov(ebx, ecx); |
| 2959 |
| 2960 __ bind(&try_allocate); |
| 2961 |
| 2962 // Save mapped parameter count. |
| 2963 __ push(ebx); |
| 2964 |
| 2965 // Compute the sizes of backing store, parameter map, and arguments object. |
| 2966 // 1. Parameter map, has 2 extra words containing context and backing store. |
| 2967 const int kParameterMapHeaderSize = |
| 2968 FixedArray::kHeaderSize + 2 * kPointerSize; |
| 2969 Label no_parameter_map; |
| 2970 __ test(ebx, Operand(ebx)); |
| 2971 __ j(zero, &no_parameter_map, Label::kNear); |
| 2972 __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); |
| 2973 __ bind(&no_parameter_map); |
| 2974 |
| 2975 // 2. Backing store. |
| 2976 __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); |
| 2977 |
| 2978 // 3. Arguments object. |
| 2979 __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize)); |
| 2980 |
| 2981 // Do the allocation of all three objects in one go. |
| 2982 __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); |
| 2983 |
| 2984 // eax = address of new object(s) (tagged) |
| 2985 // ecx = argument count (tagged) |
| 2986 // esp[0] = mapped parameter count (tagged) |
| 2987 // esp[8] = parameter count (tagged) |
| 2988 // esp[12] = address of receiver argument |
| 2989 // Get the arguments boilerplate from the current (global) context into edi. |
| 2990 Label has_mapped_parameters, copy; |
| 2991 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2992 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); |
| 2993 __ mov(ebx, Operand(esp, 0 * kPointerSize)); |
| 2994 __ test(ebx, Operand(ebx)); |
| 2995 __ j(not_zero, &has_mapped_parameters, Label::kNear); |
| 2996 __ mov(edi, Operand(edi, |
| 2997 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); |
| 2998 __ jmp(©, Label::kNear); |
| 2999 |
| 3000 __ bind(&has_mapped_parameters); |
| 3001 __ mov(edi, Operand(edi, |
| 3002 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); |
| 3003 __ bind(©); |
| 3004 |
| 3005 // eax = address of new object (tagged) |
| 3006 // ebx = mapped parameter count (tagged) |
| 3007 // ecx = argument count (tagged) |
| 3008 // edi = address of boilerplate object (tagged) |
| 3009 // esp[0] = mapped parameter count (tagged) |
| 3010 // esp[8] = parameter count (tagged) |
| 3011 // esp[12] = address of receiver argument |
| 3012 // Copy the JS object part. |
| 3013 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 3014 __ mov(edx, FieldOperand(edi, i)); |
| 3015 __ mov(FieldOperand(eax, i), edx); |
| 3016 } |
| 3017 |
| 3018 // Setup the callee in-object property. |
| 3019 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); |
| 3020 __ mov(edx, Operand(esp, 4 * kPointerSize)); |
| 3021 __ mov(FieldOperand(eax, JSObject::kHeaderSize + |
| 3022 Heap::kArgumentsCalleeIndex * kPointerSize), |
| 3023 edx); |
| 3024 |
| 3025 // Use the length (smi tagged) and set that as an in-object property too. |
| 3026 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 3027 __ mov(FieldOperand(eax, JSObject::kHeaderSize + |
| 3028 Heap::kArgumentsLengthIndex * kPointerSize), |
| 3029 ecx); |
| 3030 |
| 3031 // Setup the elements pointer in the allocated arguments object. |
| 3032 // If we allocated a parameter map, edi will point there, otherwise to the |
| 3033 // backing store. |
| 3034 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize)); |
| 3035 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); |
| 3036 |
| 3037 // eax = address of new object (tagged) |
| 3038 // ebx = mapped parameter count (tagged) |
| 3039 // ecx = argument count (tagged) |
| 3040 // edi = address of parameter map or backing store (tagged) |
| 3041 // esp[0] = mapped parameter count (tagged) |
| 3042 // esp[8] = parameter count (tagged) |
| 3043 // esp[12] = address of receiver argument |
| 3044 // Free a register. |
| 3045 __ push(eax); |
| 3046 |
| 3047 // Initialize parameter map. If there are no mapped arguments, we're done. |
| 3048 Label skip_parameter_map; |
| 3049 __ test(ebx, Operand(ebx)); |
| 3050 __ j(zero, &skip_parameter_map); |
| 3051 |
| 3052 __ mov(FieldOperand(edi, FixedArray::kMapOffset), |
| 3053 Immediate(FACTORY->non_strict_arguments_elements_map())); |
| 3054 __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); |
| 3055 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); |
| 3056 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); |
| 3057 __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); |
| 3058 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); |
| 3059 |
| 3060 // Copy the parameter slots and the holes in the arguments. |
| 3061 // We need to fill in mapped_parameter_count slots. They index the context, |
| 3062 // where parameters are stored in reverse order, at |
| 3063 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 |
| 3064 // The mapped parameter thus need to get indices |
| 3065 // MIN_CONTEXT_SLOTS+parameter_count-1 .. |
| 3066 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count |
| 3067 // We loop from right to left. |
| 3068 Label parameters_loop, parameters_test; |
| 3069 __ push(ecx); |
| 3070 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
| 3071 __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); |
| 3072 __ add(ebx, Operand(esp, 4 * kPointerSize)); |
| 3073 __ sub(ebx, Operand(eax)); |
| 3074 __ mov(ecx, FACTORY->the_hole_value()); |
| 3075 __ mov(edx, edi); |
| 3076 __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); |
| 3077 // eax = loop variable (tagged) |
| 3078 // ebx = mapping index (tagged) |
| 3079 // ecx = the hole value |
| 3080 // edx = address of parameter map (tagged) |
| 3081 // edi = address of backing store (tagged) |
| 3082 // esp[0] = argument count (tagged) |
| 3083 // esp[4] = address of new object (tagged) |
| 3084 // esp[8] = mapped parameter count (tagged) |
| 3085 // esp[16] = parameter count (tagged) |
| 3086 // esp[20] = address of receiver argument |
| 3087 __ jmp(¶meters_test, Label::kNear); |
| 3088 |
| 3089 __ bind(¶meters_loop); |
| 3090 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3091 __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); |
| 3092 __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); |
| 3093 __ add(Operand(ebx), Immediate(Smi::FromInt(1))); |
| 3094 __ bind(¶meters_test); |
| 3095 __ test(eax, Operand(eax)); |
| 3096 __ j(not_zero, ¶meters_loop, Label::kNear); |
| 3097 __ pop(ecx); |
| 3098 |
| 3099 __ bind(&skip_parameter_map); |
| 3100 |
| 3101 // ecx = argument count (tagged) |
| 3102 // edi = address of backing store (tagged) |
| 3103 // esp[0] = address of new object (tagged) |
| 3104 // esp[4] = mapped parameter count (tagged) |
| 3105 // esp[12] = parameter count (tagged) |
| 3106 // esp[16] = address of receiver argument |
| 3107 // Copy arguments header and remaining slots (if there are any). |
| 3108 __ mov(FieldOperand(edi, FixedArray::kMapOffset), |
| 3109 Immediate(FACTORY->fixed_array_map())); |
| 3110 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); |
| 3111 |
| 3112 Label arguments_loop, arguments_test; |
| 3113 __ mov(ebx, Operand(esp, 1 * kPointerSize)); |
| 3114 __ mov(edx, Operand(esp, 4 * kPointerSize)); |
| 3115 __ sub(Operand(edx), ebx); // Is there a smarter way to do negative scaling? |
| 3116 __ sub(Operand(edx), ebx); |
| 3117 __ jmp(&arguments_test, Label::kNear); |
| 3118 |
| 3119 __ bind(&arguments_loop); |
| 3120 __ sub(Operand(edx), Immediate(kPointerSize)); |
| 3121 __ mov(eax, Operand(edx, 0)); |
| 3122 __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); |
| 3123 __ add(Operand(ebx), Immediate(Smi::FromInt(1))); |
| 3124 |
| 3125 __ bind(&arguments_test); |
| 3126 __ cmp(ebx, Operand(ecx)); |
| 3127 __ j(less, &arguments_loop, Label::kNear); |
| 3128 |
| 3129 // Restore. |
| 3130 __ pop(eax); // Address of arguments object. |
| 3131 __ pop(ebx); // Parameter count. |
| 3132 |
| 3133 // Return and remove the on-stack parameters. |
| 3134 __ ret(3 * kPointerSize); |
| 3135 |
| 3136 // Do the runtime call to allocate the arguments object. |
| 3137 __ bind(&runtime); |
| 3138 __ pop(eax); // Remove saved parameter count. |
| 3139 __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count. |
| 3140 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |
| 3141 } |
| 3142 |
| 3143 |
| 3144 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { |
| 3145 // esp[0] : return address |
| 3146 // esp[4] : number of parameters |
| 3147 // esp[8] : receiver displacement |
| 3148 // esp[12] : function |
| 2961 | 3149 |
| 2962 // Check if the calling frame is an arguments adaptor frame. | 3150 // Check if the calling frame is an arguments adaptor frame. |
| 2963 Label adaptor_frame, try_allocate, runtime; | 3151 Label adaptor_frame, try_allocate, runtime; |
| 2964 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 3152 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2965 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); | 3153 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |
| 2966 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 3154 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2967 __ j(equal, &adaptor_frame); | 3155 __ j(equal, &adaptor_frame); |
| 2968 | 3156 |
| 2969 // Get the length from the frame. | 3157 // Get the length from the frame. |
| 2970 __ mov(ecx, Operand(esp, 1 * kPointerSize)); | 3158 __ mov(ecx, Operand(esp, 1 * kPointerSize)); |
| 2971 __ jmp(&try_allocate); | 3159 __ jmp(&try_allocate); |
| 2972 | 3160 |
| 2973 // Patch the arguments.length and the parameters pointer. | 3161 // Patch the arguments.length and the parameters pointer. |
| 2974 __ bind(&adaptor_frame); | 3162 __ bind(&adaptor_frame); |
| 2975 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 3163 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2976 __ mov(Operand(esp, 1 * kPointerSize), ecx); | 3164 __ mov(Operand(esp, 1 * kPointerSize), ecx); |
| 2977 __ lea(edx, Operand(edx, ecx, times_2, kDisplacement)); | 3165 __ lea(edx, Operand(edx, ecx, times_2, |
| 3166 StandardFrameConstants::kCallerSPOffset)); |
| 2978 __ mov(Operand(esp, 2 * kPointerSize), edx); | 3167 __ mov(Operand(esp, 2 * kPointerSize), edx); |
| 2979 | 3168 |
| 2980 // Try the new space allocation. Start out with computing the size of | 3169 // Try the new space allocation. Start out with computing the size of |
| 2981 // the arguments object and the elements array. | 3170 // the arguments object and the elements array. |
| 2982 Label add_arguments_object; | 3171 Label add_arguments_object; |
| 2983 __ bind(&try_allocate); | 3172 __ bind(&try_allocate); |
| 2984 __ test(ecx, Operand(ecx)); | 3173 __ test(ecx, Operand(ecx)); |
| 2985 __ j(zero, &add_arguments_object, Label::kNear); | 3174 __ j(zero, &add_arguments_object, Label::kNear); |
| 2986 __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); | 3175 __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); |
| 2987 __ bind(&add_arguments_object); | 3176 __ bind(&add_arguments_object); |
| 2988 __ add(Operand(ecx), Immediate(GetArgumentsObjectSize())); | 3177 __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict)); |
| 2989 | 3178 |
| 2990 // Do the allocation of both objects in one go. | 3179 // Do the allocation of both objects in one go. |
| 2991 __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); | 3180 __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); |
| 2992 | 3181 |
| 2993 // Get the arguments boilerplate from the current (global) context. | 3182 // Get the arguments boilerplate from the current (global) context. |
| 2994 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 3183 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2995 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); | 3184 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); |
| 2996 __ mov(edi, Operand(edi, | 3185 const int offset = |
| 2997 Context::SlotOffset(GetArgumentsBoilerplateIndex()))); | 3186 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); |
| 3187 __ mov(edi, Operand(edi, offset)); |
| 2998 | 3188 |
| 2999 // Copy the JS object part. | 3189 // Copy the JS object part. |
| 3000 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { | 3190 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 3001 __ mov(ebx, FieldOperand(edi, i)); | 3191 __ mov(ebx, FieldOperand(edi, i)); |
| 3002 __ mov(FieldOperand(eax, i), ebx); | 3192 __ mov(FieldOperand(eax, i), ebx); |
| 3003 } | 3193 } |
| 3004 | 3194 |
| 3005 if (type_ == NEW_NON_STRICT) { | |
| 3006 // Setup the callee in-object property. | |
| 3007 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); | |
| 3008 __ mov(ebx, Operand(esp, 3 * kPointerSize)); | |
| 3009 __ mov(FieldOperand(eax, JSObject::kHeaderSize + | |
| 3010 Heap::kArgumentsCalleeIndex * kPointerSize), | |
| 3011 ebx); | |
| 3012 } | |
| 3013 | |
| 3014 // Get the length (smi tagged) and set that as an in-object property too. | 3195 // Get the length (smi tagged) and set that as an in-object property too. |
| 3015 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); | 3196 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 3016 __ mov(ecx, Operand(esp, 1 * kPointerSize)); | 3197 __ mov(ecx, Operand(esp, 1 * kPointerSize)); |
| 3017 __ mov(FieldOperand(eax, JSObject::kHeaderSize + | 3198 __ mov(FieldOperand(eax, JSObject::kHeaderSize + |
| 3018 Heap::kArgumentsLengthIndex * kPointerSize), | 3199 Heap::kArgumentsLengthIndex * kPointerSize), |
| 3019 ecx); | 3200 ecx); |
| 3020 | 3201 |
| 3021 // If there are no actual arguments, we're done. | 3202 // If there are no actual arguments, we're done. |
| 3022 Label done; | 3203 Label done; |
| 3023 __ test(ecx, Operand(ecx)); | 3204 __ test(ecx, Operand(ecx)); |
| 3024 __ j(zero, &done); | 3205 __ j(zero, &done); |
| 3025 | 3206 |
| 3026 // Get the parameters pointer from the stack. | 3207 // Get the parameters pointer from the stack. |
| 3027 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 3208 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 3028 | 3209 |
| 3029 // Setup the elements pointer in the allocated arguments object and | 3210 // Setup the elements pointer in the allocated arguments object and |
| 3030 // initialize the header in the elements fixed array. | 3211 // initialize the header in the elements fixed array. |
| 3031 __ lea(edi, Operand(eax, GetArgumentsObjectSize())); | 3212 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); |
| 3032 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); | 3213 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); |
| 3033 __ mov(FieldOperand(edi, FixedArray::kMapOffset), | 3214 __ mov(FieldOperand(edi, FixedArray::kMapOffset), |
| 3034 Immediate(masm->isolate()->factory()->fixed_array_map())); | 3215 Immediate(FACTORY->fixed_array_map())); |
| 3035 | 3216 |
| 3036 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); | 3217 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); |
| 3037 // Untag the length for the loop below. | 3218 // Untag the length for the loop below. |
| 3038 __ SmiUntag(ecx); | 3219 __ SmiUntag(ecx); |
| 3039 | 3220 |
| 3040 // Copy the fixed array slots. | 3221 // Copy the fixed array slots. |
| 3041 Label loop; | 3222 Label loop; |
| 3042 __ bind(&loop); | 3223 __ bind(&loop); |
| 3043 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. | 3224 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. |
| 3044 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); | 3225 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); |
| 3045 __ add(Operand(edi), Immediate(kPointerSize)); | 3226 __ add(Operand(edi), Immediate(kPointerSize)); |
| 3046 __ sub(Operand(edx), Immediate(kPointerSize)); | 3227 __ sub(Operand(edx), Immediate(kPointerSize)); |
| 3047 __ dec(ecx); | 3228 __ dec(ecx); |
| 3048 __ j(not_zero, &loop); | 3229 __ j(not_zero, &loop); |
| 3049 | 3230 |
| 3050 // Return and remove the on-stack parameters. | 3231 // Return and remove the on-stack parameters. |
| 3051 __ bind(&done); | 3232 __ bind(&done); |
| 3052 __ ret(3 * kPointerSize); | 3233 __ ret(3 * kPointerSize); |
| 3053 | 3234 |
| 3054 // Do the runtime call to allocate the arguments object. | 3235 // Do the runtime call to allocate the arguments object. |
| 3055 __ bind(&runtime); | 3236 __ bind(&runtime); |
| 3056 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); | 3237 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |
| 3057 } | 3238 } |
| 3058 | 3239 |
| 3059 | 3240 |
| 3060 void RegExpExecStub::Generate(MacroAssembler* masm) { | 3241 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 3061 // Just jump directly to runtime if native RegExp is not selected at compile | 3242 // Just jump directly to runtime if native RegExp is not selected at compile |
| 3062 // time or if regexp entry in generated code is turned off runtime switch or | 3243 // time or if regexp entry in generated code is turned off runtime switch or |
| 3063 // at compilation. | 3244 // at compilation. |
| 3064 #ifdef V8_INTERPRETED_REGEXP | 3245 #ifdef V8_INTERPRETED_REGEXP |
| 3065 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 3246 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 3066 #else // V8_INTERPRETED_REGEXP | 3247 #else // V8_INTERPRETED_REGEXP |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3089 masm->isolate()); | 3270 masm->isolate()); |
| 3090 ExternalReference address_of_regexp_stack_memory_size = | 3271 ExternalReference address_of_regexp_stack_memory_size = |
| 3091 ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); | 3272 ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); |
| 3092 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | 3273 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
| 3093 __ test(ebx, Operand(ebx)); | 3274 __ test(ebx, Operand(ebx)); |
| 3094 __ j(zero, &runtime); | 3275 __ j(zero, &runtime); |
| 3095 | 3276 |
| 3096 // Check that the first argument is a JSRegExp object. | 3277 // Check that the first argument is a JSRegExp object. |
| 3097 __ mov(eax, Operand(esp, kJSRegExpOffset)); | 3278 __ mov(eax, Operand(esp, kJSRegExpOffset)); |
| 3098 STATIC_ASSERT(kSmiTag == 0); | 3279 STATIC_ASSERT(kSmiTag == 0); |
| 3099 __ test(eax, Immediate(kSmiTagMask)); | 3280 __ JumpIfSmi(eax, &runtime); |
| 3100 __ j(zero, &runtime); | |
| 3101 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); | 3281 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); |
| 3102 __ j(not_equal, &runtime); | 3282 __ j(not_equal, &runtime); |
| 3103 // Check that the RegExp has been compiled (data contains a fixed array). | 3283 // Check that the RegExp has been compiled (data contains a fixed array). |
| 3104 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | 3284 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
| 3105 if (FLAG_debug_code) { | 3285 if (FLAG_debug_code) { |
| 3106 __ test(ecx, Immediate(kSmiTagMask)); | 3286 __ test(ecx, Immediate(kSmiTagMask)); |
| 3107 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); | 3287 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); |
| 3108 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); | 3288 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); |
| 3109 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); | 3289 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); |
| 3110 } | 3290 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3124 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 3304 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
| 3125 __ add(Operand(edx), Immediate(2)); // edx was a smi. | 3305 __ add(Operand(edx), Immediate(2)); // edx was a smi. |
| 3126 // Check that the static offsets vector buffer is large enough. | 3306 // Check that the static offsets vector buffer is large enough. |
| 3127 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); | 3307 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); |
| 3128 __ j(above, &runtime); | 3308 __ j(above, &runtime); |
| 3129 | 3309 |
| 3130 // ecx: RegExp data (FixedArray) | 3310 // ecx: RegExp data (FixedArray) |
| 3131 // edx: Number of capture registers | 3311 // edx: Number of capture registers |
| 3132 // Check that the second argument is a string. | 3312 // Check that the second argument is a string. |
| 3133 __ mov(eax, Operand(esp, kSubjectOffset)); | 3313 __ mov(eax, Operand(esp, kSubjectOffset)); |
| 3134 __ test(eax, Immediate(kSmiTagMask)); | 3314 __ JumpIfSmi(eax, &runtime); |
| 3135 __ j(zero, &runtime); | |
| 3136 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); | 3315 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |
| 3137 __ j(NegateCondition(is_string), &runtime); | 3316 __ j(NegateCondition(is_string), &runtime); |
| 3138 // Get the length of the string to ebx. | 3317 // Get the length of the string to ebx. |
| 3139 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 3318 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
| 3140 | 3319 |
| 3141 // ebx: Length of subject string as a smi | 3320 // ebx: Length of subject string as a smi |
| 3142 // ecx: RegExp data (FixedArray) | 3321 // ecx: RegExp data (FixedArray) |
| 3143 // edx: Number of capture registers | 3322 // edx: Number of capture registers |
| 3144 // Check that the third argument is a positive smi less than the subject | 3323 // Check that the third argument is a positive smi less than the subject |
| 3145 // string length. A negative value will be greater (unsigned comparison). | 3324 // string length. A negative value will be greater (unsigned comparison). |
| 3146 __ mov(eax, Operand(esp, kPreviousIndexOffset)); | 3325 __ mov(eax, Operand(esp, kPreviousIndexOffset)); |
| 3147 __ test(eax, Immediate(kSmiTagMask)); | 3326 __ JumpIfNotSmi(eax, &runtime); |
| 3148 __ j(not_zero, &runtime); | |
| 3149 __ cmp(eax, Operand(ebx)); | 3327 __ cmp(eax, Operand(ebx)); |
| 3150 __ j(above_equal, &runtime); | 3328 __ j(above_equal, &runtime); |
| 3151 | 3329 |
| 3152 // ecx: RegExp data (FixedArray) | 3330 // ecx: RegExp data (FixedArray) |
| 3153 // edx: Number of capture registers | 3331 // edx: Number of capture registers |
| 3154 // Check that the fourth object is a JSArray object. | 3332 // Check that the fourth object is a JSArray object. |
| 3155 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 3333 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |
| 3156 __ test(eax, Immediate(kSmiTagMask)); | 3334 __ JumpIfSmi(eax, &runtime); |
| 3157 __ j(zero, &runtime); | |
| 3158 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); | 3335 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
| 3159 __ j(not_equal, &runtime); | 3336 __ j(not_equal, &runtime); |
| 3160 // Check that the JSArray is in fast case. | 3337 // Check that the JSArray is in fast case. |
| 3161 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); | 3338 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |
| 3162 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); | 3339 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); |
| 3163 Factory* factory = masm->isolate()->factory(); | 3340 Factory* factory = masm->isolate()->factory(); |
| 3164 __ cmp(eax, factory->fixed_array_map()); | 3341 __ cmp(eax, factory->fixed_array_map()); |
| 3165 __ j(not_equal, &runtime); | 3342 __ j(not_equal, &runtime); |
| 3166 // Check that the last match info has space for the capture registers and the | 3343 // Check that the last match info has space for the capture registers and the |
| 3167 // additional information. | 3344 // additional information. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3225 | 3402 |
| 3226 __ bind(&seq_two_byte_string); | 3403 __ bind(&seq_two_byte_string); |
| 3227 // eax: subject string (flat two byte) | 3404 // eax: subject string (flat two byte) |
| 3228 // ecx: RegExp data (FixedArray) | 3405 // ecx: RegExp data (FixedArray) |
| 3229 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); | 3406 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); |
| 3230 __ Set(edi, Immediate(0)); // Type is two byte. | 3407 __ Set(edi, Immediate(0)); // Type is two byte. |
| 3231 | 3408 |
| 3232 __ bind(&check_code); | 3409 __ bind(&check_code); |
| 3233 // Check that the irregexp code has been generated for the actual string | 3410 // Check that the irregexp code has been generated for the actual string |
| 3234 // encoding. If it has, the field contains a code object otherwise it contains | 3411 // encoding. If it has, the field contains a code object otherwise it contains |
| 3235 // the hole. | 3412 // a smi (code flushing support). |
| 3236 __ CmpObjectType(edx, CODE_TYPE, ebx); | 3413 __ JumpIfSmi(edx, &runtime); |
| 3237 __ j(not_equal, &runtime); | |
| 3238 | 3414 |
| 3239 // eax: subject string | 3415 // eax: subject string |
| 3240 // edx: code | 3416 // edx: code |
| 3241 // edi: encoding of subject string (1 if ascii, 0 if two_byte); | 3417 // edi: encoding of subject string (1 if ascii, 0 if two_byte); |
| 3242 // Load used arguments before starting to push arguments for call to native | 3418 // Load used arguments before starting to push arguments for call to native |
| 3243 // RegExp code to avoid handling changing stack height. | 3419 // RegExp code to avoid handling changing stack height. |
| 3244 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); | 3420 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); |
| 3245 __ SmiUntag(ebx); // Previous index from smi. | 3421 __ SmiUntag(ebx); // Previous index from smi. |
| 3246 | 3422 |
| 3247 // eax: subject string | 3423 // eax: subject string |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3425 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 3601 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 3426 #endif // V8_INTERPRETED_REGEXP | 3602 #endif // V8_INTERPRETED_REGEXP |
| 3427 } | 3603 } |
| 3428 | 3604 |
| 3429 | 3605 |
| 3430 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { | 3606 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { |
| 3431 const int kMaxInlineLength = 100; | 3607 const int kMaxInlineLength = 100; |
| 3432 Label slowcase; | 3608 Label slowcase; |
| 3433 Label done; | 3609 Label done; |
| 3434 __ mov(ebx, Operand(esp, kPointerSize * 3)); | 3610 __ mov(ebx, Operand(esp, kPointerSize * 3)); |
| 3435 __ test(ebx, Immediate(kSmiTagMask)); | 3611 __ JumpIfNotSmi(ebx, &slowcase); |
| 3436 __ j(not_zero, &slowcase); | |
| 3437 __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength))); | 3612 __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength))); |
| 3438 __ j(above, &slowcase); | 3613 __ j(above, &slowcase); |
| 3439 // Smi-tagging is equivalent to multiplying by 2. | 3614 // Smi-tagging is equivalent to multiplying by 2. |
| 3440 STATIC_ASSERT(kSmiTag == 0); | 3615 STATIC_ASSERT(kSmiTag == 0); |
| 3441 STATIC_ASSERT(kSmiTagSize == 1); | 3616 STATIC_ASSERT(kSmiTagSize == 1); |
| 3442 // Allocate RegExpResult followed by FixedArray with size in ebx. | 3617 // Allocate RegExpResult followed by FixedArray with size in ebx. |
| 3443 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] | 3618 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] |
| 3444 // Elements: [Map][Length][..elements..] | 3619 // Elements: [Map][Length][..elements..] |
| 3445 __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, | 3620 __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, |
| 3446 times_half_pointer_size, | 3621 times_half_pointer_size, |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3538 // doubles is the xor of the upper and lower words. See | 3713 // doubles is the xor of the upper and lower words. See |
| 3539 // Heap::GetNumberStringCache. | 3714 // Heap::GetNumberStringCache. |
| 3540 Label smi_hash_calculated; | 3715 Label smi_hash_calculated; |
| 3541 Label load_result_from_cache; | 3716 Label load_result_from_cache; |
| 3542 if (object_is_smi) { | 3717 if (object_is_smi) { |
| 3543 __ mov(scratch, object); | 3718 __ mov(scratch, object); |
| 3544 __ SmiUntag(scratch); | 3719 __ SmiUntag(scratch); |
| 3545 } else { | 3720 } else { |
| 3546 Label not_smi; | 3721 Label not_smi; |
| 3547 STATIC_ASSERT(kSmiTag == 0); | 3722 STATIC_ASSERT(kSmiTag == 0); |
| 3548 __ test(object, Immediate(kSmiTagMask)); | 3723 __ JumpIfNotSmi(object, ¬_smi, Label::kNear); |
| 3549 __ j(not_zero, ¬_smi, Label::kNear); | |
| 3550 __ mov(scratch, object); | 3724 __ mov(scratch, object); |
| 3551 __ SmiUntag(scratch); | 3725 __ SmiUntag(scratch); |
| 3552 __ jmp(&smi_hash_calculated, Label::kNear); | 3726 __ jmp(&smi_hash_calculated, Label::kNear); |
| 3553 __ bind(¬_smi); | 3727 __ bind(¬_smi); |
| 3554 __ cmp(FieldOperand(object, HeapObject::kMapOffset), | 3728 __ cmp(FieldOperand(object, HeapObject::kMapOffset), |
| 3555 masm->isolate()->factory()->heap_number_map()); | 3729 masm->isolate()->factory()->heap_number_map()); |
| 3556 __ j(not_equal, not_found); | 3730 __ j(not_equal, not_found); |
| 3557 STATIC_ASSERT(8 == kDoubleSize); | 3731 STATIC_ASSERT(8 == kDoubleSize); |
| 3558 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); | 3732 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); |
| 3559 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); | 3733 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); |
| 3560 // Object is heap number and hash is now in scratch. Calculate cache index. | 3734 // Object is heap number and hash is now in scratch. Calculate cache index. |
| 3561 __ and_(scratch, Operand(mask)); | 3735 __ and_(scratch, Operand(mask)); |
| 3562 Register index = scratch; | 3736 Register index = scratch; |
| 3563 Register probe = mask; | 3737 Register probe = mask; |
| 3564 __ mov(probe, | 3738 __ mov(probe, |
| 3565 FieldOperand(number_string_cache, | 3739 FieldOperand(number_string_cache, |
| 3566 index, | 3740 index, |
| 3567 times_twice_pointer_size, | 3741 times_twice_pointer_size, |
| 3568 FixedArray::kHeaderSize)); | 3742 FixedArray::kHeaderSize)); |
| 3569 __ test(probe, Immediate(kSmiTagMask)); | 3743 __ JumpIfSmi(probe, not_found); |
| 3570 __ j(zero, not_found); | |
| 3571 if (CpuFeatures::IsSupported(SSE2)) { | 3744 if (CpuFeatures::IsSupported(SSE2)) { |
| 3572 CpuFeatures::Scope fscope(SSE2); | 3745 CpuFeatures::Scope fscope(SSE2); |
| 3573 __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); | 3746 __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); |
| 3574 __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); | 3747 __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); |
| 3575 __ ucomisd(xmm0, xmm1); | 3748 __ ucomisd(xmm0, xmm1); |
| 3576 } else { | 3749 } else { |
| 3577 __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); | 3750 __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); |
| 3578 __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); | 3751 __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); |
| 3579 __ FCmp(); | 3752 __ FCmp(); |
| 3580 } | 3753 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3632 void CompareStub::Generate(MacroAssembler* masm) { | 3805 void CompareStub::Generate(MacroAssembler* masm) { |
| 3633 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 3806 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |
| 3634 | 3807 |
| 3635 Label check_unequal_objects, done; | 3808 Label check_unequal_objects, done; |
| 3636 | 3809 |
| 3637 // Compare two smis if required. | 3810 // Compare two smis if required. |
| 3638 if (include_smi_compare_) { | 3811 if (include_smi_compare_) { |
| 3639 Label non_smi, smi_done; | 3812 Label non_smi, smi_done; |
| 3640 __ mov(ecx, Operand(edx)); | 3813 __ mov(ecx, Operand(edx)); |
| 3641 __ or_(ecx, Operand(eax)); | 3814 __ or_(ecx, Operand(eax)); |
| 3642 __ test(ecx, Immediate(kSmiTagMask)); | 3815 __ JumpIfNotSmi(ecx, &non_smi); |
| 3643 __ j(not_zero, &non_smi); | |
| 3644 __ sub(edx, Operand(eax)); // Return on the result of the subtraction. | 3816 __ sub(edx, Operand(eax)); // Return on the result of the subtraction. |
| 3645 __ j(no_overflow, &smi_done); | 3817 __ j(no_overflow, &smi_done); |
| 3646 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. | 3818 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. |
| 3647 __ bind(&smi_done); | 3819 __ bind(&smi_done); |
| 3648 __ mov(eax, edx); | 3820 __ mov(eax, edx); |
| 3649 __ ret(0); | 3821 __ ret(0); |
| 3650 __ bind(&non_smi); | 3822 __ bind(&non_smi); |
| 3651 } else if (FLAG_debug_code) { | 3823 } else if (FLAG_debug_code) { |
| 3652 __ mov(ecx, Operand(edx)); | 3824 __ mov(ecx, Operand(edx)); |
| 3653 __ or_(ecx, Operand(eax)); | 3825 __ or_(ecx, Operand(eax)); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3682 if (never_nan_nan_ && (cc_ == equal)) { | 3854 if (never_nan_nan_ && (cc_ == equal)) { |
| 3683 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 3855 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 3684 __ ret(0); | 3856 __ ret(0); |
| 3685 } else { | 3857 } else { |
| 3686 Label heap_number; | 3858 Label heap_number; |
| 3687 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 3859 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 3688 Immediate(masm->isolate()->factory()->heap_number_map())); | 3860 Immediate(masm->isolate()->factory()->heap_number_map())); |
| 3689 __ j(equal, &heap_number, Label::kNear); | 3861 __ j(equal, &heap_number, Label::kNear); |
| 3690 if (cc_ != equal) { | 3862 if (cc_ != equal) { |
| 3691 // Call runtime on identical JSObjects. Otherwise return equal. | 3863 // Call runtime on identical JSObjects. Otherwise return equal. |
| 3692 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 3864 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 3693 __ j(above_equal, ¬_identical); | 3865 __ j(above_equal, ¬_identical); |
| 3694 } | 3866 } |
| 3695 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 3867 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 3696 __ ret(0); | 3868 __ ret(0); |
| 3697 | 3869 |
| 3698 __ bind(&heap_number); | 3870 __ bind(&heap_number); |
| 3699 // It is a heap number, so return non-equal if it's NaN and equal if | 3871 // It is a heap number, so return non-equal if it's NaN and equal if |
| 3700 // it's not NaN. | 3872 // it's not NaN. |
| 3701 // The representation of NaN values has all exponent bits (52..62) set, | 3873 // The representation of NaN values has all exponent bits (52..62) set, |
| 3702 // and not all mantissa bits (0..51) clear. | 3874 // and not all mantissa bits (0..51) clear. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3770 __ ret(0); | 3942 __ ret(0); |
| 3771 | 3943 |
| 3772 __ bind(¬_smis); | 3944 __ bind(¬_smis); |
| 3773 // If either operand is a JSObject or an oddball value, then they are not | 3945 // If either operand is a JSObject or an oddball value, then they are not |
| 3774 // equal since their pointers are different | 3946 // equal since their pointers are different |
| 3775 // There is no test for undetectability in strict equality. | 3947 // There is no test for undetectability in strict equality. |
| 3776 | 3948 |
| 3777 // Get the type of the first operand. | 3949 // Get the type of the first operand. |
| 3778 // If the first object is a JS object, we have done pointer comparison. | 3950 // If the first object is a JS object, we have done pointer comparison. |
| 3779 Label first_non_object; | 3951 Label first_non_object; |
| 3780 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 3952 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
| 3781 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 3953 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 3782 __ j(below, &first_non_object, Label::kNear); | 3954 __ j(below, &first_non_object, Label::kNear); |
| 3783 | 3955 |
| 3784 // Return non-zero (eax is not zero) | 3956 // Return non-zero (eax is not zero) |
| 3785 Label return_not_equal; | 3957 Label return_not_equal; |
| 3786 STATIC_ASSERT(kHeapObjectTag != 0); | 3958 STATIC_ASSERT(kHeapObjectTag != 0); |
| 3787 __ bind(&return_not_equal); | 3959 __ bind(&return_not_equal); |
| 3788 __ ret(0); | 3960 __ ret(0); |
| 3789 | 3961 |
| 3790 __ bind(&first_non_object); | 3962 __ bind(&first_non_object); |
| 3791 // Check for oddballs: true, false, null, undefined. | 3963 // Check for oddballs: true, false, null, undefined. |
| 3792 __ CmpInstanceType(ecx, ODDBALL_TYPE); | 3964 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
| 3793 __ j(equal, &return_not_equal); | 3965 __ j(equal, &return_not_equal); |
| 3794 | 3966 |
| 3795 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); | 3967 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 3796 __ j(above_equal, &return_not_equal); | 3968 __ j(above_equal, &return_not_equal); |
| 3797 | 3969 |
| 3798 // Check for oddballs: true, false, null, undefined. | 3970 // Check for oddballs: true, false, null, undefined. |
| 3799 __ CmpInstanceType(ecx, ODDBALL_TYPE); | 3971 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
| 3800 __ j(equal, &return_not_equal); | 3972 __ j(equal, &return_not_equal); |
| 3801 | 3973 |
| 3802 // Fall through to the general case. | 3974 // Fall through to the general case. |
| 3803 __ bind(&slow); | 3975 __ bind(&slow); |
| 3804 } | 3976 } |
| 3805 | 3977 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3909 Label not_both_objects; | 4081 Label not_both_objects; |
| 3910 Label return_unequal; | 4082 Label return_unequal; |
| 3911 // At most one is a smi, so we can test for smi by adding the two. | 4083 // At most one is a smi, so we can test for smi by adding the two. |
| 3912 // A smi plus a heap object has the low bit set, a heap object plus | 4084 // A smi plus a heap object has the low bit set, a heap object plus |
| 3913 // a heap object has the low bit clear. | 4085 // a heap object has the low bit clear. |
| 3914 STATIC_ASSERT(kSmiTag == 0); | 4086 STATIC_ASSERT(kSmiTag == 0); |
| 3915 STATIC_ASSERT(kSmiTagMask == 1); | 4087 STATIC_ASSERT(kSmiTagMask == 1); |
| 3916 __ lea(ecx, Operand(eax, edx, times_1, 0)); | 4088 __ lea(ecx, Operand(eax, edx, times_1, 0)); |
| 3917 __ test(ecx, Immediate(kSmiTagMask)); | 4089 __ test(ecx, Immediate(kSmiTagMask)); |
| 3918 __ j(not_zero, ¬_both_objects, Label::kNear); | 4090 __ j(not_zero, ¬_both_objects, Label::kNear); |
| 3919 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 4091 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 3920 __ j(below, ¬_both_objects, Label::kNear); | 4092 __ j(below, ¬_both_objects, Label::kNear); |
| 3921 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ebx); | 4093 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx); |
| 3922 __ j(below, ¬_both_objects, Label::kNear); | 4094 __ j(below, ¬_both_objects, Label::kNear); |
| 3923 // We do not bail out after this point. Both are JSObjects, and | 4095 // We do not bail out after this point. Both are JSObjects, and |
| 3924 // they are equal if and only if both are undetectable. | 4096 // they are equal if and only if both are undetectable. |
| 3925 // The and of the undetectable flags is 1 if and only if they are equal. | 4097 // The and of the undetectable flags is 1 if and only if they are equal. |
| 3926 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), | 4098 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), |
| 3927 1 << Map::kIsUndetectable); | 4099 1 << Map::kIsUndetectable); |
| 3928 __ j(zero, &return_unequal, Label::kNear); | 4100 __ j(zero, &return_unequal, Label::kNear); |
| 3929 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), | 4101 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), |
| 3930 1 << Map::kIsUndetectable); | 4102 1 << Map::kIsUndetectable); |
| 3931 __ j(zero, &return_unequal, Label::kNear); | 4103 __ j(zero, &return_unequal, Label::kNear); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 3959 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 4131 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 3960 // tagged as a small integer. | 4132 // tagged as a small integer. |
| 3961 __ InvokeBuiltin(builtin, JUMP_FUNCTION); | 4133 __ InvokeBuiltin(builtin, JUMP_FUNCTION); |
| 3962 } | 4134 } |
| 3963 | 4135 |
| 3964 | 4136 |
| 3965 void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, | 4137 void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, |
| 3966 Label* label, | 4138 Label* label, |
| 3967 Register object, | 4139 Register object, |
| 3968 Register scratch) { | 4140 Register scratch) { |
| 3969 __ test(object, Immediate(kSmiTagMask)); | 4141 __ JumpIfSmi(object, label); |
| 3970 __ j(zero, label); | |
| 3971 __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); | 4142 __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); |
| 3972 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 4143 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3973 __ and_(scratch, kIsSymbolMask | kIsNotStringMask); | 4144 __ and_(scratch, kIsSymbolMask | kIsNotStringMask); |
| 3974 __ cmp(scratch, kSymbolTag | kStringTag); | 4145 __ cmp(scratch, kSymbolTag | kStringTag); |
| 3975 __ j(not_equal, label); | 4146 __ j(not_equal, label); |
| 3976 } | 4147 } |
| 3977 | 4148 |
| 3978 | 4149 |
| 3979 void StackCheckStub::Generate(MacroAssembler* masm) { | 4150 void StackCheckStub::Generate(MacroAssembler* masm) { |
| 3980 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); | 4151 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 4000 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 4171 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
| 4001 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ebx); | 4172 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ebx); |
| 4002 __ bind(&call); | 4173 __ bind(&call); |
| 4003 } | 4174 } |
| 4004 | 4175 |
| 4005 // Get the function to call from the stack. | 4176 // Get the function to call from the stack. |
| 4006 // +2 ~ receiver, return address | 4177 // +2 ~ receiver, return address |
| 4007 __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize)); | 4178 __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize)); |
| 4008 | 4179 |
| 4009 // Check that the function really is a JavaScript function. | 4180 // Check that the function really is a JavaScript function. |
| 4010 __ test(edi, Immediate(kSmiTagMask)); | 4181 __ JumpIfSmi(edi, &slow); |
| 4011 __ j(zero, &slow); | |
| 4012 // Goto slow case if we do not have a function. | 4182 // Goto slow case if we do not have a function. |
| 4013 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 4183 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 4014 __ j(not_equal, &slow); | 4184 __ j(not_equal, &slow); |
| 4015 | 4185 |
| 4016 // Fast-case: Just invoke the function. | 4186 // Fast-case: Just invoke the function. |
| 4017 ParameterCount actual(argc_); | 4187 ParameterCount actual(argc_); |
| 4018 | 4188 |
| 4019 if (ReceiverMightBeImplicit()) { | 4189 if (ReceiverMightBeImplicit()) { |
| 4020 Label call_as_function; | 4190 Label call_as_function; |
| 4021 __ cmp(eax, masm->isolate()->factory()->the_hole_value()); | 4191 __ cmp(eax, masm->isolate()->factory()->the_hole_value()); |
| 4022 __ j(equal, &call_as_function); | 4192 __ j(equal, &call_as_function); |
| 4023 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 4193 __ InvokeFunction(edi, |
| 4194 actual, |
| 4195 JUMP_FUNCTION, |
| 4196 NullCallWrapper(), |
| 4197 CALL_AS_METHOD); |
| 4024 __ bind(&call_as_function); | 4198 __ bind(&call_as_function); |
| 4025 } | 4199 } |
| 4026 __ InvokeFunction(edi, | 4200 __ InvokeFunction(edi, |
| 4027 actual, | 4201 actual, |
| 4028 JUMP_FUNCTION, | 4202 JUMP_FUNCTION, |
| 4029 NullCallWrapper(), | 4203 NullCallWrapper(), |
| 4030 CALL_AS_FUNCTION); | 4204 CALL_AS_FUNCTION); |
| 4031 | 4205 |
| 4032 // Slow-case: Non-function called. | 4206 // Slow-case: Non-function called. |
| 4033 __ bind(&slow); | 4207 __ bind(&slow); |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4396 ASSERT_EQ(function.code(), InstanceofStub::right().code()); | 4570 ASSERT_EQ(function.code(), InstanceofStub::right().code()); |
| 4397 | 4571 |
| 4398 // Get the object and function - they are always both needed. | 4572 // Get the object and function - they are always both needed. |
| 4399 Label slow, not_js_object; | 4573 Label slow, not_js_object; |
| 4400 if (!HasArgsInRegisters()) { | 4574 if (!HasArgsInRegisters()) { |
| 4401 __ mov(object, Operand(esp, 2 * kPointerSize)); | 4575 __ mov(object, Operand(esp, 2 * kPointerSize)); |
| 4402 __ mov(function, Operand(esp, 1 * kPointerSize)); | 4576 __ mov(function, Operand(esp, 1 * kPointerSize)); |
| 4403 } | 4577 } |
| 4404 | 4578 |
| 4405 // Check that the left hand is a JS object. | 4579 // Check that the left hand is a JS object. |
| 4406 __ test(object, Immediate(kSmiTagMask)); | 4580 __ JumpIfSmi(object, ¬_js_object); |
| 4407 __ j(zero, ¬_js_object); | |
| 4408 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); | 4581 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); |
| 4409 | 4582 |
| 4410 // If there is a call site cache don't look in the global cache, but do the | 4583 // If there is a call site cache don't look in the global cache, but do the |
| 4411 // real lookup and update the call site cache. | 4584 // real lookup and update the call site cache. |
| 4412 if (!HasCallSiteInlineCheck()) { | 4585 if (!HasCallSiteInlineCheck()) { |
| 4413 // Look up the function and the map in the instanceof cache. | 4586 // Look up the function and the map in the instanceof cache. |
| 4414 Label miss; | 4587 Label miss; |
| 4415 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 4588 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
| 4416 __ cmp(function, | 4589 __ cmp(function, |
| 4417 Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 4590 Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
| 4418 __ j(not_equal, &miss, Label::kNear); | 4591 __ j(not_equal, &miss, Label::kNear); |
| 4419 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 4592 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
| 4420 __ cmp(map, Operand::StaticArray( | 4593 __ cmp(map, Operand::StaticArray( |
| 4421 scratch, times_pointer_size, roots_address)); | 4594 scratch, times_pointer_size, roots_address)); |
| 4422 __ j(not_equal, &miss, Label::kNear); | 4595 __ j(not_equal, &miss, Label::kNear); |
| 4423 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 4596 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| 4424 __ mov(eax, Operand::StaticArray( | 4597 __ mov(eax, Operand::StaticArray( |
| 4425 scratch, times_pointer_size, roots_address)); | 4598 scratch, times_pointer_size, roots_address)); |
| 4426 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 4599 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 4427 __ bind(&miss); | 4600 __ bind(&miss); |
| 4428 } | 4601 } |
| 4429 | 4602 |
| 4430 // Get the prototype of the function. | 4603 // Get the prototype of the function. |
| 4431 __ TryGetFunctionPrototype(function, prototype, scratch, &slow); | 4604 __ TryGetFunctionPrototype(function, prototype, scratch, &slow); |
| 4432 | 4605 |
| 4433 // Check that the function prototype is a JS object. | 4606 // Check that the function prototype is a JS object. |
| 4434 __ test(prototype, Immediate(kSmiTagMask)); | 4607 __ JumpIfSmi(prototype, &slow); |
| 4435 __ j(zero, &slow); | |
| 4436 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); | 4608 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); |
| 4437 | 4609 |
| 4438 // Update the global instanceof or call site inlined cache with the current | 4610 // Update the global instanceof or call site inlined cache with the current |
| 4439 // map and function. The cached answer will be set when it is known below. | 4611 // map and function. The cached answer will be set when it is known below. |
| 4440 if (!HasCallSiteInlineCheck()) { | 4612 if (!HasCallSiteInlineCheck()) { |
| 4441 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 4613 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
| 4442 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); | 4614 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); |
| 4443 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 4615 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
| 4444 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), | 4616 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), |
| 4445 function); | 4617 function); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4514 if (!ReturnTrueFalseObject()) { | 4686 if (!ReturnTrueFalseObject()) { |
| 4515 __ Set(eax, Immediate(Smi::FromInt(1))); | 4687 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 4516 } | 4688 } |
| 4517 } | 4689 } |
| 4518 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 4690 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 4519 | 4691 |
| 4520 Label object_not_null, object_not_null_or_smi; | 4692 Label object_not_null, object_not_null_or_smi; |
| 4521 __ bind(¬_js_object); | 4693 __ bind(¬_js_object); |
| 4522 // Before null, smi and string value checks, check that the rhs is a function | 4694 // Before null, smi and string value checks, check that the rhs is a function |
| 4523 // as for a non-function rhs an exception needs to be thrown. | 4695 // as for a non-function rhs an exception needs to be thrown. |
| 4524 __ test(function, Immediate(kSmiTagMask)); | 4696 __ JumpIfSmi(function, &slow); |
| 4525 __ j(zero, &slow); | |
| 4526 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); | 4697 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); |
| 4527 __ j(not_equal, &slow); | 4698 __ j(not_equal, &slow); |
| 4528 | 4699 |
| 4529 // Null is not instance of anything. | 4700 // Null is not instance of anything. |
| 4530 __ cmp(object, factory->null_value()); | 4701 __ cmp(object, factory->null_value()); |
| 4531 __ j(not_equal, &object_not_null); | 4702 __ j(not_equal, &object_not_null); |
| 4532 __ Set(eax, Immediate(Smi::FromInt(1))); | 4703 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 4533 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 4704 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 4534 | 4705 |
| 4535 __ bind(&object_not_null); | 4706 __ bind(&object_not_null); |
| 4536 // Smi values is not instance of anything. | 4707 // Smi values is not instance of anything. |
| 4537 __ test(object, Immediate(kSmiTagMask)); | 4708 __ JumpIfNotSmi(object, &object_not_null_or_smi); |
| 4538 __ j(not_zero, &object_not_null_or_smi); | |
| 4539 __ Set(eax, Immediate(Smi::FromInt(1))); | 4709 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 4540 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 4710 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 4541 | 4711 |
| 4542 __ bind(&object_not_null_or_smi); | 4712 __ bind(&object_not_null_or_smi); |
| 4543 // String values is not instance of anything. | 4713 // String values is not instance of anything. |
| 4544 Condition is_string = masm->IsObjectStringType(object, scratch, scratch); | 4714 Condition is_string = masm->IsObjectStringType(object, scratch, scratch); |
| 4545 __ j(NegateCondition(is_string), &slow); | 4715 __ j(NegateCondition(is_string), &slow); |
| 4546 __ Set(eax, Immediate(Smi::FromInt(1))); | 4716 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 4547 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 4717 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 4548 | 4718 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4655 // ------------------------------------------------------------------------- | 4825 // ------------------------------------------------------------------------- |
| 4656 // StringCharCodeAtGenerator | 4826 // StringCharCodeAtGenerator |
| 4657 | 4827 |
| 4658 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 4828 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 4659 Label flat_string; | 4829 Label flat_string; |
| 4660 Label ascii_string; | 4830 Label ascii_string; |
| 4661 Label got_char_code; | 4831 Label got_char_code; |
| 4662 | 4832 |
| 4663 // If the receiver is a smi trigger the non-string case. | 4833 // If the receiver is a smi trigger the non-string case. |
| 4664 STATIC_ASSERT(kSmiTag == 0); | 4834 STATIC_ASSERT(kSmiTag == 0); |
| 4665 __ test(object_, Immediate(kSmiTagMask)); | 4835 __ JumpIfSmi(object_, receiver_not_string_); |
| 4666 __ j(zero, receiver_not_string_); | |
| 4667 | 4836 |
| 4668 // Fetch the instance type of the receiver into result register. | 4837 // Fetch the instance type of the receiver into result register. |
| 4669 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 4838 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 4670 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 4839 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 4671 // If the receiver is not a string trigger the non-string case. | 4840 // If the receiver is not a string trigger the non-string case. |
| 4672 __ test(result_, Immediate(kIsNotStringMask)); | 4841 __ test(result_, Immediate(kIsNotStringMask)); |
| 4673 __ j(not_zero, receiver_not_string_); | 4842 __ j(not_zero, receiver_not_string_); |
| 4674 | 4843 |
| 4675 // If the index is non-smi trigger the non-smi case. | 4844 // If the index is non-smi trigger the non-smi case. |
| 4676 STATIC_ASSERT(kSmiTag == 0); | 4845 STATIC_ASSERT(kSmiTag == 0); |
| 4677 __ test(index_, Immediate(kSmiTagMask)); | 4846 __ JumpIfNotSmi(index_, &index_not_smi_); |
| 4678 __ j(not_zero, &index_not_smi_); | |
| 4679 | 4847 |
| 4680 // Put smi-tagged index into scratch register. | 4848 // Put smi-tagged index into scratch register. |
| 4681 __ mov(scratch_, index_); | 4849 __ mov(scratch_, index_); |
| 4682 __ bind(&got_smi_index_); | 4850 __ bind(&got_smi_index_); |
| 4683 | 4851 |
| 4684 // Check for index out of range. | 4852 // Check for index out of range. |
| 4685 __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset)); | 4853 __ cmp(scratch_, FieldOperand(object_, String::kLengthOffset)); |
| 4686 __ j(above_equal, index_out_of_range_); | 4854 __ j(above_equal, index_out_of_range_); |
| 4687 | 4855 |
| 4688 // We need special handling for non-flat strings. | 4856 // We need special handling for non-flat strings. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4766 __ mov(scratch_, eax); | 4934 __ mov(scratch_, eax); |
| 4767 } | 4935 } |
| 4768 __ pop(index_); | 4936 __ pop(index_); |
| 4769 __ pop(object_); | 4937 __ pop(object_); |
| 4770 // Reload the instance type. | 4938 // Reload the instance type. |
| 4771 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 4939 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 4772 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 4940 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 4773 call_helper.AfterCall(masm); | 4941 call_helper.AfterCall(masm); |
| 4774 // If index is still not a smi, it must be out of range. | 4942 // If index is still not a smi, it must be out of range. |
| 4775 STATIC_ASSERT(kSmiTag == 0); | 4943 STATIC_ASSERT(kSmiTag == 0); |
| 4776 __ test(scratch_, Immediate(kSmiTagMask)); | 4944 __ JumpIfNotSmi(scratch_, index_out_of_range_); |
| 4777 __ j(not_zero, index_out_of_range_); | |
| 4778 // Otherwise, return to the fast path. | 4945 // Otherwise, return to the fast path. |
| 4779 __ jmp(&got_smi_index_); | 4946 __ jmp(&got_smi_index_); |
| 4780 | 4947 |
| 4781 // Call runtime. We get here when the receiver is a string and the | 4948 // Call runtime. We get here when the receiver is a string and the |
| 4782 // index is a number, but the code of getting the actual character | 4949 // index is a number, but the code of getting the actual character |
| 4783 // is too complex (e.g., when the string needs to be flattened). | 4950 // is too complex (e.g., when the string needs to be flattened). |
| 4784 __ bind(&call_runtime_); | 4951 __ bind(&call_runtime_); |
| 4785 call_helper.BeforeCall(masm); | 4952 call_helper.BeforeCall(masm); |
| 4786 __ push(object_); | 4953 __ push(object_); |
| 4787 __ push(index_); | 4954 __ push(index_); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4861 void StringAddStub::Generate(MacroAssembler* masm) { | 5028 void StringAddStub::Generate(MacroAssembler* masm) { |
| 4862 Label string_add_runtime, call_builtin; | 5029 Label string_add_runtime, call_builtin; |
| 4863 Builtins::JavaScript builtin_id = Builtins::ADD; | 5030 Builtins::JavaScript builtin_id = Builtins::ADD; |
| 4864 | 5031 |
| 4865 // Load the two arguments. | 5032 // Load the two arguments. |
| 4866 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 5033 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
| 4867 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 5034 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
| 4868 | 5035 |
| 4869 // Make sure that both arguments are strings if not known in advance. | 5036 // Make sure that both arguments are strings if not known in advance. |
| 4870 if (flags_ == NO_STRING_ADD_FLAGS) { | 5037 if (flags_ == NO_STRING_ADD_FLAGS) { |
| 4871 __ test(eax, Immediate(kSmiTagMask)); | 5038 __ JumpIfSmi(eax, &string_add_runtime); |
| 4872 __ j(zero, &string_add_runtime); | |
| 4873 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); | 5039 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); |
| 4874 __ j(above_equal, &string_add_runtime); | 5040 __ j(above_equal, &string_add_runtime); |
| 4875 | 5041 |
| 4876 // First argument is a a string, test second. | 5042 // First argument is a a string, test second. |
| 4877 __ test(edx, Immediate(kSmiTagMask)); | 5043 __ JumpIfSmi(edx, &string_add_runtime); |
| 4878 __ j(zero, &string_add_runtime); | |
| 4879 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); | 5044 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); |
| 4880 __ j(above_equal, &string_add_runtime); | 5045 __ j(above_equal, &string_add_runtime); |
| 4881 } else { | 5046 } else { |
| 4882 // Here at least one of the arguments is definitely a string. | 5047 // Here at least one of the arguments is definitely a string. |
| 4883 // We convert the one that is not known to be a string. | 5048 // We convert the one that is not known to be a string. |
| 4884 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 5049 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { |
| 4885 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 5050 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); |
| 4886 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, | 5051 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, |
| 4887 &call_builtin); | 5052 &call_builtin); |
| 4888 builtin_id = Builtins::STRING_ADD_RIGHT; | 5053 builtin_id = Builtins::STRING_ADD_RIGHT; |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5136 | 5301 |
| 5137 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | 5302 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, |
| 5138 int stack_offset, | 5303 int stack_offset, |
| 5139 Register arg, | 5304 Register arg, |
| 5140 Register scratch1, | 5305 Register scratch1, |
| 5141 Register scratch2, | 5306 Register scratch2, |
| 5142 Register scratch3, | 5307 Register scratch3, |
| 5143 Label* slow) { | 5308 Label* slow) { |
| 5144 // First check if the argument is already a string. | 5309 // First check if the argument is already a string. |
| 5145 Label not_string, done; | 5310 Label not_string, done; |
| 5146 __ test(arg, Immediate(kSmiTagMask)); | 5311 __ JumpIfSmi(arg, ¬_string); |
| 5147 __ j(zero, ¬_string); | |
| 5148 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); | 5312 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); |
| 5149 __ j(below, &done); | 5313 __ j(below, &done); |
| 5150 | 5314 |
| 5151 // Check the number to string cache. | 5315 // Check the number to string cache. |
| 5152 Label not_cached; | 5316 Label not_cached; |
| 5153 __ bind(¬_string); | 5317 __ bind(¬_string); |
| 5154 // Puts the cached result into scratch1. | 5318 // Puts the cached result into scratch1. |
| 5155 NumberToStringStub::GenerateLookupNumberStringCache(masm, | 5319 NumberToStringStub::GenerateLookupNumberStringCache(masm, |
| 5156 arg, | 5320 arg, |
| 5157 scratch1, | 5321 scratch1, |
| 5158 scratch2, | 5322 scratch2, |
| 5159 scratch3, | 5323 scratch3, |
| 5160 false, | 5324 false, |
| 5161 ¬_cached); | 5325 ¬_cached); |
| 5162 __ mov(arg, scratch1); | 5326 __ mov(arg, scratch1); |
| 5163 __ mov(Operand(esp, stack_offset), arg); | 5327 __ mov(Operand(esp, stack_offset), arg); |
| 5164 __ jmp(&done); | 5328 __ jmp(&done); |
| 5165 | 5329 |
| 5166 // Check if the argument is a safe string wrapper. | 5330 // Check if the argument is a safe string wrapper. |
| 5167 __ bind(¬_cached); | 5331 __ bind(¬_cached); |
| 5168 __ test(arg, Immediate(kSmiTagMask)); | 5332 __ JumpIfSmi(arg, slow); |
| 5169 __ j(zero, slow); | |
| 5170 __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. | 5333 __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. |
| 5171 __ j(not_equal, slow); | 5334 __ j(not_equal, slow); |
| 5172 __ test_b(FieldOperand(scratch1, Map::kBitField2Offset), | 5335 __ test_b(FieldOperand(scratch1, Map::kBitField2Offset), |
| 5173 1 << Map::kStringWrapperSafeForDefaultValueOf); | 5336 1 << Map::kStringWrapperSafeForDefaultValueOf); |
| 5174 __ j(zero, slow); | 5337 __ j(zero, slow); |
| 5175 __ mov(arg, FieldOperand(arg, JSValue::kValueOffset)); | 5338 __ mov(arg, FieldOperand(arg, JSValue::kValueOffset)); |
| 5176 __ mov(Operand(esp, stack_offset), arg); | 5339 __ mov(Operand(esp, stack_offset), arg); |
| 5177 | 5340 |
| 5178 __ bind(&done); | 5341 __ bind(&done); |
| 5179 } | 5342 } |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5453 | 5616 |
| 5454 // Stack frame on entry. | 5617 // Stack frame on entry. |
| 5455 // esp[0]: return address | 5618 // esp[0]: return address |
| 5456 // esp[4]: to | 5619 // esp[4]: to |
| 5457 // esp[8]: from | 5620 // esp[8]: from |
| 5458 // esp[12]: string | 5621 // esp[12]: string |
| 5459 | 5622 |
| 5460 // Make sure first argument is a string. | 5623 // Make sure first argument is a string. |
| 5461 __ mov(eax, Operand(esp, 3 * kPointerSize)); | 5624 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 5462 STATIC_ASSERT(kSmiTag == 0); | 5625 STATIC_ASSERT(kSmiTag == 0); |
| 5463 __ test(eax, Immediate(kSmiTagMask)); | 5626 __ JumpIfSmi(eax, &runtime); |
| 5464 __ j(zero, &runtime); | |
| 5465 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); | 5627 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |
| 5466 __ j(NegateCondition(is_string), &runtime); | 5628 __ j(NegateCondition(is_string), &runtime); |
| 5467 | 5629 |
| 5468 // eax: string | 5630 // eax: string |
| 5469 // ebx: instance type | 5631 // ebx: instance type |
| 5470 | 5632 |
| 5471 // Calculate length of sub string using the smi values. | 5633 // Calculate length of sub string using the smi values. |
| 5472 Label result_longer_than_two; | 5634 Label result_longer_than_two; |
| 5473 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. | 5635 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. |
| 5474 __ test(ecx, Immediate(kSmiTagMask)); | 5636 __ JumpIfNotSmi(ecx, &runtime); |
| 5475 __ j(not_zero, &runtime); | |
| 5476 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. | 5637 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. |
| 5477 __ test(edx, Immediate(kSmiTagMask)); | 5638 __ JumpIfNotSmi(edx, &runtime); |
| 5478 __ j(not_zero, &runtime); | |
| 5479 __ sub(ecx, Operand(edx)); | 5639 __ sub(ecx, Operand(edx)); |
| 5480 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); | 5640 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); |
| 5481 Label return_eax; | 5641 Label return_eax; |
| 5482 __ j(equal, &return_eax); | 5642 __ j(equal, &return_eax); |
| 5483 // Special handling of sub-strings of length 1 and 2. One character strings | 5643 // Special handling of sub-strings of length 1 and 2. One character strings |
| 5484 // are handled in the runtime system (looked up in the single character | 5644 // are handled in the runtime system (looked up in the single character |
| 5485 // cache). Two character strings are looked for in the symbol cache. | 5645 // cache). Two character strings are looked for in the symbol cache. |
| 5486 __ SmiUntag(ecx); // Result length is no longer smi. | 5646 __ SmiUntag(ecx); // Result length is no longer smi. |
| 5487 __ cmp(ecx, 2); | 5647 __ cmp(ecx, 2); |
| 5488 __ j(greater, &result_longer_than_two); | 5648 __ j(greater, &result_longer_than_two); |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5760 __ bind(&runtime); | 5920 __ bind(&runtime); |
| 5761 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 5921 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 5762 } | 5922 } |
| 5763 | 5923 |
| 5764 | 5924 |
| 5765 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 5925 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 5766 ASSERT(state_ == CompareIC::SMIS); | 5926 ASSERT(state_ == CompareIC::SMIS); |
| 5767 Label miss; | 5927 Label miss; |
| 5768 __ mov(ecx, Operand(edx)); | 5928 __ mov(ecx, Operand(edx)); |
| 5769 __ or_(ecx, Operand(eax)); | 5929 __ or_(ecx, Operand(eax)); |
| 5770 __ test(ecx, Immediate(kSmiTagMask)); | 5930 __ JumpIfNotSmi(ecx, &miss, Label::kNear); |
| 5771 __ j(not_zero, &miss, Label::kNear); | |
| 5772 | 5931 |
| 5773 if (GetCondition() == equal) { | 5932 if (GetCondition() == equal) { |
| 5774 // For equality we do not care about the sign of the result. | 5933 // For equality we do not care about the sign of the result. |
| 5775 __ sub(eax, Operand(edx)); | 5934 __ sub(eax, Operand(edx)); |
| 5776 } else { | 5935 } else { |
| 5777 Label done; | 5936 Label done; |
| 5778 __ sub(edx, Operand(eax)); | 5937 __ sub(edx, Operand(eax)); |
| 5779 __ j(no_overflow, &done, Label::kNear); | 5938 __ j(no_overflow, &done, Label::kNear); |
| 5780 // Correct sign of result in case of overflow. | 5939 // Correct sign of result in case of overflow. |
| 5781 __ not_(edx); | 5940 __ not_(edx); |
| 5782 __ bind(&done); | 5941 __ bind(&done); |
| 5783 __ mov(eax, edx); | 5942 __ mov(eax, edx); |
| 5784 } | 5943 } |
| 5785 __ ret(0); | 5944 __ ret(0); |
| 5786 | 5945 |
| 5787 __ bind(&miss); | 5946 __ bind(&miss); |
| 5788 GenerateMiss(masm); | 5947 GenerateMiss(masm); |
| 5789 } | 5948 } |
| 5790 | 5949 |
| 5791 | 5950 |
| 5792 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { | 5951 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { |
| 5793 ASSERT(state_ == CompareIC::HEAP_NUMBERS); | 5952 ASSERT(state_ == CompareIC::HEAP_NUMBERS); |
| 5794 | 5953 |
| 5795 Label generic_stub; | 5954 Label generic_stub; |
| 5796 Label unordered; | 5955 Label unordered; |
| 5797 Label miss; | 5956 Label miss; |
| 5798 __ mov(ecx, Operand(edx)); | 5957 __ mov(ecx, Operand(edx)); |
| 5799 __ and_(ecx, Operand(eax)); | 5958 __ and_(ecx, Operand(eax)); |
| 5800 __ test(ecx, Immediate(kSmiTagMask)); | 5959 __ JumpIfSmi(ecx, &generic_stub, Label::kNear); |
| 5801 __ j(zero, &generic_stub, Label::kNear); | |
| 5802 | 5960 |
| 5803 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); | 5961 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); |
| 5804 __ j(not_equal, &miss, Label::kNear); | 5962 __ j(not_equal, &miss, Label::kNear); |
| 5805 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); | 5963 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); |
| 5806 __ j(not_equal, &miss, Label::kNear); | 5964 __ j(not_equal, &miss, Label::kNear); |
| 5807 | 5965 |
| 5808 // Inlining the double comparison and falling back to the general compare | 5966 // Inlining the double comparison and falling back to the general compare |
| 5809 // stub if NaN is involved or SS2 or CMOV is unsupported. | 5967 // stub if NaN is involved or SS2 or CMOV is unsupported. |
| 5810 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { | 5968 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { |
| 5811 CpuFeatures::Scope scope1(SSE2); | 5969 CpuFeatures::Scope scope1(SSE2); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5850 Register left = edx; | 6008 Register left = edx; |
| 5851 Register right = eax; | 6009 Register right = eax; |
| 5852 Register tmp1 = ecx; | 6010 Register tmp1 = ecx; |
| 5853 Register tmp2 = ebx; | 6011 Register tmp2 = ebx; |
| 5854 | 6012 |
| 5855 // Check that both operands are heap objects. | 6013 // Check that both operands are heap objects. |
| 5856 Label miss; | 6014 Label miss; |
| 5857 __ mov(tmp1, Operand(left)); | 6015 __ mov(tmp1, Operand(left)); |
| 5858 STATIC_ASSERT(kSmiTag == 0); | 6016 STATIC_ASSERT(kSmiTag == 0); |
| 5859 __ and_(tmp1, Operand(right)); | 6017 __ and_(tmp1, Operand(right)); |
| 5860 __ test(tmp1, Immediate(kSmiTagMask)); | 6018 __ JumpIfSmi(tmp1, &miss, Label::kNear); |
| 5861 __ j(zero, &miss, Label::kNear); | |
| 5862 | 6019 |
| 5863 // Check that both operands are symbols. | 6020 // Check that both operands are symbols. |
| 5864 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 6021 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 5865 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 6022 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 5866 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 6023 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 5867 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 6024 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 5868 STATIC_ASSERT(kSymbolTag != 0); | 6025 STATIC_ASSERT(kSymbolTag != 0); |
| 5869 __ and_(tmp1, Operand(tmp2)); | 6026 __ and_(tmp1, Operand(tmp2)); |
| 5870 __ test(tmp1, Immediate(kIsSymbolMask)); | 6027 __ test(tmp1, Immediate(kIsSymbolMask)); |
| 5871 __ j(zero, &miss, Label::kNear); | 6028 __ j(zero, &miss, Label::kNear); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 5897 Register left = edx; | 6054 Register left = edx; |
| 5898 Register right = eax; | 6055 Register right = eax; |
| 5899 Register tmp1 = ecx; | 6056 Register tmp1 = ecx; |
| 5900 Register tmp2 = ebx; | 6057 Register tmp2 = ebx; |
| 5901 Register tmp3 = edi; | 6058 Register tmp3 = edi; |
| 5902 | 6059 |
| 5903 // Check that both operands are heap objects. | 6060 // Check that both operands are heap objects. |
| 5904 __ mov(tmp1, Operand(left)); | 6061 __ mov(tmp1, Operand(left)); |
| 5905 STATIC_ASSERT(kSmiTag == 0); | 6062 STATIC_ASSERT(kSmiTag == 0); |
| 5906 __ and_(tmp1, Operand(right)); | 6063 __ and_(tmp1, Operand(right)); |
| 5907 __ test(tmp1, Immediate(kSmiTagMask)); | 6064 __ JumpIfSmi(tmp1, &miss); |
| 5908 __ j(zero, &miss); | |
| 5909 | 6065 |
| 5910 // Check that both operands are strings. This leaves the instance | 6066 // Check that both operands are strings. This leaves the instance |
| 5911 // types loaded in tmp1 and tmp2. | 6067 // types loaded in tmp1 and tmp2. |
| 5912 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 6068 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 5913 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 6069 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 5914 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 6070 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 5915 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 6071 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 5916 __ mov(tmp3, tmp1); | 6072 __ mov(tmp3, tmp1); |
| 5917 STATIC_ASSERT(kNotStringTag != 0); | 6073 STATIC_ASSERT(kNotStringTag != 0); |
| 5918 __ or_(tmp3, Operand(tmp2)); | 6074 __ or_(tmp3, Operand(tmp2)); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5963 __ bind(&miss); | 6119 __ bind(&miss); |
| 5964 GenerateMiss(masm); | 6120 GenerateMiss(masm); |
| 5965 } | 6121 } |
| 5966 | 6122 |
| 5967 | 6123 |
| 5968 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 6124 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
| 5969 ASSERT(state_ == CompareIC::OBJECTS); | 6125 ASSERT(state_ == CompareIC::OBJECTS); |
| 5970 Label miss; | 6126 Label miss; |
| 5971 __ mov(ecx, Operand(edx)); | 6127 __ mov(ecx, Operand(edx)); |
| 5972 __ and_(ecx, Operand(eax)); | 6128 __ and_(ecx, Operand(eax)); |
| 5973 __ test(ecx, Immediate(kSmiTagMask)); | 6129 __ JumpIfSmi(ecx, &miss, Label::kNear); |
| 5974 __ j(zero, &miss, Label::kNear); | |
| 5975 | 6130 |
| 5976 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); | 6131 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); |
| 5977 __ j(not_equal, &miss, Label::kNear); | 6132 __ j(not_equal, &miss, Label::kNear); |
| 5978 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); | 6133 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); |
| 5979 __ j(not_equal, &miss, Label::kNear); | 6134 __ j(not_equal, &miss, Label::kNear); |
| 5980 | 6135 |
| 5981 ASSERT(GetCondition() == equal); | 6136 ASSERT(GetCondition() == equal); |
| 5982 __ sub(eax, Operand(edx)); | 6137 __ sub(eax, Operand(edx)); |
| 5983 __ ret(0); | 6138 __ ret(0); |
| 5984 | 6139 |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6413 | 6568 |
| 6414 // Fall through when we need to inform the incremental marker. | 6569 // Fall through when we need to inform the incremental marker. |
| 6415 } | 6570 } |
| 6416 | 6571 |
| 6417 | 6572 |
| 6418 #undef __ | 6573 #undef __ |
| 6419 | 6574 |
| 6420 } } // namespace v8::internal | 6575 } } // namespace v8::internal |
| 6421 | 6576 |
| 6422 #endif // V8_TARGET_ARCH_IA32 | 6577 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |