| OLD | NEW | 
|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "v8.h" | 5 #include "v8.h" | 
| 6 | 6 | 
| 7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_X87 | 
| 8 | 8 | 
| 9 #include "bootstrapper.h" | 9 #include "bootstrapper.h" | 
| 10 #include "codegen.h" | 10 #include "codegen.h" | 
| 11 #include "cpu-profiler.h" | 11 #include "cpu-profiler.h" | 
| 12 #include "debug.h" | 12 #include "debug.h" | 
| 13 #include "isolate-inl.h" | 13 #include "isolate-inl.h" | 
| 14 #include "runtime.h" | 14 #include "runtime.h" | 
| 15 #include "serialize.h" | 15 #include "serialize.h" | 
| 16 | 16 | 
| 17 namespace v8 { | 17 namespace v8 { | 
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 136   test_b(Operand(scratch, MemoryChunk::kFlagsOffset), | 136   test_b(Operand(scratch, MemoryChunk::kFlagsOffset), | 
| 137          static_cast<uint8_t>(mask)); | 137          static_cast<uint8_t>(mask)); | 
| 138   j(cc, condition_met, condition_met_distance); | 138   j(cc, condition_met, condition_met_distance); | 
| 139 } | 139 } | 
| 140 | 140 | 
| 141 | 141 | 
| 142 void MacroAssembler::RememberedSetHelper( | 142 void MacroAssembler::RememberedSetHelper( | 
| 143     Register object,  // Only used for debug checks. | 143     Register object,  // Only used for debug checks. | 
| 144     Register addr, | 144     Register addr, | 
| 145     Register scratch, | 145     Register scratch, | 
| 146     SaveFPRegsMode save_fp, |  | 
| 147     MacroAssembler::RememberedSetFinalAction and_then) { | 146     MacroAssembler::RememberedSetFinalAction and_then) { | 
| 148   Label done; | 147   Label done; | 
| 149   if (emit_debug_code()) { | 148   if (emit_debug_code()) { | 
| 150     Label ok; | 149     Label ok; | 
| 151     JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); | 150     JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); | 
| 152     int3(); | 151     int3(); | 
| 153     bind(&ok); | 152     bind(&ok); | 
| 154   } | 153   } | 
| 155   // Load store buffer top. | 154   // Load store buffer top. | 
| 156   ExternalReference store_buffer = | 155   ExternalReference store_buffer = | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 168   if (and_then == kReturnAtEnd) { | 167   if (and_then == kReturnAtEnd) { | 
| 169     Label buffer_overflowed; | 168     Label buffer_overflowed; | 
| 170     j(not_equal, &buffer_overflowed, Label::kNear); | 169     j(not_equal, &buffer_overflowed, Label::kNear); | 
| 171     ret(0); | 170     ret(0); | 
| 172     bind(&buffer_overflowed); | 171     bind(&buffer_overflowed); | 
| 173   } else { | 172   } else { | 
| 174     ASSERT(and_then == kFallThroughAtEnd); | 173     ASSERT(and_then == kFallThroughAtEnd); | 
| 175     j(equal, &done, Label::kNear); | 174     j(equal, &done, Label::kNear); | 
| 176   } | 175   } | 
| 177   StoreBufferOverflowStub store_buffer_overflow = | 176   StoreBufferOverflowStub store_buffer_overflow = | 
| 178       StoreBufferOverflowStub(isolate(), save_fp); | 177       StoreBufferOverflowStub(isolate()); | 
| 179   CallStub(&store_buffer_overflow); | 178   CallStub(&store_buffer_overflow); | 
| 180   if (and_then == kReturnAtEnd) { | 179   if (and_then == kReturnAtEnd) { | 
| 181     ret(0); | 180     ret(0); | 
| 182   } else { | 181   } else { | 
| 183     ASSERT(and_then == kFallThroughAtEnd); | 182     ASSERT(and_then == kFallThroughAtEnd); | 
| 184     bind(&done); | 183     bind(&done); | 
| 185   } | 184   } | 
| 186 } | 185 } | 
| 187 | 186 | 
| 188 | 187 | 
| 189 void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg, |  | 
| 190                                         XMMRegister scratch_reg, |  | 
| 191                                         Register result_reg) { |  | 
| 192   Label done; |  | 
| 193   Label conv_failure; |  | 
| 194   xorps(scratch_reg, scratch_reg); |  | 
| 195   cvtsd2si(result_reg, input_reg); |  | 
| 196   test(result_reg, Immediate(0xFFFFFF00)); |  | 
| 197   j(zero, &done, Label::kNear); |  | 
| 198   cmp(result_reg, Immediate(0x1)); |  | 
| 199   j(overflow, &conv_failure, Label::kNear); |  | 
| 200   mov(result_reg, Immediate(0)); |  | 
| 201   setcc(sign, result_reg); |  | 
| 202   sub(result_reg, Immediate(1)); |  | 
| 203   and_(result_reg, Immediate(255)); |  | 
| 204   jmp(&done, Label::kNear); |  | 
| 205   bind(&conv_failure); |  | 
| 206   Move(result_reg, Immediate(0)); |  | 
| 207   ucomisd(input_reg, scratch_reg); |  | 
| 208   j(below, &done, Label::kNear); |  | 
| 209   Move(result_reg, Immediate(255)); |  | 
| 210   bind(&done); |  | 
| 211 } |  | 
| 212 |  | 
| 213 |  | 
| 214 void MacroAssembler::ClampUint8(Register reg) { | 188 void MacroAssembler::ClampUint8(Register reg) { | 
| 215   Label done; | 189   Label done; | 
| 216   test(reg, Immediate(0xFFFFFF00)); | 190   test(reg, Immediate(0xFFFFFF00)); | 
| 217   j(zero, &done, Label::kNear); | 191   j(zero, &done, Label::kNear); | 
| 218   setcc(negative, reg);  // 1 if negative, 0 if positive. | 192   setcc(negative, reg);  // 1 if negative, 0 if positive. | 
| 219   dec_b(reg);  // 0 if negative, 255 if positive. | 193   dec_b(reg);  // 0 if negative, 255 if positive. | 
| 220   bind(&done); | 194   bind(&done); | 
| 221 } | 195 } | 
| 222 | 196 | 
| 223 | 197 | 
| 224 void MacroAssembler::SlowTruncateToI(Register result_reg, | 198 void MacroAssembler::SlowTruncateToI(Register result_reg, | 
| 225                                      Register input_reg, | 199                                      Register input_reg, | 
| 226                                      int offset) { | 200                                      int offset) { | 
| 227   DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); | 201   DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); | 
| 228   call(stub.GetCode(), RelocInfo::CODE_TARGET); | 202   call(stub.GetCode(), RelocInfo::CODE_TARGET); | 
| 229 } | 203 } | 
| 230 | 204 | 
| 231 | 205 | 
| 232 void MacroAssembler::TruncateDoubleToI(Register result_reg, | 206 void MacroAssembler::TruncateX87TOSToI(Register result_reg) { | 
| 233                                        XMMRegister input_reg) { |  | 
| 234   Label done; |  | 
| 235   cvttsd2si(result_reg, Operand(input_reg)); |  | 
| 236   cmp(result_reg, 0x1); |  | 
| 237   j(no_overflow, &done, Label::kNear); |  | 
| 238 |  | 
| 239   sub(esp, Immediate(kDoubleSize)); | 207   sub(esp, Immediate(kDoubleSize)); | 
| 240   movsd(MemOperand(esp, 0), input_reg); | 208   fst_d(MemOperand(esp, 0)); | 
| 241   SlowTruncateToI(result_reg, esp, 0); | 209   SlowTruncateToI(result_reg, esp, 0); | 
| 242   add(esp, Immediate(kDoubleSize)); | 210   add(esp, Immediate(kDoubleSize)); | 
|  | 211 } | 
|  | 212 | 
|  | 213 | 
|  | 214 void MacroAssembler::X87TOSToI(Register result_reg, | 
|  | 215                                MinusZeroMode minus_zero_mode, | 
|  | 216                                Label* conversion_failed, | 
|  | 217                                Label::Distance dst) { | 
|  | 218   Label done; | 
|  | 219   sub(esp, Immediate(kPointerSize)); | 
|  | 220   fld(0); | 
|  | 221   fist_s(MemOperand(esp, 0)); | 
|  | 222   fild_s(MemOperand(esp, 0)); | 
|  | 223   pop(result_reg); | 
|  | 224   FCmp(); | 
|  | 225   j(not_equal, conversion_failed, dst); | 
|  | 226   j(parity_even, conversion_failed, dst); | 
|  | 227   if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { | 
|  | 228     test(result_reg, Operand(result_reg)); | 
|  | 229     j(not_zero, &done, Label::kNear); | 
|  | 230     // To check for minus zero, we load the value again as float, and check | 
|  | 231     // if that is still 0. | 
|  | 232     sub(esp, Immediate(kPointerSize)); | 
|  | 233     fst_s(MemOperand(esp, 0)); | 
|  | 234     pop(result_reg); | 
|  | 235     test(result_reg, Operand(result_reg)); | 
|  | 236     j(not_zero, conversion_failed, dst); | 
|  | 237   } | 
| 243   bind(&done); | 238   bind(&done); | 
| 244 } | 239 } | 
| 245 | 240 | 
| 246 | 241 | 
| 247 void MacroAssembler::DoubleToI(Register result_reg, |  | 
| 248                                XMMRegister input_reg, |  | 
| 249                                XMMRegister scratch, |  | 
| 250                                MinusZeroMode minus_zero_mode, |  | 
| 251                                Label* conversion_failed, |  | 
| 252                                Label::Distance dst) { |  | 
| 253   ASSERT(!input_reg.is(scratch)); |  | 
| 254   cvttsd2si(result_reg, Operand(input_reg)); |  | 
| 255   Cvtsi2sd(scratch, Operand(result_reg)); |  | 
| 256   ucomisd(scratch, input_reg); |  | 
| 257   j(not_equal, conversion_failed, dst); |  | 
| 258   j(parity_even, conversion_failed, dst);  // NaN. |  | 
| 259   if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { |  | 
| 260     Label done; |  | 
| 261     // The integer converted back is equal to the original. We |  | 
| 262     // only have to test if we got -0 as an input. |  | 
| 263     test(result_reg, Operand(result_reg)); |  | 
| 264     j(not_zero, &done, Label::kNear); |  | 
| 265     movmskpd(result_reg, input_reg); |  | 
| 266     // Bit 0 contains the sign of the double in input_reg. |  | 
| 267     // If input was positive, we are ok and return 0, otherwise |  | 
| 268     // jump to conversion_failed. |  | 
| 269     and_(result_reg, 1); |  | 
| 270     j(not_zero, conversion_failed, dst); |  | 
| 271     bind(&done); |  | 
| 272   } |  | 
| 273 } |  | 
| 274 |  | 
| 275 |  | 
| 276 void MacroAssembler::TruncateHeapNumberToI(Register result_reg, | 242 void MacroAssembler::TruncateHeapNumberToI(Register result_reg, | 
| 277                                            Register input_reg) { | 243                                            Register input_reg) { | 
| 278   Label done, slow_case; | 244   Label done, slow_case; | 
| 279 | 245 | 
| 280   if (CpuFeatures::IsSupported(SSE3)) { | 246   SlowTruncateToI(result_reg, input_reg); | 
| 281     CpuFeatureScope scope(this, SSE3); |  | 
| 282     Label convert; |  | 
| 283     // Use more powerful conversion when sse3 is available. |  | 
| 284     // Load x87 register with heap number. |  | 
| 285     fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); |  | 
| 286     // Get exponent alone and check for too-big exponent. |  | 
| 287     mov(result_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset)); |  | 
| 288     and_(result_reg, HeapNumber::kExponentMask); |  | 
| 289     const uint32_t kTooBigExponent = |  | 
| 290         (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; |  | 
| 291     cmp(Operand(result_reg), Immediate(kTooBigExponent)); |  | 
| 292     j(greater_equal, &slow_case, Label::kNear); |  | 
| 293 |  | 
| 294     // Reserve space for 64 bit answer. |  | 
| 295     sub(Operand(esp), Immediate(kDoubleSize)); |  | 
| 296     // Do conversion, which cannot fail because we checked the exponent. |  | 
| 297     fisttp_d(Operand(esp, 0)); |  | 
| 298     mov(result_reg, Operand(esp, 0));  // Low word of answer is the result. |  | 
| 299     add(Operand(esp), Immediate(kDoubleSize)); |  | 
| 300     jmp(&done, Label::kNear); |  | 
| 301 |  | 
| 302     // Slow case. |  | 
| 303     bind(&slow_case); |  | 
| 304     if (input_reg.is(result_reg)) { |  | 
| 305       // Input is clobbered. Restore number from fpu stack |  | 
| 306       sub(Operand(esp), Immediate(kDoubleSize)); |  | 
| 307       fstp_d(Operand(esp, 0)); |  | 
| 308       SlowTruncateToI(result_reg, esp, 0); |  | 
| 309       add(esp, Immediate(kDoubleSize)); |  | 
| 310     } else { |  | 
| 311       fstp(0); |  | 
| 312       SlowTruncateToI(result_reg, input_reg); |  | 
| 313     } |  | 
| 314   } else { |  | 
| 315     movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); |  | 
| 316     cvttsd2si(result_reg, Operand(xmm0)); |  | 
| 317     cmp(result_reg, 0x1); |  | 
| 318     j(no_overflow, &done, Label::kNear); |  | 
| 319     // Check if the input was 0x8000000 (kMinInt). |  | 
| 320     // If no, then we got an overflow and we deoptimize. |  | 
| 321     ExternalReference min_int = ExternalReference::address_of_min_int(); |  | 
| 322     ucomisd(xmm0, Operand::StaticVariable(min_int)); |  | 
| 323     j(not_equal, &slow_case, Label::kNear); |  | 
| 324     j(parity_even, &slow_case, Label::kNear);  // NaN. |  | 
| 325     jmp(&done, Label::kNear); |  | 
| 326 |  | 
| 327     // Slow case. |  | 
| 328     bind(&slow_case); |  | 
| 329     if (input_reg.is(result_reg)) { |  | 
| 330       // Input is clobbered. Restore number from double scratch. |  | 
| 331       sub(esp, Immediate(kDoubleSize)); |  | 
| 332       movsd(MemOperand(esp, 0), xmm0); |  | 
| 333       SlowTruncateToI(result_reg, esp, 0); |  | 
| 334       add(esp, Immediate(kDoubleSize)); |  | 
| 335     } else { |  | 
| 336       SlowTruncateToI(result_reg, input_reg); |  | 
| 337     } |  | 
| 338   } |  | 
| 339   bind(&done); | 247   bind(&done); | 
| 340 } | 248 } | 
| 341 | 249 | 
| 342 | 250 | 
| 343 void MacroAssembler::TaggedToI(Register result_reg, | 251 void MacroAssembler::TaggedToI(Register result_reg, | 
| 344                                Register input_reg, | 252                                Register input_reg, | 
| 345                                XMMRegister temp, |  | 
| 346                                MinusZeroMode minus_zero_mode, | 253                                MinusZeroMode minus_zero_mode, | 
| 347                                Label* lost_precision) { | 254                                Label* lost_precision) { | 
| 348   Label done; | 255   Label done; | 
| 349   ASSERT(!temp.is(xmm0)); |  | 
| 350 | 256 | 
| 351   cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 257   cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 
| 352       isolate()->factory()->heap_number_map()); | 258       isolate()->factory()->heap_number_map()); | 
| 353   j(not_equal, lost_precision, Label::kNear); | 259   j(not_equal, lost_precision, Label::kNear); | 
| 354 | 260 | 
| 355   ASSERT(!temp.is(no_xmm_reg)); | 261   // TODO(olivf) Converting a number on the fpu is actually quite slow. We | 
| 356 | 262   // should first try a fast conversion and then bailout to this slow case. | 
| 357   movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 263   Label lost_precision_pop, zero_check; | 
| 358   cvttsd2si(result_reg, Operand(xmm0)); | 264   Label* lost_precision_int = (minus_zero_mode == FAIL_ON_MINUS_ZERO) | 
| 359   Cvtsi2sd(temp, Operand(result_reg)); | 265       ? &lost_precision_pop : lost_precision; | 
| 360   ucomisd(xmm0, temp); | 266   sub(esp, Immediate(kPointerSize)); | 
| 361   RecordComment("Deferred TaggedToI: lost precision"); | 267   fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); | 
| 362   j(not_equal, lost_precision, Label::kNear); | 268   if (minus_zero_mode == FAIL_ON_MINUS_ZERO) fld(0); | 
| 363   RecordComment("Deferred TaggedToI: NaN"); | 269   fist_s(MemOperand(esp, 0)); | 
| 364   j(parity_even, lost_precision, Label::kNear); | 270   fild_s(MemOperand(esp, 0)); | 
|  | 271   FCmp(); | 
|  | 272   pop(result_reg); | 
|  | 273   j(not_equal, lost_precision_int, Label::kNear); | 
|  | 274   j(parity_even, lost_precision_int, Label::kNear);  // NaN. | 
| 365   if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { | 275   if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { | 
| 366     test(result_reg, Operand(result_reg)); | 276     test(result_reg, Operand(result_reg)); | 
| 367     j(not_zero, &done, Label::kNear); | 277     j(zero, &zero_check, Label::kNear); | 
| 368     movmskpd(result_reg, xmm0); | 278     fstp(0); | 
| 369     and_(result_reg, 1); | 279     jmp(&done, Label::kNear); | 
| 370     RecordComment("Deferred TaggedToI: minus zero"); | 280     bind(&zero_check); | 
| 371     j(not_zero, lost_precision, Label::kNear); | 281     // To check for minus zero, we load the value again as float, and check | 
|  | 282     // if that is still 0. | 
|  | 283     sub(esp, Immediate(kPointerSize)); | 
|  | 284     fstp_s(Operand(esp, 0)); | 
|  | 285     pop(result_reg); | 
|  | 286     test(result_reg, Operand(result_reg)); | 
|  | 287     j(zero, &done, Label::kNear); | 
|  | 288     jmp(lost_precision, Label::kNear); | 
|  | 289 | 
|  | 290     bind(&lost_precision_pop); | 
|  | 291     fstp(0); | 
|  | 292     jmp(lost_precision, Label::kNear); | 
| 372   } | 293   } | 
| 373   bind(&done); | 294   bind(&done); | 
| 374 } | 295 } | 
| 375 | 296 | 
| 376 | 297 | 
| 377 void MacroAssembler::LoadUint32(XMMRegister dst, | 298 void MacroAssembler::LoadUint32NoSSE2(Register src) { | 
| 378                                 Register src, |  | 
| 379                                 XMMRegister scratch) { |  | 
| 380   Label done; | 299   Label done; | 
|  | 300   push(src); | 
|  | 301   fild_s(Operand(esp, 0)); | 
| 381   cmp(src, Immediate(0)); | 302   cmp(src, Immediate(0)); | 
|  | 303   j(not_sign, &done, Label::kNear); | 
| 382   ExternalReference uint32_bias = | 304   ExternalReference uint32_bias = | 
| 383         ExternalReference::address_of_uint32_bias(); | 305         ExternalReference::address_of_uint32_bias(); | 
| 384   movsd(scratch, Operand::StaticVariable(uint32_bias)); | 306   fld_d(Operand::StaticVariable(uint32_bias)); | 
| 385   Cvtsi2sd(dst, src); | 307   faddp(1); | 
| 386   j(not_sign, &done, Label::kNear); |  | 
| 387   addsd(dst, scratch); |  | 
| 388   bind(&done); | 308   bind(&done); | 
|  | 309   add(esp, Immediate(kPointerSize)); | 
| 389 } | 310 } | 
| 390 | 311 | 
| 391 | 312 | 
| 392 void MacroAssembler::RecordWriteArray(Register object, | 313 void MacroAssembler::RecordWriteArray(Register object, | 
| 393                                       Register value, | 314                                       Register value, | 
| 394                                       Register index, | 315                                       Register index, | 
| 395                                       SaveFPRegsMode save_fp, |  | 
| 396                                       RememberedSetAction remembered_set_action, | 316                                       RememberedSetAction remembered_set_action, | 
| 397                                       SmiCheck smi_check) { | 317                                       SmiCheck smi_check) { | 
| 398   // First, check if a write barrier is even needed. The tests below | 318   // First, check if a write barrier is even needed. The tests below | 
| 399   // catch stores of Smis. | 319   // catch stores of Smis. | 
| 400   Label done; | 320   Label done; | 
| 401 | 321 | 
| 402   // Skip barrier if writing a smi. | 322   // Skip barrier if writing a smi. | 
| 403   if (smi_check == INLINE_SMI_CHECK) { | 323   if (smi_check == INLINE_SMI_CHECK) { | 
| 404     ASSERT_EQ(0, kSmiTag); | 324     ASSERT_EQ(0, kSmiTag); | 
| 405     test(value, Immediate(kSmiTagMask)); | 325     test(value, Immediate(kSmiTagMask)); | 
| 406     j(zero, &done); | 326     j(zero, &done); | 
| 407   } | 327   } | 
| 408 | 328 | 
| 409   // Array access: calculate the destination address in the same manner as | 329   // Array access: calculate the destination address in the same manner as | 
| 410   // KeyedStoreIC::GenerateGeneric.  Multiply a smi by 2 to get an offset | 330   // KeyedStoreIC::GenerateGeneric.  Multiply a smi by 2 to get an offset | 
| 411   // into an array of words. | 331   // into an array of words. | 
| 412   Register dst = index; | 332   Register dst = index; | 
| 413   lea(dst, Operand(object, index, times_half_pointer_size, | 333   lea(dst, Operand(object, index, times_half_pointer_size, | 
| 414                    FixedArray::kHeaderSize - kHeapObjectTag)); | 334                    FixedArray::kHeaderSize - kHeapObjectTag)); | 
| 415 | 335 | 
| 416   RecordWrite( | 336   RecordWrite( | 
| 417       object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); | 337       object, dst, value, remembered_set_action, OMIT_SMI_CHECK); | 
| 418 | 338 | 
| 419   bind(&done); | 339   bind(&done); | 
| 420 | 340 | 
| 421   // Clobber clobbered input registers when running with the debug-code flag | 341   // Clobber clobbered input registers when running with the debug-code flag | 
| 422   // turned on to provoke errors. | 342   // turned on to provoke errors. | 
| 423   if (emit_debug_code()) { | 343   if (emit_debug_code()) { | 
| 424     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 344     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 
| 425     mov(index, Immediate(BitCast<int32_t>(kZapValue))); | 345     mov(index, Immediate(BitCast<int32_t>(kZapValue))); | 
| 426   } | 346   } | 
| 427 } | 347 } | 
| 428 | 348 | 
| 429 | 349 | 
| 430 void MacroAssembler::RecordWriteField( | 350 void MacroAssembler::RecordWriteField( | 
| 431     Register object, | 351     Register object, | 
| 432     int offset, | 352     int offset, | 
| 433     Register value, | 353     Register value, | 
| 434     Register dst, | 354     Register dst, | 
| 435     SaveFPRegsMode save_fp, |  | 
| 436     RememberedSetAction remembered_set_action, | 355     RememberedSetAction remembered_set_action, | 
| 437     SmiCheck smi_check) { | 356     SmiCheck smi_check) { | 
| 438   // First, check if a write barrier is even needed. The tests below | 357   // First, check if a write barrier is even needed. The tests below | 
| 439   // catch stores of Smis. | 358   // catch stores of Smis. | 
| 440   Label done; | 359   Label done; | 
| 441 | 360 | 
| 442   // Skip barrier if writing a smi. | 361   // Skip barrier if writing a smi. | 
| 443   if (smi_check == INLINE_SMI_CHECK) { | 362   if (smi_check == INLINE_SMI_CHECK) { | 
| 444     JumpIfSmi(value, &done, Label::kNear); | 363     JumpIfSmi(value, &done, Label::kNear); | 
| 445   } | 364   } | 
| 446 | 365 | 
| 447   // Although the object register is tagged, the offset is relative to the start | 366   // Although the object register is tagged, the offset is relative to the start | 
| 448   // of the object, so so offset must be a multiple of kPointerSize. | 367   // of the object, so so offset must be a multiple of kPointerSize. | 
| 449   ASSERT(IsAligned(offset, kPointerSize)); | 368   ASSERT(IsAligned(offset, kPointerSize)); | 
| 450 | 369 | 
| 451   lea(dst, FieldOperand(object, offset)); | 370   lea(dst, FieldOperand(object, offset)); | 
| 452   if (emit_debug_code()) { | 371   if (emit_debug_code()) { | 
| 453     Label ok; | 372     Label ok; | 
| 454     test_b(dst, (1 << kPointerSizeLog2) - 1); | 373     test_b(dst, (1 << kPointerSizeLog2) - 1); | 
| 455     j(zero, &ok, Label::kNear); | 374     j(zero, &ok, Label::kNear); | 
| 456     int3(); | 375     int3(); | 
| 457     bind(&ok); | 376     bind(&ok); | 
| 458   } | 377   } | 
| 459 | 378 | 
| 460   RecordWrite( | 379   RecordWrite( | 
| 461       object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK); | 380       object, dst, value, remembered_set_action, OMIT_SMI_CHECK); | 
| 462 | 381 | 
| 463   bind(&done); | 382   bind(&done); | 
| 464 | 383 | 
| 465   // Clobber clobbered input registers when running with the debug-code flag | 384   // Clobber clobbered input registers when running with the debug-code flag | 
| 466   // turned on to provoke errors. | 385   // turned on to provoke errors. | 
| 467   if (emit_debug_code()) { | 386   if (emit_debug_code()) { | 
| 468     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 387     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 
| 469     mov(dst, Immediate(BitCast<int32_t>(kZapValue))); | 388     mov(dst, Immediate(BitCast<int32_t>(kZapValue))); | 
| 470   } | 389   } | 
| 471 } | 390 } | 
| 472 | 391 | 
| 473 | 392 | 
| 474 void MacroAssembler::RecordWriteForMap( | 393 void MacroAssembler::RecordWriteForMap( | 
| 475     Register object, | 394     Register object, | 
| 476     Handle<Map> map, | 395     Handle<Map> map, | 
| 477     Register scratch1, | 396     Register scratch1, | 
| 478     Register scratch2, | 397     Register scratch2) { | 
| 479     SaveFPRegsMode save_fp) { |  | 
| 480   Label done; | 398   Label done; | 
| 481 | 399 | 
| 482   Register address = scratch1; | 400   Register address = scratch1; | 
| 483   Register value = scratch2; | 401   Register value = scratch2; | 
| 484   if (emit_debug_code()) { | 402   if (emit_debug_code()) { | 
| 485     Label ok; | 403     Label ok; | 
| 486     lea(address, FieldOperand(object, HeapObject::kMapOffset)); | 404     lea(address, FieldOperand(object, HeapObject::kMapOffset)); | 
| 487     test_b(address, (1 << kPointerSizeLog2) - 1); | 405     test_b(address, (1 << kPointerSizeLog2) - 1); | 
| 488     j(zero, &ok, Label::kNear); | 406     j(zero, &ok, Label::kNear); | 
| 489     int3(); | 407     int3(); | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 513                       zero, | 431                       zero, | 
| 514                       &done, | 432                       &done, | 
| 515                       Label::kNear); | 433                       Label::kNear); | 
| 516 | 434 | 
| 517   // Delay the initialization of |address| and |value| for the stub until it's | 435   // Delay the initialization of |address| and |value| for the stub until it's | 
| 518   // known that the will be needed. Up until this point their values are not | 436   // known that the will be needed. Up until this point their values are not | 
| 519   // needed since they are embedded in the operands of instructions that need | 437   // needed since they are embedded in the operands of instructions that need | 
| 520   // them. | 438   // them. | 
| 521   lea(address, FieldOperand(object, HeapObject::kMapOffset)); | 439   lea(address, FieldOperand(object, HeapObject::kMapOffset)); | 
| 522   mov(value, Immediate(map)); | 440   mov(value, Immediate(map)); | 
| 523   RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET, | 441   RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET); | 
| 524                        save_fp); |  | 
| 525   CallStub(&stub); | 442   CallStub(&stub); | 
| 526 | 443 | 
| 527   bind(&done); | 444   bind(&done); | 
| 528 | 445 | 
| 529   // Clobber clobbered input registers when running with the debug-code flag | 446   // Clobber clobbered input registers when running with the debug-code flag | 
| 530   // turned on to provoke errors. | 447   // turned on to provoke errors. | 
| 531   if (emit_debug_code()) { | 448   if (emit_debug_code()) { | 
| 532     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 449     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 
| 533     mov(scratch1, Immediate(BitCast<int32_t>(kZapValue))); | 450     mov(scratch1, Immediate(BitCast<int32_t>(kZapValue))); | 
| 534     mov(scratch2, Immediate(BitCast<int32_t>(kZapValue))); | 451     mov(scratch2, Immediate(BitCast<int32_t>(kZapValue))); | 
| 535   } | 452   } | 
| 536 } | 453 } | 
| 537 | 454 | 
| 538 | 455 | 
| 539 void MacroAssembler::RecordWrite(Register object, | 456 void MacroAssembler::RecordWrite(Register object, | 
| 540                                  Register address, | 457                                  Register address, | 
| 541                                  Register value, | 458                                  Register value, | 
| 542                                  SaveFPRegsMode fp_mode, |  | 
| 543                                  RememberedSetAction remembered_set_action, | 459                                  RememberedSetAction remembered_set_action, | 
| 544                                  SmiCheck smi_check) { | 460                                  SmiCheck smi_check) { | 
| 545   ASSERT(!object.is(value)); | 461   ASSERT(!object.is(value)); | 
| 546   ASSERT(!object.is(address)); | 462   ASSERT(!object.is(address)); | 
| 547   ASSERT(!value.is(address)); | 463   ASSERT(!value.is(address)); | 
| 548   AssertNotSmi(object); | 464   AssertNotSmi(object); | 
| 549 | 465 | 
| 550   if (remembered_set_action == OMIT_REMEMBERED_SET && | 466   if (remembered_set_action == OMIT_REMEMBERED_SET && | 
| 551       !FLAG_incremental_marking) { | 467       !FLAG_incremental_marking) { | 
| 552     return; | 468     return; | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 579                 zero, | 495                 zero, | 
| 580                 &done, | 496                 &done, | 
| 581                 Label::kNear); | 497                 Label::kNear); | 
| 582   CheckPageFlag(object, | 498   CheckPageFlag(object, | 
| 583                 value,  // Used as scratch. | 499                 value,  // Used as scratch. | 
| 584                 MemoryChunk::kPointersFromHereAreInterestingMask, | 500                 MemoryChunk::kPointersFromHereAreInterestingMask, | 
| 585                 zero, | 501                 zero, | 
| 586                 &done, | 502                 &done, | 
| 587                 Label::kNear); | 503                 Label::kNear); | 
| 588 | 504 | 
| 589   RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, | 505   RecordWriteStub stub(isolate(), object, value, address, | 
| 590                        fp_mode); | 506                        remembered_set_action); | 
| 591   CallStub(&stub); | 507   CallStub(&stub); | 
| 592 | 508 | 
| 593   bind(&done); | 509   bind(&done); | 
| 594 | 510 | 
| 595   // Clobber clobbered registers when running with the debug-code flag | 511   // Clobber clobbered registers when running with the debug-code flag | 
| 596   // turned on to provoke errors. | 512   // turned on to provoke errors. | 
| 597   if (emit_debug_code()) { | 513   if (emit_debug_code()) { | 
| 598     mov(address, Immediate(BitCast<int32_t>(kZapValue))); | 514     mov(address, Immediate(BitCast<int32_t>(kZapValue))); | 
| 599     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 515     mov(value, Immediate(BitCast<int32_t>(kZapValue))); | 
| 600   } | 516   } | 
| 601 } | 517 } | 
| 602 | 518 | 
| 603 | 519 | 
| 604 void MacroAssembler::DebugBreak() { | 520 void MacroAssembler::DebugBreak() { | 
| 605   Move(eax, Immediate(0)); | 521   Move(eax, Immediate(0)); | 
| 606   mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak, isolate()))); | 522   mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak, isolate()))); | 
| 607   CEntryStub ces(isolate(), 1); | 523   CEntryStub ces(isolate(), 1); | 
| 608   call(ces.GetCode(), RelocInfo::DEBUG_BREAK); | 524   call(ces.GetCode(), RelocInfo::DEBUG_BREAK); | 
| 609 } | 525 } | 
| 610 | 526 | 
| 611 | 527 | 
| 612 void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) { |  | 
| 613   xorps(dst, dst); |  | 
| 614   cvtsi2sd(dst, src); |  | 
| 615 } |  | 
| 616 |  | 
| 617 |  | 
| 618 bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { | 528 bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { | 
| 619   static const int kMaxImmediateBits = 17; | 529   static const int kMaxImmediateBits = 17; | 
| 620   if (!RelocInfo::IsNone(x.rmode_)) return false; | 530   if (!RelocInfo::IsNone(x.rmode_)) return false; | 
| 621   return !is_intn(x.x_, kMaxImmediateBits); | 531   return !is_intn(x.x_, kMaxImmediateBits); | 
| 622 } | 532 } | 
| 623 | 533 | 
| 624 | 534 | 
| 625 void MacroAssembler::SafeMove(Register dst, const Immediate& x) { | 535 void MacroAssembler::SafeMove(Register dst, const Immediate& x) { | 
| 626   if (IsUnsafeImmediate(x) && jit_cookie() != 0) { | 536   if (IsUnsafeImmediate(x) && jit_cookie() != 0) { | 
| 627     Move(dst, Immediate(x.x_ ^ jit_cookie())); | 537     Move(dst, Immediate(x.x_ ^ jit_cookie())); | 
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 693   cmpb(FieldOperand(map, Map::kBitField2Offset), | 603   cmpb(FieldOperand(map, Map::kBitField2Offset), | 
| 694        Map::kMaximumBitField2FastHoleySmiElementValue); | 604        Map::kMaximumBitField2FastHoleySmiElementValue); | 
| 695   j(above, fail, distance); | 605   j(above, fail, distance); | 
| 696 } | 606 } | 
| 697 | 607 | 
| 698 | 608 | 
| 699 void MacroAssembler::StoreNumberToDoubleElements( | 609 void MacroAssembler::StoreNumberToDoubleElements( | 
| 700     Register maybe_number, | 610     Register maybe_number, | 
| 701     Register elements, | 611     Register elements, | 
| 702     Register key, | 612     Register key, | 
| 703     Register scratch1, | 613     Register scratch, | 
| 704     XMMRegister scratch2, |  | 
| 705     Label* fail, | 614     Label* fail, | 
| 706     int elements_offset) { | 615     int elements_offset) { | 
| 707   Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value; | 616   Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value; | 
| 708   JumpIfSmi(maybe_number, &smi_value, Label::kNear); | 617   JumpIfSmi(maybe_number, &smi_value, Label::kNear); | 
| 709 | 618 | 
| 710   CheckMap(maybe_number, | 619   CheckMap(maybe_number, | 
| 711            isolate()->factory()->heap_number_map(), | 620            isolate()->factory()->heap_number_map(), | 
| 712            fail, | 621            fail, | 
| 713            DONT_DO_SMI_CHECK); | 622            DONT_DO_SMI_CHECK); | 
| 714 | 623 | 
| 715   // Double value, canonicalize NaN. | 624   // Double value, canonicalize NaN. | 
| 716   uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); | 625   uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); | 
| 717   cmp(FieldOperand(maybe_number, offset), | 626   cmp(FieldOperand(maybe_number, offset), | 
| 718       Immediate(kNaNOrInfinityLowerBoundUpper32)); | 627       Immediate(kNaNOrInfinityLowerBoundUpper32)); | 
| 719   j(greater_equal, &maybe_nan, Label::kNear); | 628   j(greater_equal, &maybe_nan, Label::kNear); | 
| 720 | 629 | 
| 721   bind(¬_nan); | 630   bind(¬_nan); | 
| 722   ExternalReference canonical_nan_reference = | 631   ExternalReference canonical_nan_reference = | 
| 723       ExternalReference::address_of_canonical_non_hole_nan(); | 632       ExternalReference::address_of_canonical_non_hole_nan(); | 
| 724   movsd(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset)); | 633   fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset)); | 
| 725   bind(&have_double_value); | 634   bind(&have_double_value); | 
| 726   movsd(FieldOperand(elements, key, times_4, | 635   fstp_d(FieldOperand(elements, key, times_4, | 
| 727                      FixedDoubleArray::kHeaderSize - elements_offset), | 636                       FixedDoubleArray::kHeaderSize - elements_offset)); | 
| 728         scratch2); |  | 
| 729   jmp(&done); | 637   jmp(&done); | 
| 730 | 638 | 
| 731   bind(&maybe_nan); | 639   bind(&maybe_nan); | 
| 732   // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise | 640   // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise | 
| 733   // it's an Infinity, and the non-NaN code path applies. | 641   // it's an Infinity, and the non-NaN code path applies. | 
| 734   j(greater, &is_nan, Label::kNear); | 642   j(greater, &is_nan, Label::kNear); | 
| 735   cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0)); | 643   cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0)); | 
| 736   j(zero, ¬_nan); | 644   j(zero, ¬_nan); | 
| 737   bind(&is_nan); | 645   bind(&is_nan); | 
| 738   movsd(scratch2, Operand::StaticVariable(canonical_nan_reference)); | 646   fld_d(Operand::StaticVariable(canonical_nan_reference)); | 
| 739   jmp(&have_double_value, Label::kNear); | 647   jmp(&have_double_value, Label::kNear); | 
| 740 | 648 | 
| 741   bind(&smi_value); | 649   bind(&smi_value); | 
| 742   // Value is a smi. Convert to a double and store. | 650   // Value is a smi. Convert to a double and store. | 
| 743   // Preserve original value. | 651   // Preserve original value. | 
| 744   mov(scratch1, maybe_number); | 652   mov(scratch, maybe_number); | 
| 745   SmiUntag(scratch1); | 653   SmiUntag(scratch); | 
| 746   Cvtsi2sd(scratch2, scratch1); | 654   push(scratch); | 
| 747   movsd(FieldOperand(elements, key, times_4, | 655   fild_s(Operand(esp, 0)); | 
| 748                      FixedDoubleArray::kHeaderSize - elements_offset), | 656   pop(scratch); | 
| 749         scratch2); | 657   fstp_d(FieldOperand(elements, key, times_4, | 
|  | 658                       FixedDoubleArray::kHeaderSize - elements_offset)); | 
| 750   bind(&done); | 659   bind(&done); | 
| 751 } | 660 } | 
| 752 | 661 | 
| 753 | 662 | 
| 754 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { | 663 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { | 
| 755   cmp(FieldOperand(obj, HeapObject::kMapOffset), map); | 664   cmp(FieldOperand(obj, HeapObject::kMapOffset), map); | 
| 756 } | 665 } | 
| 757 | 666 | 
| 758 | 667 | 
| 759 void MacroAssembler::CheckMap(Register obj, | 668 void MacroAssembler::CheckMap(Register obj, | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 820                                             Label* fail) { | 729                                             Label* fail) { | 
| 821   movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); | 730   movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); | 
| 822   sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 731   sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 
| 823   cmp(scratch, | 732   cmp(scratch, | 
| 824       LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); | 733       LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); | 
| 825   j(above, fail); | 734   j(above, fail); | 
| 826 } | 735 } | 
| 827 | 736 | 
| 828 | 737 | 
| 829 void MacroAssembler::FCmp() { | 738 void MacroAssembler::FCmp() { | 
| 830   fucomip(); | 739   fucompp(); | 
| 831   fstp(0); | 740   push(eax); | 
|  | 741   fnstsw_ax(); | 
|  | 742   sahf(); | 
|  | 743   pop(eax); | 
| 832 } | 744 } | 
| 833 | 745 | 
| 834 | 746 | 
| 835 void MacroAssembler::AssertNumber(Register object) { | 747 void MacroAssembler::AssertNumber(Register object) { | 
| 836   if (emit_debug_code()) { | 748   if (emit_debug_code()) { | 
| 837     Label ok; | 749     Label ok; | 
| 838     JumpIfSmi(object, &ok); | 750     JumpIfSmi(object, &ok); | 
| 839     cmp(FieldOperand(object, HeapObject::kMapOffset), | 751     cmp(FieldOperand(object, HeapObject::kMapOffset), | 
| 840         isolate()->factory()->heap_number_map()); | 752         isolate()->factory()->heap_number_map()); | 
| 841     Check(equal, kOperandNotANumber); | 753     Check(equal, kOperandNotANumber); | 
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 962   push(Immediate(CodeObject()));  // Accessed from ExitFrame::code_slot. | 874   push(Immediate(CodeObject()));  // Accessed from ExitFrame::code_slot. | 
| 963 | 875 | 
| 964   // Save the frame pointer and the context in top. | 876   // Save the frame pointer and the context in top. | 
| 965   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate()); | 877   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate()); | 
| 966   ExternalReference context_address(Isolate::kContextAddress, isolate()); | 878   ExternalReference context_address(Isolate::kContextAddress, isolate()); | 
| 967   mov(Operand::StaticVariable(c_entry_fp_address), ebp); | 879   mov(Operand::StaticVariable(c_entry_fp_address), ebp); | 
| 968   mov(Operand::StaticVariable(context_address), esi); | 880   mov(Operand::StaticVariable(context_address), esi); | 
| 969 } | 881 } | 
| 970 | 882 | 
| 971 | 883 | 
| 972 void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { | 884 void MacroAssembler::EnterExitFrameEpilogue(int argc) { | 
| 973   // Optionally save all XMM registers. | 885   sub(esp, Immediate(argc * kPointerSize)); | 
| 974   if (save_doubles) { |  | 
| 975     int space = XMMRegister::kMaxNumRegisters * kDoubleSize + |  | 
| 976                 argc * kPointerSize; |  | 
| 977     sub(esp, Immediate(space)); |  | 
| 978     const int offset = -2 * kPointerSize; |  | 
| 979     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { |  | 
| 980       XMMRegister reg = XMMRegister::from_code(i); |  | 
| 981       movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg); |  | 
| 982     } |  | 
| 983   } else { |  | 
| 984     sub(esp, Immediate(argc * kPointerSize)); |  | 
| 985   } |  | 
| 986 | 886 | 
| 987   // Get the required frame alignment for the OS. | 887   // Get the required frame alignment for the OS. | 
| 988   const int kFrameAlignment = OS::ActivationFrameAlignment(); | 888   const int kFrameAlignment = OS::ActivationFrameAlignment(); | 
| 989   if (kFrameAlignment > 0) { | 889   if (kFrameAlignment > 0) { | 
| 990     ASSERT(IsPowerOf2(kFrameAlignment)); | 890     ASSERT(IsPowerOf2(kFrameAlignment)); | 
| 991     and_(esp, -kFrameAlignment); | 891     and_(esp, -kFrameAlignment); | 
| 992   } | 892   } | 
| 993 | 893 | 
| 994   // Patch the saved entry sp. | 894   // Patch the saved entry sp. | 
| 995   mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); | 895   mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); | 
| 996 } | 896 } | 
| 997 | 897 | 
| 998 | 898 | 
| 999 void MacroAssembler::EnterExitFrame(bool save_doubles) { | 899 void MacroAssembler::EnterExitFrame() { | 
| 1000   EnterExitFramePrologue(); | 900   EnterExitFramePrologue(); | 
| 1001 | 901 | 
| 1002   // Set up argc and argv in callee-saved registers. | 902   // Set up argc and argv in callee-saved registers. | 
| 1003   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; | 903   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; | 
| 1004   mov(edi, eax); | 904   mov(edi, eax); | 
| 1005   lea(esi, Operand(ebp, eax, times_4, offset)); | 905   lea(esi, Operand(ebp, eax, times_4, offset)); | 
| 1006 | 906 | 
| 1007   // Reserve space for argc, argv and isolate. | 907   // Reserve space for argc, argv and isolate. | 
| 1008   EnterExitFrameEpilogue(3, save_doubles); | 908   EnterExitFrameEpilogue(3); | 
| 1009 } | 909 } | 
| 1010 | 910 | 
| 1011 | 911 | 
| 1012 void MacroAssembler::EnterApiExitFrame(int argc) { | 912 void MacroAssembler::EnterApiExitFrame(int argc) { | 
| 1013   EnterExitFramePrologue(); | 913   EnterExitFramePrologue(); | 
| 1014   EnterExitFrameEpilogue(argc, false); | 914   EnterExitFrameEpilogue(argc); | 
| 1015 } | 915 } | 
| 1016 | 916 | 
| 1017 | 917 | 
| 1018 void MacroAssembler::LeaveExitFrame(bool save_doubles) { | 918 void MacroAssembler::LeaveExitFrame() { | 
| 1019   // Optionally restore all XMM registers. |  | 
| 1020   if (save_doubles) { |  | 
| 1021     const int offset = -2 * kPointerSize; |  | 
| 1022     for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) { |  | 
| 1023       XMMRegister reg = XMMRegister::from_code(i); |  | 
| 1024       movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize))); |  | 
| 1025     } |  | 
| 1026   } |  | 
| 1027 |  | 
| 1028   // Get the return address from the stack and restore the frame pointer. | 919   // Get the return address from the stack and restore the frame pointer. | 
| 1029   mov(ecx, Operand(ebp, 1 * kPointerSize)); | 920   mov(ecx, Operand(ebp, 1 * kPointerSize)); | 
| 1030   mov(ebp, Operand(ebp, 0 * kPointerSize)); | 921   mov(ebp, Operand(ebp, 0 * kPointerSize)); | 
| 1031 | 922 | 
| 1032   // Pop the arguments and the receiver from the caller stack. | 923   // Pop the arguments and the receiver from the caller stack. | 
| 1033   lea(esp, Operand(esi, 1 * kPointerSize)); | 924   lea(esp, Operand(esi, 1 * kPointerSize)); | 
| 1034 | 925 | 
| 1035   // Push the return address to get ready to return. | 926   // Push the return address to get ready to return. | 
| 1036   push(ecx); | 927   push(ecx); | 
| 1037 | 928 | 
| (...skipping 1032 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2070   if (String::kHashShift > kSmiTagSize) { | 1961   if (String::kHashShift > kSmiTagSize) { | 
| 2071     shr(hash, String::kHashShift - kSmiTagSize); | 1962     shr(hash, String::kHashShift - kSmiTagSize); | 
| 2072   } | 1963   } | 
| 2073   if (!index.is(hash)) { | 1964   if (!index.is(hash)) { | 
| 2074     mov(index, hash); | 1965     mov(index, hash); | 
| 2075   } | 1966   } | 
| 2076 } | 1967 } | 
| 2077 | 1968 | 
| 2078 | 1969 | 
| 2079 void MacroAssembler::CallRuntime(const Runtime::Function* f, | 1970 void MacroAssembler::CallRuntime(const Runtime::Function* f, | 
| 2080                                  int num_arguments, | 1971                                  int num_arguments) { | 
| 2081                                  SaveFPRegsMode save_doubles) { |  | 
| 2082   // If the expected number of arguments of the runtime function is | 1972   // If the expected number of arguments of the runtime function is | 
| 2083   // constant, we check that the actual number of arguments match the | 1973   // constant, we check that the actual number of arguments match the | 
| 2084   // expectation. | 1974   // expectation. | 
| 2085   CHECK(f->nargs < 0 || f->nargs == num_arguments); | 1975   CHECK(f->nargs < 0 || f->nargs == num_arguments); | 
| 2086 | 1976 | 
| 2087   // TODO(1236192): Most runtime routines don't need the number of | 1977   // TODO(1236192): Most runtime routines don't need the number of | 
| 2088   // arguments passed in because it is constant. At some point we | 1978   // arguments passed in because it is constant. At some point we | 
| 2089   // should remove this need and make the runtime routine entry code | 1979   // should remove this need and make the runtime routine entry code | 
| 2090   // smarter. | 1980   // smarter. | 
| 2091   Move(eax, Immediate(num_arguments)); | 1981   Move(eax, Immediate(num_arguments)); | 
| 2092   mov(ebx, Immediate(ExternalReference(f, isolate()))); | 1982   mov(ebx, Immediate(ExternalReference(f, isolate()))); | 
| 2093   CEntryStub ces(isolate(), 1, save_doubles); | 1983   CEntryStub ces(isolate(), 1); | 
| 2094   CallStub(&ces); | 1984   CallStub(&ces); | 
| 2095 } | 1985 } | 
| 2096 | 1986 | 
| 2097 | 1987 | 
| 2098 void MacroAssembler::CallExternalReference(ExternalReference ref, | 1988 void MacroAssembler::CallExternalReference(ExternalReference ref, | 
| 2099                                            int num_arguments) { | 1989                                            int num_arguments) { | 
| 2100   mov(eax, Immediate(num_arguments)); | 1990   mov(eax, Immediate(num_arguments)); | 
| 2101   mov(ebx, Immediate(ref)); | 1991   mov(ebx, Immediate(ref)); | 
| 2102 | 1992 | 
| 2103   CEntryStub stub(isolate(), 1); | 1993   CEntryStub stub(isolate(), 1); | 
| (...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2632     ret(bytes_dropped); | 2522     ret(bytes_dropped); | 
| 2633   } else { | 2523   } else { | 
| 2634     pop(scratch); | 2524     pop(scratch); | 
| 2635     add(esp, Immediate(bytes_dropped)); | 2525     add(esp, Immediate(bytes_dropped)); | 
| 2636     push(scratch); | 2526     push(scratch); | 
| 2637     ret(0); | 2527     ret(0); | 
| 2638   } | 2528   } | 
| 2639 } | 2529 } | 
| 2640 | 2530 | 
| 2641 | 2531 | 
|  | 2532 void MacroAssembler::VerifyX87StackDepth(uint32_t depth) { | 
|  | 2533   // Make sure the floating point stack is either empty or has depth items. | 
|  | 2534   ASSERT(depth <= 7); | 
|  | 2535   // This is very expensive. | 
|  | 2536   ASSERT(FLAG_debug_code && FLAG_enable_slow_asserts); | 
|  | 2537 | 
|  | 2538   // The top-of-stack (tos) is 7 if there is one item pushed. | 
|  | 2539   int tos = (8 - depth) % 8; | 
|  | 2540   const int kTopMask = 0x3800; | 
|  | 2541   push(eax); | 
|  | 2542   fwait(); | 
|  | 2543   fnstsw_ax(); | 
|  | 2544   and_(eax, kTopMask); | 
|  | 2545   shr(eax, 11); | 
|  | 2546   cmp(eax, Immediate(tos)); | 
|  | 2547   Check(equal, kUnexpectedFPUStackDepthAfterInstruction); | 
|  | 2548   fnclex(); | 
|  | 2549   pop(eax); | 
|  | 2550 } | 
|  | 2551 | 
|  | 2552 | 
| 2642 void MacroAssembler::Drop(int stack_elements) { | 2553 void MacroAssembler::Drop(int stack_elements) { | 
| 2643   if (stack_elements > 0) { | 2554   if (stack_elements > 0) { | 
| 2644     add(esp, Immediate(stack_elements * kPointerSize)); | 2555     add(esp, Immediate(stack_elements * kPointerSize)); | 
| 2645   } | 2556   } | 
| 2646 } | 2557 } | 
| 2647 | 2558 | 
| 2648 | 2559 | 
| 2649 void MacroAssembler::Move(Register dst, Register src) { | 2560 void MacroAssembler::Move(Register dst, Register src) { | 
| 2650   if (!dst.is(src)) { | 2561   if (!dst.is(src)) { | 
| 2651     mov(dst, src); | 2562     mov(dst, src); | 
| 2652   } | 2563   } | 
| 2653 } | 2564 } | 
| 2654 | 2565 | 
| 2655 | 2566 | 
| 2656 void MacroAssembler::Move(Register dst, const Immediate& x) { | 2567 void MacroAssembler::Move(Register dst, const Immediate& x) { | 
| 2657   if (x.is_zero()) { | 2568   if (x.is_zero()) { | 
| 2658     xor_(dst, dst);  // Shorter than mov of 32-bit immediate 0. | 2569     xor_(dst, dst);  // Shorter than mov of 32-bit immediate 0. | 
| 2659   } else { | 2570   } else { | 
| 2660     mov(dst, x); | 2571     mov(dst, x); | 
| 2661   } | 2572   } | 
| 2662 } | 2573 } | 
| 2663 | 2574 | 
| 2664 | 2575 | 
| 2665 void MacroAssembler::Move(const Operand& dst, const Immediate& x) { | 2576 void MacroAssembler::Move(const Operand& dst, const Immediate& x) { | 
| 2666   mov(dst, x); | 2577   mov(dst, x); | 
| 2667 } | 2578 } | 
| 2668 | 2579 | 
| 2669 | 2580 | 
| 2670 void MacroAssembler::Move(XMMRegister dst, double val) { |  | 
| 2671   // TODO(titzer): recognize double constants with ExternalReferences. |  | 
| 2672   uint64_t int_val = BitCast<uint64_t, double>(val); |  | 
| 2673   if (int_val == 0) { |  | 
| 2674     xorps(dst, dst); |  | 
| 2675   } else { |  | 
| 2676     int32_t lower = static_cast<int32_t>(int_val); |  | 
| 2677     int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt); |  | 
| 2678     push(Immediate(upper)); |  | 
| 2679     push(Immediate(lower)); |  | 
| 2680     movsd(dst, Operand(esp, 0)); |  | 
| 2681     add(esp, Immediate(kDoubleSize)); |  | 
| 2682   } |  | 
| 2683 } |  | 
| 2684 |  | 
| 2685 |  | 
| 2686 void MacroAssembler::SetCounter(StatsCounter* counter, int value) { | 2581 void MacroAssembler::SetCounter(StatsCounter* counter, int value) { | 
| 2687   if (FLAG_native_code_counters && counter->Enabled()) { | 2582   if (FLAG_native_code_counters && counter->Enabled()) { | 
| 2688     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); | 2583     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); | 
| 2689   } | 2584   } | 
| 2690 } | 2585 } | 
| 2691 | 2586 | 
| 2692 | 2587 | 
| 2693 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { | 2588 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { | 
| 2694   ASSERT(value > 0); | 2589   ASSERT(value > 0); | 
| 2695   if (FLAG_native_code_counters && counter->Enabled()) { | 2590   if (FLAG_native_code_counters && counter->Enabled()) { | 
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2863   mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); | 2758   mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); | 
| 2864 } | 2759 } | 
| 2865 | 2760 | 
| 2866 | 2761 | 
| 2867 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { | 2762 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { | 
| 2868   mov(dst, FieldOperand(map, Map::kBitField3Offset)); | 2763   mov(dst, FieldOperand(map, Map::kBitField3Offset)); | 
| 2869   DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); | 2764   DecodeField<Map::NumberOfOwnDescriptorsBits>(dst); | 
| 2870 } | 2765 } | 
| 2871 | 2766 | 
| 2872 | 2767 | 
| 2873 void MacroAssembler::LoadPowerOf2(XMMRegister dst, |  | 
| 2874                                   Register scratch, |  | 
| 2875                                   int power) { |  | 
| 2876   ASSERT(is_uintn(power + HeapNumber::kExponentBias, |  | 
| 2877                   HeapNumber::kExponentBits)); |  | 
| 2878   mov(scratch, Immediate(power + HeapNumber::kExponentBias)); |  | 
| 2879   movd(dst, scratch); |  | 
| 2880   psllq(dst, HeapNumber::kMantissaBits); |  | 
| 2881 } |  | 
| 2882 |  | 
| 2883 |  | 
| 2884 void MacroAssembler::LookupNumberStringCache(Register object, | 2768 void MacroAssembler::LookupNumberStringCache(Register object, | 
| 2885                                              Register result, | 2769                                              Register result, | 
| 2886                                              Register scratch1, | 2770                                              Register scratch1, | 
| 2887                                              Register scratch2, | 2771                                              Register scratch2, | 
| 2888                                              Label* not_found) { | 2772                                              Label* not_found) { | 
| 2889   // Use of registers. Register result is used as a temporary. | 2773   // Use of registers. Register result is used as a temporary. | 
| 2890   Register number_string_cache = result; | 2774   Register number_string_cache = result; | 
| 2891   Register mask = scratch1; | 2775   Register mask = scratch1; | 
| 2892   Register scratch = scratch2; | 2776   Register scratch = scratch2; | 
| 2893 | 2777 | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
| 2921   // Object is heap number and hash is now in scratch. Calculate cache index. | 2805   // Object is heap number and hash is now in scratch. Calculate cache index. | 
| 2922   and_(scratch, mask); | 2806   and_(scratch, mask); | 
| 2923   Register index = scratch; | 2807   Register index = scratch; | 
| 2924   Register probe = mask; | 2808   Register probe = mask; | 
| 2925   mov(probe, | 2809   mov(probe, | 
| 2926       FieldOperand(number_string_cache, | 2810       FieldOperand(number_string_cache, | 
| 2927                    index, | 2811                    index, | 
| 2928                    times_twice_pointer_size, | 2812                    times_twice_pointer_size, | 
| 2929                    FixedArray::kHeaderSize)); | 2813                    FixedArray::kHeaderSize)); | 
| 2930   JumpIfSmi(probe, not_found); | 2814   JumpIfSmi(probe, not_found); | 
| 2931   movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); | 2815   fld_d(FieldOperand(object, HeapNumber::kValueOffset)); | 
| 2932   ucomisd(xmm0, FieldOperand(probe, HeapNumber::kValueOffset)); | 2816   fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); | 
|  | 2817   FCmp(); | 
| 2933   j(parity_even, not_found);  // Bail out if NaN is involved. | 2818   j(parity_even, not_found);  // Bail out if NaN is involved. | 
| 2934   j(not_equal, not_found);  // The cache did not contain this value. | 2819   j(not_equal, not_found);  // The cache did not contain this value. | 
| 2935   jmp(&load_result_from_cache, Label::kNear); | 2820   jmp(&load_result_from_cache, Label::kNear); | 
| 2936 | 2821 | 
| 2937   bind(&smi_hash_calculated); | 2822   bind(&smi_hash_calculated); | 
| 2938   // Object is smi and hash is now in scratch. Calculate cache index. | 2823   // Object is smi and hash is now in scratch. Calculate cache index. | 
| 2939   and_(scratch, mask); | 2824   and_(scratch, mask); | 
| 2940   // Check if the entry is the smi we are looking for. | 2825   // Check if the entry is the smi we are looking for. | 
| 2941   cmp(object, | 2826   cmp(object, | 
| 2942       FieldOperand(number_string_cache, | 2827       FieldOperand(number_string_cache, | 
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 3458   if (divisor < 0 && ms.multiplier() > 0) sub(edx, dividend); | 3343   if (divisor < 0 && ms.multiplier() > 0) sub(edx, dividend); | 
| 3459   if (ms.shift() > 0) sar(edx, ms.shift()); | 3344   if (ms.shift() > 0) sar(edx, ms.shift()); | 
| 3460   mov(eax, dividend); | 3345   mov(eax, dividend); | 
| 3461   shr(eax, 31); | 3346   shr(eax, 31); | 
| 3462   add(edx, eax); | 3347   add(edx, eax); | 
| 3463 } | 3348 } | 
| 3464 | 3349 | 
| 3465 | 3350 | 
| 3466 } }  // namespace v8::internal | 3351 } }  // namespace v8::internal | 
| 3467 | 3352 | 
| 3468 #endif  // V8_TARGET_ARCH_IA32 | 3353 #endif  // V8_TARGET_ARCH_X87 | 
| OLD | NEW | 
|---|