| 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|    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   __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); |    46   __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); | 
|    47   __ ret(0); |    47   __ ret(0); | 
|    48  |    48  | 
|    49   __ bind(&check_heap_number); |    49   __ bind(&check_heap_number); | 
|    50   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |    50   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 
|    51   Factory* factory = masm->isolate()->factory(); |    51   Factory* factory = masm->isolate()->factory(); | 
|    52   __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); |    52   __ cmp(ebx, Immediate(factory->heap_number_map())); | 
|    53   __ j(not_equal, &call_builtin, Label::kNear); |    53   __ j(not_equal, &call_builtin, Label::kNear); | 
|    54   __ ret(0); |    54   __ ret(0); | 
|    55  |    55  | 
|    56   __ bind(&call_builtin); |    56   __ bind(&call_builtin); | 
|    57   __ pop(ecx);  // Pop return address. |    57   __ pop(ecx);  // Pop return address. | 
|    58   __ push(eax); |    58   __ push(eax); | 
|    59   __ push(ecx);  // Push return address. |    59   __ push(ecx);  // Push return address. | 
|    60   __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); |    60   __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | 
|    61 } |    61 } | 
|    62  |    62  | 
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   143   __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |   143   __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 
|   144   __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); |   144   __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); | 
|   145  |   145  | 
|   146   // Initialize the rest of the slots to undefined. |   146   // Initialize the rest of the slots to undefined. | 
|   147   __ mov(ebx, factory->undefined_value()); |   147   __ mov(ebx, factory->undefined_value()); | 
|   148   for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |   148   for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 
|   149     __ mov(Operand(eax, Context::SlotOffset(i)), ebx); |   149     __ mov(Operand(eax, Context::SlotOffset(i)), ebx); | 
|   150   } |   150   } | 
|   151  |   151  | 
|   152   // Return and remove the on-stack parameter. |   152   // Return and remove the on-stack parameter. | 
|   153   __ mov(esi, Operand(eax)); |   153   __ mov(esi, eax); | 
|   154   __ ret(1 * kPointerSize); |   154   __ ret(1 * kPointerSize); | 
|   155  |   155  | 
|   156   // Need to collect. Call into runtime system. |   156   // Need to collect. Call into runtime system. | 
|   157   __ bind(&gc); |   157   __ bind(&gc); | 
|   158   __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); |   158   __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); | 
|   159 } |   159 } | 
|   160  |   160  | 
|   161  |   161  | 
|   162 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |   162 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 
|   163   // Stack layout on entry: |   163   // Stack layout on entry: | 
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   338 } |   338 } | 
|   339  |   339  | 
|   340  |   340  | 
|   341 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |   341 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 
|   342   // We don't allow a GC during a store buffer overflow so there is no need to |   342   // We don't allow a GC during a store buffer overflow so there is no need to | 
|   343   // store the registers in any particular way, but we do have to store and |   343   // store the registers in any particular way, but we do have to store and | 
|   344   // restore them. |   344   // restore them. | 
|   345   __ pushad(); |   345   __ pushad(); | 
|   346   if (save_doubles_ == kSaveFPRegs) { |   346   if (save_doubles_ == kSaveFPRegs) { | 
|   347     CpuFeatures::Scope scope(SSE2); |   347     CpuFeatures::Scope scope(SSE2); | 
|   348     __ sub(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |   348     __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 
|   349     for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |   349     for (int i = 0; i < XMMRegister::kNumRegisters; i++) { | 
|   350       XMMRegister reg = XMMRegister::from_code(i); |   350       XMMRegister reg = XMMRegister::from_code(i); | 
|   351       __ movdbl(Operand(esp, i * kDoubleSize), reg); |   351       __ movdbl(Operand(esp, i * kDoubleSize), reg); | 
|   352     } |   352     } | 
|   353   } |   353   } | 
|   354   const int argument_count = 1; |   354   const int argument_count = 1; | 
|   355  |   355  | 
|   356   AllowExternalCallThatCantCauseGC scope(masm); |   356   AllowExternalCallThatCantCauseGC scope(masm); | 
|   357   __ PrepareCallCFunction(argument_count, ecx); |   357   __ PrepareCallCFunction(argument_count, ecx); | 
|   358   __ mov(Operand(esp, 0 * kPointerSize), |   358   __ mov(Operand(esp, 0 * kPointerSize), | 
|   359          Immediate(ExternalReference::isolate_address())); |   359          Immediate(ExternalReference::isolate_address())); | 
|   360   __ CallCFunction( |   360   __ CallCFunction( | 
|   361       ExternalReference::store_buffer_overflow_function(masm->isolate()), |   361       ExternalReference::store_buffer_overflow_function(masm->isolate()), | 
|   362       argument_count); |   362       argument_count); | 
|   363   if (save_doubles_ == kSaveFPRegs) { |   363   if (save_doubles_ == kSaveFPRegs) { | 
|   364     CpuFeatures::Scope scope(SSE2); |   364     CpuFeatures::Scope scope(SSE2); | 
|   365     for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |   365     for (int i = 0; i < XMMRegister::kNumRegisters; i++) { | 
|   366       XMMRegister reg = XMMRegister::from_code(i); |   366       XMMRegister reg = XMMRegister::from_code(i); | 
|   367       __ movdbl(reg, Operand(esp, i * kDoubleSize)); |   367       __ movdbl(reg, Operand(esp, i * kDoubleSize)); | 
|   368     } |   368     } | 
|   369     __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |   369     __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 
|   370   } |   370   } | 
|   371   __ popad(); |   371   __ popad(); | 
|   372   __ ret(0); |   372   __ ret(0); | 
|   373 } |   373 } | 
|   374  |   374  | 
|   375  |   375  | 
|   376 void ToBooleanStub::CheckOddball(MacroAssembler* masm, |   376 void ToBooleanStub::CheckOddball(MacroAssembler* masm, | 
|   377                                  Type type, |   377                                  Type type, | 
|   378                                  Heap::RootListIndex value, |   378                                  Heap::RootListIndex value, | 
|   379                                  bool result) { |   379                                  bool result) { | 
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   500   // Get exponent word. |   500   // Get exponent word. | 
|   501   __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); |   501   __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 
|   502   // Get exponent alone in scratch2. |   502   // Get exponent alone in scratch2. | 
|   503   __ mov(scratch2, scratch); |   503   __ mov(scratch2, scratch); | 
|   504   __ and_(scratch2, HeapNumber::kExponentMask); |   504   __ and_(scratch2, HeapNumber::kExponentMask); | 
|   505   if (use_sse3) { |   505   if (use_sse3) { | 
|   506     CpuFeatures::Scope scope(SSE3); |   506     CpuFeatures::Scope scope(SSE3); | 
|   507     // Check whether the exponent is too big for a 64 bit signed integer. |   507     // Check whether the exponent is too big for a 64 bit signed integer. | 
|   508     static const uint32_t kTooBigExponent = |   508     static const uint32_t kTooBigExponent = | 
|   509         (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; |   509         (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | 
|   510     __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); |   510     __ cmp(scratch2, Immediate(kTooBigExponent)); | 
|   511     __ j(greater_equal, conversion_failure); |   511     __ j(greater_equal, conversion_failure); | 
|   512     // Load x87 register with heap number. |   512     // Load x87 register with heap number. | 
|   513     __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); |   513     __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); | 
|   514     // Reserve space for 64 bit answer. |   514     // Reserve space for 64 bit answer. | 
|   515     __ sub(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint. |   515     __ sub(esp, Immediate(sizeof(uint64_t)));  // Nolint. | 
|   516     // Do conversion, which cannot fail because we checked the exponent. |   516     // Do conversion, which cannot fail because we checked the exponent. | 
|   517     __ fisttp_d(Operand(esp, 0)); |   517     __ fisttp_d(Operand(esp, 0)); | 
|   518     __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx. |   518     __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx. | 
|   519     __ add(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint. |   519     __ add(esp, Immediate(sizeof(uint64_t)));  // Nolint. | 
|   520   } else { |   520   } else { | 
|   521     // Load ecx with zero.  We use this either for the final shift or |   521     // Load ecx with zero.  We use this either for the final shift or | 
|   522     // for the answer. |   522     // for the answer. | 
|   523     __ xor_(ecx, Operand(ecx)); |   523     __ xor_(ecx, ecx); | 
|   524     // Check whether the exponent matches a 32 bit signed int that cannot be |   524     // Check whether the exponent matches a 32 bit signed int that cannot be | 
|   525     // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the |   525     // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the | 
|   526     // exponent is 30 (biased).  This is the exponent that we are fastest at and |   526     // exponent is 30 (biased).  This is the exponent that we are fastest at and | 
|   527     // also the highest exponent we can handle here. |   527     // also the highest exponent we can handle here. | 
|   528     const uint32_t non_smi_exponent = |   528     const uint32_t non_smi_exponent = | 
|   529         (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; |   529         (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; | 
|   530     __ cmp(Operand(scratch2), Immediate(non_smi_exponent)); |   530     __ cmp(scratch2, Immediate(non_smi_exponent)); | 
|   531     // If we have a match of the int32-but-not-Smi exponent then skip some |   531     // If we have a match of the int32-but-not-Smi exponent then skip some | 
|   532     // logic. |   532     // logic. | 
|   533     __ j(equal, &right_exponent, Label::kNear); |   533     __ j(equal, &right_exponent, Label::kNear); | 
|   534     // If the exponent is higher than that then go to slow case.  This catches |   534     // If the exponent is higher than that then go to slow case.  This catches | 
|   535     // numbers that don't fit in a signed int32, infinities and NaNs. |   535     // numbers that don't fit in a signed int32, infinities and NaNs. | 
|   536     __ j(less, &normal_exponent, Label::kNear); |   536     __ j(less, &normal_exponent, Label::kNear); | 
|   537  |   537  | 
|   538     { |   538     { | 
|   539       // Handle a big exponent.  The only reason we have this code is that the |   539       // Handle a big exponent.  The only reason we have this code is that the | 
|   540       // >>> operator has a tendency to generate numbers with an exponent of 31. |   540       // >>> operator has a tendency to generate numbers with an exponent of 31. | 
|   541       const uint32_t big_non_smi_exponent = |   541       const uint32_t big_non_smi_exponent = | 
|   542           (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; |   542           (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; | 
|   543       __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent)); |   543       __ cmp(scratch2, Immediate(big_non_smi_exponent)); | 
|   544       __ j(not_equal, conversion_failure); |   544       __ j(not_equal, conversion_failure); | 
|   545       // We have the big exponent, typically from >>>.  This means the number is |   545       // We have the big exponent, typically from >>>.  This means the number is | 
|   546       // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa. |   546       // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa. | 
|   547       __ mov(scratch2, scratch); |   547       __ mov(scratch2, scratch); | 
|   548       __ and_(scratch2, HeapNumber::kMantissaMask); |   548       __ and_(scratch2, HeapNumber::kMantissaMask); | 
|   549       // Put back the implicit 1. |   549       // Put back the implicit 1. | 
|   550       __ or_(scratch2, 1 << HeapNumber::kExponentShift); |   550       __ or_(scratch2, 1 << HeapNumber::kExponentShift); | 
|   551       // Shift up the mantissa bits to take up the space the exponent used to |   551       // Shift up the mantissa bits to take up the space the exponent used to | 
|   552       // take. We just orred in the implicit bit so that took care of one and |   552       // take. We just orred in the implicit bit so that took care of one and | 
|   553       // we want to use the full unsigned range so we subtract 1 bit from the |   553       // we want to use the full unsigned range so we subtract 1 bit from the | 
|   554       // shift distance. |   554       // shift distance. | 
|   555       const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; |   555       const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; | 
|   556       __ shl(scratch2, big_shift_distance); |   556       __ shl(scratch2, big_shift_distance); | 
|   557       // Get the second half of the double. |   557       // Get the second half of the double. | 
|   558       __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); |   558       __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); | 
|   559       // Shift down 21 bits to get the most significant 11 bits or the low |   559       // Shift down 21 bits to get the most significant 11 bits or the low | 
|   560       // mantissa word. |   560       // mantissa word. | 
|   561       __ shr(ecx, 32 - big_shift_distance); |   561       __ shr(ecx, 32 - big_shift_distance); | 
|   562       __ or_(ecx, Operand(scratch2)); |   562       __ or_(ecx, scratch2); | 
|   563       // We have the answer in ecx, but we may need to negate it. |   563       // We have the answer in ecx, but we may need to negate it. | 
|   564       __ test(scratch, Operand(scratch)); |   564       __ test(scratch, scratch); | 
|   565       __ j(positive, &done, Label::kNear); |   565       __ j(positive, &done, Label::kNear); | 
|   566       __ neg(ecx); |   566       __ neg(ecx); | 
|   567       __ jmp(&done, Label::kNear); |   567       __ jmp(&done, Label::kNear); | 
|   568     } |   568     } | 
|   569  |   569  | 
|   570     __ bind(&normal_exponent); |   570     __ bind(&normal_exponent); | 
|   571     // Exponent word in scratch, exponent part of exponent word in scratch2. |   571     // Exponent word in scratch, exponent part of exponent word in scratch2. | 
|   572     // Zero in ecx. |   572     // Zero in ecx. | 
|   573     // We know the exponent is smaller than 30 (biased).  If it is less than |   573     // We know the exponent is smaller than 30 (biased).  If it is less than | 
|   574     // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie |   574     // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie | 
|   575     // it rounds to zero. |   575     // it rounds to zero. | 
|   576     const uint32_t zero_exponent = |   576     const uint32_t zero_exponent = | 
|   577         (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; |   577         (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; | 
|   578     __ sub(Operand(scratch2), Immediate(zero_exponent)); |   578     __ sub(scratch2, Immediate(zero_exponent)); | 
|   579     // ecx already has a Smi zero. |   579     // ecx already has a Smi zero. | 
|   580     __ j(less, &done, Label::kNear); |   580     __ j(less, &done, Label::kNear); | 
|   581  |   581  | 
|   582     // We have a shifted exponent between 0 and 30 in scratch2. |   582     // We have a shifted exponent between 0 and 30 in scratch2. | 
|   583     __ shr(scratch2, HeapNumber::kExponentShift); |   583     __ shr(scratch2, HeapNumber::kExponentShift); | 
|   584     __ mov(ecx, Immediate(30)); |   584     __ mov(ecx, Immediate(30)); | 
|   585     __ sub(ecx, Operand(scratch2)); |   585     __ sub(ecx, scratch2); | 
|   586  |   586  | 
|   587     __ bind(&right_exponent); |   587     __ bind(&right_exponent); | 
|   588     // Here ecx is the shift, scratch is the exponent word. |   588     // Here ecx is the shift, scratch is the exponent word. | 
|   589     // Get the top bits of the mantissa. |   589     // Get the top bits of the mantissa. | 
|   590     __ and_(scratch, HeapNumber::kMantissaMask); |   590     __ and_(scratch, HeapNumber::kMantissaMask); | 
|   591     // Put back the implicit 1. |   591     // Put back the implicit 1. | 
|   592     __ or_(scratch, 1 << HeapNumber::kExponentShift); |   592     __ or_(scratch, 1 << HeapNumber::kExponentShift); | 
|   593     // Shift up the mantissa bits to take up the space the exponent used to |   593     // Shift up the mantissa bits to take up the space the exponent used to | 
|   594     // take. We have kExponentShift + 1 significant bits int he low end of the |   594     // take. We have kExponentShift + 1 significant bits int he low end of the | 
|   595     // word.  Shift them to the top bits. |   595     // word.  Shift them to the top bits. | 
|   596     const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; |   596     const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; | 
|   597     __ shl(scratch, shift_distance); |   597     __ shl(scratch, shift_distance); | 
|   598     // Get the second half of the double. For some exponents we don't |   598     // Get the second half of the double. For some exponents we don't | 
|   599     // actually need this because the bits get shifted out again, but |   599     // actually need this because the bits get shifted out again, but | 
|   600     // it's probably slower to test than just to do it. |   600     // it's probably slower to test than just to do it. | 
|   601     __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); |   601     __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); | 
|   602     // Shift down 22 bits to get the most significant 10 bits or the low |   602     // Shift down 22 bits to get the most significant 10 bits or the low | 
|   603     // mantissa word. |   603     // mantissa word. | 
|   604     __ shr(scratch2, 32 - shift_distance); |   604     __ shr(scratch2, 32 - shift_distance); | 
|   605     __ or_(scratch2, Operand(scratch)); |   605     __ or_(scratch2, scratch); | 
|   606     // Move down according to the exponent. |   606     // Move down according to the exponent. | 
|   607     __ shr_cl(scratch2); |   607     __ shr_cl(scratch2); | 
|   608     // Now the unsigned answer is in scratch2.  We need to move it to ecx and |   608     // Now the unsigned answer is in scratch2.  We need to move it to ecx and | 
|   609     // we may need to fix the sign. |   609     // we may need to fix the sign. | 
|   610     Label negative; |   610     Label negative; | 
|   611     __ xor_(ecx, Operand(ecx)); |   611     __ xor_(ecx, ecx); | 
|   612     __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); |   612     __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); | 
|   613     __ j(greater, &negative, Label::kNear); |   613     __ j(greater, &negative, Label::kNear); | 
|   614     __ mov(ecx, scratch2); |   614     __ mov(ecx, scratch2); | 
|   615     __ jmp(&done, Label::kNear); |   615     __ jmp(&done, Label::kNear); | 
|   616     __ bind(&negative); |   616     __ bind(&negative); | 
|   617     __ sub(ecx, Operand(scratch2)); |   617     __ sub(ecx, scratch2); | 
|   618     __ bind(&done); |   618     __ bind(&done); | 
|   619   } |   619   } | 
|   620 } |   620 } | 
|   621  |   621  | 
|   622  |   622  | 
|   623 void UnaryOpStub::PrintName(StringStream* stream) { |   623 void UnaryOpStub::PrintName(StringStream* stream) { | 
|   624   const char* op_name = Token::Name(op_); |   624   const char* op_name = Token::Name(op_); | 
|   625   const char* overwrite_name = NULL;  // Make g++ happy. |   625   const char* overwrite_name = NULL;  // Make g++ happy. | 
|   626   switch (mode_) { |   626   switch (mode_) { | 
|   627     case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |   627     case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   709                                      Label* non_smi, |   709                                      Label* non_smi, | 
|   710                                      Label* undo, |   710                                      Label* undo, | 
|   711                                      Label* slow, |   711                                      Label* slow, | 
|   712                                      Label::Distance non_smi_near, |   712                                      Label::Distance non_smi_near, | 
|   713                                      Label::Distance undo_near, |   713                                      Label::Distance undo_near, | 
|   714                                      Label::Distance slow_near) { |   714                                      Label::Distance slow_near) { | 
|   715   // Check whether the value is a smi. |   715   // Check whether the value is a smi. | 
|   716   __ JumpIfNotSmi(eax, non_smi, non_smi_near); |   716   __ JumpIfNotSmi(eax, non_smi, non_smi_near); | 
|   717  |   717  | 
|   718   // We can't handle -0 with smis, so use a type transition for that case. |   718   // We can't handle -0 with smis, so use a type transition for that case. | 
|   719   __ test(eax, Operand(eax)); |   719   __ test(eax, eax); | 
|   720   __ j(zero, slow, slow_near); |   720   __ j(zero, slow, slow_near); | 
|   721  |   721  | 
|   722   // Try optimistic subtraction '0 - value', saving operand in eax for undo. |   722   // Try optimistic subtraction '0 - value', saving operand in eax for undo. | 
|   723   __ mov(edx, Operand(eax)); |   723   __ mov(edx, eax); | 
|   724   __ Set(eax, Immediate(0)); |   724   __ Set(eax, Immediate(0)); | 
|   725   __ sub(eax, Operand(edx)); |   725   __ sub(eax, edx); | 
|   726   __ j(overflow, undo, undo_near); |   726   __ j(overflow, undo, undo_near); | 
|   727   __ ret(0); |   727   __ ret(0); | 
|   728 } |   728 } | 
|   729  |   729  | 
|   730  |   730  | 
|   731 void UnaryOpStub::GenerateSmiCodeBitNot( |   731 void UnaryOpStub::GenerateSmiCodeBitNot( | 
|   732     MacroAssembler* masm, |   732     MacroAssembler* masm, | 
|   733     Label* non_smi, |   733     Label* non_smi, | 
|   734     Label::Distance non_smi_near) { |   734     Label::Distance non_smi_near) { | 
|   735   // Check whether the value is a smi. |   735   // Check whether the value is a smi. | 
|   736   __ JumpIfNotSmi(eax, non_smi, non_smi_near); |   736   __ JumpIfNotSmi(eax, non_smi, non_smi_near); | 
|   737  |   737  | 
|   738   // Flip bits and revert inverted smi-tag. |   738   // Flip bits and revert inverted smi-tag. | 
|   739   __ not_(eax); |   739   __ not_(eax); | 
|   740   __ and_(eax, ~kSmiTagMask); |   740   __ and_(eax, ~kSmiTagMask); | 
|   741   __ ret(0); |   741   __ ret(0); | 
|   742 } |   742 } | 
|   743  |   743  | 
|   744  |   744  | 
|   745 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { |   745 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { | 
|   746   __ mov(eax, Operand(edx)); |   746   __ mov(eax, edx); | 
|   747 } |   747 } | 
|   748  |   748  | 
|   749  |   749  | 
|   750 // TODO(svenpanne): Use virtual functions instead of switch. |   750 // TODO(svenpanne): Use virtual functions instead of switch. | 
|   751 void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { |   751 void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 
|   752   switch (op_) { |   752   switch (op_) { | 
|   753     case Token::SUB: |   753     case Token::SUB: | 
|   754       GenerateHeapNumberStubSub(masm); |   754       GenerateHeapNumberStubSub(masm); | 
|   755       break; |   755       break; | 
|   756     case Token::BIT_NOT: |   756     case Token::BIT_NOT: | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   790 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, |   790 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, | 
|   791                                             Label* slow) { |   791                                             Label* slow) { | 
|   792   __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |   792   __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 
|   793   __ cmp(edx, masm->isolate()->factory()->heap_number_map()); |   793   __ cmp(edx, masm->isolate()->factory()->heap_number_map()); | 
|   794   __ j(not_equal, slow); |   794   __ j(not_equal, slow); | 
|   795  |   795  | 
|   796   if (mode_ == UNARY_OVERWRITE) { |   796   if (mode_ == UNARY_OVERWRITE) { | 
|   797     __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), |   797     __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), | 
|   798             Immediate(HeapNumber::kSignMask));  // Flip sign. |   798             Immediate(HeapNumber::kSignMask));  // Flip sign. | 
|   799   } else { |   799   } else { | 
|   800     __ mov(edx, Operand(eax)); |   800     __ mov(edx, eax); | 
|   801     // edx: operand |   801     // edx: operand | 
|   802  |   802  | 
|   803     Label slow_allocate_heapnumber, heapnumber_allocated; |   803     Label slow_allocate_heapnumber, heapnumber_allocated; | 
|   804     __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); |   804     __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); | 
|   805     __ jmp(&heapnumber_allocated, Label::kNear); |   805     __ jmp(&heapnumber_allocated, Label::kNear); | 
|   806  |   806  | 
|   807     __ bind(&slow_allocate_heapnumber); |   807     __ bind(&slow_allocate_heapnumber); | 
|   808     { |   808     { | 
|   809       FrameScope scope(masm, StackFrame::INTERNAL); |   809       FrameScope scope(masm, StackFrame::INTERNAL); | 
|   810       __ push(edx); |   810       __ push(edx); | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   865     } |   865     } | 
|   866     // IntegerConvert uses ebx and edi as scratch registers. |   866     // IntegerConvert uses ebx and edi as scratch registers. | 
|   867     // This conversion won't go slow-case. |   867     // This conversion won't go slow-case. | 
|   868     IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); |   868     IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); | 
|   869     __ not_(ecx); |   869     __ not_(ecx); | 
|   870  |   870  | 
|   871     __ bind(&heapnumber_allocated); |   871     __ bind(&heapnumber_allocated); | 
|   872   } |   872   } | 
|   873   if (CpuFeatures::IsSupported(SSE2)) { |   873   if (CpuFeatures::IsSupported(SSE2)) { | 
|   874     CpuFeatures::Scope use_sse2(SSE2); |   874     CpuFeatures::Scope use_sse2(SSE2); | 
|   875     __ cvtsi2sd(xmm0, Operand(ecx)); |   875     __ cvtsi2sd(xmm0, ecx); | 
|   876     __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |   876     __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 
|   877   } else { |   877   } else { | 
|   878     __ push(ecx); |   878     __ push(ecx); | 
|   879     __ fild_s(Operand(esp, 0)); |   879     __ fild_s(Operand(esp, 0)); | 
|   880     __ pop(ecx); |   880     __ pop(ecx); | 
|   881     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |   881     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|   882   } |   882   } | 
|   883   __ ret(0); |   883   __ ret(0); | 
|   884 } |   884 } | 
|   885  |   885  | 
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1058   Comment smi_check_comment(masm, "-- Smi check arguments"); |  1058   Comment smi_check_comment(masm, "-- Smi check arguments"); | 
|  1059   Label not_smis; |  1059   Label not_smis; | 
|  1060   Register combined = ecx; |  1060   Register combined = ecx; | 
|  1061   ASSERT(!left.is(combined) && !right.is(combined)); |  1061   ASSERT(!left.is(combined) && !right.is(combined)); | 
|  1062   switch (op_) { |  1062   switch (op_) { | 
|  1063     case Token::BIT_OR: |  1063     case Token::BIT_OR: | 
|  1064       // Perform the operation into eax and smi check the result.  Preserve |  1064       // Perform the operation into eax and smi check the result.  Preserve | 
|  1065       // eax in case the result is not a smi. |  1065       // eax in case the result is not a smi. | 
|  1066       ASSERT(!left.is(ecx) && !right.is(ecx)); |  1066       ASSERT(!left.is(ecx) && !right.is(ecx)); | 
|  1067       __ mov(ecx, right); |  1067       __ mov(ecx, right); | 
|  1068       __ or_(right, Operand(left));  // Bitwise or is commutative. |  1068       __ or_(right, left);  // Bitwise or is commutative. | 
|  1069       combined = right; |  1069       combined = right; | 
|  1070       break; |  1070       break; | 
|  1071  |  1071  | 
|  1072     case Token::BIT_XOR: |  1072     case Token::BIT_XOR: | 
|  1073     case Token::BIT_AND: |  1073     case Token::BIT_AND: | 
|  1074     case Token::ADD: |  1074     case Token::ADD: | 
|  1075     case Token::SUB: |  1075     case Token::SUB: | 
|  1076     case Token::MUL: |  1076     case Token::MUL: | 
|  1077     case Token::DIV: |  1077     case Token::DIV: | 
|  1078     case Token::MOD: |  1078     case Token::MOD: | 
|  1079       __ mov(combined, right); |  1079       __ mov(combined, right); | 
|  1080       __ or_(combined, Operand(left)); |  1080       __ or_(combined, left); | 
|  1081       break; |  1081       break; | 
|  1082  |  1082  | 
|  1083     case Token::SHL: |  1083     case Token::SHL: | 
|  1084     case Token::SAR: |  1084     case Token::SAR: | 
|  1085     case Token::SHR: |  1085     case Token::SHR: | 
|  1086       // Move the right operand into ecx for the shift operation, use eax |  1086       // Move the right operand into ecx for the shift operation, use eax | 
|  1087       // for the smi check register. |  1087       // for the smi check register. | 
|  1088       ASSERT(!left.is(ecx) && !right.is(ecx)); |  1088       ASSERT(!left.is(ecx) && !right.is(ecx)); | 
|  1089       __ mov(ecx, right); |  1089       __ mov(ecx, right); | 
|  1090       __ or_(right, Operand(left)); |  1090       __ or_(right, left); | 
|  1091       combined = right; |  1091       combined = right; | 
|  1092       break; |  1092       break; | 
|  1093  |  1093  | 
|  1094     default: |  1094     default: | 
|  1095       break; |  1095       break; | 
|  1096   } |  1096   } | 
|  1097  |  1097  | 
|  1098   // 3. Perform the smi check of the operands. |  1098   // 3. Perform the smi check of the operands. | 
|  1099   STATIC_ASSERT(kSmiTag == 0);  // Adjust zero check if not the case. |  1099   STATIC_ASSERT(kSmiTag == 0);  // Adjust zero check if not the case. | 
|  1100   __ JumpIfNotSmi(combined, ¬_smis); |  1100   __ JumpIfNotSmi(combined, ¬_smis); | 
|  1101  |  1101  | 
|  1102   // 4. Operands are both smis, perform the operation leaving the result in |  1102   // 4. Operands are both smis, perform the operation leaving the result in | 
|  1103   // eax and check the result if necessary. |  1103   // eax and check the result if necessary. | 
|  1104   Comment perform_smi(masm, "-- Perform smi operation"); |  1104   Comment perform_smi(masm, "-- Perform smi operation"); | 
|  1105   Label use_fp_on_smis; |  1105   Label use_fp_on_smis; | 
|  1106   switch (op_) { |  1106   switch (op_) { | 
|  1107     case Token::BIT_OR: |  1107     case Token::BIT_OR: | 
|  1108       // Nothing to do. |  1108       // Nothing to do. | 
|  1109       break; |  1109       break; | 
|  1110  |  1110  | 
|  1111     case Token::BIT_XOR: |  1111     case Token::BIT_XOR: | 
|  1112       ASSERT(right.is(eax)); |  1112       ASSERT(right.is(eax)); | 
|  1113       __ xor_(right, Operand(left));  // Bitwise xor is commutative. |  1113       __ xor_(right, left);  // Bitwise xor is commutative. | 
|  1114       break; |  1114       break; | 
|  1115  |  1115  | 
|  1116     case Token::BIT_AND: |  1116     case Token::BIT_AND: | 
|  1117       ASSERT(right.is(eax)); |  1117       ASSERT(right.is(eax)); | 
|  1118       __ and_(right, Operand(left));  // Bitwise and is commutative. |  1118       __ and_(right, left);  // Bitwise and is commutative. | 
|  1119       break; |  1119       break; | 
|  1120  |  1120  | 
|  1121     case Token::SHL: |  1121     case Token::SHL: | 
|  1122       // Remove tags from operands (but keep sign). |  1122       // Remove tags from operands (but keep sign). | 
|  1123       __ SmiUntag(left); |  1123       __ SmiUntag(left); | 
|  1124       __ SmiUntag(ecx); |  1124       __ SmiUntag(ecx); | 
|  1125       // Perform the operation. |  1125       // Perform the operation. | 
|  1126       __ shl_cl(left); |  1126       __ shl_cl(left); | 
|  1127       // Check that the *signed* result fits in a smi. |  1127       // Check that the *signed* result fits in a smi. | 
|  1128       __ cmp(left, 0xc0000000); |  1128       __ cmp(left, 0xc0000000); | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
|  1157       // by 0 or 1 when handed a valid smi. |  1157       // by 0 or 1 when handed a valid smi. | 
|  1158       __ test(left, Immediate(0xc0000000)); |  1158       __ test(left, Immediate(0xc0000000)); | 
|  1159       __ j(not_zero, &use_fp_on_smis); |  1159       __ j(not_zero, &use_fp_on_smis); | 
|  1160       // Tag the result and store it in register eax. |  1160       // Tag the result and store it in register eax. | 
|  1161       __ SmiTag(left); |  1161       __ SmiTag(left); | 
|  1162       __ mov(eax, left); |  1162       __ mov(eax, left); | 
|  1163       break; |  1163       break; | 
|  1164  |  1164  | 
|  1165     case Token::ADD: |  1165     case Token::ADD: | 
|  1166       ASSERT(right.is(eax)); |  1166       ASSERT(right.is(eax)); | 
|  1167       __ add(right, Operand(left));  // Addition is commutative. |  1167       __ add(right, left);  // Addition is commutative. | 
|  1168       __ j(overflow, &use_fp_on_smis); |  1168       __ j(overflow, &use_fp_on_smis); | 
|  1169       break; |  1169       break; | 
|  1170  |  1170  | 
|  1171     case Token::SUB: |  1171     case Token::SUB: | 
|  1172       __ sub(left, Operand(right)); |  1172       __ sub(left, right); | 
|  1173       __ j(overflow, &use_fp_on_smis); |  1173       __ j(overflow, &use_fp_on_smis); | 
|  1174       __ mov(eax, left); |  1174       __ mov(eax, left); | 
|  1175       break; |  1175       break; | 
|  1176  |  1176  | 
|  1177     case Token::MUL: |  1177     case Token::MUL: | 
|  1178       // If the smi tag is 0 we can just leave the tag on one operand. |  1178       // If the smi tag is 0 we can just leave the tag on one operand. | 
|  1179       STATIC_ASSERT(kSmiTag == 0);  // Adjust code below if not the case. |  1179       STATIC_ASSERT(kSmiTag == 0);  // Adjust code below if not the case. | 
|  1180       // We can't revert the multiplication if the result is not a smi |  1180       // We can't revert the multiplication if the result is not a smi | 
|  1181       // so save the right operand. |  1181       // so save the right operand. | 
|  1182       __ mov(ebx, right); |  1182       __ mov(ebx, right); | 
|  1183       // Remove tag from one of the operands (but keep sign). |  1183       // Remove tag from one of the operands (but keep sign). | 
|  1184       __ SmiUntag(right); |  1184       __ SmiUntag(right); | 
|  1185       // Do multiplication. |  1185       // Do multiplication. | 
|  1186       __ imul(right, Operand(left));  // Multiplication is commutative. |  1186       __ imul(right, left);  // Multiplication is commutative. | 
|  1187       __ j(overflow, &use_fp_on_smis); |  1187       __ j(overflow, &use_fp_on_smis); | 
|  1188       // Check for negative zero result.  Use combined = left | right. |  1188       // Check for negative zero result.  Use combined = left | right. | 
|  1189       __ NegativeZeroTest(right, combined, &use_fp_on_smis); |  1189       __ NegativeZeroTest(right, combined, &use_fp_on_smis); | 
|  1190       break; |  1190       break; | 
|  1191  |  1191  | 
|  1192     case Token::DIV: |  1192     case Token::DIV: | 
|  1193       // We can't revert the division if the result is not a smi so |  1193       // We can't revert the division if the result is not a smi so | 
|  1194       // save the left operand. |  1194       // save the left operand. | 
|  1195       __ mov(edi, left); |  1195       __ mov(edi, left); | 
|  1196       // Check for 0 divisor. |  1196       // Check for 0 divisor. | 
|  1197       __ test(right, Operand(right)); |  1197       __ test(right, right); | 
|  1198       __ j(zero, &use_fp_on_smis); |  1198       __ j(zero, &use_fp_on_smis); | 
|  1199       // Sign extend left into edx:eax. |  1199       // Sign extend left into edx:eax. | 
|  1200       ASSERT(left.is(eax)); |  1200       ASSERT(left.is(eax)); | 
|  1201       __ cdq(); |  1201       __ cdq(); | 
|  1202       // Divide edx:eax by right. |  1202       // Divide edx:eax by right. | 
|  1203       __ idiv(right); |  1203       __ idiv(right); | 
|  1204       // Check for the corner case of dividing the most negative smi by |  1204       // Check for the corner case of dividing the most negative smi by | 
|  1205       // -1. We cannot use the overflow flag, since it is not set by idiv |  1205       // -1. We cannot use the overflow flag, since it is not set by idiv | 
|  1206       // instruction. |  1206       // instruction. | 
|  1207       STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |  1207       STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 
|  1208       __ cmp(eax, 0x40000000); |  1208       __ cmp(eax, 0x40000000); | 
|  1209       __ j(equal, &use_fp_on_smis); |  1209       __ j(equal, &use_fp_on_smis); | 
|  1210       // Check for negative zero result.  Use combined = left | right. |  1210       // Check for negative zero result.  Use combined = left | right. | 
|  1211       __ NegativeZeroTest(eax, combined, &use_fp_on_smis); |  1211       __ NegativeZeroTest(eax, combined, &use_fp_on_smis); | 
|  1212       // Check that the remainder is zero. |  1212       // Check that the remainder is zero. | 
|  1213       __ test(edx, Operand(edx)); |  1213       __ test(edx, edx); | 
|  1214       __ j(not_zero, &use_fp_on_smis); |  1214       __ j(not_zero, &use_fp_on_smis); | 
|  1215       // Tag the result and store it in register eax. |  1215       // Tag the result and store it in register eax. | 
|  1216       __ SmiTag(eax); |  1216       __ SmiTag(eax); | 
|  1217       break; |  1217       break; | 
|  1218  |  1218  | 
|  1219     case Token::MOD: |  1219     case Token::MOD: | 
|  1220       // Check for 0 divisor. |  1220       // Check for 0 divisor. | 
|  1221       __ test(right, Operand(right)); |  1221       __ test(right, right); | 
|  1222       __ j(zero, ¬_smis); |  1222       __ j(zero, ¬_smis); | 
|  1223  |  1223  | 
|  1224       // Sign extend left into edx:eax. |  1224       // Sign extend left into edx:eax. | 
|  1225       ASSERT(left.is(eax)); |  1225       ASSERT(left.is(eax)); | 
|  1226       __ cdq(); |  1226       __ cdq(); | 
|  1227       // Divide edx:eax by right. |  1227       // Divide edx:eax by right. | 
|  1228       __ idiv(right); |  1228       __ idiv(right); | 
|  1229       // Check for negative zero result.  Use combined = left | right. |  1229       // Check for negative zero result.  Use combined = left | right. | 
|  1230       __ NegativeZeroTest(edx, combined, slow); |  1230       __ NegativeZeroTest(edx, combined, slow); | 
|  1231       // Move remainder to register eax. |  1231       // Move remainder to register eax. | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|  1262   // overflowed the smi range). |  1262   // overflowed the smi range). | 
|  1263   if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { |  1263   if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { | 
|  1264     __ bind(&use_fp_on_smis); |  1264     __ bind(&use_fp_on_smis); | 
|  1265     switch (op_) { |  1265     switch (op_) { | 
|  1266       // Undo the effects of some operations, and some register moves. |  1266       // Undo the effects of some operations, and some register moves. | 
|  1267       case Token::SHL: |  1267       case Token::SHL: | 
|  1268         // The arguments are saved on the stack, and only used from there. |  1268         // The arguments are saved on the stack, and only used from there. | 
|  1269         break; |  1269         break; | 
|  1270       case Token::ADD: |  1270       case Token::ADD: | 
|  1271         // Revert right = right + left. |  1271         // Revert right = right + left. | 
|  1272         __ sub(right, Operand(left)); |  1272         __ sub(right, left); | 
|  1273         break; |  1273         break; | 
|  1274       case Token::SUB: |  1274       case Token::SUB: | 
|  1275         // Revert left = left - right. |  1275         // Revert left = left - right. | 
|  1276         __ add(left, Operand(right)); |  1276         __ add(left, right); | 
|  1277         break; |  1277         break; | 
|  1278       case Token::MUL: |  1278       case Token::MUL: | 
|  1279         // Right was clobbered but a copy is in ebx. |  1279         // Right was clobbered but a copy is in ebx. | 
|  1280         __ mov(right, ebx); |  1280         __ mov(right, ebx); | 
|  1281         break; |  1281         break; | 
|  1282       case Token::DIV: |  1282       case Token::DIV: | 
|  1283         // Left was clobbered but a copy is in edi.  Right is in ebx for |  1283         // Left was clobbered but a copy is in edi.  Right is in ebx for | 
|  1284         // division.  They should be in eax, ebx for jump to not_smi. |  1284         // division.  They should be in eax, ebx for jump to not_smi. | 
|  1285         __ mov(eax, edi); |  1285         __ mov(eax, edi); | 
|  1286         break; |  1286         break; | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
|  1304         // are about to return. |  1304         // are about to return. | 
|  1305         if (op_ == Token::SHR) { |  1305         if (op_ == Token::SHR) { | 
|  1306           __ mov(Operand(esp, 1 * kPointerSize), left); |  1306           __ mov(Operand(esp, 1 * kPointerSize), left); | 
|  1307           __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); |  1307           __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); | 
|  1308           __ fild_d(Operand(esp, 1 * kPointerSize)); |  1308           __ fild_d(Operand(esp, 1 * kPointerSize)); | 
|  1309           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |  1309           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  1310         } else { |  1310         } else { | 
|  1311           ASSERT_EQ(Token::SHL, op_); |  1311           ASSERT_EQ(Token::SHL, op_); | 
|  1312           if (CpuFeatures::IsSupported(SSE2)) { |  1312           if (CpuFeatures::IsSupported(SSE2)) { | 
|  1313             CpuFeatures::Scope use_sse2(SSE2); |  1313             CpuFeatures::Scope use_sse2(SSE2); | 
|  1314             __ cvtsi2sd(xmm0, Operand(left)); |  1314             __ cvtsi2sd(xmm0, left); | 
|  1315             __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |  1315             __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 
|  1316           } else { |  1316           } else { | 
|  1317             __ mov(Operand(esp, 1 * kPointerSize), left); |  1317             __ mov(Operand(esp, 1 * kPointerSize), left); | 
|  1318             __ fild_s(Operand(esp, 1 * kPointerSize)); |  1318             __ fild_s(Operand(esp, 1 * kPointerSize)); | 
|  1319             __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |  1319             __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  1320           } |  1320           } | 
|  1321         } |  1321         } | 
|  1322         __ ret(2 * kPointerSize); |  1322         __ ret(2 * kPointerSize); | 
|  1323         break; |  1323         break; | 
|  1324       } |  1324       } | 
|  1325  |  1325  | 
|  1326       case Token::ADD: |  1326       case Token::ADD: | 
|  1327       case Token::SUB: |  1327       case Token::SUB: | 
|  1328       case Token::MUL: |  1328       case Token::MUL: | 
|  1329       case Token::DIV: { |  1329       case Token::DIV: { | 
|  1330         Comment perform_float(masm, "-- Perform float operation on smis"); |  1330         Comment perform_float(masm, "-- Perform float operation on smis"); | 
|  1331         __ bind(&use_fp_on_smis); |  1331         __ bind(&use_fp_on_smis); | 
|  1332         // Restore arguments to edx, eax. |  1332         // Restore arguments to edx, eax. | 
|  1333         switch (op_) { |  1333         switch (op_) { | 
|  1334           case Token::ADD: |  1334           case Token::ADD: | 
|  1335             // Revert right = right + left. |  1335             // Revert right = right + left. | 
|  1336             __ sub(right, Operand(left)); |  1336             __ sub(right, left); | 
|  1337             break; |  1337             break; | 
|  1338           case Token::SUB: |  1338           case Token::SUB: | 
|  1339             // Revert left = left - right. |  1339             // Revert left = left - right. | 
|  1340             __ add(left, Operand(right)); |  1340             __ add(left, right); | 
|  1341             break; |  1341             break; | 
|  1342           case Token::MUL: |  1342           case Token::MUL: | 
|  1343             // Right was clobbered but a copy is in ebx. |  1343             // Right was clobbered but a copy is in ebx. | 
|  1344             __ mov(right, ebx); |  1344             __ mov(right, ebx); | 
|  1345             break; |  1345             break; | 
|  1346           case Token::DIV: |  1346           case Token::DIV: | 
|  1347             // Left was clobbered but a copy is in edi.  Right is in ebx for |  1347             // Left was clobbered but a copy is in edi.  Right is in ebx for | 
|  1348             // division. |  1348             // division. | 
|  1349             __ mov(edx, edi); |  1349             __ mov(edx, edi); | 
|  1350             __ mov(eax, right); |  1350             __ mov(eax, right); | 
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1522         switch (op_) { |  1522         switch (op_) { | 
|  1523           case Token::ADD: __ addsd(xmm0, xmm1); break; |  1523           case Token::ADD: __ addsd(xmm0, xmm1); break; | 
|  1524           case Token::SUB: __ subsd(xmm0, xmm1); break; |  1524           case Token::SUB: __ subsd(xmm0, xmm1); break; | 
|  1525           case Token::MUL: __ mulsd(xmm0, xmm1); break; |  1525           case Token::MUL: __ mulsd(xmm0, xmm1); break; | 
|  1526           case Token::DIV: __ divsd(xmm0, xmm1); break; |  1526           case Token::DIV: __ divsd(xmm0, xmm1); break; | 
|  1527           default: UNREACHABLE(); |  1527           default: UNREACHABLE(); | 
|  1528         } |  1528         } | 
|  1529         // Check result type if it is currently Int32. |  1529         // Check result type if it is currently Int32. | 
|  1530         if (result_type_ <= BinaryOpIC::INT32) { |  1530         if (result_type_ <= BinaryOpIC::INT32) { | 
|  1531           __ cvttsd2si(ecx, Operand(xmm0)); |  1531           __ cvttsd2si(ecx, Operand(xmm0)); | 
|  1532           __ cvtsi2sd(xmm2, Operand(ecx)); |  1532           __ cvtsi2sd(xmm2, ecx); | 
|  1533           __ ucomisd(xmm0, xmm2); |  1533           __ ucomisd(xmm0, xmm2); | 
|  1534           __ j(not_zero, ¬_int32); |  1534           __ j(not_zero, ¬_int32); | 
|  1535           __ j(carry, ¬_int32); |  1535           __ j(carry, ¬_int32); | 
|  1536         } |  1536         } | 
|  1537         GenerateHeapResultAllocation(masm, &call_runtime); |  1537         GenerateHeapResultAllocation(masm, &call_runtime); | 
|  1538         __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |  1538         __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 
|  1539         __ ret(0); |  1539         __ ret(0); | 
|  1540       } else {  // SSE2 not available, use FPU. |  1540       } else {  // SSE2 not available, use FPU. | 
|  1541         FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); |  1541         FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); | 
|  1542         FloatingPointHelper::LoadFloatOperands( |  1542         FloatingPointHelper::LoadFloatOperands( | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1584         CpuFeatures::Scope use_sse2(SSE2); |  1584         CpuFeatures::Scope use_sse2(SSE2); | 
|  1585         FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |  1585         FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 
|  1586         FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); |  1586         FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); | 
|  1587         }*/ |  1587         }*/ | 
|  1588       FloatingPointHelper::LoadUnknownsAsIntegers(masm, |  1588       FloatingPointHelper::LoadUnknownsAsIntegers(masm, | 
|  1589                                                   use_sse3_, |  1589                                                   use_sse3_, | 
|  1590                                                   ¬_floats); |  1590                                                   ¬_floats); | 
|  1591       FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, |  1591       FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, | 
|  1592                                                         ¬_int32); |  1592                                                         ¬_int32); | 
|  1593       switch (op_) { |  1593       switch (op_) { | 
|  1594         case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break; |  1594         case Token::BIT_OR:  __ or_(eax, ecx); break; | 
|  1595         case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |  1595         case Token::BIT_AND: __ and_(eax, ecx); break; | 
|  1596         case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; |  1596         case Token::BIT_XOR: __ xor_(eax, ecx); break; | 
|  1597         case Token::SAR: __ sar_cl(eax); break; |  1597         case Token::SAR: __ sar_cl(eax); break; | 
|  1598         case Token::SHL: __ shl_cl(eax); break; |  1598         case Token::SHL: __ shl_cl(eax); break; | 
|  1599         case Token::SHR: __ shr_cl(eax); break; |  1599         case Token::SHR: __ shr_cl(eax); break; | 
|  1600         default: UNREACHABLE(); |  1600         default: UNREACHABLE(); | 
|  1601       } |  1601       } | 
|  1602       if (op_ == Token::SHR) { |  1602       if (op_ == Token::SHR) { | 
|  1603         // Check if result is non-negative and fits in a smi. |  1603         // Check if result is non-negative and fits in a smi. | 
|  1604         __ test(eax, Immediate(0xc0000000)); |  1604         __ test(eax, Immediate(0xc0000000)); | 
|  1605         __ j(not_zero, &call_runtime); |  1605         __ j(not_zero, &call_runtime); | 
|  1606       } else { |  1606       } else { | 
|  1607         // Check if result fits in a smi. |  1607         // Check if result fits in a smi. | 
|  1608         __ cmp(eax, 0xc0000000); |  1608         __ cmp(eax, 0xc0000000); | 
|  1609         __ j(negative, &non_smi_result, Label::kNear); |  1609         __ j(negative, &non_smi_result, Label::kNear); | 
|  1610       } |  1610       } | 
|  1611       // Tag smi result and return. |  1611       // Tag smi result and return. | 
|  1612       __ SmiTag(eax); |  1612       __ SmiTag(eax); | 
|  1613       __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. |  1613       __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. | 
|  1614  |  1614  | 
|  1615       // All ops except SHR return a signed int32 that we load in |  1615       // All ops except SHR return a signed int32 that we load in | 
|  1616       // a HeapNumber. |  1616       // a HeapNumber. | 
|  1617       if (op_ != Token::SHR) { |  1617       if (op_ != Token::SHR) { | 
|  1618         __ bind(&non_smi_result); |  1618         __ bind(&non_smi_result); | 
|  1619         // Allocate a heap number if needed. |  1619         // Allocate a heap number if needed. | 
|  1620         __ mov(ebx, Operand(eax));  // ebx: result |  1620         __ mov(ebx, eax);  // ebx: result | 
|  1621         Label skip_allocation; |  1621         Label skip_allocation; | 
|  1622         switch (mode_) { |  1622         switch (mode_) { | 
|  1623           case OVERWRITE_LEFT: |  1623           case OVERWRITE_LEFT: | 
|  1624           case OVERWRITE_RIGHT: |  1624           case OVERWRITE_RIGHT: | 
|  1625             // If the operand was an object, we skip the |  1625             // If the operand was an object, we skip the | 
|  1626             // allocation of a heap number. |  1626             // allocation of a heap number. | 
|  1627             __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |  1627             __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | 
|  1628                                 1 * kPointerSize : 2 * kPointerSize)); |  1628                                 1 * kPointerSize : 2 * kPointerSize)); | 
|  1629             __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |  1629             __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); | 
|  1630             // Fall through! |  1630             // Fall through! | 
|  1631           case NO_OVERWRITE: |  1631           case NO_OVERWRITE: | 
|  1632             __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |  1632             __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 
|  1633             __ bind(&skip_allocation); |  1633             __ bind(&skip_allocation); | 
|  1634             break; |  1634             break; | 
|  1635           default: UNREACHABLE(); |  1635           default: UNREACHABLE(); | 
|  1636         } |  1636         } | 
|  1637         // Store the result in the HeapNumber and return. |  1637         // Store the result in the HeapNumber and return. | 
|  1638         if (CpuFeatures::IsSupported(SSE2)) { |  1638         if (CpuFeatures::IsSupported(SSE2)) { | 
|  1639           CpuFeatures::Scope use_sse2(SSE2); |  1639           CpuFeatures::Scope use_sse2(SSE2); | 
|  1640           __ cvtsi2sd(xmm0, Operand(ebx)); |  1640           __ cvtsi2sd(xmm0, ebx); | 
|  1641           __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |  1641           __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 
|  1642         } else { |  1642         } else { | 
|  1643           __ mov(Operand(esp, 1 * kPointerSize), ebx); |  1643           __ mov(Operand(esp, 1 * kPointerSize), ebx); | 
|  1644           __ fild_s(Operand(esp, 1 * kPointerSize)); |  1644           __ fild_s(Operand(esp, 1 * kPointerSize)); | 
|  1645           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |  1645           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  1646         } |  1646         } | 
|  1647         __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. |  1647         __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. | 
|  1648       } |  1648       } | 
|  1649  |  1649  | 
|  1650       __ bind(¬_floats); |  1650       __ bind(¬_floats); | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1711     GenerateAddStrings(masm); |  1711     GenerateAddStrings(masm); | 
|  1712   } |  1712   } | 
|  1713  |  1713  | 
|  1714   Factory* factory = masm->isolate()->factory(); |  1714   Factory* factory = masm->isolate()->factory(); | 
|  1715  |  1715  | 
|  1716   // Convert odd ball arguments to numbers. |  1716   // Convert odd ball arguments to numbers. | 
|  1717   Label check, done; |  1717   Label check, done; | 
|  1718   __ cmp(edx, factory->undefined_value()); |  1718   __ cmp(edx, factory->undefined_value()); | 
|  1719   __ j(not_equal, &check, Label::kNear); |  1719   __ j(not_equal, &check, Label::kNear); | 
|  1720   if (Token::IsBitOp(op_)) { |  1720   if (Token::IsBitOp(op_)) { | 
|  1721     __ xor_(edx, Operand(edx)); |  1721     __ xor_(edx, edx); | 
|  1722   } else { |  1722   } else { | 
|  1723     __ mov(edx, Immediate(factory->nan_value())); |  1723     __ mov(edx, Immediate(factory->nan_value())); | 
|  1724   } |  1724   } | 
|  1725   __ jmp(&done, Label::kNear); |  1725   __ jmp(&done, Label::kNear); | 
|  1726   __ bind(&check); |  1726   __ bind(&check); | 
|  1727   __ cmp(eax, factory->undefined_value()); |  1727   __ cmp(eax, factory->undefined_value()); | 
|  1728   __ j(not_equal, &done, Label::kNear); |  1728   __ j(not_equal, &done, Label::kNear); | 
|  1729   if (Token::IsBitOp(op_)) { |  1729   if (Token::IsBitOp(op_)) { | 
|  1730     __ xor_(eax, Operand(eax)); |  1730     __ xor_(eax, eax); | 
|  1731   } else { |  1731   } else { | 
|  1732     __ mov(eax, Immediate(factory->nan_value())); |  1732     __ mov(eax, Immediate(factory->nan_value())); | 
|  1733   } |  1733   } | 
|  1734   __ bind(&done); |  1734   __ bind(&done); | 
|  1735  |  1735  | 
|  1736   GenerateHeapNumberStub(masm); |  1736   GenerateHeapNumberStub(masm); | 
|  1737 } |  1737 } | 
|  1738  |  1738  | 
|  1739  |  1739  | 
|  1740 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { |  1740 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1798     case Token::SAR: |  1798     case Token::SAR: | 
|  1799     case Token::SHL: |  1799     case Token::SHL: | 
|  1800     case Token::SHR: { |  1800     case Token::SHR: { | 
|  1801       GenerateRegisterArgsPush(masm); |  1801       GenerateRegisterArgsPush(masm); | 
|  1802       Label not_floats; |  1802       Label not_floats; | 
|  1803       Label non_smi_result; |  1803       Label non_smi_result; | 
|  1804       FloatingPointHelper::LoadUnknownsAsIntegers(masm, |  1804       FloatingPointHelper::LoadUnknownsAsIntegers(masm, | 
|  1805                                                   use_sse3_, |  1805                                                   use_sse3_, | 
|  1806                                                   ¬_floats); |  1806                                                   ¬_floats); | 
|  1807       switch (op_) { |  1807       switch (op_) { | 
|  1808         case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break; |  1808         case Token::BIT_OR:  __ or_(eax, ecx); break; | 
|  1809         case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |  1809         case Token::BIT_AND: __ and_(eax, ecx); break; | 
|  1810         case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; |  1810         case Token::BIT_XOR: __ xor_(eax, ecx); break; | 
|  1811         case Token::SAR: __ sar_cl(eax); break; |  1811         case Token::SAR: __ sar_cl(eax); break; | 
|  1812         case Token::SHL: __ shl_cl(eax); break; |  1812         case Token::SHL: __ shl_cl(eax); break; | 
|  1813         case Token::SHR: __ shr_cl(eax); break; |  1813         case Token::SHR: __ shr_cl(eax); break; | 
|  1814         default: UNREACHABLE(); |  1814         default: UNREACHABLE(); | 
|  1815       } |  1815       } | 
|  1816       if (op_ == Token::SHR) { |  1816       if (op_ == Token::SHR) { | 
|  1817         // Check if result is non-negative and fits in a smi. |  1817         // Check if result is non-negative and fits in a smi. | 
|  1818         __ test(eax, Immediate(0xc0000000)); |  1818         __ test(eax, Immediate(0xc0000000)); | 
|  1819         __ j(not_zero, &call_runtime); |  1819         __ j(not_zero, &call_runtime); | 
|  1820       } else { |  1820       } else { | 
|  1821         // Check if result fits in a smi. |  1821         // Check if result fits in a smi. | 
|  1822         __ cmp(eax, 0xc0000000); |  1822         __ cmp(eax, 0xc0000000); | 
|  1823         __ j(negative, &non_smi_result, Label::kNear); |  1823         __ j(negative, &non_smi_result, Label::kNear); | 
|  1824       } |  1824       } | 
|  1825       // Tag smi result and return. |  1825       // Tag smi result and return. | 
|  1826       __ SmiTag(eax); |  1826       __ SmiTag(eax); | 
|  1827       __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. |  1827       __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. | 
|  1828  |  1828  | 
|  1829       // All ops except SHR return a signed int32 that we load in |  1829       // All ops except SHR return a signed int32 that we load in | 
|  1830       // a HeapNumber. |  1830       // a HeapNumber. | 
|  1831       if (op_ != Token::SHR) { |  1831       if (op_ != Token::SHR) { | 
|  1832         __ bind(&non_smi_result); |  1832         __ bind(&non_smi_result); | 
|  1833         // Allocate a heap number if needed. |  1833         // Allocate a heap number if needed. | 
|  1834         __ mov(ebx, Operand(eax));  // ebx: result |  1834         __ mov(ebx, eax);  // ebx: result | 
|  1835         Label skip_allocation; |  1835         Label skip_allocation; | 
|  1836         switch (mode_) { |  1836         switch (mode_) { | 
|  1837           case OVERWRITE_LEFT: |  1837           case OVERWRITE_LEFT: | 
|  1838           case OVERWRITE_RIGHT: |  1838           case OVERWRITE_RIGHT: | 
|  1839             // If the operand was an object, we skip the |  1839             // If the operand was an object, we skip the | 
|  1840             // allocation of a heap number. |  1840             // allocation of a heap number. | 
|  1841             __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |  1841             __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | 
|  1842                                 1 * kPointerSize : 2 * kPointerSize)); |  1842                                 1 * kPointerSize : 2 * kPointerSize)); | 
|  1843             __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |  1843             __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); | 
|  1844             // Fall through! |  1844             // Fall through! | 
|  1845           case NO_OVERWRITE: |  1845           case NO_OVERWRITE: | 
|  1846             __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |  1846             __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 
|  1847             __ bind(&skip_allocation); |  1847             __ bind(&skip_allocation); | 
|  1848             break; |  1848             break; | 
|  1849           default: UNREACHABLE(); |  1849           default: UNREACHABLE(); | 
|  1850         } |  1850         } | 
|  1851         // Store the result in the HeapNumber and return. |  1851         // Store the result in the HeapNumber and return. | 
|  1852         if (CpuFeatures::IsSupported(SSE2)) { |  1852         if (CpuFeatures::IsSupported(SSE2)) { | 
|  1853           CpuFeatures::Scope use_sse2(SSE2); |  1853           CpuFeatures::Scope use_sse2(SSE2); | 
|  1854           __ cvtsi2sd(xmm0, Operand(ebx)); |  1854           __ cvtsi2sd(xmm0, ebx); | 
|  1855           __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |  1855           __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 
|  1856         } else { |  1856         } else { | 
|  1857           __ mov(Operand(esp, 1 * kPointerSize), ebx); |  1857           __ mov(Operand(esp, 1 * kPointerSize), ebx); | 
|  1858           __ fild_s(Operand(esp, 1 * kPointerSize)); |  1858           __ fild_s(Operand(esp, 1 * kPointerSize)); | 
|  1859           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |  1859           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  1860         } |  1860         } | 
|  1861         __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. |  1861         __ ret(2 * kPointerSize);  // Drop two pushed arguments from the stack. | 
|  1862       } |  1862       } | 
|  1863  |  1863  | 
|  1864       __ bind(¬_floats); |  1864       __ bind(¬_floats); | 
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1997     case Token::BIT_AND: |  1997     case Token::BIT_AND: | 
|  1998       case Token::BIT_XOR: |  1998       case Token::BIT_XOR: | 
|  1999     case Token::SAR: |  1999     case Token::SAR: | 
|  2000     case Token::SHL: |  2000     case Token::SHL: | 
|  2001     case Token::SHR: { |  2001     case Token::SHR: { | 
|  2002       Label non_smi_result; |  2002       Label non_smi_result; | 
|  2003       FloatingPointHelper::LoadUnknownsAsIntegers(masm, |  2003       FloatingPointHelper::LoadUnknownsAsIntegers(masm, | 
|  2004                                                   use_sse3_, |  2004                                                   use_sse3_, | 
|  2005                                                   &call_runtime); |  2005                                                   &call_runtime); | 
|  2006       switch (op_) { |  2006       switch (op_) { | 
|  2007         case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break; |  2007         case Token::BIT_OR:  __ or_(eax, ecx); break; | 
|  2008         case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |  2008         case Token::BIT_AND: __ and_(eax, ecx); break; | 
|  2009         case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; |  2009         case Token::BIT_XOR: __ xor_(eax, ecx); break; | 
|  2010         case Token::SAR: __ sar_cl(eax); break; |  2010         case Token::SAR: __ sar_cl(eax); break; | 
|  2011         case Token::SHL: __ shl_cl(eax); break; |  2011         case Token::SHL: __ shl_cl(eax); break; | 
|  2012         case Token::SHR: __ shr_cl(eax); break; |  2012         case Token::SHR: __ shr_cl(eax); break; | 
|  2013         default: UNREACHABLE(); |  2013         default: UNREACHABLE(); | 
|  2014       } |  2014       } | 
|  2015       if (op_ == Token::SHR) { |  2015       if (op_ == Token::SHR) { | 
|  2016         // Check if result is non-negative and fits in a smi. |  2016         // Check if result is non-negative and fits in a smi. | 
|  2017         __ test(eax, Immediate(0xc0000000)); |  2017         __ test(eax, Immediate(0xc0000000)); | 
|  2018         __ j(not_zero, &call_runtime); |  2018         __ j(not_zero, &call_runtime); | 
|  2019       } else { |  2019       } else { | 
|  2020         // Check if result fits in a smi. |  2020         // Check if result fits in a smi. | 
|  2021         __ cmp(eax, 0xc0000000); |  2021         __ cmp(eax, 0xc0000000); | 
|  2022         __ j(negative, &non_smi_result, Label::kNear); |  2022         __ j(negative, &non_smi_result, Label::kNear); | 
|  2023       } |  2023       } | 
|  2024       // Tag smi result and return. |  2024       // Tag smi result and return. | 
|  2025       __ SmiTag(eax); |  2025       __ SmiTag(eax); | 
|  2026       __ ret(2 * kPointerSize);  // Drop the arguments from the stack. |  2026       __ ret(2 * kPointerSize);  // Drop the arguments from the stack. | 
|  2027  |  2027  | 
|  2028       // All ops except SHR return a signed int32 that we load in |  2028       // All ops except SHR return a signed int32 that we load in | 
|  2029       // a HeapNumber. |  2029       // a HeapNumber. | 
|  2030       if (op_ != Token::SHR) { |  2030       if (op_ != Token::SHR) { | 
|  2031         __ bind(&non_smi_result); |  2031         __ bind(&non_smi_result); | 
|  2032         // Allocate a heap number if needed. |  2032         // Allocate a heap number if needed. | 
|  2033         __ mov(ebx, Operand(eax));  // ebx: result |  2033         __ mov(ebx, eax);  // ebx: result | 
|  2034         Label skip_allocation; |  2034         Label skip_allocation; | 
|  2035         switch (mode_) { |  2035         switch (mode_) { | 
|  2036           case OVERWRITE_LEFT: |  2036           case OVERWRITE_LEFT: | 
|  2037           case OVERWRITE_RIGHT: |  2037           case OVERWRITE_RIGHT: | 
|  2038             // If the operand was an object, we skip the |  2038             // If the operand was an object, we skip the | 
|  2039               // allocation of a heap number. |  2039               // allocation of a heap number. | 
|  2040             __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |  2040             __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | 
|  2041                                 1 * kPointerSize : 2 * kPointerSize)); |  2041                                 1 * kPointerSize : 2 * kPointerSize)); | 
|  2042             __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |  2042             __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); | 
|  2043             // Fall through! |  2043             // Fall through! | 
|  2044           case NO_OVERWRITE: |  2044           case NO_OVERWRITE: | 
|  2045             __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |  2045             __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 
|  2046             __ bind(&skip_allocation); |  2046             __ bind(&skip_allocation); | 
|  2047             break; |  2047             break; | 
|  2048           default: UNREACHABLE(); |  2048           default: UNREACHABLE(); | 
|  2049         } |  2049         } | 
|  2050         // Store the result in the HeapNumber and return. |  2050         // Store the result in the HeapNumber and return. | 
|  2051         if (CpuFeatures::IsSupported(SSE2)) { |  2051         if (CpuFeatures::IsSupported(SSE2)) { | 
|  2052           CpuFeatures::Scope use_sse2(SSE2); |  2052           CpuFeatures::Scope use_sse2(SSE2); | 
|  2053           __ cvtsi2sd(xmm0, Operand(ebx)); |  2053           __ cvtsi2sd(xmm0, ebx); | 
|  2054           __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |  2054           __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 
|  2055         } else { |  2055         } else { | 
|  2056           __ mov(Operand(esp, 1 * kPointerSize), ebx); |  2056           __ mov(Operand(esp, 1 * kPointerSize), ebx); | 
|  2057           __ fild_s(Operand(esp, 1 * kPointerSize)); |  2057           __ fild_s(Operand(esp, 1 * kPointerSize)); | 
|  2058           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |  2058           __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  2059         } |  2059         } | 
|  2060         __ ret(2 * kPointerSize); |  2060         __ ret(2 * kPointerSize); | 
|  2061       } |  2061       } | 
|  2062       break; |  2062       break; | 
|  2063     } |  2063     } | 
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2153   switch (mode) { |  2153   switch (mode) { | 
|  2154     case OVERWRITE_LEFT: { |  2154     case OVERWRITE_LEFT: { | 
|  2155       // If the argument in edx is already an object, we skip the |  2155       // If the argument in edx is already an object, we skip the | 
|  2156       // allocation of a heap number. |  2156       // allocation of a heap number. | 
|  2157       __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); |  2157       __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); | 
|  2158       // Allocate a heap number for the result. Keep eax and edx intact |  2158       // Allocate a heap number for the result. Keep eax and edx intact | 
|  2159       // for the possible runtime call. |  2159       // for the possible runtime call. | 
|  2160       __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |  2160       __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); | 
|  2161       // Now edx can be overwritten losing one of the arguments as we are |  2161       // Now edx can be overwritten losing one of the arguments as we are | 
|  2162       // now done and will not need it any more. |  2162       // now done and will not need it any more. | 
|  2163       __ mov(edx, Operand(ebx)); |  2163       __ mov(edx, ebx); | 
|  2164       __ bind(&skip_allocation); |  2164       __ bind(&skip_allocation); | 
|  2165       // Use object in edx as a result holder |  2165       // Use object in edx as a result holder | 
|  2166       __ mov(eax, Operand(edx)); |  2166       __ mov(eax, edx); | 
|  2167       break; |  2167       break; | 
|  2168     } |  2168     } | 
|  2169     case OVERWRITE_RIGHT: |  2169     case OVERWRITE_RIGHT: | 
|  2170       // If the argument in eax is already an object, we skip the |  2170       // If the argument in eax is already an object, we skip the | 
|  2171       // allocation of a heap number. |  2171       // allocation of a heap number. | 
|  2172       __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |  2172       __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); | 
|  2173       // Fall through! |  2173       // Fall through! | 
|  2174     case NO_OVERWRITE: |  2174     case NO_OVERWRITE: | 
|  2175       // Allocate a heap number for the result. Keep eax and edx intact |  2175       // Allocate a heap number for the result. Keep eax and edx intact | 
|  2176       // for the possible runtime call. |  2176       // for the possible runtime call. | 
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2214   if (tagged) { |  2214   if (tagged) { | 
|  2215     // Test that eax is a number. |  2215     // Test that eax is a number. | 
|  2216     Label input_not_smi; |  2216     Label input_not_smi; | 
|  2217     Label loaded; |  2217     Label loaded; | 
|  2218     __ mov(eax, Operand(esp, kPointerSize)); |  2218     __ mov(eax, Operand(esp, kPointerSize)); | 
|  2219     __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); |  2219     __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); | 
|  2220     // Input is a smi. Untag and load it onto the FPU stack. |  2220     // Input is a smi. Untag and load it onto the FPU stack. | 
|  2221     // Then load the low and high words of the double into ebx, edx. |  2221     // Then load the low and high words of the double into ebx, edx. | 
|  2222     STATIC_ASSERT(kSmiTagSize == 1); |  2222     STATIC_ASSERT(kSmiTagSize == 1); | 
|  2223     __ sar(eax, 1); |  2223     __ sar(eax, 1); | 
|  2224     __ sub(Operand(esp), Immediate(2 * kPointerSize)); |  2224     __ sub(esp, Immediate(2 * kPointerSize)); | 
|  2225     __ mov(Operand(esp, 0), eax); |  2225     __ mov(Operand(esp, 0), eax); | 
|  2226     __ fild_s(Operand(esp, 0)); |  2226     __ fild_s(Operand(esp, 0)); | 
|  2227     __ fst_d(Operand(esp, 0)); |  2227     __ fst_d(Operand(esp, 0)); | 
|  2228     __ pop(edx); |  2228     __ pop(edx); | 
|  2229     __ pop(ebx); |  2229     __ pop(ebx); | 
|  2230     __ jmp(&loaded, Label::kNear); |  2230     __ jmp(&loaded, Label::kNear); | 
|  2231     __ bind(&input_not_smi); |  2231     __ bind(&input_not_smi); | 
|  2232     // Check if input is a HeapNumber. |  2232     // Check if input is a HeapNumber. | 
|  2233     __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |  2233     __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 
|  2234     Factory* factory = masm->isolate()->factory(); |  2234     Factory* factory = masm->isolate()->factory(); | 
|  2235     __ cmp(Operand(ebx), Immediate(factory->heap_number_map())); |  2235     __ cmp(ebx, Immediate(factory->heap_number_map())); | 
|  2236     __ j(not_equal, &runtime_call); |  2236     __ j(not_equal, &runtime_call); | 
|  2237     // Input is a HeapNumber. Push it on the FPU stack and load its |  2237     // Input is a HeapNumber. Push it on the FPU stack and load its | 
|  2238     // low and high words into ebx, edx. |  2238     // low and high words into ebx, edx. | 
|  2239     __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |  2239     __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  2240     __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); |  2240     __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); | 
|  2241     __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); |  2241     __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); | 
|  2242  |  2242  | 
|  2243     __ bind(&loaded); |  2243     __ bind(&loaded); | 
|  2244   } else {  // UNTAGGED. |  2244   } else {  // UNTAGGED. | 
|  2245     if (CpuFeatures::IsSupported(SSE4_1)) { |  2245     if (CpuFeatures::IsSupported(SSE4_1)) { | 
|  2246       CpuFeatures::Scope sse4_scope(SSE4_1); |  2246       CpuFeatures::Scope sse4_scope(SSE4_1); | 
|  2247       __ pextrd(Operand(edx), xmm1, 0x1);  // copy xmm1[63..32] to edx. |  2247       __ pextrd(edx, xmm1, 0x1);  // copy xmm1[63..32] to edx. | 
|  2248     } else { |  2248     } else { | 
|  2249       __ pshufd(xmm0, xmm1, 0x1); |  2249       __ pshufd(xmm0, xmm1, 0x1); | 
|  2250       __ movd(Operand(edx), xmm0); |  2250       __ movd(edx, xmm0); | 
|  2251     } |  2251     } | 
|  2252     __ movd(Operand(ebx), xmm1); |  2252     __ movd(ebx, xmm1); | 
|  2253   } |  2253   } | 
|  2254  |  2254  | 
|  2255   // ST[0] or xmm1  == double value |  2255   // ST[0] or xmm1  == double value | 
|  2256   // ebx = low 32 bits of double value |  2256   // ebx = low 32 bits of double value | 
|  2257   // edx = high 32 bits of double value |  2257   // edx = high 32 bits of double value | 
|  2258   // Compute hash (the shifts are arithmetic): |  2258   // Compute hash (the shifts are arithmetic): | 
|  2259   //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); |  2259   //   h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); | 
|  2260   __ mov(ecx, ebx); |  2260   __ mov(ecx, ebx); | 
|  2261   __ xor_(ecx, Operand(edx)); |  2261   __ xor_(ecx, edx); | 
|  2262   __ mov(eax, ecx); |  2262   __ mov(eax, ecx); | 
|  2263   __ sar(eax, 16); |  2263   __ sar(eax, 16); | 
|  2264   __ xor_(ecx, Operand(eax)); |  2264   __ xor_(ecx, eax); | 
|  2265   __ mov(eax, ecx); |  2265   __ mov(eax, ecx); | 
|  2266   __ sar(eax, 8); |  2266   __ sar(eax, 8); | 
|  2267   __ xor_(ecx, Operand(eax)); |  2267   __ xor_(ecx, eax); | 
|  2268   ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); |  2268   ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); | 
|  2269   __ and_(Operand(ecx), |  2269   __ and_(ecx, | 
|  2270           Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); |  2270           Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); | 
|  2271  |  2271  | 
|  2272   // ST[0] or xmm1 == double value. |  2272   // ST[0] or xmm1 == double value. | 
|  2273   // ebx = low 32 bits of double value. |  2273   // ebx = low 32 bits of double value. | 
|  2274   // edx = high 32 bits of double value. |  2274   // edx = high 32 bits of double value. | 
|  2275   // ecx = TranscendentalCache::hash(double value). |  2275   // ecx = TranscendentalCache::hash(double value). | 
|  2276   ExternalReference cache_array = |  2276   ExternalReference cache_array = | 
|  2277       ExternalReference::transcendental_cache_array_address(masm->isolate()); |  2277       ExternalReference::transcendental_cache_array_address(masm->isolate()); | 
|  2278   __ mov(eax, Immediate(cache_array)); |  2278   __ mov(eax, Immediate(cache_array)); | 
|  2279   int cache_array_index = |  2279   int cache_array_index = | 
|  2280       type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]); |  2280       type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]); | 
|  2281   __ mov(eax, Operand(eax, cache_array_index)); |  2281   __ mov(eax, Operand(eax, cache_array_index)); | 
|  2282   // Eax points to the cache for the type type_. |  2282   // Eax points to the cache for the type type_. | 
|  2283   // If NULL, the cache hasn't been initialized yet, so go through runtime. |  2283   // If NULL, the cache hasn't been initialized yet, so go through runtime. | 
|  2284   __ test(eax, Operand(eax)); |  2284   __ test(eax, eax); | 
|  2285   __ j(zero, &runtime_call_clear_stack); |  2285   __ j(zero, &runtime_call_clear_stack); | 
|  2286 #ifdef DEBUG |  2286 #ifdef DEBUG | 
|  2287   // Check that the layout of cache elements match expectations. |  2287   // Check that the layout of cache elements match expectations. | 
|  2288   { TranscendentalCache::SubCache::Element test_elem[2]; |  2288   { TranscendentalCache::SubCache::Element test_elem[2]; | 
|  2289     char* elem_start = reinterpret_cast<char*>(&test_elem[0]); |  2289     char* elem_start = reinterpret_cast<char*>(&test_elem[0]); | 
|  2290     char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); |  2290     char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); | 
|  2291     char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0])); |  2291     char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0])); | 
|  2292     char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1])); |  2292     char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1])); | 
|  2293     char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); |  2293     char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); | 
|  2294     CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer. |  2294     CHECK_EQ(12, elem2_start - elem_start);  // Two uint_32's and a pointer. | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
|  2317   } |  2317   } | 
|  2318  |  2318  | 
|  2319   __ bind(&cache_miss); |  2319   __ bind(&cache_miss); | 
|  2320   // Update cache with new value. |  2320   // Update cache with new value. | 
|  2321   // We are short on registers, so use no_reg as scratch. |  2321   // We are short on registers, so use no_reg as scratch. | 
|  2322   // This gives slightly larger code. |  2322   // This gives slightly larger code. | 
|  2323   if (tagged) { |  2323   if (tagged) { | 
|  2324     __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); |  2324     __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); | 
|  2325   } else {  // UNTAGGED. |  2325   } else {  // UNTAGGED. | 
|  2326     __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); |  2326     __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); | 
|  2327     __ sub(Operand(esp), Immediate(kDoubleSize)); |  2327     __ sub(esp, Immediate(kDoubleSize)); | 
|  2328     __ movdbl(Operand(esp, 0), xmm1); |  2328     __ movdbl(Operand(esp, 0), xmm1); | 
|  2329     __ fld_d(Operand(esp, 0)); |  2329     __ fld_d(Operand(esp, 0)); | 
|  2330     __ add(Operand(esp), Immediate(kDoubleSize)); |  2330     __ add(esp, Immediate(kDoubleSize)); | 
|  2331   } |  2331   } | 
|  2332   GenerateOperation(masm); |  2332   GenerateOperation(masm); | 
|  2333   __ mov(Operand(ecx, 0), ebx); |  2333   __ mov(Operand(ecx, 0), ebx); | 
|  2334   __ mov(Operand(ecx, kIntSize), edx); |  2334   __ mov(Operand(ecx, kIntSize), edx); | 
|  2335   __ mov(Operand(ecx, 2 * kIntSize), eax); |  2335   __ mov(Operand(ecx, 2 * kIntSize), eax); | 
|  2336   __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |  2336   __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  2337   if (tagged) { |  2337   if (tagged) { | 
|  2338     __ ret(kPointerSize); |  2338     __ ret(kPointerSize); | 
|  2339   } else {  // UNTAGGED. |  2339   } else {  // UNTAGGED. | 
|  2340     __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |  2340     __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  2341     __ Ret(); |  2341     __ Ret(); | 
|  2342  |  2342  | 
|  2343     // Skip cache and return answer directly, only in untagged case. |  2343     // Skip cache and return answer directly, only in untagged case. | 
|  2344     __ bind(&skip_cache); |  2344     __ bind(&skip_cache); | 
|  2345     __ sub(Operand(esp), Immediate(kDoubleSize)); |  2345     __ sub(esp, Immediate(kDoubleSize)); | 
|  2346     __ movdbl(Operand(esp, 0), xmm1); |  2346     __ movdbl(Operand(esp, 0), xmm1); | 
|  2347     __ fld_d(Operand(esp, 0)); |  2347     __ fld_d(Operand(esp, 0)); | 
|  2348     GenerateOperation(masm); |  2348     GenerateOperation(masm); | 
|  2349     __ fstp_d(Operand(esp, 0)); |  2349     __ fstp_d(Operand(esp, 0)); | 
|  2350     __ movdbl(xmm1, Operand(esp, 0)); |  2350     __ movdbl(xmm1, Operand(esp, 0)); | 
|  2351     __ add(Operand(esp), Immediate(kDoubleSize)); |  2351     __ add(esp, Immediate(kDoubleSize)); | 
|  2352     // We return the value in xmm1 without adding it to the cache, but |  2352     // We return the value in xmm1 without adding it to the cache, but | 
|  2353     // we cause a scavenging GC so that future allocations will succeed. |  2353     // we cause a scavenging GC so that future allocations will succeed. | 
|  2354     { |  2354     { | 
|  2355       FrameScope scope(masm, StackFrame::INTERNAL); |  2355       FrameScope scope(masm, StackFrame::INTERNAL); | 
|  2356       // Allocate an unused object bigger than a HeapNumber. |  2356       // Allocate an unused object bigger than a HeapNumber. | 
|  2357       __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); |  2357       __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); | 
|  2358       __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); |  2358       __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); | 
|  2359     } |  2359     } | 
|  2360     __ Ret(); |  2360     __ Ret(); | 
|  2361   } |  2361   } | 
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2402   // Input value is possibly in xmm1. |  2402   // Input value is possibly in xmm1. | 
|  2403   // Address of result (a newly allocated HeapNumber) may be in eax. |  2403   // Address of result (a newly allocated HeapNumber) may be in eax. | 
|  2404   if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { |  2404   if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { | 
|  2405     // Both fsin and fcos require arguments in the range +/-2^63 and |  2405     // Both fsin and fcos require arguments in the range +/-2^63 and | 
|  2406     // return NaN for infinities and NaN. They can share all code except |  2406     // return NaN for infinities and NaN. They can share all code except | 
|  2407     // the actual fsin/fcos operation. |  2407     // the actual fsin/fcos operation. | 
|  2408     Label in_range, done; |  2408     Label in_range, done; | 
|  2409     // If argument is outside the range -2^63..2^63, fsin/cos doesn't |  2409     // If argument is outside the range -2^63..2^63, fsin/cos doesn't | 
|  2410     // work. We must reduce it to the appropriate range. |  2410     // work. We must reduce it to the appropriate range. | 
|  2411     __ mov(edi, edx); |  2411     __ mov(edi, edx); | 
|  2412     __ and_(Operand(edi), Immediate(0x7ff00000));  // Exponent only. |  2412     __ and_(edi, Immediate(0x7ff00000));  // Exponent only. | 
|  2413     int supported_exponent_limit = |  2413     int supported_exponent_limit = | 
|  2414         (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; |  2414         (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; | 
|  2415     __ cmp(Operand(edi), Immediate(supported_exponent_limit)); |  2415     __ cmp(edi, Immediate(supported_exponent_limit)); | 
|  2416     __ j(below, &in_range, Label::kNear); |  2416     __ j(below, &in_range, Label::kNear); | 
|  2417     // Check for infinity and NaN. Both return NaN for sin. |  2417     // Check for infinity and NaN. Both return NaN for sin. | 
|  2418     __ cmp(Operand(edi), Immediate(0x7ff00000)); |  2418     __ cmp(edi, Immediate(0x7ff00000)); | 
|  2419     Label non_nan_result; |  2419     Label non_nan_result; | 
|  2420     __ j(not_equal, &non_nan_result, Label::kNear); |  2420     __ j(not_equal, &non_nan_result, Label::kNear); | 
|  2421     // Input is +/-Infinity or NaN. Result is NaN. |  2421     // Input is +/-Infinity or NaN. Result is NaN. | 
|  2422     __ fstp(0); |  2422     __ fstp(0); | 
|  2423     // NaN is represented by 0x7ff8000000000000. |  2423     // NaN is represented by 0x7ff8000000000000. | 
|  2424     __ push(Immediate(0x7ff80000)); |  2424     __ push(Immediate(0x7ff80000)); | 
|  2425     __ push(Immediate(0)); |  2425     __ push(Immediate(0)); | 
|  2426     __ fld_d(Operand(esp, 0)); |  2426     __ fld_d(Operand(esp, 0)); | 
|  2427     __ add(Operand(esp), Immediate(2 * kPointerSize)); |  2427     __ add(esp, Immediate(2 * kPointerSize)); | 
|  2428     __ jmp(&done, Label::kNear); |  2428     __ jmp(&done, Label::kNear); | 
|  2429  |  2429  | 
|  2430     __ bind(&non_nan_result); |  2430     __ bind(&non_nan_result); | 
|  2431  |  2431  | 
|  2432     // Use fpmod to restrict argument to the range +/-2*PI. |  2432     // Use fpmod to restrict argument to the range +/-2*PI. | 
|  2433     __ mov(edi, eax);  // Save eax before using fnstsw_ax. |  2433     __ mov(edi, eax);  // Save eax before using fnstsw_ax. | 
|  2434     __ fldpi(); |  2434     __ fldpi(); | 
|  2435     __ fadd(0); |  2435     __ fadd(0); | 
|  2436     __ fld(1); |  2436     __ fld(1); | 
|  2437     // FPU Stack: input, 2*pi, input. |  2437     // FPU Stack: input, 2*pi, input. | 
|  2438     { |  2438     { | 
|  2439       Label no_exceptions; |  2439       Label no_exceptions; | 
|  2440       __ fwait(); |  2440       __ fwait(); | 
|  2441       __ fnstsw_ax(); |  2441       __ fnstsw_ax(); | 
|  2442       // Clear if Illegal Operand or Zero Division exceptions are set. |  2442       // Clear if Illegal Operand or Zero Division exceptions are set. | 
|  2443       __ test(Operand(eax), Immediate(5)); |  2443       __ test(eax, Immediate(5)); | 
|  2444       __ j(zero, &no_exceptions, Label::kNear); |  2444       __ j(zero, &no_exceptions, Label::kNear); | 
|  2445       __ fnclex(); |  2445       __ fnclex(); | 
|  2446       __ bind(&no_exceptions); |  2446       __ bind(&no_exceptions); | 
|  2447     } |  2447     } | 
|  2448  |  2448  | 
|  2449     // Compute st(0) % st(1) |  2449     // Compute st(0) % st(1) | 
|  2450     { |  2450     { | 
|  2451       Label partial_remainder_loop; |  2451       Label partial_remainder_loop; | 
|  2452       __ bind(&partial_remainder_loop); |  2452       __ bind(&partial_remainder_loop); | 
|  2453       __ fprem1(); |  2453       __ fprem1(); | 
|  2454       __ fwait(); |  2454       __ fwait(); | 
|  2455       __ fnstsw_ax(); |  2455       __ fnstsw_ax(); | 
|  2456       __ test(Operand(eax), Immediate(0x400 /* C2 */)); |  2456       __ test(eax, Immediate(0x400 /* C2 */)); | 
|  2457       // If C2 is set, computation only has partial result. Loop to |  2457       // If C2 is set, computation only has partial result. Loop to | 
|  2458       // continue computation. |  2458       // continue computation. | 
|  2459       __ j(not_zero, &partial_remainder_loop); |  2459       __ j(not_zero, &partial_remainder_loop); | 
|  2460     } |  2460     } | 
|  2461     // FPU Stack: input, 2*pi, input % 2*pi |  2461     // FPU Stack: input, 2*pi, input % 2*pi | 
|  2462     __ fstp(2); |  2462     __ fstp(2); | 
|  2463     __ fstp(0); |  2463     __ fstp(0); | 
|  2464     __ mov(eax, edi);  // Restore eax (allocated HeapNumber pointer). |  2464     __ mov(eax, edi);  // Restore eax (allocated HeapNumber pointer). | 
|  2465  |  2465  | 
|  2466     // FPU Stack: input % 2*pi |  2466     // FPU Stack: input % 2*pi | 
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2579   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |  2579   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 
|  2580  |  2580  | 
|  2581   __ bind(&load_eax); |  2581   __ bind(&load_eax); | 
|  2582   // Load operand in eax into xmm1. |  2582   // Load operand in eax into xmm1. | 
|  2583   __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); |  2583   __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); | 
|  2584   __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |  2584   __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  2585   __ jmp(&done, Label::kNear); |  2585   __ jmp(&done, Label::kNear); | 
|  2586  |  2586  | 
|  2587   __ bind(&load_smi_edx); |  2587   __ bind(&load_smi_edx); | 
|  2588   __ SmiUntag(edx);  // Untag smi before converting to float. |  2588   __ SmiUntag(edx);  // Untag smi before converting to float. | 
|  2589   __ cvtsi2sd(xmm0, Operand(edx)); |  2589   __ cvtsi2sd(xmm0, edx); | 
|  2590   __ SmiTag(edx);  // Retag smi for heap number overwriting test. |  2590   __ SmiTag(edx);  // Retag smi for heap number overwriting test. | 
|  2591   __ jmp(&load_eax); |  2591   __ jmp(&load_eax); | 
|  2592  |  2592  | 
|  2593   __ bind(&load_smi_eax); |  2593   __ bind(&load_smi_eax); | 
|  2594   __ SmiUntag(eax);  // Untag smi before converting to float. |  2594   __ SmiUntag(eax);  // Untag smi before converting to float. | 
|  2595   __ cvtsi2sd(xmm1, Operand(eax)); |  2595   __ cvtsi2sd(xmm1, eax); | 
|  2596   __ SmiTag(eax);  // Retag smi for heap number overwriting test. |  2596   __ SmiTag(eax);  // Retag smi for heap number overwriting test. | 
|  2597  |  2597  | 
|  2598   __ bind(&done); |  2598   __ bind(&done); | 
|  2599 } |  2599 } | 
|  2600  |  2600  | 
|  2601  |  2601  | 
|  2602 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, |  2602 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, | 
|  2603                                            Label* not_numbers) { |  2603                                            Label* not_numbers) { | 
|  2604   Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; |  2604   Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; | 
|  2605   // Load operand in edx into xmm0, or branch to not_numbers. |  2605   // Load operand in edx into xmm0, or branch to not_numbers. | 
|  2606   __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); |  2606   __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); | 
|  2607   Factory* factory = masm->isolate()->factory(); |  2607   Factory* factory = masm->isolate()->factory(); | 
|  2608   __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); |  2608   __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); | 
|  2609   __ j(not_equal, not_numbers);  // Argument in edx is not a number. |  2609   __ j(not_equal, not_numbers);  // Argument in edx is not a number. | 
|  2610   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |  2610   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 
|  2611   __ bind(&load_eax); |  2611   __ bind(&load_eax); | 
|  2612   // Load operand in eax into xmm1, or branch to not_numbers. |  2612   // Load operand in eax into xmm1, or branch to not_numbers. | 
|  2613   __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); |  2613   __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); | 
|  2614   __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); |  2614   __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); | 
|  2615   __ j(equal, &load_float_eax, Label::kNear); |  2615   __ j(equal, &load_float_eax, Label::kNear); | 
|  2616   __ jmp(not_numbers);  // Argument in eax is not a number. |  2616   __ jmp(not_numbers);  // Argument in eax is not a number. | 
|  2617   __ bind(&load_smi_edx); |  2617   __ bind(&load_smi_edx); | 
|  2618   __ SmiUntag(edx);  // Untag smi before converting to float. |  2618   __ SmiUntag(edx);  // Untag smi before converting to float. | 
|  2619   __ cvtsi2sd(xmm0, Operand(edx)); |  2619   __ cvtsi2sd(xmm0, edx); | 
|  2620   __ SmiTag(edx);  // Retag smi for heap number overwriting test. |  2620   __ SmiTag(edx);  // Retag smi for heap number overwriting test. | 
|  2621   __ jmp(&load_eax); |  2621   __ jmp(&load_eax); | 
|  2622   __ bind(&load_smi_eax); |  2622   __ bind(&load_smi_eax); | 
|  2623   __ SmiUntag(eax);  // Untag smi before converting to float. |  2623   __ SmiUntag(eax);  // Untag smi before converting to float. | 
|  2624   __ cvtsi2sd(xmm1, Operand(eax)); |  2624   __ cvtsi2sd(xmm1, eax); | 
|  2625   __ SmiTag(eax);  // Retag smi for heap number overwriting test. |  2625   __ SmiTag(eax);  // Retag smi for heap number overwriting test. | 
|  2626   __ jmp(&done, Label::kNear); |  2626   __ jmp(&done, Label::kNear); | 
|  2627   __ bind(&load_float_eax); |  2627   __ bind(&load_float_eax); | 
|  2628   __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |  2628   __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  2629   __ bind(&done); |  2629   __ bind(&done); | 
|  2630 } |  2630 } | 
|  2631  |  2631  | 
|  2632  |  2632  | 
|  2633 void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, |  2633 void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, | 
|  2634                                        Register scratch) { |  2634                                        Register scratch) { | 
|  2635   const Register left = edx; |  2635   const Register left = edx; | 
|  2636   const Register right = eax; |  2636   const Register right = eax; | 
|  2637   __ mov(scratch, left); |  2637   __ mov(scratch, left); | 
|  2638   ASSERT(!scratch.is(right));  // We're about to clobber scratch. |  2638   ASSERT(!scratch.is(right));  // We're about to clobber scratch. | 
|  2639   __ SmiUntag(scratch); |  2639   __ SmiUntag(scratch); | 
|  2640   __ cvtsi2sd(xmm0, Operand(scratch)); |  2640   __ cvtsi2sd(xmm0, scratch); | 
|  2641  |  2641  | 
|  2642   __ mov(scratch, right); |  2642   __ mov(scratch, right); | 
|  2643   __ SmiUntag(scratch); |  2643   __ SmiUntag(scratch); | 
|  2644   __ cvtsi2sd(xmm1, Operand(scratch)); |  2644   __ cvtsi2sd(xmm1, scratch); | 
|  2645 } |  2645 } | 
|  2646  |  2646  | 
|  2647  |  2647  | 
|  2648 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, |  2648 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, | 
|  2649                                                     Label* non_int32, |  2649                                                     Label* non_int32, | 
|  2650                                                     Register scratch) { |  2650                                                     Register scratch) { | 
|  2651   __ cvttsd2si(scratch, Operand(xmm0)); |  2651   __ cvttsd2si(scratch, Operand(xmm0)); | 
|  2652   __ cvtsi2sd(xmm2, Operand(scratch)); |  2652   __ cvtsi2sd(xmm2, scratch); | 
|  2653   __ ucomisd(xmm0, xmm2); |  2653   __ ucomisd(xmm0, xmm2); | 
|  2654   __ j(not_zero, non_int32); |  2654   __ j(not_zero, non_int32); | 
|  2655   __ j(carry, non_int32); |  2655   __ j(carry, non_int32); | 
|  2656   __ cvttsd2si(scratch, Operand(xmm1)); |  2656   __ cvttsd2si(scratch, Operand(xmm1)); | 
|  2657   __ cvtsi2sd(xmm2, Operand(scratch)); |  2657   __ cvtsi2sd(xmm2, scratch); | 
|  2658   __ ucomisd(xmm1, xmm2); |  2658   __ ucomisd(xmm1, xmm2); | 
|  2659   __ j(not_zero, non_int32); |  2659   __ j(not_zero, non_int32); | 
|  2660   __ j(carry, non_int32); |  2660   __ j(carry, non_int32); | 
|  2661 } |  2661 } | 
|  2662  |  2662  | 
|  2663  |  2663  | 
|  2664 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |  2664 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 
|  2665                                             Register scratch, |  2665                                             Register scratch, | 
|  2666                                             ArgLocation arg_location) { |  2666                                             ArgLocation arg_location) { | 
|  2667   Label load_smi_1, load_smi_2, done_load_1, done; |  2667   Label load_smi_1, load_smi_2, done_load_1, done; | 
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2755  |  2755  | 
|  2756   CpuFeatures::Scope use_sse2(SSE2); |  2756   CpuFeatures::Scope use_sse2(SSE2); | 
|  2757   Label allocate_return, call_runtime; |  2757   Label allocate_return, call_runtime; | 
|  2758  |  2758  | 
|  2759   // Load input parameters. |  2759   // Load input parameters. | 
|  2760   __ mov(edx, Operand(esp, 2 * kPointerSize)); |  2760   __ mov(edx, Operand(esp, 2 * kPointerSize)); | 
|  2761   __ mov(eax, Operand(esp, 1 * kPointerSize)); |  2761   __ mov(eax, Operand(esp, 1 * kPointerSize)); | 
|  2762  |  2762  | 
|  2763   // Save 1 in xmm3 - we need this several times later on. |  2763   // Save 1 in xmm3 - we need this several times later on. | 
|  2764   __ mov(ecx, Immediate(1)); |  2764   __ mov(ecx, Immediate(1)); | 
|  2765   __ cvtsi2sd(xmm3, Operand(ecx)); |  2765   __ cvtsi2sd(xmm3, ecx); | 
|  2766  |  2766  | 
|  2767   Label exponent_nonsmi; |  2767   Label exponent_nonsmi; | 
|  2768   Label base_nonsmi; |  2768   Label base_nonsmi; | 
|  2769   // If the exponent is a heap number go to that specific case. |  2769   // If the exponent is a heap number go to that specific case. | 
|  2770   __ JumpIfNotSmi(eax, &exponent_nonsmi); |  2770   __ JumpIfNotSmi(eax, &exponent_nonsmi); | 
|  2771   __ JumpIfNotSmi(edx, &base_nonsmi); |  2771   __ JumpIfNotSmi(edx, &base_nonsmi); | 
|  2772  |  2772  | 
|  2773   // Optimized version when both exponent and base are smis. |  2773   // Optimized version when both exponent and base are smis. | 
|  2774   Label powi; |  2774   Label powi; | 
|  2775   __ SmiUntag(edx); |  2775   __ SmiUntag(edx); | 
|  2776   __ cvtsi2sd(xmm0, Operand(edx)); |  2776   __ cvtsi2sd(xmm0, edx); | 
|  2777   __ jmp(&powi); |  2777   __ jmp(&powi); | 
|  2778   // exponent is smi and base is a heapnumber. |  2778   // exponent is smi and base is a heapnumber. | 
|  2779   __ bind(&base_nonsmi); |  2779   __ bind(&base_nonsmi); | 
|  2780   Factory* factory = masm->isolate()->factory(); |  2780   Factory* factory = masm->isolate()->factory(); | 
|  2781   __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |  2781   __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 
|  2782          factory->heap_number_map()); |  2782          factory->heap_number_map()); | 
|  2783   __ j(not_equal, &call_runtime); |  2783   __ j(not_equal, &call_runtime); | 
|  2784  |  2784  | 
|  2785   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |  2785   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 
|  2786  |  2786  | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
|  2808   __ bind(&while_true); |  2808   __ bind(&while_true); | 
|  2809   __ shr(eax, 1); |  2809   __ shr(eax, 1); | 
|  2810   __ j(not_carry, &no_multiply, Label::kNear); |  2810   __ j(not_carry, &no_multiply, Label::kNear); | 
|  2811   __ mulsd(xmm1, xmm0); |  2811   __ mulsd(xmm1, xmm0); | 
|  2812   __ bind(&no_multiply); |  2812   __ bind(&no_multiply); | 
|  2813   __ mulsd(xmm0, xmm0); |  2813   __ mulsd(xmm0, xmm0); | 
|  2814   __ j(not_zero, &while_true); |  2814   __ j(not_zero, &while_true); | 
|  2815  |  2815  | 
|  2816   // base has the original value of the exponent - if the exponent  is |  2816   // base has the original value of the exponent - if the exponent  is | 
|  2817   // negative return 1/result. |  2817   // negative return 1/result. | 
|  2818   __ test(edx, Operand(edx)); |  2818   __ test(edx, edx); | 
|  2819   __ j(positive, &allocate_return); |  2819   __ j(positive, &allocate_return); | 
|  2820   // Special case if xmm1 has reached infinity. |  2820   // Special case if xmm1 has reached infinity. | 
|  2821   __ mov(ecx, Immediate(0x7FB00000)); |  2821   __ mov(ecx, Immediate(0x7FB00000)); | 
|  2822   __ movd(xmm0, Operand(ecx)); |  2822   __ movd(xmm0, ecx); | 
|  2823   __ cvtss2sd(xmm0, xmm0); |  2823   __ cvtss2sd(xmm0, xmm0); | 
|  2824   __ ucomisd(xmm0, xmm1); |  2824   __ ucomisd(xmm0, xmm1); | 
|  2825   __ j(equal, &call_runtime); |  2825   __ j(equal, &call_runtime); | 
|  2826   __ divsd(xmm3, xmm1); |  2826   __ divsd(xmm3, xmm1); | 
|  2827   __ movsd(xmm1, xmm3); |  2827   __ movsd(xmm1, xmm3); | 
|  2828   __ jmp(&allocate_return); |  2828   __ jmp(&allocate_return); | 
|  2829  |  2829  | 
|  2830   // exponent (or both) is a heapnumber - no matter what we should now work |  2830   // exponent (or both) is a heapnumber - no matter what we should now work | 
|  2831   // on doubles. |  2831   // on doubles. | 
|  2832   __ bind(&exponent_nonsmi); |  2832   __ bind(&exponent_nonsmi); | 
|  2833   __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |  2833   __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 
|  2834          factory->heap_number_map()); |  2834          factory->heap_number_map()); | 
|  2835   __ j(not_equal, &call_runtime); |  2835   __ j(not_equal, &call_runtime); | 
|  2836   __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |  2836   __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  2837   // Test if exponent is nan. |  2837   // Test if exponent is nan. | 
|  2838   __ ucomisd(xmm1, xmm1); |  2838   __ ucomisd(xmm1, xmm1); | 
|  2839   __ j(parity_even, &call_runtime); |  2839   __ j(parity_even, &call_runtime); | 
|  2840  |  2840  | 
|  2841   Label base_not_smi; |  2841   Label base_not_smi; | 
|  2842   Label handle_special_cases; |  2842   Label handle_special_cases; | 
|  2843   __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); |  2843   __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); | 
|  2844   __ SmiUntag(edx); |  2844   __ SmiUntag(edx); | 
|  2845   __ cvtsi2sd(xmm0, Operand(edx)); |  2845   __ cvtsi2sd(xmm0, edx); | 
|  2846   __ jmp(&handle_special_cases, Label::kNear); |  2846   __ jmp(&handle_special_cases, Label::kNear); | 
|  2847  |  2847  | 
|  2848   __ bind(&base_not_smi); |  2848   __ bind(&base_not_smi); | 
|  2849   __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |  2849   __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 
|  2850          factory->heap_number_map()); |  2850          factory->heap_number_map()); | 
|  2851   __ j(not_equal, &call_runtime); |  2851   __ j(not_equal, &call_runtime); | 
|  2852   __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); |  2852   __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 
|  2853   __ and_(ecx, HeapNumber::kExponentMask); |  2853   __ and_(ecx, HeapNumber::kExponentMask); | 
|  2854   __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask)); |  2854   __ cmp(ecx, Immediate(HeapNumber::kExponentMask)); | 
|  2855   // base is NaN or +/-Infinity |  2855   // base is NaN or +/-Infinity | 
|  2856   __ j(greater_equal, &call_runtime); |  2856   __ j(greater_equal, &call_runtime); | 
|  2857   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |  2857   __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 
|  2858  |  2858  | 
|  2859   // base is in xmm0 and exponent is in xmm1. |  2859   // base is in xmm0 and exponent is in xmm1. | 
|  2860   __ bind(&handle_special_cases); |  2860   __ bind(&handle_special_cases); | 
|  2861   Label not_minus_half; |  2861   Label not_minus_half; | 
|  2862   // Test for -0.5. |  2862   // Test for -0.5. | 
|  2863   // Load xmm2 with -0.5. |  2863   // Load xmm2 with -0.5. | 
|  2864   __ mov(ecx, Immediate(0xBF000000)); |  2864   __ mov(ecx, Immediate(0xBF000000)); | 
|  2865   __ movd(xmm2, Operand(ecx)); |  2865   __ movd(xmm2, ecx); | 
|  2866   __ cvtss2sd(xmm2, xmm2); |  2866   __ cvtss2sd(xmm2, xmm2); | 
|  2867   // xmm2 now has -0.5. |  2867   // xmm2 now has -0.5. | 
|  2868   __ ucomisd(xmm2, xmm1); |  2868   __ ucomisd(xmm2, xmm1); | 
|  2869   __ j(not_equal, ¬_minus_half, Label::kNear); |  2869   __ j(not_equal, ¬_minus_half, Label::kNear); | 
|  2870  |  2870  | 
|  2871   // Calculates reciprocal of square root. |  2871   // Calculates reciprocal of square root. | 
|  2872   // sqrtsd returns -0 when input is -0.  ECMA spec requires +0. |  2872   // sqrtsd returns -0 when input is -0.  ECMA spec requires +0. | 
|  2873   __ xorps(xmm1, xmm1); |  2873   __ xorps(xmm1, xmm1); | 
|  2874   __ addsd(xmm1, xmm0); |  2874   __ addsd(xmm1, xmm0); | 
|  2875   __ sqrtsd(xmm1, xmm1); |  2875   __ sqrtsd(xmm1, xmm1); | 
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2911   static const int kDisplacement = 1 * kPointerSize; |  2911   static const int kDisplacement = 1 * kPointerSize; | 
|  2912  |  2912  | 
|  2913   // Check that the key is a smi. |  2913   // Check that the key is a smi. | 
|  2914   Label slow; |  2914   Label slow; | 
|  2915   __ JumpIfNotSmi(edx, &slow, Label::kNear); |  2915   __ JumpIfNotSmi(edx, &slow, Label::kNear); | 
|  2916  |  2916  | 
|  2917   // Check if the calling frame is an arguments adaptor frame. |  2917   // Check if the calling frame is an arguments adaptor frame. | 
|  2918   Label adaptor; |  2918   Label adaptor; | 
|  2919   __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |  2919   __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 
|  2920   __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); |  2920   __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); | 
|  2921   __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |  2921   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 
|  2922   __ j(equal, &adaptor, Label::kNear); |  2922   __ j(equal, &adaptor, Label::kNear); | 
|  2923  |  2923  | 
|  2924   // Check index against formal parameters count limit passed in |  2924   // Check index against formal parameters count limit passed in | 
|  2925   // through register eax. Use unsigned comparison to get negative |  2925   // through register eax. Use unsigned comparison to get negative | 
|  2926   // check for free. |  2926   // check for free. | 
|  2927   __ cmp(edx, Operand(eax)); |  2927   __ cmp(edx, eax); | 
|  2928   __ j(above_equal, &slow, Label::kNear); |  2928   __ j(above_equal, &slow, Label::kNear); | 
|  2929  |  2929  | 
|  2930   // Read the argument from the stack and return it. |  2930   // Read the argument from the stack and return it. | 
|  2931   STATIC_ASSERT(kSmiTagSize == 1); |  2931   STATIC_ASSERT(kSmiTagSize == 1); | 
|  2932   STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these. |  2932   STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these. | 
|  2933   __ lea(ebx, Operand(ebp, eax, times_2, 0)); |  2933   __ lea(ebx, Operand(ebp, eax, times_2, 0)); | 
|  2934   __ neg(edx); |  2934   __ neg(edx); | 
|  2935   __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); |  2935   __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); | 
|  2936   __ ret(0); |  2936   __ ret(0); | 
|  2937  |  2937  | 
|  2938   // Arguments adaptor case: Check index against actual arguments |  2938   // Arguments adaptor case: Check index against actual arguments | 
|  2939   // limit found in the arguments adaptor frame. Use unsigned |  2939   // limit found in the arguments adaptor frame. Use unsigned | 
|  2940   // comparison to get negative check for free. |  2940   // comparison to get negative check for free. | 
|  2941   __ bind(&adaptor); |  2941   __ bind(&adaptor); | 
|  2942   __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |  2942   __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 
|  2943   __ cmp(edx, Operand(ecx)); |  2943   __ cmp(edx, ecx); | 
|  2944   __ j(above_equal, &slow, Label::kNear); |  2944   __ j(above_equal, &slow, Label::kNear); | 
|  2945  |  2945  | 
|  2946   // Read the argument from the stack and return it. |  2946   // Read the argument from the stack and return it. | 
|  2947   STATIC_ASSERT(kSmiTagSize == 1); |  2947   STATIC_ASSERT(kSmiTagSize == 1); | 
|  2948   STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these. |  2948   STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these. | 
|  2949   __ lea(ebx, Operand(ebx, ecx, times_2, 0)); |  2949   __ lea(ebx, Operand(ebx, ecx, times_2, 0)); | 
|  2950   __ neg(edx); |  2950   __ neg(edx); | 
|  2951   __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); |  2951   __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); | 
|  2952   __ ret(0); |  2952   __ ret(0); | 
|  2953  |  2953  | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
|  2964 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { |  2964 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { | 
|  2965   // esp[0] : return address |  2965   // esp[0] : return address | 
|  2966   // esp[4] : number of parameters |  2966   // esp[4] : number of parameters | 
|  2967   // esp[8] : receiver displacement |  2967   // esp[8] : receiver displacement | 
|  2968   // esp[12] : function |  2968   // esp[12] : function | 
|  2969  |  2969  | 
|  2970   // Check if the calling frame is an arguments adaptor frame. |  2970   // Check if the calling frame is an arguments adaptor frame. | 
|  2971   Label runtime; |  2971   Label runtime; | 
|  2972   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |  2972   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 
|  2973   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |  2973   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); | 
|  2974   __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |  2974   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 
|  2975   __ j(not_equal, &runtime, Label::kNear); |  2975   __ j(not_equal, &runtime, Label::kNear); | 
|  2976  |  2976  | 
|  2977   // Patch the arguments.length and the parameters pointer. |  2977   // Patch the arguments.length and the parameters pointer. | 
|  2978   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |  2978   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 
|  2979   __ mov(Operand(esp, 1 * kPointerSize), ecx); |  2979   __ mov(Operand(esp, 1 * kPointerSize), ecx); | 
|  2980   __ lea(edx, Operand(edx, ecx, times_2, |  2980   __ lea(edx, Operand(edx, ecx, times_2, | 
|  2981               StandardFrameConstants::kCallerSPOffset)); |  2981               StandardFrameConstants::kCallerSPOffset)); | 
|  2982   __ mov(Operand(esp, 2 * kPointerSize), edx); |  2982   __ mov(Operand(esp, 2 * kPointerSize), edx); | 
|  2983  |  2983  | 
|  2984   __ bind(&runtime); |  2984   __ bind(&runtime); | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
|  2995   // ebx = parameter count (tagged) |  2995   // ebx = parameter count (tagged) | 
|  2996   __ mov(ebx, Operand(esp, 1 * kPointerSize)); |  2996   __ mov(ebx, Operand(esp, 1 * kPointerSize)); | 
|  2997  |  2997  | 
|  2998   // Check if the calling frame is an arguments adaptor frame. |  2998   // Check if the calling frame is an arguments adaptor frame. | 
|  2999   // TODO(rossberg): Factor out some of the bits that are shared with the other |  2999   // TODO(rossberg): Factor out some of the bits that are shared with the other | 
|  3000   // Generate* functions. |  3000   // Generate* functions. | 
|  3001   Label runtime; |  3001   Label runtime; | 
|  3002   Label adaptor_frame, try_allocate; |  3002   Label adaptor_frame, try_allocate; | 
|  3003   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |  3003   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 
|  3004   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |  3004   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); | 
|  3005   __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |  3005   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 
|  3006   __ j(equal, &adaptor_frame, Label::kNear); |  3006   __ j(equal, &adaptor_frame, Label::kNear); | 
|  3007  |  3007  | 
|  3008   // No adaptor, parameter count = argument count. |  3008   // No adaptor, parameter count = argument count. | 
|  3009   __ mov(ecx, ebx); |  3009   __ mov(ecx, ebx); | 
|  3010   __ jmp(&try_allocate, Label::kNear); |  3010   __ jmp(&try_allocate, Label::kNear); | 
|  3011  |  3011  | 
|  3012   // We have an adaptor frame. Patch the parameters pointer. |  3012   // We have an adaptor frame. Patch the parameters pointer. | 
|  3013   __ bind(&adaptor_frame); |  3013   __ bind(&adaptor_frame); | 
|  3014   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |  3014   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 
|  3015   __ lea(edx, Operand(edx, ecx, times_2, |  3015   __ lea(edx, Operand(edx, ecx, times_2, | 
|  3016                       StandardFrameConstants::kCallerSPOffset)); |  3016                       StandardFrameConstants::kCallerSPOffset)); | 
|  3017   __ mov(Operand(esp, 2 * kPointerSize), edx); |  3017   __ mov(Operand(esp, 2 * kPointerSize), edx); | 
|  3018  |  3018  | 
|  3019   // ebx = parameter count (tagged) |  3019   // ebx = parameter count (tagged) | 
|  3020   // ecx = argument count (tagged) |  3020   // ecx = argument count (tagged) | 
|  3021   // esp[4] = parameter count (tagged) |  3021   // esp[4] = parameter count (tagged) | 
|  3022   // esp[8] = address of receiver argument |  3022   // esp[8] = address of receiver argument | 
|  3023   // Compute the mapped parameter count = min(ebx, ecx) in ebx. |  3023   // Compute the mapped parameter count = min(ebx, ecx) in ebx. | 
|  3024   __ cmp(ebx, Operand(ecx)); |  3024   __ cmp(ebx, ecx); | 
|  3025   __ j(less_equal, &try_allocate, Label::kNear); |  3025   __ j(less_equal, &try_allocate, Label::kNear); | 
|  3026   __ mov(ebx, ecx); |  3026   __ mov(ebx, ecx); | 
|  3027  |  3027  | 
|  3028   __ bind(&try_allocate); |  3028   __ bind(&try_allocate); | 
|  3029  |  3029  | 
|  3030   // Save mapped parameter count. |  3030   // Save mapped parameter count. | 
|  3031   __ push(ebx); |  3031   __ push(ebx); | 
|  3032  |  3032  | 
|  3033   // Compute the sizes of backing store, parameter map, and arguments object. |  3033   // Compute the sizes of backing store, parameter map, and arguments object. | 
|  3034   // 1. Parameter map, has 2 extra words containing context and backing store. |  3034   // 1. Parameter map, has 2 extra words containing context and backing store. | 
|  3035   const int kParameterMapHeaderSize = |  3035   const int kParameterMapHeaderSize = | 
|  3036       FixedArray::kHeaderSize + 2 * kPointerSize; |  3036       FixedArray::kHeaderSize + 2 * kPointerSize; | 
|  3037   Label no_parameter_map; |  3037   Label no_parameter_map; | 
|  3038   __ test(ebx, Operand(ebx)); |  3038   __ test(ebx, ebx); | 
|  3039   __ j(zero, &no_parameter_map, Label::kNear); |  3039   __ j(zero, &no_parameter_map, Label::kNear); | 
|  3040   __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); |  3040   __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); | 
|  3041   __ bind(&no_parameter_map); |  3041   __ bind(&no_parameter_map); | 
|  3042  |  3042  | 
|  3043   // 2. Backing store. |  3043   // 2. Backing store. | 
|  3044   __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); |  3044   __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); | 
|  3045  |  3045  | 
|  3046   // 3. Arguments object. |  3046   // 3. Arguments object. | 
|  3047   __ add(Operand(ebx), Immediate(Heap::kArgumentsObjectSize)); |  3047   __ add(ebx, Immediate(Heap::kArgumentsObjectSize)); | 
|  3048  |  3048  | 
|  3049   // Do the allocation of all three objects in one go. |  3049   // Do the allocation of all three objects in one go. | 
|  3050   __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); |  3050   __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); | 
|  3051  |  3051  | 
|  3052   // eax = address of new object(s) (tagged) |  3052   // eax = address of new object(s) (tagged) | 
|  3053   // ecx = argument count (tagged) |  3053   // ecx = argument count (tagged) | 
|  3054   // esp[0] = mapped parameter count (tagged) |  3054   // esp[0] = mapped parameter count (tagged) | 
|  3055   // esp[8] = parameter count (tagged) |  3055   // esp[8] = parameter count (tagged) | 
|  3056   // esp[12] = address of receiver argument |  3056   // esp[12] = address of receiver argument | 
|  3057   // Get the arguments boilerplate from the current (global) context into edi. |  3057   // Get the arguments boilerplate from the current (global) context into edi. | 
|  3058   Label has_mapped_parameters, copy; |  3058   Label has_mapped_parameters, copy; | 
|  3059   __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |  3059   __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 
|  3060   __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); |  3060   __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); | 
|  3061   __ mov(ebx, Operand(esp, 0 * kPointerSize)); |  3061   __ mov(ebx, Operand(esp, 0 * kPointerSize)); | 
|  3062   __ test(ebx, Operand(ebx)); |  3062   __ test(ebx, ebx); | 
|  3063   __ j(not_zero, &has_mapped_parameters, Label::kNear); |  3063   __ j(not_zero, &has_mapped_parameters, Label::kNear); | 
|  3064   __ mov(edi, Operand(edi, |  3064   __ mov(edi, Operand(edi, | 
|  3065          Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); |  3065          Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); | 
|  3066   __ jmp(©, Label::kNear); |  3066   __ jmp(©, Label::kNear); | 
|  3067  |  3067  | 
|  3068   __ bind(&has_mapped_parameters); |  3068   __ bind(&has_mapped_parameters); | 
|  3069   __ mov(edi, Operand(edi, |  3069   __ mov(edi, Operand(edi, | 
|  3070             Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); |  3070             Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); | 
|  3071   __ bind(©); |  3071   __ bind(©); | 
|  3072  |  3072  | 
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  3107   // ecx = argument count (tagged) |  3107   // ecx = argument count (tagged) | 
|  3108   // edi = address of parameter map or backing store (tagged) |  3108   // edi = address of parameter map or backing store (tagged) | 
|  3109   // esp[0] = mapped parameter count (tagged) |  3109   // esp[0] = mapped parameter count (tagged) | 
|  3110   // esp[8] = parameter count (tagged) |  3110   // esp[8] = parameter count (tagged) | 
|  3111   // esp[12] = address of receiver argument |  3111   // esp[12] = address of receiver argument | 
|  3112   // Free a register. |  3112   // Free a register. | 
|  3113   __ push(eax); |  3113   __ push(eax); | 
|  3114  |  3114  | 
|  3115   // Initialize parameter map. If there are no mapped arguments, we're done. |  3115   // Initialize parameter map. If there are no mapped arguments, we're done. | 
|  3116   Label skip_parameter_map; |  3116   Label skip_parameter_map; | 
|  3117   __ test(ebx, Operand(ebx)); |  3117   __ test(ebx, ebx); | 
|  3118   __ j(zero, &skip_parameter_map); |  3118   __ j(zero, &skip_parameter_map); | 
|  3119  |  3119  | 
|  3120   __ mov(FieldOperand(edi, FixedArray::kMapOffset), |  3120   __ mov(FieldOperand(edi, FixedArray::kMapOffset), | 
|  3121          Immediate(FACTORY->non_strict_arguments_elements_map())); |  3121          Immediate(FACTORY->non_strict_arguments_elements_map())); | 
|  3122   __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); |  3122   __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); | 
|  3123   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); |  3123   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); | 
|  3124   __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); |  3124   __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); | 
|  3125   __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); |  3125   __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); | 
|  3126   __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); |  3126   __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); | 
|  3127  |  3127  | 
|  3128   // Copy the parameter slots and the holes in the arguments. |  3128   // Copy the parameter slots and the holes in the arguments. | 
|  3129   // We need to fill in mapped_parameter_count slots. They index the context, |  3129   // We need to fill in mapped_parameter_count slots. They index the context, | 
|  3130   // where parameters are stored in reverse order, at |  3130   // where parameters are stored in reverse order, at | 
|  3131   //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 |  3131   //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 | 
|  3132   // The mapped parameter thus need to get indices |  3132   // The mapped parameter thus need to get indices | 
|  3133   //   MIN_CONTEXT_SLOTS+parameter_count-1 .. |  3133   //   MIN_CONTEXT_SLOTS+parameter_count-1 .. | 
|  3134   //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count |  3134   //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count | 
|  3135   // We loop from right to left. |  3135   // We loop from right to left. | 
|  3136   Label parameters_loop, parameters_test; |  3136   Label parameters_loop, parameters_test; | 
|  3137   __ push(ecx); |  3137   __ push(ecx); | 
|  3138   __ mov(eax, Operand(esp, 2 * kPointerSize)); |  3138   __ mov(eax, Operand(esp, 2 * kPointerSize)); | 
|  3139   __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); |  3139   __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); | 
|  3140   __ add(ebx, Operand(esp, 4 * kPointerSize)); |  3140   __ add(ebx, Operand(esp, 4 * kPointerSize)); | 
|  3141   __ sub(ebx, Operand(eax)); |  3141   __ sub(ebx, eax); | 
|  3142   __ mov(ecx, FACTORY->the_hole_value()); |  3142   __ mov(ecx, FACTORY->the_hole_value()); | 
|  3143   __ mov(edx, edi); |  3143   __ mov(edx, edi); | 
|  3144   __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); |  3144   __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); | 
|  3145   // eax = loop variable (tagged) |  3145   // eax = loop variable (tagged) | 
|  3146   // ebx = mapping index (tagged) |  3146   // ebx = mapping index (tagged) | 
|  3147   // ecx = the hole value |  3147   // ecx = the hole value | 
|  3148   // edx = address of parameter map (tagged) |  3148   // edx = address of parameter map (tagged) | 
|  3149   // edi = address of backing store (tagged) |  3149   // edi = address of backing store (tagged) | 
|  3150   // esp[0] = argument count (tagged) |  3150   // esp[0] = argument count (tagged) | 
|  3151   // esp[4] = address of new object (tagged) |  3151   // esp[4] = address of new object (tagged) | 
|  3152   // esp[8] = mapped parameter count (tagged) |  3152   // esp[8] = mapped parameter count (tagged) | 
|  3153   // esp[16] = parameter count (tagged) |  3153   // esp[16] = parameter count (tagged) | 
|  3154   // esp[20] = address of receiver argument |  3154   // esp[20] = address of receiver argument | 
|  3155   __ jmp(¶meters_test, Label::kNear); |  3155   __ jmp(¶meters_test, Label::kNear); | 
|  3156  |  3156  | 
|  3157   __ bind(¶meters_loop); |  3157   __ bind(¶meters_loop); | 
|  3158   __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |  3158   __ sub(eax, Immediate(Smi::FromInt(1))); | 
|  3159   __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); |  3159   __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); | 
|  3160   __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); |  3160   __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); | 
|  3161   __ add(Operand(ebx), Immediate(Smi::FromInt(1))); |  3161   __ add(ebx, Immediate(Smi::FromInt(1))); | 
|  3162   __ bind(¶meters_test); |  3162   __ bind(¶meters_test); | 
|  3163   __ test(eax, Operand(eax)); |  3163   __ test(eax, eax); | 
|  3164   __ j(not_zero, ¶meters_loop, Label::kNear); |  3164   __ j(not_zero, ¶meters_loop, Label::kNear); | 
|  3165   __ pop(ecx); |  3165   __ pop(ecx); | 
|  3166  |  3166  | 
|  3167   __ bind(&skip_parameter_map); |  3167   __ bind(&skip_parameter_map); | 
|  3168  |  3168  | 
|  3169   // ecx = argument count (tagged) |  3169   // ecx = argument count (tagged) | 
|  3170   // edi = address of backing store (tagged) |  3170   // edi = address of backing store (tagged) | 
|  3171   // esp[0] = address of new object (tagged) |  3171   // esp[0] = address of new object (tagged) | 
|  3172   // esp[4] = mapped parameter count (tagged) |  3172   // esp[4] = mapped parameter count (tagged) | 
|  3173   // esp[12] = parameter count (tagged) |  3173   // esp[12] = parameter count (tagged) | 
|  3174   // esp[16] = address of receiver argument |  3174   // esp[16] = address of receiver argument | 
|  3175   // Copy arguments header and remaining slots (if there are any). |  3175   // Copy arguments header and remaining slots (if there are any). | 
|  3176   __ mov(FieldOperand(edi, FixedArray::kMapOffset), |  3176   __ mov(FieldOperand(edi, FixedArray::kMapOffset), | 
|  3177          Immediate(FACTORY->fixed_array_map())); |  3177          Immediate(FACTORY->fixed_array_map())); | 
|  3178   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); |  3178   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); | 
|  3179  |  3179  | 
|  3180   Label arguments_loop, arguments_test; |  3180   Label arguments_loop, arguments_test; | 
|  3181   __ mov(ebx, Operand(esp, 1 * kPointerSize)); |  3181   __ mov(ebx, Operand(esp, 1 * kPointerSize)); | 
|  3182   __ mov(edx, Operand(esp, 4 * kPointerSize)); |  3182   __ mov(edx, Operand(esp, 4 * kPointerSize)); | 
|  3183   __ sub(Operand(edx), ebx);  // Is there a smarter way to do negative scaling? |  3183   __ sub(edx, ebx);  // Is there a smarter way to do negative scaling? | 
|  3184   __ sub(Operand(edx), ebx); |  3184   __ sub(edx, ebx); | 
|  3185   __ jmp(&arguments_test, Label::kNear); |  3185   __ jmp(&arguments_test, Label::kNear); | 
|  3186  |  3186  | 
|  3187   __ bind(&arguments_loop); |  3187   __ bind(&arguments_loop); | 
|  3188   __ sub(Operand(edx), Immediate(kPointerSize)); |  3188   __ sub(edx, Immediate(kPointerSize)); | 
|  3189   __ mov(eax, Operand(edx, 0)); |  3189   __ mov(eax, Operand(edx, 0)); | 
|  3190   __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); |  3190   __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); | 
|  3191   __ add(Operand(ebx), Immediate(Smi::FromInt(1))); |  3191   __ add(ebx, Immediate(Smi::FromInt(1))); | 
|  3192  |  3192  | 
|  3193   __ bind(&arguments_test); |  3193   __ bind(&arguments_test); | 
|  3194   __ cmp(ebx, Operand(ecx)); |  3194   __ cmp(ebx, ecx); | 
|  3195   __ j(less, &arguments_loop, Label::kNear); |  3195   __ j(less, &arguments_loop, Label::kNear); | 
|  3196  |  3196  | 
|  3197   // Restore. |  3197   // Restore. | 
|  3198   __ pop(eax);  // Address of arguments object. |  3198   __ pop(eax);  // Address of arguments object. | 
|  3199   __ pop(ebx);  // Parameter count. |  3199   __ pop(ebx);  // Parameter count. | 
|  3200  |  3200  | 
|  3201   // Return and remove the on-stack parameters. |  3201   // Return and remove the on-stack parameters. | 
|  3202   __ ret(3 * kPointerSize); |  3202   __ ret(3 * kPointerSize); | 
|  3203  |  3203  | 
|  3204   // Do the runtime call to allocate the arguments object. |  3204   // Do the runtime call to allocate the arguments object. | 
|  3205   __ bind(&runtime); |  3205   __ bind(&runtime); | 
|  3206   __ pop(eax);  // Remove saved parameter count. |  3206   __ pop(eax);  // Remove saved parameter count. | 
|  3207   __ mov(Operand(esp, 1 * kPointerSize), ecx);  // Patch argument count. |  3207   __ mov(Operand(esp, 1 * kPointerSize), ecx);  // Patch argument count. | 
|  3208   __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |  3208   __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); | 
|  3209 } |  3209 } | 
|  3210  |  3210  | 
|  3211  |  3211  | 
|  3212 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { |  3212 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { | 
|  3213   // esp[0] : return address |  3213   // esp[0] : return address | 
|  3214   // esp[4] : number of parameters |  3214   // esp[4] : number of parameters | 
|  3215   // esp[8] : receiver displacement |  3215   // esp[8] : receiver displacement | 
|  3216   // esp[12] : function |  3216   // esp[12] : function | 
|  3217  |  3217  | 
|  3218   // Check if the calling frame is an arguments adaptor frame. |  3218   // Check if the calling frame is an arguments adaptor frame. | 
|  3219   Label adaptor_frame, try_allocate, runtime; |  3219   Label adaptor_frame, try_allocate, runtime; | 
|  3220   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |  3220   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 
|  3221   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |  3221   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); | 
|  3222   __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |  3222   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 
|  3223   __ j(equal, &adaptor_frame, Label::kNear); |  3223   __ j(equal, &adaptor_frame, Label::kNear); | 
|  3224  |  3224  | 
|  3225   // Get the length from the frame. |  3225   // Get the length from the frame. | 
|  3226   __ mov(ecx, Operand(esp, 1 * kPointerSize)); |  3226   __ mov(ecx, Operand(esp, 1 * kPointerSize)); | 
|  3227   __ jmp(&try_allocate, Label::kNear); |  3227   __ jmp(&try_allocate, Label::kNear); | 
|  3228  |  3228  | 
|  3229   // Patch the arguments.length and the parameters pointer. |  3229   // Patch the arguments.length and the parameters pointer. | 
|  3230   __ bind(&adaptor_frame); |  3230   __ bind(&adaptor_frame); | 
|  3231   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |  3231   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 
|  3232   __ mov(Operand(esp, 1 * kPointerSize), ecx); |  3232   __ mov(Operand(esp, 1 * kPointerSize), ecx); | 
|  3233   __ lea(edx, Operand(edx, ecx, times_2, |  3233   __ lea(edx, Operand(edx, ecx, times_2, | 
|  3234                       StandardFrameConstants::kCallerSPOffset)); |  3234                       StandardFrameConstants::kCallerSPOffset)); | 
|  3235   __ mov(Operand(esp, 2 * kPointerSize), edx); |  3235   __ mov(Operand(esp, 2 * kPointerSize), edx); | 
|  3236  |  3236  | 
|  3237   // Try the new space allocation. Start out with computing the size of |  3237   // Try the new space allocation. Start out with computing the size of | 
|  3238   // the arguments object and the elements array. |  3238   // the arguments object and the elements array. | 
|  3239   Label add_arguments_object; |  3239   Label add_arguments_object; | 
|  3240   __ bind(&try_allocate); |  3240   __ bind(&try_allocate); | 
|  3241   __ test(ecx, Operand(ecx)); |  3241   __ test(ecx, ecx); | 
|  3242   __ j(zero, &add_arguments_object, Label::kNear); |  3242   __ j(zero, &add_arguments_object, Label::kNear); | 
|  3243   __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); |  3243   __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); | 
|  3244   __ bind(&add_arguments_object); |  3244   __ bind(&add_arguments_object); | 
|  3245   __ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSizeStrict)); |  3245   __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict)); | 
|  3246  |  3246  | 
|  3247   // Do the allocation of both objects in one go. |  3247   // Do the allocation of both objects in one go. | 
|  3248   __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); |  3248   __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); | 
|  3249  |  3249  | 
|  3250   // Get the arguments boilerplate from the current (global) context. |  3250   // Get the arguments boilerplate from the current (global) context. | 
|  3251   __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |  3251   __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 
|  3252   __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); |  3252   __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); | 
|  3253   const int offset = |  3253   const int offset = | 
|  3254       Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); |  3254       Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); | 
|  3255   __ mov(edi, Operand(edi, offset)); |  3255   __ mov(edi, Operand(edi, offset)); | 
|  3256  |  3256  | 
|  3257   // Copy the JS object part. |  3257   // Copy the JS object part. | 
|  3258   for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |  3258   for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { | 
|  3259     __ mov(ebx, FieldOperand(edi, i)); |  3259     __ mov(ebx, FieldOperand(edi, i)); | 
|  3260     __ mov(FieldOperand(eax, i), ebx); |  3260     __ mov(FieldOperand(eax, i), ebx); | 
|  3261   } |  3261   } | 
|  3262  |  3262  | 
|  3263   // Get the length (smi tagged) and set that as an in-object property too. |  3263   // Get the length (smi tagged) and set that as an in-object property too. | 
|  3264   STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |  3264   STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); | 
|  3265   __ mov(ecx, Operand(esp, 1 * kPointerSize)); |  3265   __ mov(ecx, Operand(esp, 1 * kPointerSize)); | 
|  3266   __ mov(FieldOperand(eax, JSObject::kHeaderSize + |  3266   __ mov(FieldOperand(eax, JSObject::kHeaderSize + | 
|  3267                       Heap::kArgumentsLengthIndex * kPointerSize), |  3267                       Heap::kArgumentsLengthIndex * kPointerSize), | 
|  3268          ecx); |  3268          ecx); | 
|  3269  |  3269  | 
|  3270   // If there are no actual arguments, we're done. |  3270   // If there are no actual arguments, we're done. | 
|  3271   Label done; |  3271   Label done; | 
|  3272   __ test(ecx, Operand(ecx)); |  3272   __ test(ecx, ecx); | 
|  3273   __ j(zero, &done, Label::kNear); |  3273   __ j(zero, &done, Label::kNear); | 
|  3274  |  3274  | 
|  3275   // Get the parameters pointer from the stack. |  3275   // Get the parameters pointer from the stack. | 
|  3276   __ mov(edx, Operand(esp, 2 * kPointerSize)); |  3276   __ mov(edx, Operand(esp, 2 * kPointerSize)); | 
|  3277  |  3277  | 
|  3278   // Setup the elements pointer in the allocated arguments object and |  3278   // Setup the elements pointer in the allocated arguments object and | 
|  3279   // initialize the header in the elements fixed array. |  3279   // initialize the header in the elements fixed array. | 
|  3280   __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); |  3280   __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); | 
|  3281   __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); |  3281   __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); | 
|  3282   __ mov(FieldOperand(edi, FixedArray::kMapOffset), |  3282   __ mov(FieldOperand(edi, FixedArray::kMapOffset), | 
|  3283          Immediate(FACTORY->fixed_array_map())); |  3283          Immediate(FACTORY->fixed_array_map())); | 
|  3284  |  3284  | 
|  3285   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); |  3285   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); | 
|  3286   // Untag the length for the loop below. |  3286   // Untag the length for the loop below. | 
|  3287   __ SmiUntag(ecx); |  3287   __ SmiUntag(ecx); | 
|  3288  |  3288  | 
|  3289   // Copy the fixed array slots. |  3289   // Copy the fixed array slots. | 
|  3290   Label loop; |  3290   Label loop; | 
|  3291   __ bind(&loop); |  3291   __ bind(&loop); | 
|  3292   __ mov(ebx, Operand(edx, -1 * kPointerSize));  // Skip receiver. |  3292   __ mov(ebx, Operand(edx, -1 * kPointerSize));  // Skip receiver. | 
|  3293   __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); |  3293   __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); | 
|  3294   __ add(Operand(edi), Immediate(kPointerSize)); |  3294   __ add(edi, Immediate(kPointerSize)); | 
|  3295   __ sub(Operand(edx), Immediate(kPointerSize)); |  3295   __ sub(edx, Immediate(kPointerSize)); | 
|  3296   __ dec(ecx); |  3296   __ dec(ecx); | 
|  3297   __ j(not_zero, &loop); |  3297   __ j(not_zero, &loop); | 
|  3298  |  3298  | 
|  3299   // Return and remove the on-stack parameters. |  3299   // Return and remove the on-stack parameters. | 
|  3300   __ bind(&done); |  3300   __ bind(&done); | 
|  3301   __ ret(3 * kPointerSize); |  3301   __ ret(3 * kPointerSize); | 
|  3302  |  3302  | 
|  3303   // Do the runtime call to allocate the arguments object. |  3303   // Do the runtime call to allocate the arguments object. | 
|  3304   __ bind(&runtime); |  3304   __ bind(&runtime); | 
|  3305   __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |  3305   __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
|  3332  |  3332  | 
|  3333   Label runtime, invoke_regexp; |  3333   Label runtime, invoke_regexp; | 
|  3334  |  3334  | 
|  3335   // Ensure that a RegExp stack is allocated. |  3335   // Ensure that a RegExp stack is allocated. | 
|  3336   ExternalReference address_of_regexp_stack_memory_address = |  3336   ExternalReference address_of_regexp_stack_memory_address = | 
|  3337       ExternalReference::address_of_regexp_stack_memory_address( |  3337       ExternalReference::address_of_regexp_stack_memory_address( | 
|  3338           masm->isolate()); |  3338           masm->isolate()); | 
|  3339   ExternalReference address_of_regexp_stack_memory_size = |  3339   ExternalReference address_of_regexp_stack_memory_size = | 
|  3340       ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); |  3340       ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); | 
|  3341   __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |  3341   __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | 
|  3342   __ test(ebx, Operand(ebx)); |  3342   __ test(ebx, ebx); | 
|  3343   __ j(zero, &runtime); |  3343   __ j(zero, &runtime); | 
|  3344  |  3344  | 
|  3345   // Check that the first argument is a JSRegExp object. |  3345   // Check that the first argument is a JSRegExp object. | 
|  3346   __ mov(eax, Operand(esp, kJSRegExpOffset)); |  3346   __ mov(eax, Operand(esp, kJSRegExpOffset)); | 
|  3347   STATIC_ASSERT(kSmiTag == 0); |  3347   STATIC_ASSERT(kSmiTag == 0); | 
|  3348   __ JumpIfSmi(eax, &runtime); |  3348   __ JumpIfSmi(eax, &runtime); | 
|  3349   __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); |  3349   __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); | 
|  3350   __ j(not_equal, &runtime); |  3350   __ j(not_equal, &runtime); | 
|  3351   // Check that the RegExp has been compiled (data contains a fixed array). |  3351   // Check that the RegExp has been compiled (data contains a fixed array). | 
|  3352   __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |  3352   __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | 
|  3353   if (FLAG_debug_code) { |  3353   if (FLAG_debug_code) { | 
|  3354     __ test(ecx, Immediate(kSmiTagMask)); |  3354     __ test(ecx, Immediate(kSmiTagMask)); | 
|  3355     __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); |  3355     __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); | 
|  3356     __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); |  3356     __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); | 
|  3357     __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); |  3357     __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); | 
|  3358   } |  3358   } | 
|  3359  |  3359  | 
|  3360   // ecx: RegExp data (FixedArray) |  3360   // ecx: RegExp data (FixedArray) | 
|  3361   // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |  3361   // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 
|  3362   __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); |  3362   __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); | 
|  3363   __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); |  3363   __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); | 
|  3364   __ j(not_equal, &runtime); |  3364   __ j(not_equal, &runtime); | 
|  3365  |  3365  | 
|  3366   // ecx: RegExp data (FixedArray) |  3366   // ecx: RegExp data (FixedArray) | 
|  3367   // Check that the number of captures fit in the static offsets vector buffer. |  3367   // Check that the number of captures fit in the static offsets vector buffer. | 
|  3368   __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |  3368   __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | 
|  3369   // Calculate number of capture registers (number_of_captures + 1) * 2. This |  3369   // Calculate number of capture registers (number_of_captures + 1) * 2. This | 
|  3370   // uses the asumption that smis are 2 * their untagged value. |  3370   // uses the asumption that smis are 2 * their untagged value. | 
|  3371   STATIC_ASSERT(kSmiTag == 0); |  3371   STATIC_ASSERT(kSmiTag == 0); | 
|  3372   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |  3372   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 
|  3373   __ add(Operand(edx), Immediate(2));  // edx was a smi. |  3373   __ add(edx, Immediate(2));  // edx was a smi. | 
|  3374   // Check that the static offsets vector buffer is large enough. |  3374   // Check that the static offsets vector buffer is large enough. | 
|  3375   __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); |  3375   __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); | 
|  3376   __ j(above, &runtime); |  3376   __ j(above, &runtime); | 
|  3377  |  3377  | 
|  3378   // ecx: RegExp data (FixedArray) |  3378   // ecx: RegExp data (FixedArray) | 
|  3379   // edx: Number of capture registers |  3379   // edx: Number of capture registers | 
|  3380   // Check that the second argument is a string. |  3380   // Check that the second argument is a string. | 
|  3381   __ mov(eax, Operand(esp, kSubjectOffset)); |  3381   __ mov(eax, Operand(esp, kSubjectOffset)); | 
|  3382   __ JumpIfSmi(eax, &runtime); |  3382   __ JumpIfSmi(eax, &runtime); | 
|  3383   Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |  3383   Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); | 
|  3384   __ j(NegateCondition(is_string), &runtime); |  3384   __ j(NegateCondition(is_string), &runtime); | 
|  3385   // Get the length of the string to ebx. |  3385   // Get the length of the string to ebx. | 
|  3386   __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |  3386   __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 
|  3387  |  3387  | 
|  3388   // ebx: Length of subject string as a smi |  3388   // ebx: Length of subject string as a smi | 
|  3389   // ecx: RegExp data (FixedArray) |  3389   // ecx: RegExp data (FixedArray) | 
|  3390   // edx: Number of capture registers |  3390   // edx: Number of capture registers | 
|  3391   // Check that the third argument is a positive smi less than the subject |  3391   // Check that the third argument is a positive smi less than the subject | 
|  3392   // string length. A negative value will be greater (unsigned comparison). |  3392   // string length. A negative value will be greater (unsigned comparison). | 
|  3393   __ mov(eax, Operand(esp, kPreviousIndexOffset)); |  3393   __ mov(eax, Operand(esp, kPreviousIndexOffset)); | 
|  3394   __ JumpIfNotSmi(eax, &runtime); |  3394   __ JumpIfNotSmi(eax, &runtime); | 
|  3395   __ cmp(eax, Operand(ebx)); |  3395   __ cmp(eax, ebx); | 
|  3396   __ j(above_equal, &runtime); |  3396   __ j(above_equal, &runtime); | 
|  3397  |  3397  | 
|  3398   // ecx: RegExp data (FixedArray) |  3398   // ecx: RegExp data (FixedArray) | 
|  3399   // edx: Number of capture registers |  3399   // edx: Number of capture registers | 
|  3400   // Check that the fourth object is a JSArray object. |  3400   // Check that the fourth object is a JSArray object. | 
|  3401   __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |  3401   __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 
|  3402   __ JumpIfSmi(eax, &runtime); |  3402   __ JumpIfSmi(eax, &runtime); | 
|  3403   __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |  3403   __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); | 
|  3404   __ j(not_equal, &runtime); |  3404   __ j(not_equal, &runtime); | 
|  3405   // Check that the JSArray is in fast case. |  3405   // Check that the JSArray is in fast case. | 
|  3406   __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |  3406   __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); | 
|  3407   __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); |  3407   __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); | 
|  3408   Factory* factory = masm->isolate()->factory(); |  3408   Factory* factory = masm->isolate()->factory(); | 
|  3409   __ cmp(eax, factory->fixed_array_map()); |  3409   __ cmp(eax, factory->fixed_array_map()); | 
|  3410   __ j(not_equal, &runtime); |  3410   __ j(not_equal, &runtime); | 
|  3411   // Check that the last match info has space for the capture registers and the |  3411   // Check that the last match info has space for the capture registers and the | 
|  3412   // additional information. |  3412   // additional information. | 
|  3413   __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); |  3413   __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); | 
|  3414   __ SmiUntag(eax); |  3414   __ SmiUntag(eax); | 
|  3415   __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); |  3415   __ add(edx, Immediate(RegExpImpl::kLastMatchOverhead)); | 
|  3416   __ cmp(edx, Operand(eax)); |  3416   __ cmp(edx, eax); | 
|  3417   __ j(greater, &runtime); |  3417   __ j(greater, &runtime); | 
|  3418  |  3418  | 
|  3419   // Reset offset for possibly sliced string. |  3419   // Reset offset for possibly sliced string. | 
|  3420   __ Set(edi, Immediate(0)); |  3420   __ Set(edi, Immediate(0)); | 
|  3421   // ecx: RegExp data (FixedArray) |  3421   // ecx: RegExp data (FixedArray) | 
|  3422   // Check the representation and encoding of the subject string. |  3422   // Check the representation and encoding of the subject string. | 
|  3423   Label seq_ascii_string, seq_two_byte_string, check_code; |  3423   Label seq_ascii_string, seq_two_byte_string, check_code; | 
|  3424   __ mov(eax, Operand(esp, kSubjectOffset)); |  3424   __ mov(eax, Operand(esp, kSubjectOffset)); | 
|  3425   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |  3425   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 
|  3426   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |  3426   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 
|  3427   // First check for flat two byte string. |  3427   // First check for flat two byte string. | 
|  3428   __ and_(ebx, |  3428   __ and_(ebx, | 
|  3429           kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); |  3429           kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); | 
|  3430   STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |  3430   STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | 
|  3431   __ j(zero, &seq_two_byte_string, Label::kNear); |  3431   __ j(zero, &seq_two_byte_string, Label::kNear); | 
|  3432   // Any other flat string must be a flat ascii string. |  3432   // Any other flat string must be a flat ascii string. | 
|  3433   __ and_(Operand(ebx), |  3433   __ and_(ebx, Immediate(kIsNotStringMask | kStringRepresentationMask)); | 
|  3434           Immediate(kIsNotStringMask | kStringRepresentationMask)); |  | 
|  3435   __ j(zero, &seq_ascii_string, Label::kNear); |  3434   __ j(zero, &seq_ascii_string, Label::kNear); | 
|  3436  |  3435  | 
|  3437   // Check for flat cons string or sliced string. |  3436   // Check for flat cons string or sliced string. | 
|  3438   // A flat cons string is a cons string where the second part is the empty |  3437   // A flat cons string is a cons string where the second part is the empty | 
|  3439   // string. In that case the subject string is just the first part of the cons |  3438   // string. In that case the subject string is just the first part of the cons | 
|  3440   // string. Also in this case the first part of the cons string is known to be |  3439   // string. Also in this case the first part of the cons string is known to be | 
|  3441   // a sequential string or an external string. |  3440   // a sequential string or an external string. | 
|  3442   // In the case of a sliced string its offset has to be taken into account. |  3441   // In the case of a sliced string its offset has to be taken into account. | 
|  3443   Label cons_string, check_encoding; |  3442   Label cons_string, check_encoding; | 
|  3444   STATIC_ASSERT(kConsStringTag < kExternalStringTag); |  3443   STATIC_ASSERT(kConsStringTag < kExternalStringTag); | 
|  3445   STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |  3444   STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | 
|  3446   __ cmp(Operand(ebx), Immediate(kExternalStringTag)); |  3445   __ cmp(ebx, Immediate(kExternalStringTag)); | 
|  3447   __ j(less, &cons_string); |  3446   __ j(less, &cons_string); | 
|  3448   __ j(equal, &runtime); |  3447   __ j(equal, &runtime); | 
|  3449  |  3448  | 
|  3450   // String is sliced. |  3449   // String is sliced. | 
|  3451   __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); |  3450   __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); | 
|  3452   __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); |  3451   __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); | 
|  3453   // edi: offset of sliced string, smi-tagged. |  3452   // edi: offset of sliced string, smi-tagged. | 
|  3454   // eax: parent string. |  3453   // eax: parent string. | 
|  3455   __ jmp(&check_encoding, Label::kNear); |  3454   __ jmp(&check_encoding, Label::kNear); | 
|  3456   // String is a cons string, check whether it is flat. |  3455   // String is a cons string, check whether it is flat. | 
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  3542   // esi: original subject string |  3541   // esi: original subject string | 
|  3543   // eax: underlying subject string |  3542   // eax: underlying subject string | 
|  3544   // ebx: previous index |  3543   // ebx: previous index | 
|  3545   // ecx: encoding of subject string (1 if ascii 0 if two_byte); |  3544   // ecx: encoding of subject string (1 if ascii 0 if two_byte); | 
|  3546   // edx: code |  3545   // edx: code | 
|  3547   // Argument 4: End of string data |  3546   // Argument 4: End of string data | 
|  3548   // Argument 3: Start of string data |  3547   // Argument 3: Start of string data | 
|  3549   // Prepare start and end index of the input. |  3548   // Prepare start and end index of the input. | 
|  3550   // Load the length from the original sliced string if that is the case. |  3549   // Load the length from the original sliced string if that is the case. | 
|  3551   __ mov(esi, FieldOperand(esi, String::kLengthOffset)); |  3550   __ mov(esi, FieldOperand(esi, String::kLengthOffset)); | 
|  3552   __ add(esi, Operand(edi));  // Calculate input end wrt offset. |  3551   __ add(esi, edi);  // Calculate input end wrt offset. | 
|  3553   __ SmiUntag(edi); |  3552   __ SmiUntag(edi); | 
|  3554   __ add(ebx, Operand(edi));  // Calculate input start wrt offset. |  3553   __ add(ebx, edi);  // Calculate input start wrt offset. | 
|  3555  |  3554  | 
|  3556   // ebx: start index of the input string |  3555   // ebx: start index of the input string | 
|  3557   // esi: end index of the input string |  3556   // esi: end index of the input string | 
|  3558   Label setup_two_byte, setup_rest; |  3557   Label setup_two_byte, setup_rest; | 
|  3559   __ test(ecx, Operand(ecx)); |  3558   __ test(ecx, ecx); | 
|  3560   __ j(zero, &setup_two_byte, Label::kNear); |  3559   __ j(zero, &setup_two_byte, Label::kNear); | 
|  3561   __ SmiUntag(esi); |  3560   __ SmiUntag(esi); | 
|  3562   __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize)); |  3561   __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize)); | 
|  3563   __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4. |  3562   __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4. | 
|  3564   __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |  3563   __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 
|  3565   __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3. |  3564   __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3. | 
|  3566   __ jmp(&setup_rest, Label::kNear); |  3565   __ jmp(&setup_rest, Label::kNear); | 
|  3567  |  3566  | 
|  3568   __ bind(&setup_two_byte); |  3567   __ bind(&setup_two_byte); | 
|  3569   STATIC_ASSERT(kSmiTag == 0); |  3568   STATIC_ASSERT(kSmiTag == 0); | 
|  3570   STATIC_ASSERT(kSmiTagSize == 1);  // esi is smi (powered by 2). |  3569   STATIC_ASSERT(kSmiTagSize == 1);  // esi is smi (powered by 2). | 
|  3571   __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); |  3570   __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); | 
|  3572   __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4. |  3571   __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4. | 
|  3573   __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); |  3572   __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | 
|  3574   __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3. |  3573   __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3. | 
|  3575  |  3574  | 
|  3576   __ bind(&setup_rest); |  3575   __ bind(&setup_rest); | 
|  3577  |  3576  | 
|  3578   // Locate the code entry and call it. |  3577   // Locate the code entry and call it. | 
|  3579   __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); |  3578   __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 
|  3580   __ call(Operand(edx)); |  3579   __ call(edx); | 
|  3581  |  3580  | 
|  3582   // Drop arguments and come back to JS mode. |  3581   // Drop arguments and come back to JS mode. | 
|  3583   __ LeaveApiExitFrame(); |  3582   __ LeaveApiExitFrame(); | 
|  3584  |  3583  | 
|  3585   // Check the result. |  3584   // Check the result. | 
|  3586   Label success; |  3585   Label success; | 
|  3587   __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); |  3586   __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); | 
|  3588   __ j(equal, &success); |  3587   __ j(equal, &success); | 
|  3589   Label failure; |  3588   Label failure; | 
|  3590   __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); |  3589   __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); | 
|  3591   __ j(equal, &failure); |  3590   __ j(equal, &failure); | 
|  3592   __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); |  3591   __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); | 
|  3593   // If not exception it can only be retry. Handle that in the runtime system. |  3592   // If not exception it can only be retry. Handle that in the runtime system. | 
|  3594   __ j(not_equal, &runtime); |  3593   __ j(not_equal, &runtime); | 
|  3595   // Result must now be exception. If there is no pending exception already a |  3594   // Result must now be exception. If there is no pending exception already a | 
|  3596   // stack overflow (on the backtrack stack) was detected in RegExp code but |  3595   // stack overflow (on the backtrack stack) was detected in RegExp code but | 
|  3597   // haven't created the exception yet. Handle that in the runtime system. |  3596   // haven't created the exception yet. Handle that in the runtime system. | 
|  3598   // TODO(592): Rerunning the RegExp to get the stack overflow exception. |  3597   // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 
|  3599   ExternalReference pending_exception(Isolate::kPendingExceptionAddress, |  3598   ExternalReference pending_exception(Isolate::kPendingExceptionAddress, | 
|  3600                                       masm->isolate()); |  3599                                       masm->isolate()); | 
|  3601   __ mov(edx, |  3600   __ mov(edx, | 
|  3602          Operand::StaticVariable(ExternalReference::the_hole_value_location( |  3601          Operand::StaticVariable(ExternalReference::the_hole_value_location( | 
|  3603              masm->isolate()))); |  3602              masm->isolate()))); | 
|  3604   __ mov(eax, Operand::StaticVariable(pending_exception)); |  3603   __ mov(eax, Operand::StaticVariable(pending_exception)); | 
|  3605   __ cmp(edx, Operand(eax)); |  3604   __ cmp(edx, eax); | 
|  3606   __ j(equal, &runtime); |  3605   __ j(equal, &runtime); | 
|  3607   // For exception, throw the exception again. |  3606   // For exception, throw the exception again. | 
|  3608  |  3607  | 
|  3609   // Clear the pending exception variable. |  3608   // Clear the pending exception variable. | 
|  3610   __ mov(Operand::StaticVariable(pending_exception), edx); |  3609   __ mov(Operand::StaticVariable(pending_exception), edx); | 
|  3611  |  3610  | 
|  3612   // Special handling of termination exceptions which are uncatchable |  3611   // Special handling of termination exceptions which are uncatchable | 
|  3613   // by javascript code. |  3612   // by javascript code. | 
|  3614   __ cmp(eax, factory->termination_exception()); |  3613   __ cmp(eax, factory->termination_exception()); | 
|  3615   Label throw_termination_exception; |  3614   Label throw_termination_exception; | 
|  3616   __ j(equal, &throw_termination_exception, Label::kNear); |  3615   __ j(equal, &throw_termination_exception, Label::kNear); | 
|  3617  |  3616  | 
|  3618   // Handle normal exception by following handler chain. |  3617   // Handle normal exception by following handler chain. | 
|  3619   __ Throw(eax); |  3618   __ Throw(eax); | 
|  3620  |  3619  | 
|  3621   __ bind(&throw_termination_exception); |  3620   __ bind(&throw_termination_exception); | 
|  3622   __ ThrowUncatchable(TERMINATION, eax); |  3621   __ ThrowUncatchable(TERMINATION, eax); | 
|  3623  |  3622  | 
|  3624   __ bind(&failure); |  3623   __ bind(&failure); | 
|  3625   // For failure to match, return null. |  3624   // For failure to match, return null. | 
|  3626   __ mov(Operand(eax), factory->null_value()); |  3625   __ mov(eax, factory->null_value()); | 
|  3627   __ ret(4 * kPointerSize); |  3626   __ ret(4 * kPointerSize); | 
|  3628  |  3627  | 
|  3629   // Load RegExp data. |  3628   // Load RegExp data. | 
|  3630   __ bind(&success); |  3629   __ bind(&success); | 
|  3631   __ mov(eax, Operand(esp, kJSRegExpOffset)); |  3630   __ mov(eax, Operand(esp, kJSRegExpOffset)); | 
|  3632   __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |  3631   __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | 
|  3633   __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |  3632   __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | 
|  3634   // Calculate number of capture registers (number_of_captures + 1) * 2. |  3633   // Calculate number of capture registers (number_of_captures + 1) * 2. | 
|  3635   STATIC_ASSERT(kSmiTag == 0); |  3634   STATIC_ASSERT(kSmiTag == 0); | 
|  3636   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |  3635   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 
|  3637   __ add(Operand(edx), Immediate(2));  // edx was a smi. |  3636   __ add(edx, Immediate(2));  // edx was a smi. | 
|  3638  |  3637  | 
|  3639   // edx: Number of capture registers |  3638   // edx: Number of capture registers | 
|  3640   // Load last_match_info which is still known to be a fast case JSArray. |  3639   // Load last_match_info which is still known to be a fast case JSArray. | 
|  3641   __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |  3640   __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 
|  3642   __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |  3641   __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); | 
|  3643  |  3642  | 
|  3644   // ebx: last_match_info backing store (FixedArray) |  3643   // ebx: last_match_info backing store (FixedArray) | 
|  3645   // edx: number of capture registers |  3644   // edx: number of capture registers | 
|  3646   // Store the capture count. |  3645   // Store the capture count. | 
|  3647   __ SmiTag(edx);  // Number of capture registers to smi. |  3646   __ SmiTag(edx);  // Number of capture registers to smi. | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|  3668       ExternalReference::address_of_static_offsets_vector(masm->isolate()); |  3667       ExternalReference::address_of_static_offsets_vector(masm->isolate()); | 
|  3669   __ mov(ecx, Immediate(address_of_static_offsets_vector)); |  3668   __ mov(ecx, Immediate(address_of_static_offsets_vector)); | 
|  3670  |  3669  | 
|  3671   // ebx: last_match_info backing store (FixedArray) |  3670   // ebx: last_match_info backing store (FixedArray) | 
|  3672   // ecx: offsets vector |  3671   // ecx: offsets vector | 
|  3673   // edx: number of capture registers |  3672   // edx: number of capture registers | 
|  3674   Label next_capture, done; |  3673   Label next_capture, done; | 
|  3675   // Capture register counter starts from number of capture registers and |  3674   // Capture register counter starts from number of capture registers and | 
|  3676   // counts down until wraping after zero. |  3675   // counts down until wraping after zero. | 
|  3677   __ bind(&next_capture); |  3676   __ bind(&next_capture); | 
|  3678   __ sub(Operand(edx), Immediate(1)); |  3677   __ sub(edx, Immediate(1)); | 
|  3679   __ j(negative, &done, Label::kNear); |  3678   __ j(negative, &done, Label::kNear); | 
|  3680   // Read the value from the static offsets vector buffer. |  3679   // Read the value from the static offsets vector buffer. | 
|  3681   __ mov(edi, Operand(ecx, edx, times_int_size, 0)); |  3680   __ mov(edi, Operand(ecx, edx, times_int_size, 0)); | 
|  3682   __ SmiTag(edi); |  3681   __ SmiTag(edi); | 
|  3683   // Store the smi value in the last match info. |  3682   // Store the smi value in the last match info. | 
|  3684   __ mov(FieldOperand(ebx, |  3683   __ mov(FieldOperand(ebx, | 
|  3685                       edx, |  3684                       edx, | 
|  3686                       times_pointer_size, |  3685                       times_pointer_size, | 
|  3687                       RegExpImpl::kFirstCaptureOffset), |  3686                       RegExpImpl::kFirstCaptureOffset), | 
|  3688                       edi); |  3687                       edi); | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
|  3699 #endif  // V8_INTERPRETED_REGEXP |  3698 #endif  // V8_INTERPRETED_REGEXP | 
|  3700 } |  3699 } | 
|  3701  |  3700  | 
|  3702  |  3701  | 
|  3703 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { |  3702 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { | 
|  3704   const int kMaxInlineLength = 100; |  3703   const int kMaxInlineLength = 100; | 
|  3705   Label slowcase; |  3704   Label slowcase; | 
|  3706   Label done; |  3705   Label done; | 
|  3707   __ mov(ebx, Operand(esp, kPointerSize * 3)); |  3706   __ mov(ebx, Operand(esp, kPointerSize * 3)); | 
|  3708   __ JumpIfNotSmi(ebx, &slowcase); |  3707   __ JumpIfNotSmi(ebx, &slowcase); | 
|  3709   __ cmp(Operand(ebx), Immediate(Smi::FromInt(kMaxInlineLength))); |  3708   __ cmp(ebx, Immediate(Smi::FromInt(kMaxInlineLength))); | 
|  3710   __ j(above, &slowcase); |  3709   __ j(above, &slowcase); | 
|  3711   // Smi-tagging is equivalent to multiplying by 2. |  3710   // Smi-tagging is equivalent to multiplying by 2. | 
|  3712   STATIC_ASSERT(kSmiTag == 0); |  3711   STATIC_ASSERT(kSmiTag == 0); | 
|  3713   STATIC_ASSERT(kSmiTagSize == 1); |  3712   STATIC_ASSERT(kSmiTagSize == 1); | 
|  3714   // Allocate RegExpResult followed by FixedArray with size in ebx. |  3713   // Allocate RegExpResult followed by FixedArray with size in ebx. | 
|  3715   // JSArray:   [Map][empty properties][Elements][Length-smi][index][input] |  3714   // JSArray:   [Map][empty properties][Elements][Length-smi][index][input] | 
|  3716   // Elements:  [Map][Length][..elements..] |  3715   // Elements:  [Map][Length][..elements..] | 
|  3717   __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, |  3716   __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, | 
|  3718                         times_half_pointer_size, |  3717                         times_half_pointer_size, | 
|  3719                         ebx,  // In: Number of elements (times 2, being a smi) |  3718                         ebx,  // In: Number of elements (times 2, being a smi) | 
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  3759   // Fill contents of fixed-array with the-hole. |  3758   // Fill contents of fixed-array with the-hole. | 
|  3760   __ SmiUntag(ecx); |  3759   __ SmiUntag(ecx); | 
|  3761   __ mov(edx, Immediate(factory->the_hole_value())); |  3760   __ mov(edx, Immediate(factory->the_hole_value())); | 
|  3762   __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); |  3761   __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); | 
|  3763   // Fill fixed array elements with hole. |  3762   // Fill fixed array elements with hole. | 
|  3764   // eax: JSArray. |  3763   // eax: JSArray. | 
|  3765   // ecx: Number of elements to fill. |  3764   // ecx: Number of elements to fill. | 
|  3766   // ebx: Start of elements in FixedArray. |  3765   // ebx: Start of elements in FixedArray. | 
|  3767   // edx: the hole. |  3766   // edx: the hole. | 
|  3768   Label loop; |  3767   Label loop; | 
|  3769   __ test(ecx, Operand(ecx)); |  3768   __ test(ecx, ecx); | 
|  3770   __ bind(&loop); |  3769   __ bind(&loop); | 
|  3771   __ j(less_equal, &done, Label::kNear);  // Jump if ecx is negative or zero. |  3770   __ j(less_equal, &done, Label::kNear);  // Jump if ecx is negative or zero. | 
|  3772   __ sub(Operand(ecx), Immediate(1)); |  3771   __ sub(ecx, Immediate(1)); | 
|  3773   __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx); |  3772   __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx); | 
|  3774   __ jmp(&loop); |  3773   __ jmp(&loop); | 
|  3775  |  3774  | 
|  3776   __ bind(&done); |  3775   __ bind(&done); | 
|  3777   __ ret(3 * kPointerSize); |  3776   __ ret(3 * kPointerSize); | 
|  3778  |  3777  | 
|  3779   __ bind(&slowcase); |  3778   __ bind(&slowcase); | 
|  3780   __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); |  3779   __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); | 
|  3781 } |  3780 } | 
|  3782  |  3781  | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
|  3796   // Load the number string cache. |  3795   // Load the number string cache. | 
|  3797   ExternalReference roots_address = |  3796   ExternalReference roots_address = | 
|  3798       ExternalReference::roots_address(masm->isolate()); |  3797       ExternalReference::roots_address(masm->isolate()); | 
|  3799   __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); |  3798   __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); | 
|  3800   __ mov(number_string_cache, |  3799   __ mov(number_string_cache, | 
|  3801          Operand::StaticArray(scratch, times_pointer_size, roots_address)); |  3800          Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 
|  3802   // Make the hash mask from the length of the number string cache. It |  3801   // Make the hash mask from the length of the number string cache. It | 
|  3803   // contains two elements (number and string) for each cache entry. |  3802   // contains two elements (number and string) for each cache entry. | 
|  3804   __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); |  3803   __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); | 
|  3805   __ shr(mask, kSmiTagSize + 1);  // Untag length and divide it by two. |  3804   __ shr(mask, kSmiTagSize + 1);  // Untag length and divide it by two. | 
|  3806   __ sub(Operand(mask), Immediate(1));  // Make mask. |  3805   __ sub(mask, Immediate(1));  // Make mask. | 
|  3807  |  3806  | 
|  3808   // Calculate the entry in the number string cache. The hash value in the |  3807   // Calculate the entry in the number string cache. The hash value in the | 
|  3809   // number string cache for smis is just the smi value, and the hash for |  3808   // number string cache for smis is just the smi value, and the hash for | 
|  3810   // doubles is the xor of the upper and lower words. See |  3809   // doubles is the xor of the upper and lower words. See | 
|  3811   // Heap::GetNumberStringCache. |  3810   // Heap::GetNumberStringCache. | 
|  3812   Label smi_hash_calculated; |  3811   Label smi_hash_calculated; | 
|  3813   Label load_result_from_cache; |  3812   Label load_result_from_cache; | 
|  3814   if (object_is_smi) { |  3813   if (object_is_smi) { | 
|  3815     __ mov(scratch, object); |  3814     __ mov(scratch, object); | 
|  3816     __ SmiUntag(scratch); |  3815     __ SmiUntag(scratch); | 
|  3817   } else { |  3816   } else { | 
|  3818     Label not_smi; |  3817     Label not_smi; | 
|  3819     STATIC_ASSERT(kSmiTag == 0); |  3818     STATIC_ASSERT(kSmiTag == 0); | 
|  3820     __ JumpIfNotSmi(object, ¬_smi, Label::kNear); |  3819     __ JumpIfNotSmi(object, ¬_smi, Label::kNear); | 
|  3821     __ mov(scratch, object); |  3820     __ mov(scratch, object); | 
|  3822     __ SmiUntag(scratch); |  3821     __ SmiUntag(scratch); | 
|  3823     __ jmp(&smi_hash_calculated, Label::kNear); |  3822     __ jmp(&smi_hash_calculated, Label::kNear); | 
|  3824     __ bind(¬_smi); |  3823     __ bind(¬_smi); | 
|  3825     __ cmp(FieldOperand(object, HeapObject::kMapOffset), |  3824     __ cmp(FieldOperand(object, HeapObject::kMapOffset), | 
|  3826            masm->isolate()->factory()->heap_number_map()); |  3825            masm->isolate()->factory()->heap_number_map()); | 
|  3827     __ j(not_equal, not_found); |  3826     __ j(not_equal, not_found); | 
|  3828     STATIC_ASSERT(8 == kDoubleSize); |  3827     STATIC_ASSERT(8 == kDoubleSize); | 
|  3829     __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); |  3828     __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); | 
|  3830     __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); |  3829     __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); | 
|  3831     // Object is heap number and hash is now in scratch. Calculate cache index. |  3830     // Object is heap number and hash is now in scratch. Calculate cache index. | 
|  3832     __ and_(scratch, Operand(mask)); |  3831     __ and_(scratch, mask); | 
|  3833     Register index = scratch; |  3832     Register index = scratch; | 
|  3834     Register probe = mask; |  3833     Register probe = mask; | 
|  3835     __ mov(probe, |  3834     __ mov(probe, | 
|  3836            FieldOperand(number_string_cache, |  3835            FieldOperand(number_string_cache, | 
|  3837                         index, |  3836                         index, | 
|  3838                         times_twice_pointer_size, |  3837                         times_twice_pointer_size, | 
|  3839                         FixedArray::kHeaderSize)); |  3838                         FixedArray::kHeaderSize)); | 
|  3840     __ JumpIfSmi(probe, not_found); |  3839     __ JumpIfSmi(probe, not_found); | 
|  3841     if (CpuFeatures::IsSupported(SSE2)) { |  3840     if (CpuFeatures::IsSupported(SSE2)) { | 
|  3842       CpuFeatures::Scope fscope(SSE2); |  3841       CpuFeatures::Scope fscope(SSE2); | 
|  3843       __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); |  3842       __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); | 
|  3844       __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); |  3843       __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); | 
|  3845       __ ucomisd(xmm0, xmm1); |  3844       __ ucomisd(xmm0, xmm1); | 
|  3846     } else { |  3845     } else { | 
|  3847       __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); |  3846       __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); | 
|  3848       __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); |  3847       __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); | 
|  3849       __ FCmp(); |  3848       __ FCmp(); | 
|  3850     } |  3849     } | 
|  3851     __ j(parity_even, not_found);  // Bail out if NaN is involved. |  3850     __ j(parity_even, not_found);  // Bail out if NaN is involved. | 
|  3852     __ j(not_equal, not_found);  // The cache did not contain this value. |  3851     __ j(not_equal, not_found);  // The cache did not contain this value. | 
|  3853     __ jmp(&load_result_from_cache, Label::kNear); |  3852     __ jmp(&load_result_from_cache, Label::kNear); | 
|  3854   } |  3853   } | 
|  3855  |  3854  | 
|  3856   __ bind(&smi_hash_calculated); |  3855   __ bind(&smi_hash_calculated); | 
|  3857   // Object is smi and hash is now in scratch. Calculate cache index. |  3856   // Object is smi and hash is now in scratch. Calculate cache index. | 
|  3858   __ and_(scratch, Operand(mask)); |  3857   __ and_(scratch, mask); | 
|  3859   Register index = scratch; |  3858   Register index = scratch; | 
|  3860   // Check if the entry is the smi we are looking for. |  3859   // Check if the entry is the smi we are looking for. | 
|  3861   __ cmp(object, |  3860   __ cmp(object, | 
|  3862          FieldOperand(number_string_cache, |  3861          FieldOperand(number_string_cache, | 
|  3863                       index, |  3862                       index, | 
|  3864                       times_twice_pointer_size, |  3863                       times_twice_pointer_size, | 
|  3865                       FixedArray::kHeaderSize)); |  3864                       FixedArray::kHeaderSize)); | 
|  3866   __ j(not_equal, not_found); |  3865   __ j(not_equal, not_found); | 
|  3867  |  3866  | 
|  3868   // Get the result from the cache. |  3867   // Get the result from the cache. | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  3900 } |  3899 } | 
|  3901  |  3900  | 
|  3902 void CompareStub::Generate(MacroAssembler* masm) { |  3901 void CompareStub::Generate(MacroAssembler* masm) { | 
|  3903   ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |  3902   ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 
|  3904  |  3903  | 
|  3905   Label check_unequal_objects; |  3904   Label check_unequal_objects; | 
|  3906  |  3905  | 
|  3907   // Compare two smis if required. |  3906   // Compare two smis if required. | 
|  3908   if (include_smi_compare_) { |  3907   if (include_smi_compare_) { | 
|  3909     Label non_smi, smi_done; |  3908     Label non_smi, smi_done; | 
|  3910     __ mov(ecx, Operand(edx)); |  3909     __ mov(ecx, edx); | 
|  3911     __ or_(ecx, Operand(eax)); |  3910     __ or_(ecx, eax); | 
|  3912     __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); |  3911     __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); | 
|  3913     __ sub(edx, Operand(eax));  // Return on the result of the subtraction. |  3912     __ sub(edx, eax);  // Return on the result of the subtraction. | 
|  3914     __ j(no_overflow, &smi_done, Label::kNear); |  3913     __ j(no_overflow, &smi_done, Label::kNear); | 
|  3915     __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here. |  3914     __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here. | 
|  3916     __ bind(&smi_done); |  3915     __ bind(&smi_done); | 
|  3917     __ mov(eax, edx); |  3916     __ mov(eax, edx); | 
|  3918     __ ret(0); |  3917     __ ret(0); | 
|  3919     __ bind(&non_smi); |  3918     __ bind(&non_smi); | 
|  3920   } else if (FLAG_debug_code) { |  3919   } else if (FLAG_debug_code) { | 
|  3921     __ mov(ecx, Operand(edx)); |  3920     __ mov(ecx, edx); | 
|  3922     __ or_(ecx, Operand(eax)); |  3921     __ or_(ecx, eax); | 
|  3923     __ test(ecx, Immediate(kSmiTagMask)); |  3922     __ test(ecx, Immediate(kSmiTagMask)); | 
|  3924     __ Assert(not_zero, "Unexpected smi operands."); |  3923     __ Assert(not_zero, "Unexpected smi operands."); | 
|  3925   } |  3924   } | 
|  3926  |  3925  | 
|  3927   // NOTICE! This code is only reached after a smi-fast-case check, so |  3926   // NOTICE! This code is only reached after a smi-fast-case check, so | 
|  3928   // it is certain that at least one operand isn't a smi. |  3927   // it is certain that at least one operand isn't a smi. | 
|  3929  |  3928  | 
|  3930   // Identical objects can be compared fast, but there are some tricky cases |  3929   // Identical objects can be compared fast, but there are some tricky cases | 
|  3931   // for NaN and undefined. |  3930   // for NaN and undefined. | 
|  3932   { |  3931   { | 
|  3933     Label not_identical; |  3932     Label not_identical; | 
|  3934     __ cmp(eax, Operand(edx)); |  3933     __ cmp(eax, edx); | 
|  3935     __ j(not_equal, ¬_identical); |  3934     __ j(not_equal, ¬_identical); | 
|  3936  |  3935  | 
|  3937     if (cc_ != equal) { |  3936     if (cc_ != equal) { | 
|  3938       // Check for undefined.  undefined OP undefined is false even though |  3937       // Check for undefined.  undefined OP undefined is false even though | 
|  3939       // undefined == undefined. |  3938       // undefined == undefined. | 
|  3940       Label check_for_nan; |  3939       Label check_for_nan; | 
|  3941       __ cmp(edx, masm->isolate()->factory()->undefined_value()); |  3940       __ cmp(edx, masm->isolate()->factory()->undefined_value()); | 
|  3942       __ j(not_equal, &check_for_nan, Label::kNear); |  3941       __ j(not_equal, &check_for_nan, Label::kNear); | 
|  3943       __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); |  3942       __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); | 
|  3944       __ ret(0); |  3943       __ ret(0); | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
|  3973       // Read top bits of double representation (second word of value). |  3972       // Read top bits of double representation (second word of value). | 
|  3974  |  3973  | 
|  3975       // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., |  3974       // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., | 
|  3976       // all bits in the mask are set. We only need to check the word |  3975       // all bits in the mask are set. We only need to check the word | 
|  3977       // that contains the exponent and high bit of the mantissa. |  3976       // that contains the exponent and high bit of the mantissa. | 
|  3978       STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); |  3977       STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); | 
|  3979       __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); |  3978       __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 
|  3980       __ Set(eax, Immediate(0)); |  3979       __ Set(eax, Immediate(0)); | 
|  3981       // Shift value and mask so kQuietNaNHighBitsMask applies to topmost |  3980       // Shift value and mask so kQuietNaNHighBitsMask applies to topmost | 
|  3982       // bits. |  3981       // bits. | 
|  3983       __ add(edx, Operand(edx)); |  3982       __ add(edx, edx); | 
|  3984       __ cmp(edx, kQuietNaNHighBitsMask << 1); |  3983       __ cmp(edx, kQuietNaNHighBitsMask << 1); | 
|  3985       if (cc_ == equal) { |  3984       if (cc_ == equal) { | 
|  3986         STATIC_ASSERT(EQUAL != 1); |  3985         STATIC_ASSERT(EQUAL != 1); | 
|  3987         __ setcc(above_equal, eax); |  3986         __ setcc(above_equal, eax); | 
|  3988         __ ret(0); |  3987         __ ret(0); | 
|  3989       } else { |  3988       } else { | 
|  3990         Label nan; |  3989         Label nan; | 
|  3991         __ j(above_equal, &nan, Label::kNear); |  3990         __ j(above_equal, &nan, Label::kNear); | 
|  3992         __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |  3991         __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 
|  3993         __ ret(0); |  3992         __ ret(0); | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
|  4007     Label not_smis; |  4006     Label not_smis; | 
|  4008     // If we're doing a strict equality comparison, we don't have to do |  4007     // If we're doing a strict equality comparison, we don't have to do | 
|  4009     // type conversion, so we generate code to do fast comparison for objects |  4008     // type conversion, so we generate code to do fast comparison for objects | 
|  4010     // and oddballs. Non-smi numbers and strings still go through the usual |  4009     // and oddballs. Non-smi numbers and strings still go through the usual | 
|  4011     // slow-case code. |  4010     // slow-case code. | 
|  4012     // If either is a Smi (we know that not both are), then they can only |  4011     // If either is a Smi (we know that not both are), then they can only | 
|  4013     // be equal if the other is a HeapNumber. If so, use the slow case. |  4012     // be equal if the other is a HeapNumber. If so, use the slow case. | 
|  4014     STATIC_ASSERT(kSmiTag == 0); |  4013     STATIC_ASSERT(kSmiTag == 0); | 
|  4015     ASSERT_EQ(0, Smi::FromInt(0)); |  4014     ASSERT_EQ(0, Smi::FromInt(0)); | 
|  4016     __ mov(ecx, Immediate(kSmiTagMask)); |  4015     __ mov(ecx, Immediate(kSmiTagMask)); | 
|  4017     __ and_(ecx, Operand(eax)); |  4016     __ and_(ecx, eax); | 
|  4018     __ test(ecx, Operand(edx)); |  4017     __ test(ecx, edx); | 
|  4019     __ j(not_zero, ¬_smis, Label::kNear); |  4018     __ j(not_zero, ¬_smis, Label::kNear); | 
|  4020     // One operand is a smi. |  4019     // One operand is a smi. | 
|  4021  |  4020  | 
|  4022     // Check whether the non-smi is a heap number. |  4021     // Check whether the non-smi is a heap number. | 
|  4023     STATIC_ASSERT(kSmiTagMask == 1); |  4022     STATIC_ASSERT(kSmiTagMask == 1); | 
|  4024     // ecx still holds eax & kSmiTag, which is either zero or one. |  4023     // ecx still holds eax & kSmiTag, which is either zero or one. | 
|  4025     __ sub(Operand(ecx), Immediate(0x01)); |  4024     __ sub(ecx, Immediate(0x01)); | 
|  4026     __ mov(ebx, edx); |  4025     __ mov(ebx, edx); | 
|  4027     __ xor_(ebx, Operand(eax)); |  4026     __ xor_(ebx, eax); | 
|  4028     __ and_(ebx, Operand(ecx));  // ebx holds either 0 or eax ^ edx. |  4027     __ and_(ebx, ecx);  // ebx holds either 0 or eax ^ edx. | 
|  4029     __ xor_(ebx, Operand(eax)); |  4028     __ xor_(ebx, eax); | 
|  4030     // if eax was smi, ebx is now edx, else eax. |  4029     // if eax was smi, ebx is now edx, else eax. | 
|  4031  |  4030  | 
|  4032     // Check if the non-smi operand is a heap number. |  4031     // Check if the non-smi operand is a heap number. | 
|  4033     __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |  4032     __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 
|  4034            Immediate(masm->isolate()->factory()->heap_number_map())); |  4033            Immediate(masm->isolate()->factory()->heap_number_map())); | 
|  4035     // If heap number, handle it in the slow case. |  4034     // If heap number, handle it in the slow case. | 
|  4036     __ j(equal, &slow, Label::kNear); |  4035     __ j(equal, &slow, Label::kNear); | 
|  4037     // Return non-equal (ebx is not zero) |  4036     // Return non-equal (ebx is not zero) | 
|  4038     __ mov(eax, ebx); |  4037     __ mov(eax, ebx); | 
|  4039     __ ret(0); |  4038     __ ret(0); | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  4081       CpuFeatures::Scope use_cmov(CMOV); |  4080       CpuFeatures::Scope use_cmov(CMOV); | 
|  4082  |  4081  | 
|  4083       FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); |  4082       FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); | 
|  4084       __ ucomisd(xmm0, xmm1); |  4083       __ ucomisd(xmm0, xmm1); | 
|  4085  |  4084  | 
|  4086       // Don't base result on EFLAGS when a NaN is involved. |  4085       // Don't base result on EFLAGS when a NaN is involved. | 
|  4087       __ j(parity_even, &unordered, Label::kNear); |  4086       __ j(parity_even, &unordered, Label::kNear); | 
|  4088       // Return a result of -1, 0, or 1, based on EFLAGS. |  4087       // Return a result of -1, 0, or 1, based on EFLAGS. | 
|  4089       __ mov(eax, 0);  // equal |  4088       __ mov(eax, 0);  // equal | 
|  4090       __ mov(ecx, Immediate(Smi::FromInt(1))); |  4089       __ mov(ecx, Immediate(Smi::FromInt(1))); | 
|  4091       __ cmov(above, eax, Operand(ecx)); |  4090       __ cmov(above, eax, ecx); | 
|  4092       __ mov(ecx, Immediate(Smi::FromInt(-1))); |  4091       __ mov(ecx, Immediate(Smi::FromInt(-1))); | 
|  4093       __ cmov(below, eax, Operand(ecx)); |  4092       __ cmov(below, eax, ecx); | 
|  4094       __ ret(0); |  4093       __ ret(0); | 
|  4095     } else { |  4094     } else { | 
|  4096       FloatingPointHelper::CheckFloatOperands( |  4095       FloatingPointHelper::CheckFloatOperands( | 
|  4097           masm, &non_number_comparison, ebx); |  4096           masm, &non_number_comparison, ebx); | 
|  4098       FloatingPointHelper::LoadFloatOperand(masm, eax); |  4097       FloatingPointHelper::LoadFloatOperand(masm, eax); | 
|  4099       FloatingPointHelper::LoadFloatOperand(masm, edx); |  4098       FloatingPointHelper::LoadFloatOperand(masm, edx); | 
|  4100       __ FCmp(); |  4099       __ FCmp(); | 
|  4101  |  4100  | 
|  4102       // Don't base result on EFLAGS when a NaN is involved. |  4101       // Don't base result on EFLAGS when a NaN is involved. | 
|  4103       __ j(parity_even, &unordered, Label::kNear); |  4102       __ j(parity_even, &unordered, Label::kNear); | 
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  4309     // instruction stream after the call.  Cache states are uninitialized, |  4308     // instruction stream after the call.  Cache states are uninitialized, | 
|  4310     // monomorphic (indicated by a JSFunction), and megamorphic. |  4309     // monomorphic (indicated by a JSFunction), and megamorphic. | 
|  4311     Label initialize, call; |  4310     Label initialize, call; | 
|  4312     // Load the cache cell address into ebx and the cache state into ecx. |  4311     // Load the cache cell address into ebx and the cache state into ecx. | 
|  4313     __ mov(ebx, Operand(esp, 0));  // Return address. |  4312     __ mov(ebx, Operand(esp, 0));  // Return address. | 
|  4314     __ mov(ebx, Operand(ebx, 1));  // 1 ~ sizeof 'test eax' opcode in bytes. |  4313     __ mov(ebx, Operand(ebx, 1));  // 1 ~ sizeof 'test eax' opcode in bytes. | 
|  4315     __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |  4314     __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | 
|  4316  |  4315  | 
|  4317     // A monomorphic cache hit or an already megamorphic state: invoke the |  4316     // A monomorphic cache hit or an already megamorphic state: invoke the | 
|  4318     // function without changing the state. |  4317     // function without changing the state. | 
|  4319     __ cmp(ecx, Operand(edi)); |  4318     __ cmp(ecx, edi); | 
|  4320     __ j(equal, &call, Label::kNear); |  4319     __ j(equal, &call, Label::kNear); | 
|  4321     __ cmp(Operand(ecx), Immediate(MegamorphicSentinel(isolate))); |  4320     __ cmp(ecx, Immediate(MegamorphicSentinel(isolate))); | 
|  4322     __ j(equal, &call, Label::kNear); |  4321     __ j(equal, &call, Label::kNear); | 
|  4323  |  4322  | 
|  4324     // A monomorphic miss (i.e, here the cache is not uninitialized) goes |  4323     // A monomorphic miss (i.e, here the cache is not uninitialized) goes | 
|  4325     // megamorphic. |  4324     // megamorphic. | 
|  4326     __ cmp(Operand(ecx), Immediate(UninitializedSentinel(isolate))); |  4325     __ cmp(ecx, Immediate(UninitializedSentinel(isolate))); | 
|  4327     __ j(equal, &initialize, Label::kNear); |  4326     __ j(equal, &initialize, Label::kNear); | 
|  4328     // MegamorphicSentinel is a root so no write-barrier is needed. |  4327     // MegamorphicSentinel is a root so no write-barrier is needed. | 
|  4329     __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), |  4328     __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), | 
|  4330            Immediate(MegamorphicSentinel(isolate))); |  4329            Immediate(MegamorphicSentinel(isolate))); | 
|  4331     __ jmp(&call, Label::kNear); |  4330     __ jmp(&call, Label::kNear); | 
|  4332  |  4331  | 
|  4333     // An uninitialized cache is patched with the function. |  4332     // An uninitialized cache is patched with the function. | 
|  4334     __ bind(&initialize); |  4333     __ bind(&initialize); | 
|  4335     __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); |  4334     __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); | 
|  4336     __ mov(ecx, edi); |  4335     __ mov(ecx, edi); | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  4476       ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); |  4475       ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); | 
|  4477   if (always_allocate_scope) { |  4476   if (always_allocate_scope) { | 
|  4478     __ inc(Operand::StaticVariable(scope_depth)); |  4477     __ inc(Operand::StaticVariable(scope_depth)); | 
|  4479   } |  4478   } | 
|  4480  |  4479  | 
|  4481   // Call C function. |  4480   // Call C function. | 
|  4482   __ mov(Operand(esp, 0 * kPointerSize), edi);  // argc. |  4481   __ mov(Operand(esp, 0 * kPointerSize), edi);  // argc. | 
|  4483   __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv. |  4482   __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv. | 
|  4484   __ mov(Operand(esp, 2 * kPointerSize), |  4483   __ mov(Operand(esp, 2 * kPointerSize), | 
|  4485          Immediate(ExternalReference::isolate_address())); |  4484          Immediate(ExternalReference::isolate_address())); | 
|  4486   __ call(Operand(ebx)); |  4485   __ call(ebx); | 
|  4487   // Result is in eax or edx:eax - do not destroy these registers! |  4486   // Result is in eax or edx:eax - do not destroy these registers! | 
|  4488  |  4487  | 
|  4489   if (always_allocate_scope) { |  4488   if (always_allocate_scope) { | 
|  4490     __ dec(Operand::StaticVariable(scope_depth)); |  4489     __ dec(Operand::StaticVariable(scope_depth)); | 
|  4491   } |  4490   } | 
|  4492  |  4491  | 
|  4493   // Make sure we're not trying to return 'the hole' from the runtime |  4492   // Make sure we're not trying to return 'the hole' from the runtime | 
|  4494   // call as this may lead to crashes in the IC code later. |  4493   // call as this may lead to crashes in the IC code later. | 
|  4495   if (FLAG_debug_code) { |  4494   if (FLAG_debug_code) { | 
|  4496     Label okay; |  4495     Label okay; | 
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  4631   GenerateThrowTOS(masm); |  4630   GenerateThrowTOS(masm); | 
|  4632 } |  4631 } | 
|  4633  |  4632  | 
|  4634  |  4633  | 
|  4635 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |  4634 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { | 
|  4636   Label invoke, exit; |  4635   Label invoke, exit; | 
|  4637   Label not_outermost_js, not_outermost_js_2; |  4636   Label not_outermost_js, not_outermost_js_2; | 
|  4638  |  4637  | 
|  4639   // Setup frame. |  4638   // Setup frame. | 
|  4640   __ push(ebp); |  4639   __ push(ebp); | 
|  4641   __ mov(ebp, Operand(esp)); |  4640   __ mov(ebp, esp); | 
|  4642  |  4641  | 
|  4643   // Push marker in two places. |  4642   // Push marker in two places. | 
|  4644   int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |  4643   int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; | 
|  4645   __ push(Immediate(Smi::FromInt(marker)));  // context slot |  4644   __ push(Immediate(Smi::FromInt(marker)));  // context slot | 
|  4646   __ push(Immediate(Smi::FromInt(marker)));  // function slot |  4645   __ push(Immediate(Smi::FromInt(marker)));  // function slot | 
|  4647   // Save callee-saved registers (C calling conventions). |  4646   // Save callee-saved registers (C calling conventions). | 
|  4648   __ push(edi); |  4647   __ push(edi); | 
|  4649   __ push(esi); |  4648   __ push(esi); | 
|  4650   __ push(ebx); |  4649   __ push(ebx); | 
|  4651  |  4650  | 
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  4699         Builtins::kJSConstructEntryTrampoline, |  4698         Builtins::kJSConstructEntryTrampoline, | 
|  4700         masm->isolate()); |  4699         masm->isolate()); | 
|  4701     __ mov(edx, Immediate(construct_entry)); |  4700     __ mov(edx, Immediate(construct_entry)); | 
|  4702   } else { |  4701   } else { | 
|  4703     ExternalReference entry(Builtins::kJSEntryTrampoline, |  4702     ExternalReference entry(Builtins::kJSEntryTrampoline, | 
|  4704                             masm->isolate()); |  4703                             masm->isolate()); | 
|  4705     __ mov(edx, Immediate(entry)); |  4704     __ mov(edx, Immediate(entry)); | 
|  4706   } |  4705   } | 
|  4707   __ mov(edx, Operand(edx, 0));  // deref address |  4706   __ mov(edx, Operand(edx, 0));  // deref address | 
|  4708   __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |  4707   __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 
|  4709   __ call(Operand(edx)); |  4708   __ call(edx); | 
|  4710  |  4709  | 
|  4711   // Unlink this frame from the handler chain. |  4710   // Unlink this frame from the handler chain. | 
|  4712   __ PopTryHandler(); |  4711   __ PopTryHandler(); | 
|  4713  |  4712  | 
|  4714   __ bind(&exit); |  4713   __ bind(&exit); | 
|  4715   // Check if the current stack frame is marked as the outermost JS frame. |  4714   // Check if the current stack frame is marked as the outermost JS frame. | 
|  4716   __ pop(ebx); |  4715   __ pop(ebx); | 
|  4717   __ cmp(Operand(ebx), |  4716   __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); | 
|  4718          Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); |  | 
|  4719   __ j(not_equal, ¬_outermost_js_2); |  4717   __ j(not_equal, ¬_outermost_js_2); | 
|  4720   __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); |  4718   __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); | 
|  4721   __ bind(¬_outermost_js_2); |  4719   __ bind(¬_outermost_js_2); | 
|  4722  |  4720  | 
|  4723   // Restore the top frame descriptor from the stack. |  4721   // Restore the top frame descriptor from the stack. | 
|  4724   __ pop(Operand::StaticVariable(ExternalReference( |  4722   __ pop(Operand::StaticVariable(ExternalReference( | 
|  4725       Isolate::kCEntryFPAddress, |  4723       Isolate::kCEntryFPAddress, | 
|  4726       masm->isolate()))); |  4724       masm->isolate()))); | 
|  4727  |  4725  | 
|  4728   // Restore callee-saved registers (C calling conventions). |  4726   // Restore callee-saved registers (C calling conventions). | 
|  4729   __ pop(ebx); |  4727   __ pop(ebx); | 
|  4730   __ pop(esi); |  4728   __ pop(esi); | 
|  4731   __ pop(edi); |  4729   __ pop(edi); | 
|  4732   __ add(Operand(esp), Immediate(2 * kPointerSize));  // remove markers |  4730   __ add(esp, Immediate(2 * kPointerSize));  // remove markers | 
|  4733  |  4731  | 
|  4734   // Restore frame pointer and return. |  4732   // Restore frame pointer and return. | 
|  4735   __ pop(ebp); |  4733   __ pop(ebp); | 
|  4736   __ ret(0); |  4734   __ ret(0); | 
|  4737 } |  4735 } | 
|  4738  |  4736  | 
|  4739  |  4737  | 
|  4740 // Generate stub code for instanceof. |  4738 // Generate stub code for instanceof. | 
|  4741 // This code can patch a call site inlined cache of the instance of check, |  4739 // This code can patch a call site inlined cache of the instance of check, | 
|  4742 // which looks like this. |  4740 // which looks like this. | 
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  4838       __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); |  4836       __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); | 
|  4839     } |  4837     } | 
|  4840     __ mov(Operand(scratch, kDeltaToCmpImmediate), map); |  4838     __ mov(Operand(scratch, kDeltaToCmpImmediate), map); | 
|  4841   } |  4839   } | 
|  4842  |  4840  | 
|  4843   // Loop through the prototype chain of the object looking for the function |  4841   // Loop through the prototype chain of the object looking for the function | 
|  4844   // prototype. |  4842   // prototype. | 
|  4845   __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); |  4843   __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); | 
|  4846   Label loop, is_instance, is_not_instance; |  4844   Label loop, is_instance, is_not_instance; | 
|  4847   __ bind(&loop); |  4845   __ bind(&loop); | 
|  4848   __ cmp(scratch, Operand(prototype)); |  4846   __ cmp(scratch, prototype); | 
|  4849   __ j(equal, &is_instance, Label::kNear); |  4847   __ j(equal, &is_instance, Label::kNear); | 
|  4850   Factory* factory = masm->isolate()->factory(); |  4848   Factory* factory = masm->isolate()->factory(); | 
|  4851   __ cmp(Operand(scratch), Immediate(factory->null_value())); |  4849   __ cmp(scratch, Immediate(factory->null_value())); | 
|  4852   __ j(equal, &is_not_instance, Label::kNear); |  4850   __ j(equal, &is_not_instance, Label::kNear); | 
|  4853   __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |  4851   __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 
|  4854   __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); |  4852   __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); | 
|  4855   __ jmp(&loop); |  4853   __ jmp(&loop); | 
|  4856  |  4854  | 
|  4857   __ bind(&is_instance); |  4855   __ bind(&is_instance); | 
|  4858   if (!HasCallSiteInlineCheck()) { |  4856   if (!HasCallSiteInlineCheck()) { | 
|  4859     __ Set(eax, Immediate(0)); |  4857     __ Set(eax, Immediate(0)); | 
|  4860     __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |  4858     __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 
|  4861     __ mov(Operand::StaticArray(scratch, |  4859     __ mov(Operand::StaticArray(scratch, | 
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  4939     __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |  4937     __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 
|  4940   } else { |  4938   } else { | 
|  4941     // Call the builtin and convert 0/1 to true/false. |  4939     // Call the builtin and convert 0/1 to true/false. | 
|  4942     { |  4940     { | 
|  4943       FrameScope scope(masm, StackFrame::INTERNAL); |  4941       FrameScope scope(masm, StackFrame::INTERNAL); | 
|  4944       __ push(object); |  4942       __ push(object); | 
|  4945       __ push(function); |  4943       __ push(function); | 
|  4946       __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); |  4944       __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); | 
|  4947     } |  4945     } | 
|  4948     Label true_value, done; |  4946     Label true_value, done; | 
|  4949     __ test(eax, Operand(eax)); |  4947     __ test(eax, eax); | 
|  4950     __ j(zero, &true_value, Label::kNear); |  4948     __ j(zero, &true_value, Label::kNear); | 
|  4951     __ mov(eax, factory->false_value()); |  4949     __ mov(eax, factory->false_value()); | 
|  4952     __ jmp(&done, Label::kNear); |  4950     __ jmp(&done, Label::kNear); | 
|  4953     __ bind(&true_value); |  4951     __ bind(&true_value); | 
|  4954     __ mov(eax, factory->true_value()); |  4952     __ mov(eax, factory->true_value()); | 
|  4955     __ bind(&done); |  4953     __ bind(&done); | 
|  4956     __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |  4954     __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 
|  4957   } |  4955   } | 
|  4958 } |  4956 } | 
|  4959  |  4957  | 
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  5255     } |  5253     } | 
|  5256   } |  5254   } | 
|  5257  |  5255  | 
|  5258   // Both arguments are strings. |  5256   // Both arguments are strings. | 
|  5259   // eax: first string |  5257   // eax: first string | 
|  5260   // edx: second string |  5258   // edx: second string | 
|  5261   // Check if either of the strings are empty. In that case return the other. |  5259   // Check if either of the strings are empty. In that case return the other. | 
|  5262   Label second_not_zero_length, both_not_zero_length; |  5260   Label second_not_zero_length, both_not_zero_length; | 
|  5263   __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); |  5261   __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | 
|  5264   STATIC_ASSERT(kSmiTag == 0); |  5262   STATIC_ASSERT(kSmiTag == 0); | 
|  5265   __ test(ecx, Operand(ecx)); |  5263   __ test(ecx, ecx); | 
|  5266   __ j(not_zero, &second_not_zero_length, Label::kNear); |  5264   __ j(not_zero, &second_not_zero_length, Label::kNear); | 
|  5267   // Second string is empty, result is first string which is already in eax. |  5265   // Second string is empty, result is first string which is already in eax. | 
|  5268   Counters* counters = masm->isolate()->counters(); |  5266   Counters* counters = masm->isolate()->counters(); | 
|  5269   __ IncrementCounter(counters->string_add_native(), 1); |  5267   __ IncrementCounter(counters->string_add_native(), 1); | 
|  5270   __ ret(2 * kPointerSize); |  5268   __ ret(2 * kPointerSize); | 
|  5271   __ bind(&second_not_zero_length); |  5269   __ bind(&second_not_zero_length); | 
|  5272   __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |  5270   __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 
|  5273   STATIC_ASSERT(kSmiTag == 0); |  5271   STATIC_ASSERT(kSmiTag == 0); | 
|  5274   __ test(ebx, Operand(ebx)); |  5272   __ test(ebx, ebx); | 
|  5275   __ j(not_zero, &both_not_zero_length, Label::kNear); |  5273   __ j(not_zero, &both_not_zero_length, Label::kNear); | 
|  5276   // First string is empty, result is second string which is in edx. |  5274   // First string is empty, result is second string which is in edx. | 
|  5277   __ mov(eax, edx); |  5275   __ mov(eax, edx); | 
|  5278   __ IncrementCounter(counters->string_add_native(), 1); |  5276   __ IncrementCounter(counters->string_add_native(), 1); | 
|  5279   __ ret(2 * kPointerSize); |  5277   __ ret(2 * kPointerSize); | 
|  5280  |  5278  | 
|  5281   // Both strings are non-empty. |  5279   // Both strings are non-empty. | 
|  5282   // eax: first string |  5280   // eax: first string | 
|  5283   // ebx: length of first string as a smi |  5281   // ebx: length of first string as a smi | 
|  5284   // ecx: length of second string as a smi |  5282   // ecx: length of second string as a smi | 
|  5285   // edx: second string |  5283   // edx: second string | 
|  5286   // Look at the length of the result of adding the two strings. |  5284   // Look at the length of the result of adding the two strings. | 
|  5287   Label string_add_flat_result, longer_than_two; |  5285   Label string_add_flat_result, longer_than_two; | 
|  5288   __ bind(&both_not_zero_length); |  5286   __ bind(&both_not_zero_length); | 
|  5289   __ add(ebx, Operand(ecx)); |  5287   __ add(ebx, ecx); | 
|  5290   STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); |  5288   STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); | 
|  5291   // Handle exceptionally long strings in the runtime system. |  5289   // Handle exceptionally long strings in the runtime system. | 
|  5292   __ j(overflow, &string_add_runtime); |  5290   __ j(overflow, &string_add_runtime); | 
|  5293   // Use the symbol table when adding two one character strings, as it |  5291   // Use the symbol table when adding two one character strings, as it | 
|  5294   // helps later optimizations to return a symbol here. |  5292   // helps later optimizations to return a symbol here. | 
|  5295   __ cmp(Operand(ebx), Immediate(Smi::FromInt(2))); |  5293   __ cmp(ebx, Immediate(Smi::FromInt(2))); | 
|  5296   __ j(not_equal, &longer_than_two); |  5294   __ j(not_equal, &longer_than_two); | 
|  5297  |  5295  | 
|  5298   // Check that both strings are non-external ascii strings. |  5296   // Check that both strings are non-external ascii strings. | 
|  5299   __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, |  5297   __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, | 
|  5300                                          &string_add_runtime); |  5298                                          &string_add_runtime); | 
|  5301  |  5299  | 
|  5302   // Get the two characters forming the new string. |  5300   // Get the two characters forming the new string. | 
|  5303   __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |  5301   __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 
|  5304   __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |  5302   __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 
|  5305  |  5303  | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
|  5322   __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |  5320   __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 
|  5323   __ bind(&make_two_character_string_no_reload); |  5321   __ bind(&make_two_character_string_no_reload); | 
|  5324   __ IncrementCounter(counters->string_add_make_two_char(), 1); |  5322   __ IncrementCounter(counters->string_add_make_two_char(), 1); | 
|  5325   __ AllocateAsciiString(eax,  // Result. |  5323   __ AllocateAsciiString(eax,  // Result. | 
|  5326                          2,    // Length. |  5324                          2,    // Length. | 
|  5327                          edi,  // Scratch 1. |  5325                          edi,  // Scratch 1. | 
|  5328                          edx,  // Scratch 2. |  5326                          edx,  // Scratch 2. | 
|  5329                          &string_add_runtime); |  5327                          &string_add_runtime); | 
|  5330   // Pack both characters in ebx. |  5328   // Pack both characters in ebx. | 
|  5331   __ shl(ecx, kBitsPerByte); |  5329   __ shl(ecx, kBitsPerByte); | 
|  5332   __ or_(ebx, Operand(ecx)); |  5330   __ or_(ebx, ecx); | 
|  5333   // Set the characters in the new string. |  5331   // Set the characters in the new string. | 
|  5334   __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); |  5332   __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); | 
|  5335   __ IncrementCounter(counters->string_add_native(), 1); |  5333   __ IncrementCounter(counters->string_add_native(), 1); | 
|  5336   __ ret(2 * kPointerSize); |  5334   __ ret(2 * kPointerSize); | 
|  5337  |  5335  | 
|  5338   __ bind(&longer_than_two); |  5336   __ bind(&longer_than_two); | 
|  5339   // Check if resulting string will be flat. |  5337   // Check if resulting string will be flat. | 
|  5340   __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); |  5338   __ cmp(ebx, Immediate(Smi::FromInt(String::kMinNonFlatLength))); | 
|  5341   __ j(below, &string_add_flat_result); |  5339   __ j(below, &string_add_flat_result); | 
|  5342  |  5340  | 
|  5343   // If result is not supposed to be flat allocate a cons string object. If both |  5341   // If result is not supposed to be flat allocate a cons string object. If both | 
|  5344   // strings are ascii the result is an ascii cons string. |  5342   // strings are ascii the result is an ascii cons string. | 
|  5345   Label non_ascii, allocated, ascii_data; |  5343   Label non_ascii, allocated, ascii_data; | 
|  5346   __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); |  5344   __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); | 
|  5347   __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); |  5345   __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); | 
|  5348   __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |  5346   __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 
|  5349   __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); |  5347   __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | 
|  5350   __ and_(ecx, Operand(edi)); |  5348   __ and_(ecx, edi); | 
|  5351   STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); |  5349   STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); | 
|  5352   STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |  5350   STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 
|  5353   __ test(ecx, Immediate(kStringEncodingMask)); |  5351   __ test(ecx, Immediate(kStringEncodingMask)); | 
|  5354   __ j(zero, &non_ascii); |  5352   __ j(zero, &non_ascii); | 
|  5355   __ bind(&ascii_data); |  5353   __ bind(&ascii_data); | 
|  5356   // Allocate an acsii cons string. |  5354   // Allocate an acsii cons string. | 
|  5357   __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); |  5355   __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); | 
|  5358   __ bind(&allocated); |  5356   __ bind(&allocated); | 
|  5359   // Fill the fields of the cons string. |  5357   // Fill the fields of the cons string. | 
|  5360   if (FLAG_debug_code) __ AbortIfNotSmi(ebx); |  5358   if (FLAG_debug_code) __ AbortIfNotSmi(ebx); | 
|  5361   __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); |  5359   __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | 
|  5362   __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), |  5360   __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | 
|  5363          Immediate(String::kEmptyHashField)); |  5361          Immediate(String::kEmptyHashField)); | 
|  5364   __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); |  5362   __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | 
|  5365   __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); |  5363   __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | 
|  5366   __ mov(eax, ecx); |  5364   __ mov(eax, ecx); | 
|  5367   __ IncrementCounter(counters->string_add_native(), 1); |  5365   __ IncrementCounter(counters->string_add_native(), 1); | 
|  5368   __ ret(2 * kPointerSize); |  5366   __ ret(2 * kPointerSize); | 
|  5369   __ bind(&non_ascii); |  5367   __ bind(&non_ascii); | 
|  5370   // At least one of the strings is two-byte. Check whether it happens |  5368   // At least one of the strings is two-byte. Check whether it happens | 
|  5371   // to contain only ascii characters. |  5369   // to contain only ascii characters. | 
|  5372   // ecx: first instance type AND second instance type. |  5370   // ecx: first instance type AND second instance type. | 
|  5373   // edi: second instance type. |  5371   // edi: second instance type. | 
|  5374   __ test(ecx, Immediate(kAsciiDataHintMask)); |  5372   __ test(ecx, Immediate(kAsciiDataHintMask)); | 
|  5375   __ j(not_zero, &ascii_data); |  5373   __ j(not_zero, &ascii_data); | 
|  5376   __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |  5374   __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 
|  5377   __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |  5375   __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 
|  5378   __ xor_(edi, Operand(ecx)); |  5376   __ xor_(edi, ecx); | 
|  5379   STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |  5377   STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 
|  5380   __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); |  5378   __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); | 
|  5381   __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); |  5379   __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); | 
|  5382   __ j(equal, &ascii_data); |  5380   __ j(equal, &ascii_data); | 
|  5383   // Allocate a two byte cons string. |  5381   // Allocate a two byte cons string. | 
|  5384   __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime); |  5382   __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime); | 
|  5385   __ jmp(&allocated); |  5383   __ jmp(&allocated); | 
|  5386  |  5384  | 
|  5387   // Handle creating a flat result. First check that both strings are not |  5385   // Handle creating a flat result. First check that both strings are not | 
|  5388   // external strings. |  5386   // external strings. | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
|  5416   __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); |  5414   __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); | 
|  5417   __ j(zero, &string_add_runtime); |  5415   __ j(zero, &string_add_runtime); | 
|  5418  |  5416  | 
|  5419   // Both strings are ascii strings.  As they are short they are both flat. |  5417   // Both strings are ascii strings.  As they are short they are both flat. | 
|  5420   // ebx: length of resulting flat string as a smi |  5418   // ebx: length of resulting flat string as a smi | 
|  5421   __ SmiUntag(ebx); |  5419   __ SmiUntag(ebx); | 
|  5422   __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); |  5420   __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 
|  5423   // eax: result string |  5421   // eax: result string | 
|  5424   __ mov(ecx, eax); |  5422   __ mov(ecx, eax); | 
|  5425   // Locate first character of result. |  5423   // Locate first character of result. | 
|  5426   __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |  5424   __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
|  5427   // Load first argument and locate first character. |  5425   // Load first argument and locate first character. | 
|  5428   __ mov(edx, Operand(esp, 2 * kPointerSize)); |  5426   __ mov(edx, Operand(esp, 2 * kPointerSize)); | 
|  5429   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |  5427   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 
|  5430   __ SmiUntag(edi); |  5428   __ SmiUntag(edi); | 
|  5431   __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |  5429   __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
|  5432   // eax: result string |  5430   // eax: result string | 
|  5433   // ecx: first character of result |  5431   // ecx: first character of result | 
|  5434   // edx: first char of first argument |  5432   // edx: first char of first argument | 
|  5435   // edi: length of first argument |  5433   // edi: length of first argument | 
|  5436   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |  5434   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 
|  5437   // Load second argument and locate first character. |  5435   // Load second argument and locate first character. | 
|  5438   __ mov(edx, Operand(esp, 1 * kPointerSize)); |  5436   __ mov(edx, Operand(esp, 1 * kPointerSize)); | 
|  5439   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |  5437   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 
|  5440   __ SmiUntag(edi); |  5438   __ SmiUntag(edi); | 
|  5441   __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |  5439   __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
|  5442   // eax: result string |  5440   // eax: result string | 
|  5443   // ecx: next character of result |  5441   // ecx: next character of result | 
|  5444   // edx: first char of second argument |  5442   // edx: first char of second argument | 
|  5445   // edi: length of second argument |  5443   // edi: length of second argument | 
|  5446   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |  5444   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 
|  5447   __ IncrementCounter(counters->string_add_native(), 1); |  5445   __ IncrementCounter(counters->string_add_native(), 1); | 
|  5448   __ ret(2 * kPointerSize); |  5446   __ ret(2 * kPointerSize); | 
|  5449  |  5447  | 
|  5450   // Handle creating a flat two byte result. |  5448   // Handle creating a flat two byte result. | 
|  5451   // eax: first string - known to be two byte |  5449   // eax: first string - known to be two byte | 
|  5452   // ebx: length of resulting flat string as a smi |  5450   // ebx: length of resulting flat string as a smi | 
|  5453   // edx: second string |  5451   // edx: second string | 
|  5454   __ bind(&non_ascii_string_add_flat_result); |  5452   __ bind(&non_ascii_string_add_flat_result); | 
|  5455   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |  5453   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 
|  5456   __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); |  5454   __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask); | 
|  5457   __ j(not_zero, &string_add_runtime); |  5455   __ j(not_zero, &string_add_runtime); | 
|  5458   // Both strings are two byte strings. As they are short they are both |  5456   // Both strings are two byte strings. As they are short they are both | 
|  5459   // flat. |  5457   // flat. | 
|  5460   __ SmiUntag(ebx); |  5458   __ SmiUntag(ebx); | 
|  5461   __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); |  5459   __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 
|  5462   // eax: result string |  5460   // eax: result string | 
|  5463   __ mov(ecx, eax); |  5461   __ mov(ecx, eax); | 
|  5464   // Locate first character of result. |  5462   // Locate first character of result. | 
|  5465   __ add(Operand(ecx), |  5463   __ add(ecx, | 
|  5466          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |  5464          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 
|  5467   // Load first argument and locate first character. |  5465   // Load first argument and locate first character. | 
|  5468   __ mov(edx, Operand(esp, 2 * kPointerSize)); |  5466   __ mov(edx, Operand(esp, 2 * kPointerSize)); | 
|  5469   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |  5467   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 
|  5470   __ SmiUntag(edi); |  5468   __ SmiUntag(edi); | 
|  5471   __ add(Operand(edx), |  5469   __ add(edx, | 
|  5472          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |  5470          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 
|  5473   // eax: result string |  5471   // eax: result string | 
|  5474   // ecx: first character of result |  5472   // ecx: first character of result | 
|  5475   // edx: first char of first argument |  5473   // edx: first char of first argument | 
|  5476   // edi: length of first argument |  5474   // edi: length of first argument | 
|  5477   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |  5475   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 
|  5478   // Load second argument and locate first character. |  5476   // Load second argument and locate first character. | 
|  5479   __ mov(edx, Operand(esp, 1 * kPointerSize)); |  5477   __ mov(edx, Operand(esp, 1 * kPointerSize)); | 
|  5480   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |  5478   __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 
|  5481   __ SmiUntag(edi); |  5479   __ SmiUntag(edi); | 
|  5482   __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |  5480   __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
|  5483   // eax: result string |  5481   // eax: result string | 
|  5484   // ecx: next character of result |  5482   // ecx: next character of result | 
|  5485   // edx: first char of second argument |  5483   // edx: first char of second argument | 
|  5486   // edi: length of second argument |  5484   // edi: length of second argument | 
|  5487   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |  5485   StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 
|  5488   __ IncrementCounter(counters->string_add_native(), 1); |  5486   __ IncrementCounter(counters->string_add_native(), 1); | 
|  5489   __ ret(2 * kPointerSize); |  5487   __ ret(2 * kPointerSize); | 
|  5490  |  5488  | 
|  5491   // Just jump to runtime to add the two strings. |  5489   // Just jump to runtime to add the two strings. | 
|  5492   __ bind(&string_add_runtime); |  5490   __ bind(&string_add_runtime); | 
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  5548                                           Register count, |  5546                                           Register count, | 
|  5549                                           Register scratch, |  5547                                           Register scratch, | 
|  5550                                           bool ascii) { |  5548                                           bool ascii) { | 
|  5551   Label loop; |  5549   Label loop; | 
|  5552   __ bind(&loop); |  5550   __ bind(&loop); | 
|  5553   // This loop just copies one character at a time, as it is only used for very |  5551   // This loop just copies one character at a time, as it is only used for very | 
|  5554   // short strings. |  5552   // short strings. | 
|  5555   if (ascii) { |  5553   if (ascii) { | 
|  5556     __ mov_b(scratch, Operand(src, 0)); |  5554     __ mov_b(scratch, Operand(src, 0)); | 
|  5557     __ mov_b(Operand(dest, 0), scratch); |  5555     __ mov_b(Operand(dest, 0), scratch); | 
|  5558     __ add(Operand(src), Immediate(1)); |  5556     __ add(src, Immediate(1)); | 
|  5559     __ add(Operand(dest), Immediate(1)); |  5557     __ add(dest, Immediate(1)); | 
|  5560   } else { |  5558   } else { | 
|  5561     __ mov_w(scratch, Operand(src, 0)); |  5559     __ mov_w(scratch, Operand(src, 0)); | 
|  5562     __ mov_w(Operand(dest, 0), scratch); |  5560     __ mov_w(Operand(dest, 0), scratch); | 
|  5563     __ add(Operand(src), Immediate(2)); |  5561     __ add(src, Immediate(2)); | 
|  5564     __ add(Operand(dest), Immediate(2)); |  5562     __ add(dest, Immediate(2)); | 
|  5565   } |  5563   } | 
|  5566   __ sub(Operand(count), Immediate(1)); |  5564   __ sub(count, Immediate(1)); | 
|  5567   __ j(not_zero, &loop); |  5565   __ j(not_zero, &loop); | 
|  5568 } |  5566 } | 
|  5569  |  5567  | 
|  5570  |  5568  | 
|  5571 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |  5569 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, | 
|  5572                                              Register dest, |  5570                                              Register dest, | 
|  5573                                              Register src, |  5571                                              Register src, | 
|  5574                                              Register count, |  5572                                              Register count, | 
|  5575                                              Register scratch, |  5573                                              Register scratch, | 
|  5576                                              bool ascii) { |  5574                                              bool ascii) { | 
|  5577   // Copy characters using rep movs of doublewords. |  5575   // Copy characters using rep movs of doublewords. | 
|  5578   // The destination is aligned on a 4 byte boundary because we are |  5576   // The destination is aligned on a 4 byte boundary because we are | 
|  5579   // copying to the beginning of a newly allocated string. |  5577   // copying to the beginning of a newly allocated string. | 
|  5580   ASSERT(dest.is(edi));  // rep movs destination |  5578   ASSERT(dest.is(edi));  // rep movs destination | 
|  5581   ASSERT(src.is(esi));  // rep movs source |  5579   ASSERT(src.is(esi));  // rep movs source | 
|  5582   ASSERT(count.is(ecx));  // rep movs count |  5580   ASSERT(count.is(ecx));  // rep movs count | 
|  5583   ASSERT(!scratch.is(dest)); |  5581   ASSERT(!scratch.is(dest)); | 
|  5584   ASSERT(!scratch.is(src)); |  5582   ASSERT(!scratch.is(src)); | 
|  5585   ASSERT(!scratch.is(count)); |  5583   ASSERT(!scratch.is(count)); | 
|  5586  |  5584  | 
|  5587   // Nothing to do for zero characters. |  5585   // Nothing to do for zero characters. | 
|  5588   Label done; |  5586   Label done; | 
|  5589   __ test(count, Operand(count)); |  5587   __ test(count, count); | 
|  5590   __ j(zero, &done); |  5588   __ j(zero, &done); | 
|  5591  |  5589  | 
|  5592   // Make count the number of bytes to copy. |  5590   // Make count the number of bytes to copy. | 
|  5593   if (!ascii) { |  5591   if (!ascii) { | 
|  5594     __ shl(count, 1); |  5592     __ shl(count, 1); | 
|  5595   } |  5593   } | 
|  5596  |  5594  | 
|  5597   // Don't enter the rep movs if there are less than 4 bytes to copy. |  5595   // Don't enter the rep movs if there are less than 4 bytes to copy. | 
|  5598   Label last_bytes; |  5596   Label last_bytes; | 
|  5599   __ test(count, Immediate(~3)); |  5597   __ test(count, Immediate(~3)); | 
|  5600   __ j(zero, &last_bytes, Label::kNear); |  5598   __ j(zero, &last_bytes, Label::kNear); | 
|  5601  |  5599  | 
|  5602   // Copy from edi to esi using rep movs instruction. |  5600   // Copy from edi to esi using rep movs instruction. | 
|  5603   __ mov(scratch, count); |  5601   __ mov(scratch, count); | 
|  5604   __ sar(count, 2);  // Number of doublewords to copy. |  5602   __ sar(count, 2);  // Number of doublewords to copy. | 
|  5605   __ cld(); |  5603   __ cld(); | 
|  5606   __ rep_movs(); |  5604   __ rep_movs(); | 
|  5607  |  5605  | 
|  5608   // Find number of bytes left. |  5606   // Find number of bytes left. | 
|  5609   __ mov(count, scratch); |  5607   __ mov(count, scratch); | 
|  5610   __ and_(count, 3); |  5608   __ and_(count, 3); | 
|  5611  |  5609  | 
|  5612   // Check if there are more bytes to copy. |  5610   // Check if there are more bytes to copy. | 
|  5613   __ bind(&last_bytes); |  5611   __ bind(&last_bytes); | 
|  5614   __ test(count, Operand(count)); |  5612   __ test(count, count); | 
|  5615   __ j(zero, &done); |  5613   __ j(zero, &done); | 
|  5616  |  5614  | 
|  5617   // Copy remaining characters. |  5615   // Copy remaining characters. | 
|  5618   Label loop; |  5616   Label loop; | 
|  5619   __ bind(&loop); |  5617   __ bind(&loop); | 
|  5620   __ mov_b(scratch, Operand(src, 0)); |  5618   __ mov_b(scratch, Operand(src, 0)); | 
|  5621   __ mov_b(Operand(dest, 0), scratch); |  5619   __ mov_b(Operand(dest, 0), scratch); | 
|  5622   __ add(Operand(src), Immediate(1)); |  5620   __ add(src, Immediate(1)); | 
|  5623   __ add(Operand(dest), Immediate(1)); |  5621   __ add(dest, Immediate(1)); | 
|  5624   __ sub(Operand(count), Immediate(1)); |  5622   __ sub(count, Immediate(1)); | 
|  5625   __ j(not_zero, &loop); |  5623   __ j(not_zero, &loop); | 
|  5626  |  5624  | 
|  5627   __ bind(&done); |  5625   __ bind(&done); | 
|  5628 } |  5626 } | 
|  5629  |  5627  | 
|  5630  |  5628  | 
|  5631 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |  5629 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, | 
|  5632                                                         Register c1, |  5630                                                         Register c1, | 
|  5633                                                         Register c2, |  5631                                                         Register c2, | 
|  5634                                                         Register scratch1, |  5632                                                         Register scratch1, | 
|  5635                                                         Register scratch2, |  5633                                                         Register scratch2, | 
|  5636                                                         Register scratch3, |  5634                                                         Register scratch3, | 
|  5637                                                         Label* not_probed, |  5635                                                         Label* not_probed, | 
|  5638                                                         Label* not_found) { |  5636                                                         Label* not_found) { | 
|  5639   // Register scratch3 is the general scratch register in this function. |  5637   // Register scratch3 is the general scratch register in this function. | 
|  5640   Register scratch = scratch3; |  5638   Register scratch = scratch3; | 
|  5641  |  5639  | 
|  5642   // Make sure that both characters are not digits as such strings has a |  5640   // Make sure that both characters are not digits as such strings has a | 
|  5643   // different hash algorithm. Don't try to look for these in the symbol table. |  5641   // different hash algorithm. Don't try to look for these in the symbol table. | 
|  5644   Label not_array_index; |  5642   Label not_array_index; | 
|  5645   __ mov(scratch, c1); |  5643   __ mov(scratch, c1); | 
|  5646   __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); |  5644   __ sub(scratch, Immediate(static_cast<int>('0'))); | 
|  5647   __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); |  5645   __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); | 
|  5648   __ j(above, ¬_array_index, Label::kNear); |  5646   __ j(above, ¬_array_index, Label::kNear); | 
|  5649   __ mov(scratch, c2); |  5647   __ mov(scratch, c2); | 
|  5650   __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); |  5648   __ sub(scratch, Immediate(static_cast<int>('0'))); | 
|  5651   __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); |  5649   __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); | 
|  5652   __ j(below_equal, not_probed); |  5650   __ j(below_equal, not_probed); | 
|  5653  |  5651  | 
|  5654   __ bind(¬_array_index); |  5652   __ bind(¬_array_index); | 
|  5655   // Calculate the two character string hash. |  5653   // Calculate the two character string hash. | 
|  5656   Register hash = scratch1; |  5654   Register hash = scratch1; | 
|  5657   GenerateHashInit(masm, hash, c1, scratch); |  5655   GenerateHashInit(masm, hash, c1, scratch); | 
|  5658   GenerateHashAddCharacter(masm, hash, c2, scratch); |  5656   GenerateHashAddCharacter(masm, hash, c2, scratch); | 
|  5659   GenerateHashGetHash(masm, hash, scratch); |  5657   GenerateHashGetHash(masm, hash, scratch); | 
|  5660  |  5658  | 
|  5661   // Collect the two characters in a register. |  5659   // Collect the two characters in a register. | 
|  5662   Register chars = c1; |  5660   Register chars = c1; | 
|  5663   __ shl(c2, kBitsPerByte); |  5661   __ shl(c2, kBitsPerByte); | 
|  5664   __ or_(chars, Operand(c2)); |  5662   __ or_(chars, c2); | 
|  5665  |  5663  | 
|  5666   // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |  5664   // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | 
|  5667   // hash:  hash of two character string. |  5665   // hash:  hash of two character string. | 
|  5668  |  5666  | 
|  5669   // Load the symbol table. |  5667   // Load the symbol table. | 
|  5670   Register symbol_table = c2; |  5668   Register symbol_table = c2; | 
|  5671   ExternalReference roots_address = |  5669   ExternalReference roots_address = | 
|  5672       ExternalReference::roots_address(masm->isolate()); |  5670       ExternalReference::roots_address(masm->isolate()); | 
|  5673   __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); |  5671   __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); | 
|  5674   __ mov(symbol_table, |  5672   __ mov(symbol_table, | 
|  5675          Operand::StaticArray(scratch, times_pointer_size, roots_address)); |  5673          Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 
|  5676  |  5674  | 
|  5677   // Calculate capacity mask from the symbol table capacity. |  5675   // Calculate capacity mask from the symbol table capacity. | 
|  5678   Register mask = scratch2; |  5676   Register mask = scratch2; | 
|  5679   __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); |  5677   __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); | 
|  5680   __ SmiUntag(mask); |  5678   __ SmiUntag(mask); | 
|  5681   __ sub(Operand(mask), Immediate(1)); |  5679   __ sub(mask, Immediate(1)); | 
|  5682  |  5680  | 
|  5683   // Registers |  5681   // Registers | 
|  5684   // chars:        two character string, char 1 in byte 0 and char 2 in byte 1. |  5682   // chars:        two character string, char 1 in byte 0 and char 2 in byte 1. | 
|  5685   // hash:         hash of two character string |  5683   // hash:         hash of two character string | 
|  5686   // symbol_table: symbol table |  5684   // symbol_table: symbol table | 
|  5687   // mask:         capacity mask |  5685   // mask:         capacity mask | 
|  5688   // scratch:      - |  5686   // scratch:      - | 
|  5689  |  5687  | 
|  5690   // Perform a number of probes in the symbol table. |  5688   // Perform a number of probes in the symbol table. | 
|  5691   static const int kProbes = 4; |  5689   static const int kProbes = 4; | 
|  5692   Label found_in_symbol_table; |  5690   Label found_in_symbol_table; | 
|  5693   Label next_probe[kProbes], next_probe_pop_mask[kProbes]; |  5691   Label next_probe[kProbes], next_probe_pop_mask[kProbes]; | 
|  5694   for (int i = 0; i < kProbes; i++) { |  5692   for (int i = 0; i < kProbes; i++) { | 
|  5695     // Calculate entry in symbol table. |  5693     // Calculate entry in symbol table. | 
|  5696     __ mov(scratch, hash); |  5694     __ mov(scratch, hash); | 
|  5697     if (i > 0) { |  5695     if (i > 0) { | 
|  5698       __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); |  5696       __ add(scratch, Immediate(SymbolTable::GetProbeOffset(i))); | 
|  5699     } |  5697     } | 
|  5700     __ and_(scratch, Operand(mask)); |  5698     __ and_(scratch, mask); | 
|  5701  |  5699  | 
|  5702     // Load the entry from the symbol table. |  5700     // Load the entry from the symbol table. | 
|  5703     Register candidate = scratch;  // Scratch register contains candidate. |  5701     Register candidate = scratch;  // Scratch register contains candidate. | 
|  5704     STATIC_ASSERT(SymbolTable::kEntrySize == 1); |  5702     STATIC_ASSERT(SymbolTable::kEntrySize == 1); | 
|  5705     __ mov(candidate, |  5703     __ mov(candidate, | 
|  5706            FieldOperand(symbol_table, |  5704            FieldOperand(symbol_table, | 
|  5707                         scratch, |  5705                         scratch, | 
|  5708                         times_pointer_size, |  5706                         times_pointer_size, | 
|  5709                         SymbolTable::kElementsStartOffset)); |  5707                         SymbolTable::kElementsStartOffset)); | 
|  5710  |  5708  | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
|  5727  |  5725  | 
|  5728     // Check that the candidate is a non-external ascii string. |  5726     // Check that the candidate is a non-external ascii string. | 
|  5729     __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); |  5727     __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); | 
|  5730     __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); |  5728     __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | 
|  5731     __ JumpIfInstanceTypeIsNotSequentialAscii( |  5729     __ JumpIfInstanceTypeIsNotSequentialAscii( | 
|  5732         temp, temp, &next_probe_pop_mask[i]); |  5730         temp, temp, &next_probe_pop_mask[i]); | 
|  5733  |  5731  | 
|  5734     // Check if the two characters match. |  5732     // Check if the two characters match. | 
|  5735     __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); |  5733     __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); | 
|  5736     __ and_(temp, 0x0000ffff); |  5734     __ and_(temp, 0x0000ffff); | 
|  5737     __ cmp(chars, Operand(temp)); |  5735     __ cmp(chars, temp); | 
|  5738     __ j(equal, &found_in_symbol_table); |  5736     __ j(equal, &found_in_symbol_table); | 
|  5739     __ bind(&next_probe_pop_mask[i]); |  5737     __ bind(&next_probe_pop_mask[i]); | 
|  5740     __ pop(mask); |  5738     __ pop(mask); | 
|  5741     __ bind(&next_probe[i]); |  5739     __ bind(&next_probe[i]); | 
|  5742   } |  5740   } | 
|  5743  |  5741  | 
|  5744   // No matching 2 character string found by probing. |  5742   // No matching 2 character string found by probing. | 
|  5745   __ jmp(not_found); |  5743   __ jmp(not_found); | 
|  5746  |  5744  | 
|  5747   // Scratch register contains result when we fall through to here. |  5745   // Scratch register contains result when we fall through to here. | 
|  5748   Register result = scratch; |  5746   Register result = scratch; | 
|  5749   __ bind(&found_in_symbol_table); |  5747   __ bind(&found_in_symbol_table); | 
|  5750   __ pop(mask);  // Pop saved mask from the stack. |  5748   __ pop(mask);  // Pop saved mask from the stack. | 
|  5751   if (!result.is(eax)) { |  5749   if (!result.is(eax)) { | 
|  5752     __ mov(eax, result); |  5750     __ mov(eax, result); | 
|  5753   } |  5751   } | 
|  5754 } |  5752 } | 
|  5755  |  5753  | 
|  5756  |  5754  | 
|  5757 void StringHelper::GenerateHashInit(MacroAssembler* masm, |  5755 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 
|  5758                                     Register hash, |  5756                                     Register hash, | 
|  5759                                     Register character, |  5757                                     Register character, | 
|  5760                                     Register scratch) { |  5758                                     Register scratch) { | 
|  5761   // hash = character + (character << 10); |  5759   // hash = character + (character << 10); | 
|  5762   __ mov(hash, character); |  5760   __ mov(hash, character); | 
|  5763   __ shl(hash, 10); |  5761   __ shl(hash, 10); | 
|  5764   __ add(hash, Operand(character)); |  5762   __ add(hash, character); | 
|  5765   // hash ^= hash >> 6; |  5763   // hash ^= hash >> 6; | 
|  5766   __ mov(scratch, hash); |  5764   __ mov(scratch, hash); | 
|  5767   __ sar(scratch, 6); |  5765   __ sar(scratch, 6); | 
|  5768   __ xor_(hash, Operand(scratch)); |  5766   __ xor_(hash, scratch); | 
|  5769 } |  5767 } | 
|  5770  |  5768  | 
|  5771  |  5769  | 
|  5772 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, |  5770 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, | 
|  5773                                             Register hash, |  5771                                             Register hash, | 
|  5774                                             Register character, |  5772                                             Register character, | 
|  5775                                             Register scratch) { |  5773                                             Register scratch) { | 
|  5776   // hash += character; |  5774   // hash += character; | 
|  5777   __ add(hash, Operand(character)); |  5775   __ add(hash, character); | 
|  5778   // hash += hash << 10; |  5776   // hash += hash << 10; | 
|  5779   __ mov(scratch, hash); |  5777   __ mov(scratch, hash); | 
|  5780   __ shl(scratch, 10); |  5778   __ shl(scratch, 10); | 
|  5781   __ add(hash, Operand(scratch)); |  5779   __ add(hash, scratch); | 
|  5782   // hash ^= hash >> 6; |  5780   // hash ^= hash >> 6; | 
|  5783   __ mov(scratch, hash); |  5781   __ mov(scratch, hash); | 
|  5784   __ sar(scratch, 6); |  5782   __ sar(scratch, 6); | 
|  5785   __ xor_(hash, Operand(scratch)); |  5783   __ xor_(hash, scratch); | 
|  5786 } |  5784 } | 
|  5787  |  5785  | 
|  5788  |  5786  | 
|  5789 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, |  5787 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, | 
|  5790                                        Register hash, |  5788                                        Register hash, | 
|  5791                                        Register scratch) { |  5789                                        Register scratch) { | 
|  5792   // hash += hash << 3; |  5790   // hash += hash << 3; | 
|  5793   __ mov(scratch, hash); |  5791   __ mov(scratch, hash); | 
|  5794   __ shl(scratch, 3); |  5792   __ shl(scratch, 3); | 
|  5795   __ add(hash, Operand(scratch)); |  5793   __ add(hash, scratch); | 
|  5796   // hash ^= hash >> 11; |  5794   // hash ^= hash >> 11; | 
|  5797   __ mov(scratch, hash); |  5795   __ mov(scratch, hash); | 
|  5798   __ sar(scratch, 11); |  5796   __ sar(scratch, 11); | 
|  5799   __ xor_(hash, Operand(scratch)); |  5797   __ xor_(hash, scratch); | 
|  5800   // hash += hash << 15; |  5798   // hash += hash << 15; | 
|  5801   __ mov(scratch, hash); |  5799   __ mov(scratch, hash); | 
|  5802   __ shl(scratch, 15); |  5800   __ shl(scratch, 15); | 
|  5803   __ add(hash, Operand(scratch)); |  5801   __ add(hash, scratch); | 
|  5804  |  5802  | 
|  5805   // if (hash == 0) hash = 27; |  5803   // if (hash == 0) hash = 27; | 
|  5806   Label hash_not_zero; |  5804   Label hash_not_zero; | 
|  5807   __ test(hash, Operand(hash)); |  5805   __ test(hash, hash); | 
|  5808   __ j(not_zero, &hash_not_zero, Label::kNear); |  5806   __ j(not_zero, &hash_not_zero, Label::kNear); | 
|  5809   __ mov(hash, Immediate(27)); |  5807   __ mov(hash, Immediate(27)); | 
|  5810   __ bind(&hash_not_zero); |  5808   __ bind(&hash_not_zero); | 
|  5811 } |  5809 } | 
|  5812  |  5810  | 
|  5813  |  5811  | 
|  5814 void SubStringStub::Generate(MacroAssembler* masm) { |  5812 void SubStringStub::Generate(MacroAssembler* masm) { | 
|  5815   Label runtime; |  5813   Label runtime; | 
|  5816  |  5814  | 
|  5817   // Stack frame on entry. |  5815   // Stack frame on entry. | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
|  5829  |  5827  | 
|  5830   // eax: string |  5828   // eax: string | 
|  5831   // ebx: instance type |  5829   // ebx: instance type | 
|  5832  |  5830  | 
|  5833   // Calculate length of sub string using the smi values. |  5831   // Calculate length of sub string using the smi values. | 
|  5834   Label result_longer_than_two; |  5832   Label result_longer_than_two; | 
|  5835   __ mov(ecx, Operand(esp, 1 * kPointerSize));  // To index. |  5833   __ mov(ecx, Operand(esp, 1 * kPointerSize));  // To index. | 
|  5836   __ JumpIfNotSmi(ecx, &runtime); |  5834   __ JumpIfNotSmi(ecx, &runtime); | 
|  5837   __ mov(edx, Operand(esp, 2 * kPointerSize));  // From index. |  5835   __ mov(edx, Operand(esp, 2 * kPointerSize));  // From index. | 
|  5838   __ JumpIfNotSmi(edx, &runtime); |  5836   __ JumpIfNotSmi(edx, &runtime); | 
|  5839   __ sub(ecx, Operand(edx)); |  5837   __ sub(ecx, edx); | 
|  5840   __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); |  5838   __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); | 
|  5841   Label return_eax; |  5839   Label return_eax; | 
|  5842   __ j(equal, &return_eax); |  5840   __ j(equal, &return_eax); | 
|  5843   // Special handling of sub-strings of length 1 and 2. One character strings |  5841   // Special handling of sub-strings of length 1 and 2. One character strings | 
|  5844   // are handled in the runtime system (looked up in the single character |  5842   // are handled in the runtime system (looked up in the single character | 
|  5845   // cache). Two character strings are looked for in the symbol cache. |  5843   // cache). Two character strings are looked for in the symbol cache. | 
|  5846   __ SmiUntag(ecx);  // Result length is no longer smi. |  5844   __ SmiUntag(ecx);  // Result length is no longer smi. | 
|  5847   __ cmp(ecx, 2); |  5845   __ cmp(ecx, 2); | 
|  5848   __ j(greater, &result_longer_than_two); |  5846   __ j(greater, &result_longer_than_two); | 
|  5849   __ j(less, &runtime); |  5847   __ j(less, &runtime); | 
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  5961   __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat); |  5959   __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &non_ascii_flat); | 
|  5962  |  5960  | 
|  5963   // Allocate the result. |  5961   // Allocate the result. | 
|  5964   __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime); |  5962   __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime); | 
|  5965  |  5963  | 
|  5966   // eax: result string |  5964   // eax: result string | 
|  5967   // ecx: result string length |  5965   // ecx: result string length | 
|  5968   __ mov(edx, esi);  // esi used by following code. |  5966   __ mov(edx, esi);  // esi used by following code. | 
|  5969   // Locate first character of result. |  5967   // Locate first character of result. | 
|  5970   __ mov(edi, eax); |  5968   __ mov(edi, eax); | 
|  5971   __ add(Operand(edi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |  5969   __ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
|  5972   // Load string argument and locate character of sub string start. |  5970   // Load string argument and locate character of sub string start. | 
|  5973   __ mov(esi, Operand(esp, 3 * kPointerSize)); |  5971   __ mov(esi, Operand(esp, 3 * kPointerSize)); | 
|  5974   __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |  5972   __ add(esi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 
|  5975   __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from |  5973   __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from | 
|  5976   __ SmiUntag(ebx); |  5974   __ SmiUntag(ebx); | 
|  5977   __ add(esi, Operand(ebx)); |  5975   __ add(esi, ebx); | 
|  5978  |  5976  | 
|  5979   // eax: result string |  5977   // eax: result string | 
|  5980   // ecx: result length |  5978   // ecx: result length | 
|  5981   // edx: original value of esi |  5979   // edx: original value of esi | 
|  5982   // edi: first character of result |  5980   // edi: first character of result | 
|  5983   // esi: character of sub string start |  5981   // esi: character of sub string start | 
|  5984   StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); |  5982   StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); | 
|  5985   __ mov(esi, edx);  // Restore esi. |  5983   __ mov(esi, edx);  // Restore esi. | 
|  5986   Counters* counters = masm->isolate()->counters(); |  5984   Counters* counters = masm->isolate()->counters(); | 
|  5987   __ IncrementCounter(counters->sub_string_native(), 1); |  5985   __ IncrementCounter(counters->sub_string_native(), 1); | 
|  5988   __ ret(3 * kPointerSize); |  5986   __ ret(3 * kPointerSize); | 
|  5989  |  5987  | 
|  5990   __ bind(&non_ascii_flat); |  5988   __ bind(&non_ascii_flat); | 
|  5991   // eax: string |  5989   // eax: string | 
|  5992   // ebx: instance type & kStringRepresentationMask | kStringEncodingMask |  5990   // ebx: instance type & kStringRepresentationMask | kStringEncodingMask | 
|  5993   // ecx: result string length |  5991   // ecx: result string length | 
|  5994   // Check for flat two byte string |  5992   // Check for flat two byte string | 
|  5995   __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); |  5993   __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); | 
|  5996   __ j(not_equal, &runtime); |  5994   __ j(not_equal, &runtime); | 
|  5997  |  5995  | 
|  5998   // Allocate the result. |  5996   // Allocate the result. | 
|  5999   __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime); |  5997   __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime); | 
|  6000  |  5998  | 
|  6001   // eax: result string |  5999   // eax: result string | 
|  6002   // ecx: result string length |  6000   // ecx: result string length | 
|  6003   __ mov(edx, esi);  // esi used by following code. |  6001   __ mov(edx, esi);  // esi used by following code. | 
|  6004   // Locate first character of result. |  6002   // Locate first character of result. | 
|  6005   __ mov(edi, eax); |  6003   __ mov(edi, eax); | 
|  6006   __ add(Operand(edi), |  6004   __ add(edi, | 
|  6007          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |  6005          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 
|  6008   // Load string argument and locate character of sub string start. |  6006   // Load string argument and locate character of sub string start. | 
|  6009   __ mov(esi, Operand(esp, 3 * kPointerSize)); |  6007   __ mov(esi, Operand(esp, 3 * kPointerSize)); | 
|  6010   __ add(Operand(esi), |  6008   __ add(esi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 
|  6011          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |  | 
|  6012   __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from |  6009   __ mov(ebx, Operand(esp, 2 * kPointerSize));  // from | 
|  6013   // As from is a smi it is 2 times the value which matches the size of a two |  6010   // As from is a smi it is 2 times the value which matches the size of a two | 
|  6014   // byte character. |  6011   // byte character. | 
|  6015   STATIC_ASSERT(kSmiTag == 0); |  6012   STATIC_ASSERT(kSmiTag == 0); | 
|  6016   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |  6013   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 
|  6017   __ add(esi, Operand(ebx)); |  6014   __ add(esi, ebx); | 
|  6018  |  6015  | 
|  6019   // eax: result string |  6016   // eax: result string | 
|  6020   // ecx: result length |  6017   // ecx: result length | 
|  6021   // edx: original value of esi |  6018   // edx: original value of esi | 
|  6022   // edi: first character of result |  6019   // edi: first character of result | 
|  6023   // esi: character of sub string start |  6020   // esi: character of sub string start | 
|  6024   StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); |  6021   StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); | 
|  6025   __ mov(esi, edx);  // Restore esi. |  6022   __ mov(esi, edx);  // Restore esi. | 
|  6026  |  6023  | 
|  6027   __ bind(&return_eax); |  6024   __ bind(&return_eax); | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|  6047   __ cmp(length, FieldOperand(right, String::kLengthOffset)); |  6044   __ cmp(length, FieldOperand(right, String::kLengthOffset)); | 
|  6048   __ j(equal, &check_zero_length, Label::kNear); |  6045   __ j(equal, &check_zero_length, Label::kNear); | 
|  6049   __ bind(&strings_not_equal); |  6046   __ bind(&strings_not_equal); | 
|  6050   __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); |  6047   __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); | 
|  6051   __ ret(0); |  6048   __ ret(0); | 
|  6052  |  6049  | 
|  6053   // Check if the length is zero. |  6050   // Check if the length is zero. | 
|  6054   Label compare_chars; |  6051   Label compare_chars; | 
|  6055   __ bind(&check_zero_length); |  6052   __ bind(&check_zero_length); | 
|  6056   STATIC_ASSERT(kSmiTag == 0); |  6053   STATIC_ASSERT(kSmiTag == 0); | 
|  6057   __ test(length, Operand(length)); |  6054   __ test(length, length); | 
|  6058   __ j(not_zero, &compare_chars, Label::kNear); |  6055   __ j(not_zero, &compare_chars, Label::kNear); | 
|  6059   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |  6056   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 
|  6060   __ ret(0); |  6057   __ ret(0); | 
|  6061  |  6058  | 
|  6062   // Compare characters. |  6059   // Compare characters. | 
|  6063   __ bind(&compare_chars); |  6060   __ bind(&compare_chars); | 
|  6064   GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, |  6061   GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, | 
|  6065                                 &strings_not_equal, Label::kNear); |  6062                                 &strings_not_equal, Label::kNear); | 
|  6066  |  6063  | 
|  6067   // Characters are equal. |  6064   // Characters are equal. | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
|  6082   // Find minimum length. |  6079   // Find minimum length. | 
|  6083   Label left_shorter; |  6080   Label left_shorter; | 
|  6084   __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |  6081   __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 
|  6085   __ mov(scratch3, scratch1); |  6082   __ mov(scratch3, scratch1); | 
|  6086   __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |  6083   __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); | 
|  6087  |  6084  | 
|  6088   Register length_delta = scratch3; |  6085   Register length_delta = scratch3; | 
|  6089  |  6086  | 
|  6090   __ j(less_equal, &left_shorter, Label::kNear); |  6087   __ j(less_equal, &left_shorter, Label::kNear); | 
|  6091   // Right string is shorter. Change scratch1 to be length of right string. |  6088   // Right string is shorter. Change scratch1 to be length of right string. | 
|  6092   __ sub(scratch1, Operand(length_delta)); |  6089   __ sub(scratch1, length_delta); | 
|  6093   __ bind(&left_shorter); |  6090   __ bind(&left_shorter); | 
|  6094  |  6091  | 
|  6095   Register min_length = scratch1; |  6092   Register min_length = scratch1; | 
|  6096  |  6093  | 
|  6097   // If either length is zero, just compare lengths. |  6094   // If either length is zero, just compare lengths. | 
|  6098   Label compare_lengths; |  6095   Label compare_lengths; | 
|  6099   __ test(min_length, Operand(min_length)); |  6096   __ test(min_length, min_length); | 
|  6100   __ j(zero, &compare_lengths, Label::kNear); |  6097   __ j(zero, &compare_lengths, Label::kNear); | 
|  6101  |  6098  | 
|  6102   // Compare characters. |  6099   // Compare characters. | 
|  6103   Label result_not_equal; |  6100   Label result_not_equal; | 
|  6104   GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, |  6101   GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, | 
|  6105                                 &result_not_equal, Label::kNear); |  6102                                 &result_not_equal, Label::kNear); | 
|  6106  |  6103  | 
|  6107   // Compare lengths -  strings up to min-length are equal. |  6104   // Compare lengths -  strings up to min-length are equal. | 
|  6108   __ bind(&compare_lengths); |  6105   __ bind(&compare_lengths); | 
|  6109   __ test(length_delta, Operand(length_delta)); |  6106   __ test(length_delta, length_delta); | 
|  6110   __ j(not_zero, &result_not_equal, Label::kNear); |  6107   __ j(not_zero, &result_not_equal, Label::kNear); | 
|  6111  |  6108  | 
|  6112   // Result is EQUAL. |  6109   // Result is EQUAL. | 
|  6113   STATIC_ASSERT(EQUAL == 0); |  6110   STATIC_ASSERT(EQUAL == 0); | 
|  6114   STATIC_ASSERT(kSmiTag == 0); |  6111   STATIC_ASSERT(kSmiTag == 0); | 
|  6115   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |  6112   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 
|  6116   __ ret(0); |  6113   __ ret(0); | 
|  6117  |  6114  | 
|  6118   Label result_greater; |  6115   Label result_greater; | 
|  6119   __ bind(&result_not_equal); |  6116   __ bind(&result_not_equal); | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
|  6148          FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); |  6145          FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); | 
|  6149   __ neg(length); |  6146   __ neg(length); | 
|  6150   Register index = length;  // index = -length; |  6147   Register index = length;  // index = -length; | 
|  6151  |  6148  | 
|  6152   // Compare loop. |  6149   // Compare loop. | 
|  6153   Label loop; |  6150   Label loop; | 
|  6154   __ bind(&loop); |  6151   __ bind(&loop); | 
|  6155   __ mov_b(scratch, Operand(left, index, times_1, 0)); |  6152   __ mov_b(scratch, Operand(left, index, times_1, 0)); | 
|  6156   __ cmpb(scratch, Operand(right, index, times_1, 0)); |  6153   __ cmpb(scratch, Operand(right, index, times_1, 0)); | 
|  6157   __ j(not_equal, chars_not_equal, chars_not_equal_near); |  6154   __ j(not_equal, chars_not_equal, chars_not_equal_near); | 
|  6158   __ add(Operand(index), Immediate(1)); |  6155   __ add(index, Immediate(1)); | 
|  6159   __ j(not_zero, &loop); |  6156   __ j(not_zero, &loop); | 
|  6160 } |  6157 } | 
|  6161  |  6158  | 
|  6162  |  6159  | 
|  6163 void StringCompareStub::Generate(MacroAssembler* masm) { |  6160 void StringCompareStub::Generate(MacroAssembler* masm) { | 
|  6164   Label runtime; |  6161   Label runtime; | 
|  6165  |  6162  | 
|  6166   // Stack frame on entry. |  6163   // Stack frame on entry. | 
|  6167   //  esp[0]: return address |  6164   //  esp[0]: return address | 
|  6168   //  esp[4]: right string |  6165   //  esp[4]: right string | 
|  6169   //  esp[8]: left string |  6166   //  esp[8]: left string | 
|  6170  |  6167  | 
|  6171   __ mov(edx, Operand(esp, 2 * kPointerSize));  // left |  6168   __ mov(edx, Operand(esp, 2 * kPointerSize));  // left | 
|  6172   __ mov(eax, Operand(esp, 1 * kPointerSize));  // right |  6169   __ mov(eax, Operand(esp, 1 * kPointerSize));  // right | 
|  6173  |  6170  | 
|  6174   Label not_same; |  6171   Label not_same; | 
|  6175   __ cmp(edx, Operand(eax)); |  6172   __ cmp(edx, eax); | 
|  6176   __ j(not_equal, ¬_same, Label::kNear); |  6173   __ j(not_equal, ¬_same, Label::kNear); | 
|  6177   STATIC_ASSERT(EQUAL == 0); |  6174   STATIC_ASSERT(EQUAL == 0); | 
|  6178   STATIC_ASSERT(kSmiTag == 0); |  6175   STATIC_ASSERT(kSmiTag == 0); | 
|  6179   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |  6176   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 
|  6180   __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1); |  6177   __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1); | 
|  6181   __ ret(2 * kPointerSize); |  6178   __ ret(2 * kPointerSize); | 
|  6182  |  6179  | 
|  6183   __ bind(¬_same); |  6180   __ bind(¬_same); | 
|  6184  |  6181  | 
|  6185   // Check that both objects are sequential ascii strings. |  6182   // Check that both objects are sequential ascii strings. | 
|  6186   __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |  6183   __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); | 
|  6187  |  6184  | 
|  6188   // Compare flat ascii strings. |  6185   // Compare flat ascii strings. | 
|  6189   // Drop arguments from the stack. |  6186   // Drop arguments from the stack. | 
|  6190   __ pop(ecx); |  6187   __ pop(ecx); | 
|  6191   __ add(Operand(esp), Immediate(2 * kPointerSize)); |  6188   __ add(esp, Immediate(2 * kPointerSize)); | 
|  6192   __ push(ecx); |  6189   __ push(ecx); | 
|  6193   GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |  6190   GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 
|  6194  |  6191  | 
|  6195   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |  6192   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 
|  6196   // tagged as a small integer. |  6193   // tagged as a small integer. | 
|  6197   __ bind(&runtime); |  6194   __ bind(&runtime); | 
|  6198   __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |  6195   __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 
|  6199 } |  6196 } | 
|  6200  |  6197  | 
|  6201  |  6198  | 
|  6202 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |  6199 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 
|  6203   ASSERT(state_ == CompareIC::SMIS); |  6200   ASSERT(state_ == CompareIC::SMIS); | 
|  6204   Label miss; |  6201   Label miss; | 
|  6205   __ mov(ecx, Operand(edx)); |  6202   __ mov(ecx, edx); | 
|  6206   __ or_(ecx, Operand(eax)); |  6203   __ or_(ecx, eax); | 
|  6207   __ JumpIfNotSmi(ecx, &miss, Label::kNear); |  6204   __ JumpIfNotSmi(ecx, &miss, Label::kNear); | 
|  6208  |  6205  | 
|  6209   if (GetCondition() == equal) { |  6206   if (GetCondition() == equal) { | 
|  6210     // For equality we do not care about the sign of the result. |  6207     // For equality we do not care about the sign of the result. | 
|  6211     __ sub(eax, Operand(edx)); |  6208     __ sub(eax, edx); | 
|  6212   } else { |  6209   } else { | 
|  6213     Label done; |  6210     Label done; | 
|  6214     __ sub(edx, Operand(eax)); |  6211     __ sub(edx, eax); | 
|  6215     __ j(no_overflow, &done, Label::kNear); |  6212     __ j(no_overflow, &done, Label::kNear); | 
|  6216     // Correct sign of result in case of overflow. |  6213     // Correct sign of result in case of overflow. | 
|  6217     __ not_(edx); |  6214     __ not_(edx); | 
|  6218     __ bind(&done); |  6215     __ bind(&done); | 
|  6219     __ mov(eax, edx); |  6216     __ mov(eax, edx); | 
|  6220   } |  6217   } | 
|  6221   __ ret(0); |  6218   __ ret(0); | 
|  6222  |  6219  | 
|  6223   __ bind(&miss); |  6220   __ bind(&miss); | 
|  6224   GenerateMiss(masm); |  6221   GenerateMiss(masm); | 
|  6225 } |  6222 } | 
|  6226  |  6223  | 
|  6227  |  6224  | 
|  6228 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { |  6225 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { | 
|  6229   ASSERT(state_ == CompareIC::HEAP_NUMBERS); |  6226   ASSERT(state_ == CompareIC::HEAP_NUMBERS); | 
|  6230  |  6227  | 
|  6231   Label generic_stub; |  6228   Label generic_stub; | 
|  6232   Label unordered; |  6229   Label unordered; | 
|  6233   Label miss; |  6230   Label miss; | 
|  6234   __ mov(ecx, Operand(edx)); |  6231   __ mov(ecx, edx); | 
|  6235   __ and_(ecx, Operand(eax)); |  6232   __ and_(ecx, eax); | 
|  6236   __ JumpIfSmi(ecx, &generic_stub, Label::kNear); |  6233   __ JumpIfSmi(ecx, &generic_stub, Label::kNear); | 
|  6237  |  6234  | 
|  6238   __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); |  6235   __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); | 
|  6239   __ j(not_equal, &miss, Label::kNear); |  6236   __ j(not_equal, &miss, Label::kNear); | 
|  6240   __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); |  6237   __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); | 
|  6241   __ j(not_equal, &miss, Label::kNear); |  6238   __ j(not_equal, &miss, Label::kNear); | 
|  6242  |  6239  | 
|  6243   // Inlining the double comparison and falling back to the general compare |  6240   // Inlining the double comparison and falling back to the general compare | 
|  6244   // stub if NaN is involved or SS2 or CMOV is unsupported. |  6241   // stub if NaN is involved or SS2 or CMOV is unsupported. | 
|  6245   if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { |  6242   if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { | 
|  6246     CpuFeatures::Scope scope1(SSE2); |  6243     CpuFeatures::Scope scope1(SSE2); | 
|  6247     CpuFeatures::Scope scope2(CMOV); |  6244     CpuFeatures::Scope scope2(CMOV); | 
|  6248  |  6245  | 
|  6249     // Load left and right operand |  6246     // Load left and right operand | 
|  6250     __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |  6247     __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 
|  6251     __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |  6248     __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 
|  6252  |  6249  | 
|  6253     // Compare operands |  6250     // Compare operands | 
|  6254     __ ucomisd(xmm0, xmm1); |  6251     __ ucomisd(xmm0, xmm1); | 
|  6255  |  6252  | 
|  6256     // Don't base result on EFLAGS when a NaN is involved. |  6253     // Don't base result on EFLAGS when a NaN is involved. | 
|  6257     __ j(parity_even, &unordered, Label::kNear); |  6254     __ j(parity_even, &unordered, Label::kNear); | 
|  6258  |  6255  | 
|  6259     // Return a result of -1, 0, or 1, based on EFLAGS. |  6256     // Return a result of -1, 0, or 1, based on EFLAGS. | 
|  6260     // Performing mov, because xor would destroy the flag register. |  6257     // Performing mov, because xor would destroy the flag register. | 
|  6261     __ mov(eax, 0);  // equal |  6258     __ mov(eax, 0);  // equal | 
|  6262     __ mov(ecx, Immediate(Smi::FromInt(1))); |  6259     __ mov(ecx, Immediate(Smi::FromInt(1))); | 
|  6263     __ cmov(above, eax, Operand(ecx)); |  6260     __ cmov(above, eax, ecx); | 
|  6264     __ mov(ecx, Immediate(Smi::FromInt(-1))); |  6261     __ mov(ecx, Immediate(Smi::FromInt(-1))); | 
|  6265     __ cmov(below, eax, Operand(ecx)); |  6262     __ cmov(below, eax, ecx); | 
|  6266     __ ret(0); |  6263     __ ret(0); | 
|  6267  |  6264  | 
|  6268     __ bind(&unordered); |  6265     __ bind(&unordered); | 
|  6269   } |  6266   } | 
|  6270  |  6267  | 
|  6271   CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); |  6268   CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); | 
|  6272   __ bind(&generic_stub); |  6269   __ bind(&generic_stub); | 
|  6273   __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); |  6270   __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); | 
|  6274  |  6271  | 
|  6275   __ bind(&miss); |  6272   __ bind(&miss); | 
|  6276   GenerateMiss(masm); |  6273   GenerateMiss(masm); | 
|  6277 } |  6274 } | 
|  6278  |  6275  | 
|  6279  |  6276  | 
|  6280 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { |  6277 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { | 
|  6281   ASSERT(state_ == CompareIC::SYMBOLS); |  6278   ASSERT(state_ == CompareIC::SYMBOLS); | 
|  6282   ASSERT(GetCondition() == equal); |  6279   ASSERT(GetCondition() == equal); | 
|  6283  |  6280  | 
|  6284   // Registers containing left and right operands respectively. |  6281   // Registers containing left and right operands respectively. | 
|  6285   Register left = edx; |  6282   Register left = edx; | 
|  6286   Register right = eax; |  6283   Register right = eax; | 
|  6287   Register tmp1 = ecx; |  6284   Register tmp1 = ecx; | 
|  6288   Register tmp2 = ebx; |  6285   Register tmp2 = ebx; | 
|  6289  |  6286  | 
|  6290   // Check that both operands are heap objects. |  6287   // Check that both operands are heap objects. | 
|  6291   Label miss; |  6288   Label miss; | 
|  6292   __ mov(tmp1, Operand(left)); |  6289   __ mov(tmp1, left); | 
|  6293   STATIC_ASSERT(kSmiTag == 0); |  6290   STATIC_ASSERT(kSmiTag == 0); | 
|  6294   __ and_(tmp1, Operand(right)); |  6291   __ and_(tmp1, right); | 
|  6295   __ JumpIfSmi(tmp1, &miss, Label::kNear); |  6292   __ JumpIfSmi(tmp1, &miss, Label::kNear); | 
|  6296  |  6293  | 
|  6297   // Check that both operands are symbols. |  6294   // Check that both operands are symbols. | 
|  6298   __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |  6295   __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 
|  6299   __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |  6296   __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 
|  6300   __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |  6297   __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 
|  6301   __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |  6298   __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 
|  6302   STATIC_ASSERT(kSymbolTag != 0); |  6299   STATIC_ASSERT(kSymbolTag != 0); | 
|  6303   __ and_(tmp1, Operand(tmp2)); |  6300   __ and_(tmp1, tmp2); | 
|  6304   __ test(tmp1, Immediate(kIsSymbolMask)); |  6301   __ test(tmp1, Immediate(kIsSymbolMask)); | 
|  6305   __ j(zero, &miss, Label::kNear); |  6302   __ j(zero, &miss, Label::kNear); | 
|  6306  |  6303  | 
|  6307   // Symbols are compared by identity. |  6304   // Symbols are compared by identity. | 
|  6308   Label done; |  6305   Label done; | 
|  6309   __ cmp(left, Operand(right)); |  6306   __ cmp(left, right); | 
|  6310   // Make sure eax is non-zero. At this point input operands are |  6307   // Make sure eax is non-zero. At this point input operands are | 
|  6311   // guaranteed to be non-zero. |  6308   // guaranteed to be non-zero. | 
|  6312   ASSERT(right.is(eax)); |  6309   ASSERT(right.is(eax)); | 
|  6313   __ j(not_equal, &done, Label::kNear); |  6310   __ j(not_equal, &done, Label::kNear); | 
|  6314   STATIC_ASSERT(EQUAL == 0); |  6311   STATIC_ASSERT(EQUAL == 0); | 
|  6315   STATIC_ASSERT(kSmiTag == 0); |  6312   STATIC_ASSERT(kSmiTag == 0); | 
|  6316   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |  6313   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 
|  6317   __ bind(&done); |  6314   __ bind(&done); | 
|  6318   __ ret(0); |  6315   __ ret(0); | 
|  6319  |  6316  | 
|  6320   __ bind(&miss); |  6317   __ bind(&miss); | 
|  6321   GenerateMiss(masm); |  6318   GenerateMiss(masm); | 
|  6322 } |  6319 } | 
|  6323  |  6320  | 
|  6324  |  6321  | 
|  6325 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { |  6322 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { | 
|  6326   ASSERT(state_ == CompareIC::STRINGS); |  6323   ASSERT(state_ == CompareIC::STRINGS); | 
|  6327   ASSERT(GetCondition() == equal); |  6324   ASSERT(GetCondition() == equal); | 
|  6328   Label miss; |  6325   Label miss; | 
|  6329  |  6326  | 
|  6330   // Registers containing left and right operands respectively. |  6327   // Registers containing left and right operands respectively. | 
|  6331   Register left = edx; |  6328   Register left = edx; | 
|  6332   Register right = eax; |  6329   Register right = eax; | 
|  6333   Register tmp1 = ecx; |  6330   Register tmp1 = ecx; | 
|  6334   Register tmp2 = ebx; |  6331   Register tmp2 = ebx; | 
|  6335   Register tmp3 = edi; |  6332   Register tmp3 = edi; | 
|  6336  |  6333  | 
|  6337   // Check that both operands are heap objects. |  6334   // Check that both operands are heap objects. | 
|  6338   __ mov(tmp1, Operand(left)); |  6335   __ mov(tmp1, left); | 
|  6339   STATIC_ASSERT(kSmiTag == 0); |  6336   STATIC_ASSERT(kSmiTag == 0); | 
|  6340   __ and_(tmp1, Operand(right)); |  6337   __ and_(tmp1, right); | 
|  6341   __ JumpIfSmi(tmp1, &miss); |  6338   __ JumpIfSmi(tmp1, &miss); | 
|  6342  |  6339  | 
|  6343   // Check that both operands are strings. This leaves the instance |  6340   // Check that both operands are strings. This leaves the instance | 
|  6344   // types loaded in tmp1 and tmp2. |  6341   // types loaded in tmp1 and tmp2. | 
|  6345   __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |  6342   __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 
|  6346   __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |  6343   __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 
|  6347   __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |  6344   __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 
|  6348   __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |  6345   __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 
|  6349   __ mov(tmp3, tmp1); |  6346   __ mov(tmp3, tmp1); | 
|  6350   STATIC_ASSERT(kNotStringTag != 0); |  6347   STATIC_ASSERT(kNotStringTag != 0); | 
|  6351   __ or_(tmp3, Operand(tmp2)); |  6348   __ or_(tmp3, tmp2); | 
|  6352   __ test(tmp3, Immediate(kIsNotStringMask)); |  6349   __ test(tmp3, Immediate(kIsNotStringMask)); | 
|  6353   __ j(not_zero, &miss); |  6350   __ j(not_zero, &miss); | 
|  6354  |  6351  | 
|  6355   // Fast check for identical strings. |  6352   // Fast check for identical strings. | 
|  6356   Label not_same; |  6353   Label not_same; | 
|  6357   __ cmp(left, Operand(right)); |  6354   __ cmp(left, right); | 
|  6358   __ j(not_equal, ¬_same, Label::kNear); |  6355   __ j(not_equal, ¬_same, Label::kNear); | 
|  6359   STATIC_ASSERT(EQUAL == 0); |  6356   STATIC_ASSERT(EQUAL == 0); | 
|  6360   STATIC_ASSERT(kSmiTag == 0); |  6357   STATIC_ASSERT(kSmiTag == 0); | 
|  6361   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |  6358   __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 
|  6362   __ ret(0); |  6359   __ ret(0); | 
|  6363  |  6360  | 
|  6364   // Handle not identical strings. |  6361   // Handle not identical strings. | 
|  6365   __ bind(¬_same); |  6362   __ bind(¬_same); | 
|  6366  |  6363  | 
|  6367   // Check that both strings are symbols. If they are, we're done |  6364   // Check that both strings are symbols. If they are, we're done | 
|  6368   // because we already know they are not identical. |  6365   // because we already know they are not identical. | 
|  6369   Label do_compare; |  6366   Label do_compare; | 
|  6370   STATIC_ASSERT(kSymbolTag != 0); |  6367   STATIC_ASSERT(kSymbolTag != 0); | 
|  6371   __ and_(tmp1, Operand(tmp2)); |  6368   __ and_(tmp1, tmp2); | 
|  6372   __ test(tmp1, Immediate(kIsSymbolMask)); |  6369   __ test(tmp1, Immediate(kIsSymbolMask)); | 
|  6373   __ j(zero, &do_compare, Label::kNear); |  6370   __ j(zero, &do_compare, Label::kNear); | 
|  6374   // Make sure eax is non-zero. At this point input operands are |  6371   // Make sure eax is non-zero. At this point input operands are | 
|  6375   // guaranteed to be non-zero. |  6372   // guaranteed to be non-zero. | 
|  6376   ASSERT(right.is(eax)); |  6373   ASSERT(right.is(eax)); | 
|  6377   __ ret(0); |  6374   __ ret(0); | 
|  6378  |  6375  | 
|  6379   // Check that both strings are sequential ASCII. |  6376   // Check that both strings are sequential ASCII. | 
|  6380   Label runtime; |  6377   Label runtime; | 
|  6381   __ bind(&do_compare); |  6378   __ bind(&do_compare); | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
|  6394   __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |  6391   __ TailCallRuntime(Runtime::kStringEquals, 2, 1); | 
|  6395  |  6392  | 
|  6396   __ bind(&miss); |  6393   __ bind(&miss); | 
|  6397   GenerateMiss(masm); |  6394   GenerateMiss(masm); | 
|  6398 } |  6395 } | 
|  6399  |  6396  | 
|  6400  |  6397  | 
|  6401 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |  6398 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 
|  6402   ASSERT(state_ == CompareIC::OBJECTS); |  6399   ASSERT(state_ == CompareIC::OBJECTS); | 
|  6403   Label miss; |  6400   Label miss; | 
|  6404   __ mov(ecx, Operand(edx)); |  6401   __ mov(ecx, edx); | 
|  6405   __ and_(ecx, Operand(eax)); |  6402   __ and_(ecx, eax); | 
|  6406   __ JumpIfSmi(ecx, &miss, Label::kNear); |  6403   __ JumpIfSmi(ecx, &miss, Label::kNear); | 
|  6407  |  6404  | 
|  6408   __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); |  6405   __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); | 
|  6409   __ j(not_equal, &miss, Label::kNear); |  6406   __ j(not_equal, &miss, Label::kNear); | 
|  6410   __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); |  6407   __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); | 
|  6411   __ j(not_equal, &miss, Label::kNear); |  6408   __ j(not_equal, &miss, Label::kNear); | 
|  6412  |  6409  | 
|  6413   ASSERT(GetCondition() == equal); |  6410   ASSERT(GetCondition() == equal); | 
|  6414   __ sub(eax, Operand(edx)); |  6411   __ sub(eax, edx); | 
|  6415   __ ret(0); |  6412   __ ret(0); | 
|  6416  |  6413  | 
|  6417   __ bind(&miss); |  6414   __ bind(&miss); | 
|  6418   GenerateMiss(masm); |  6415   GenerateMiss(masm); | 
|  6419 } |  6416 } | 
|  6420  |  6417  | 
|  6421  |  6418  | 
|  6422 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { |  6419 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { | 
|  6423   // Save the registers. |  6420   // Save the registers. | 
|  6424   __ pop(ecx); |  6421   __ pop(ecx); | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
|  6440   // Compute the entry point of the rewritten stub. |  6437   // Compute the entry point of the rewritten stub. | 
|  6441   __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); |  6438   __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); | 
|  6442  |  6439  | 
|  6443   // Restore registers. |  6440   // Restore registers. | 
|  6444   __ pop(ecx); |  6441   __ pop(ecx); | 
|  6445   __ pop(eax); |  6442   __ pop(eax); | 
|  6446   __ pop(edx); |  6443   __ pop(edx); | 
|  6447   __ push(ecx); |  6444   __ push(ecx); | 
|  6448  |  6445  | 
|  6449   // Do a tail call to the rewritten stub. |  6446   // Do a tail call to the rewritten stub. | 
|  6450   __ jmp(Operand(edi)); |  6447   __ jmp(edi); | 
|  6451 } |  6448 } | 
|  6452  |  6449  | 
|  6453  |  6450  | 
|  6454 // Helper function used to check that the dictionary doesn't contain |  6451 // Helper function used to check that the dictionary doesn't contain | 
|  6455 // the property. This function may return false negatives, so miss_label |  6452 // the property. This function may return false negatives, so miss_label | 
|  6456 // must always call a backup property check that is complete. |  6453 // must always call a backup property check that is complete. | 
|  6457 // This function is safe to call if the receiver has fast properties. |  6454 // This function is safe to call if the receiver has fast properties. | 
|  6458 // Name must be a symbol and receiver must be a heap object. |  6455 // Name must be a symbol and receiver must be a heap object. | 
|  6459 MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( |  6456 MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( | 
|  6460     MacroAssembler* masm, |  6457     MacroAssembler* masm, | 
|  6461     Label* miss, |  6458     Label* miss, | 
|  6462     Label* done, |  6459     Label* done, | 
|  6463     Register properties, |  6460     Register properties, | 
|  6464     String* name, |  6461     String* name, | 
|  6465     Register r0) { |  6462     Register r0) { | 
|  6466   ASSERT(name->IsSymbol()); |  6463   ASSERT(name->IsSymbol()); | 
|  6467  |  6464  | 
|  6468   // If names of slots in range from 1 to kProbes - 1 for the hash value are |  6465   // If names of slots in range from 1 to kProbes - 1 for the hash value are | 
|  6469   // not equal to the name and kProbes-th slot is not used (its name is the |  6466   // not equal to the name and kProbes-th slot is not used (its name is the | 
|  6470   // undefined value), it guarantees the hash table doesn't contain the |  6467   // undefined value), it guarantees the hash table doesn't contain the | 
|  6471   // property. It's true even if some slots represent deleted properties |  6468   // property. It's true even if some slots represent deleted properties | 
|  6472   // (their names are the null value). |  6469   // (their names are the null value). | 
|  6473   for (int i = 0; i < kInlinedProbes; i++) { |  6470   for (int i = 0; i < kInlinedProbes; i++) { | 
|  6474     // Compute the masked index: (hash + i + i * i) & mask. |  6471     // Compute the masked index: (hash + i + i * i) & mask. | 
|  6475     Register index = r0; |  6472     Register index = r0; | 
|  6476     // Capacity is smi 2^n. |  6473     // Capacity is smi 2^n. | 
|  6477     __ mov(index, FieldOperand(properties, kCapacityOffset)); |  6474     __ mov(index, FieldOperand(properties, kCapacityOffset)); | 
|  6478     __ dec(index); |  6475     __ dec(index); | 
|  6479     __ and_(Operand(index), |  6476     __ and_(index, | 
|  6480            Immediate(Smi::FromInt(name->Hash() + |  6477             Immediate(Smi::FromInt(name->Hash() + | 
|  6481                                    StringDictionary::GetProbeOffset(i)))); |  6478                                    StringDictionary::GetProbeOffset(i)))); | 
|  6482  |  6479  | 
|  6483     // Scale the index by multiplying by the entry size. |  6480     // Scale the index by multiplying by the entry size. | 
|  6484     ASSERT(StringDictionary::kEntrySize == 3); |  6481     ASSERT(StringDictionary::kEntrySize == 3); | 
|  6485     __ lea(index, Operand(index, index, times_2, 0));  // index *= 3. |  6482     __ lea(index, Operand(index, index, times_2, 0));  // index *= 3. | 
|  6486     Register entity_name = r0; |  6483     Register entity_name = r0; | 
|  6487     // Having undefined at this place means the name is not contained. |  6484     // Having undefined at this place means the name is not contained. | 
|  6488     ASSERT_EQ(kSmiTagSize, 1); |  6485     ASSERT_EQ(kSmiTagSize, 1); | 
|  6489     __ mov(entity_name, Operand(properties, index, times_half_pointer_size, |  6486     __ mov(entity_name, Operand(properties, index, times_half_pointer_size, | 
|  6490                                 kElementsStartOffset - kHeapObjectTag)); |  6487                                 kElementsStartOffset - kHeapObjectTag)); | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
|  6503   } |  6500   } | 
|  6504  |  6501  | 
|  6505   StringDictionaryLookupStub stub(properties, |  6502   StringDictionaryLookupStub stub(properties, | 
|  6506                                   r0, |  6503                                   r0, | 
|  6507                                   r0, |  6504                                   r0, | 
|  6508                                   StringDictionaryLookupStub::NEGATIVE_LOOKUP); |  6505                                   StringDictionaryLookupStub::NEGATIVE_LOOKUP); | 
|  6509   __ push(Immediate(Handle<Object>(name))); |  6506   __ push(Immediate(Handle<Object>(name))); | 
|  6510   __ push(Immediate(name->Hash())); |  6507   __ push(Immediate(name->Hash())); | 
|  6511   MaybeObject* result = masm->TryCallStub(&stub); |  6508   MaybeObject* result = masm->TryCallStub(&stub); | 
|  6512   if (result->IsFailure()) return result; |  6509   if (result->IsFailure()) return result; | 
|  6513   __ test(r0, Operand(r0)); |  6510   __ test(r0, r0); | 
|  6514   __ j(not_zero, miss); |  6511   __ j(not_zero, miss); | 
|  6515   __ jmp(done); |  6512   __ jmp(done); | 
|  6516   return result; |  6513   return result; | 
|  6517 } |  6514 } | 
|  6518  |  6515  | 
|  6519  |  6516  | 
|  6520 // Probe the string dictionary in the |elements| register. Jump to the |  6517 // Probe the string dictionary in the |elements| register. Jump to the | 
|  6521 // |done| label if a property with the given name is found leaving the |  6518 // |done| label if a property with the given name is found leaving the | 
|  6522 // index into the dictionary in |r0|. Jump to the |miss| label |  6519 // index into the dictionary in |r0|. Jump to the |miss| label | 
|  6523 // otherwise. |  6520 // otherwise. | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
|  6536   __ dec(r1); |  6533   __ dec(r1); | 
|  6537  |  6534  | 
|  6538   // Generate an unrolled loop that performs a few probes before |  6535   // Generate an unrolled loop that performs a few probes before | 
|  6539   // giving up. Measurements done on Gmail indicate that 2 probes |  6536   // giving up. Measurements done on Gmail indicate that 2 probes | 
|  6540   // cover ~93% of loads from dictionaries. |  6537   // cover ~93% of loads from dictionaries. | 
|  6541   for (int i = 0; i < kInlinedProbes; i++) { |  6538   for (int i = 0; i < kInlinedProbes; i++) { | 
|  6542     // Compute the masked index: (hash + i + i * i) & mask. |  6539     // Compute the masked index: (hash + i + i * i) & mask. | 
|  6543     __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); |  6540     __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); | 
|  6544     __ shr(r0, String::kHashShift); |  6541     __ shr(r0, String::kHashShift); | 
|  6545     if (i > 0) { |  6542     if (i > 0) { | 
|  6546       __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); |  6543       __ add(r0, Immediate(StringDictionary::GetProbeOffset(i))); | 
|  6547     } |  6544     } | 
|  6548     __ and_(r0, Operand(r1)); |  6545     __ and_(r0, r1); | 
|  6549  |  6546  | 
|  6550     // Scale the index by multiplying by the entry size. |  6547     // Scale the index by multiplying by the entry size. | 
|  6551     ASSERT(StringDictionary::kEntrySize == 3); |  6548     ASSERT(StringDictionary::kEntrySize == 3); | 
|  6552     __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3 |  6549     __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3 | 
|  6553  |  6550  | 
|  6554     // Check if the key is identical to the name. |  6551     // Check if the key is identical to the name. | 
|  6555     __ cmp(name, Operand(elements, |  6552     __ cmp(name, Operand(elements, | 
|  6556                          r0, |  6553                          r0, | 
|  6557                          times_4, |  6554                          times_4, | 
|  6558                          kElementsStartOffset - kHeapObjectTag)); |  6555                          kElementsStartOffset - kHeapObjectTag)); | 
|  6559     __ j(equal, done); |  6556     __ j(equal, done); | 
|  6560   } |  6557   } | 
|  6561  |  6558  | 
|  6562   StringDictionaryLookupStub stub(elements, |  6559   StringDictionaryLookupStub stub(elements, | 
|  6563                                   r1, |  6560                                   r1, | 
|  6564                                   r0, |  6561                                   r0, | 
|  6565                                   POSITIVE_LOOKUP); |  6562                                   POSITIVE_LOOKUP); | 
|  6566   __ push(name); |  6563   __ push(name); | 
|  6567   __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); |  6564   __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); | 
|  6568   __ shr(r0, String::kHashShift); |  6565   __ shr(r0, String::kHashShift); | 
|  6569   __ push(r0); |  6566   __ push(r0); | 
|  6570   __ CallStub(&stub); |  6567   __ CallStub(&stub); | 
|  6571  |  6568  | 
|  6572   __ test(r1, Operand(r1)); |  6569   __ test(r1, r1); | 
|  6573   __ j(zero, miss); |  6570   __ j(zero, miss); | 
|  6574   __ jmp(done); |  6571   __ jmp(done); | 
|  6575 } |  6572 } | 
|  6576  |  6573  | 
|  6577  |  6574  | 
|  6578 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { |  6575 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { | 
|  6579   // This stub overrides SometimesSetsUpAFrame() to return false.  That means |  6576   // This stub overrides SometimesSetsUpAFrame() to return false.  That means | 
|  6580   // we cannot call anything that could cause a GC from this stub. |  6577   // we cannot call anything that could cause a GC from this stub. | 
|  6581   // Stack frame on entry: |  6578   // Stack frame on entry: | 
|  6582   //  esp[0 * kPointerSize]: return address. |  6579   //  esp[0 * kPointerSize]: return address. | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
|  6601  |  6598  | 
|  6602   // If names of slots in range from 1 to kProbes - 1 for the hash value are |  6599   // If names of slots in range from 1 to kProbes - 1 for the hash value are | 
|  6603   // not equal to the name and kProbes-th slot is not used (its name is the |  6600   // not equal to the name and kProbes-th slot is not used (its name is the | 
|  6604   // undefined value), it guarantees the hash table doesn't contain the |  6601   // undefined value), it guarantees the hash table doesn't contain the | 
|  6605   // property. It's true even if some slots represent deleted properties |  6602   // property. It's true even if some slots represent deleted properties | 
|  6606   // (their names are the null value). |  6603   // (their names are the null value). | 
|  6607   for (int i = kInlinedProbes; i < kTotalProbes; i++) { |  6604   for (int i = kInlinedProbes; i < kTotalProbes; i++) { | 
|  6608     // Compute the masked index: (hash + i + i * i) & mask. |  6605     // Compute the masked index: (hash + i + i * i) & mask. | 
|  6609     __ mov(scratch, Operand(esp, 2 * kPointerSize)); |  6606     __ mov(scratch, Operand(esp, 2 * kPointerSize)); | 
|  6610     if (i > 0) { |  6607     if (i > 0) { | 
|  6611       __ add(Operand(scratch), |  6608       __ add(scratch, Immediate(StringDictionary::GetProbeOffset(i))); | 
|  6612              Immediate(StringDictionary::GetProbeOffset(i))); |  | 
|  6613     } |  6609     } | 
|  6614     __ and_(scratch, Operand(esp, 0)); |  6610     __ and_(scratch, Operand(esp, 0)); | 
|  6615  |  6611  | 
|  6616     // Scale the index by multiplying by the entry size. |  6612     // Scale the index by multiplying by the entry size. | 
|  6617     ASSERT(StringDictionary::kEntrySize == 3); |  6613     ASSERT(StringDictionary::kEntrySize == 3); | 
|  6618     __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3. |  6614     __ lea(index_, Operand(scratch, scratch, times_2, 0));  // index *= 3. | 
|  6619  |  6615  | 
|  6620     // Having undefined at this place means the name is not contained. |  6616     // Having undefined at this place means the name is not contained. | 
|  6621     ASSERT_EQ(kSmiTagSize, 1); |  6617     ASSERT_EQ(kSmiTagSize, 1); | 
|  6622     __ mov(scratch, Operand(dictionary_, |  6618     __ mov(scratch, Operand(dictionary_, | 
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  6931  |  6927  | 
|  6932   // Fall through when we need to inform the incremental marker. |  6928   // Fall through when we need to inform the incremental marker. | 
|  6933 } |  6929 } | 
|  6934  |  6930  | 
|  6935  |  6931  | 
|  6936 #undef __ |  6932 #undef __ | 
|  6937  |  6933  | 
|  6938 } }  // namespace v8::internal |  6934 } }  // namespace v8::internal | 
|  6939  |  6935  | 
|  6940 #endif  // V8_TARGET_ARCH_IA32 |  6936 #endif  // V8_TARGET_ARCH_IA32 | 
| OLD | NEW |