 Chromium Code Reviews
 Chromium Code Reviews Issue 6729016:
  Implemented FastAsciiStringJoin in X64 full codegen.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 6729016:
  Implemented FastAsciiStringJoin in X64 full codegen.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| 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 1227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1238 } | 1238 } | 
| 1239 } | 1239 } | 
| 1240 | 1240 | 
| 1241 | 1241 | 
| 1242 void MacroAssembler::SmiAdd(Register dst, | 1242 void MacroAssembler::SmiAdd(Register dst, | 
| 1243 Register src1, | 1243 Register src1, | 
| 1244 Register src2) { | 1244 Register src2) { | 
| 1245 // No overflow checking. Use only when it's known that | 1245 // No overflow checking. Use only when it's known that | 
| 1246 // overflowing is impossible. | 1246 // overflowing is impossible. | 
| 1247 ASSERT(!dst.is(src2)); | 1247 ASSERT(!dst.is(src2)); | 
| 1248 if (dst.is(src1)) { | 1248 if (!dst.is(src1)) { | 
| 1249 addq(dst, src2); | |
| 1250 } else { | |
| 1251 movq(dst, src1); | 1249 movq(dst, src1); | 
| 1252 addq(dst, src2); | |
| 1253 } | 1250 } | 
| 1251 addq(dst, src2); | |
| 1254 Assert(no_overflow, "Smi addition overflow"); | 1252 Assert(no_overflow, "Smi addition overflow"); | 
| 1255 } | 1253 } | 
| 1256 | 1254 | 
| 1257 | 1255 | 
| 1258 void MacroAssembler::SmiSub(Register dst, Register src1, Register src2) { | 1256 void MacroAssembler::SmiSub(Register dst, Register src1, Register src2) { | 
| 1259 // No overflow checking. Use only when it's known that | 1257 // No overflow checking. Use only when it's known that | 
| 1260 // overflowing is impossible (e.g., subtracting two positive smis). | 1258 // overflowing is impossible (e.g., subtracting two positive smis). | 
| 1261 ASSERT(!dst.is(src2)); | 1259 ASSERT(!dst.is(src2)); | 
| 1262 if (dst.is(src1)) { | 1260 if (!dst.is(src1)) { | 
| 1263 subq(dst, src2); | |
| 1264 } else { | |
| 1265 movq(dst, src1); | 1261 movq(dst, src1); | 
| 1266 subq(dst, src2); | |
| 1267 } | 1262 } | 
| 1263 subq(dst, src2); | |
| 1268 Assert(no_overflow, "Smi subtraction overflow"); | 1264 Assert(no_overflow, "Smi subtraction overflow"); | 
| 1269 } | 1265 } | 
| 1270 | 1266 | 
| 1271 | 1267 | 
| 1272 void MacroAssembler::SmiSub(Register dst, | 1268 void MacroAssembler::SmiSub(Register dst, | 
| 1273 Register src1, | 1269 Register src1, | 
| 1274 const Operand& src2) { | 1270 const Operand& src2) { | 
| 1275 // No overflow checking. Use only when it's known that | 1271 // No overflow checking. Use only when it's known that | 
| 1276 // overflowing is impossible (e.g., subtracting two positive smis). | 1272 // overflowing is impossible (e.g., subtracting two positive smis). | 
| 1277 if (dst.is(src1)) { | 1273 if (!dst.is(src1)) { | 
| 1278 subq(dst, src2); | |
| 1279 } else { | |
| 1280 movq(dst, src1); | 1274 movq(dst, src1); | 
| 1281 subq(dst, src2); | |
| 1282 } | 1275 } | 
| 1276 subq(dst, src2); | |
| 1283 Assert(no_overflow, "Smi subtraction overflow"); | 1277 Assert(no_overflow, "Smi subtraction overflow"); | 
| 1284 } | 1278 } | 
| 1285 | 1279 | 
| 1286 | 1280 | 
| 1287 void MacroAssembler::SmiNot(Register dst, Register src) { | 1281 void MacroAssembler::SmiNot(Register dst, Register src) { | 
| 1288 ASSERT(!dst.is(kScratchRegister)); | 1282 ASSERT(!dst.is(kScratchRegister)); | 
| 1289 ASSERT(!src.is(kScratchRegister)); | 1283 ASSERT(!src.is(kScratchRegister)); | 
| 1290 // Set tag and padding bits before negating, so that they are zero afterwards. | 1284 // Set tag and padding bits before negating, so that they are zero afterwards. | 
| 1291 movl(kScratchRegister, Immediate(~0)); | 1285 movl(kScratchRegister, Immediate(~0)); | 
| 1292 if (dst.is(src)) { | 1286 if (dst.is(src)) { | 
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1459 neg(dst); | 1453 neg(dst); | 
| 1460 if (shift < kSmiShift) { | 1454 if (shift < kSmiShift) { | 
| 1461 sar(dst, Immediate(kSmiShift - shift)); | 1455 sar(dst, Immediate(kSmiShift - shift)); | 
| 1462 } else { | 1456 } else { | 
| 1463 shl(dst, Immediate(shift - kSmiShift)); | 1457 shl(dst, Immediate(shift - kSmiShift)); | 
| 1464 } | 1458 } | 
| 1465 return SmiIndex(dst, times_1); | 1459 return SmiIndex(dst, times_1); | 
| 1466 } | 1460 } | 
| 1467 | 1461 | 
| 1468 | 1462 | 
| 1463 void MacroAssembler::AddSmiField(Register dst, const Operand& src) { | |
| 1464 addl(dst, Operand(src, kSmiShift / kBitsPerByte)); | |
| 
William Hesse
2011/03/24 12:02:21
ASSERT(kSmiShift % kBitsPerByte == 0);
 
Lasse Reichstein
2011/03/24 12:14:08
Done.
 | |
| 1465 } | |
| 1466 | |
| 1467 | |
| 1468 | |
| 1469 void MacroAssembler::Move(Register dst, Register src) { | 1469 void MacroAssembler::Move(Register dst, Register src) { | 
| 1470 if (!dst.is(src)) { | 1470 if (!dst.is(src)) { | 
| 1471 movq(dst, src); | 1471 movq(dst, src); | 
| 1472 } | 1472 } | 
| 1473 } | 1473 } | 
| 1474 | 1474 | 
| 1475 | 1475 | 
| 1476 void MacroAssembler::Move(Register dst, Handle<Object> source) { | 1476 void MacroAssembler::Move(Register dst, Handle<Object> source) { | 
| 1477 ASSERT(!source->IsFailure()); | 1477 ASSERT(!source->IsFailure()); | 
| 1478 if (source->IsSmi()) { | 1478 if (source->IsSmi()) { | 
| (...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2694 scratch2, | 2694 scratch2, | 
| 2695 gc_required, | 2695 gc_required, | 
| 2696 TAG_OBJECT); | 2696 TAG_OBJECT); | 
| 2697 | 2697 | 
| 2698 // Set the map. The other fields are left uninitialized. | 2698 // Set the map. The other fields are left uninitialized. | 
| 2699 LoadRoot(kScratchRegister, Heap::kConsAsciiStringMapRootIndex); | 2699 LoadRoot(kScratchRegister, Heap::kConsAsciiStringMapRootIndex); | 
| 2700 movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); | 2700 movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); | 
| 2701 } | 2701 } | 
| 2702 | 2702 | 
| 2703 | 2703 | 
| 2704 // Copy memory, byte-by-byte, from source to destination. Not optimized for | |
| 2705 // long or aligned copies. The contents of scratch and length are destroyed. | |
| 2706 // Source and destination are incremented by length. | |
| 2707 // A simpler loop is faster on small copies, but 30% slower on large ones. | |
| 2708 // The cld() instruction must have been emitted, to set the direction flag(), | |
| 2709 // before calling this function. | |
| 2710 void MacroAssembler::CopyBytes(Register destination, | |
| 2711 Register source, | |
| 2712 Register length, | |
| 2713 int min_length, | |
| 2714 Register scratch) { | |
| 2715 ASSERT(min_length >= 0); | |
| 2716 if (FLAG_debug_code) { | |
| 2717 cmpl(length, Immediate(min_length)); | |
| 2718 Assert(greater_equal, "Invalid min_length"); | |
| 2719 } | |
| 2720 Label loop, done, short_string, short_loop; | |
| 2721 // Experimentation shows that the short string loop is faster if length < 10. | |
| 
William Hesse
2011/03/24 12:02:21
Comment disagrees with chosen constant.
 
Lasse Reichstein
2011/03/24 12:14:08
Comment removed.
We should do tests to see what th
 | |
| 2722 const int kLongStringLimit = 20; | |
| 2723 if (min_length <= kLongStringLimit) { | |
| 2724 cmpl(length, Immediate(kLongStringLimit)); | |
| 2725 j(less_equal, &short_string); | |
| 2726 } | |
| 2727 | |
| 2728 ASSERT(source.is(rsi)); | |
| 2729 ASSERT(destination.is(rdi)); | |
| 2730 ASSERT(length.is(rcx)); | |
| 2731 | |
| 2732 // Because source is 8-byte aligned in our uses of this function, | |
| 2733 // we keep source aligned for the rep movs operation by copying the odd bytes | |
| 2734 // at the end of the ranges. | |
| 2735 movq(scratch, length); | |
| 2736 shrl(length, Immediate(3)); | |
| 2737 repmovsq(); | |
| 2738 // Move remaining bytes of length. | |
| 2739 andl(scratch, Immediate(0x7)); | |
| 2740 movq(length, Operand(source, scratch, times_1, -8)); | |
| 2741 movq(Operand(destination, scratch, times_1, -8), length); | |
| 2742 addq(destination, scratch); | |
| 2743 | |
| 2744 if (min_length <= kLongStringLimit) { | |
| 2745 jmp(&done); | |
| 2746 | |
| 2747 bind(&short_string); | |
| 2748 if (min_length == 0) { | |
| 2749 testl(length, length); | |
| 2750 j(zero, &done); | |
| 2751 } | |
| 2752 lea(scratch, Operand(destination, length, times_1, 0)); | |
| 2753 | |
| 2754 bind(&short_loop); | |
| 2755 movb(length, Operand(source, 0)); | |
| 2756 movb(Operand(destination, 0), length); | |
| 2757 incq(source); | |
| 2758 incq(destination); | |
| 2759 cmpq(destination, scratch); | |
| 2760 j(not_equal, &short_loop); | |
| 2761 | |
| 2762 bind(&done); | |
| 2763 } | |
| 2764 } | |
| 2765 | |
| 2766 | |
| 2704 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { | 2767 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { | 
| 2705 if (context_chain_length > 0) { | 2768 if (context_chain_length > 0) { | 
| 2706 // Move up the chain of contexts to the context containing the slot. | 2769 // Move up the chain of contexts to the context containing the slot. | 
| 2707 movq(dst, Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX))); | 2770 movq(dst, Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX))); | 
| 2708 // Load the function context (which is the incoming, outer context). | 2771 // Load the function context (which is the incoming, outer context). | 
| 2709 movq(dst, FieldOperand(dst, JSFunction::kContextOffset)); | 2772 movq(dst, FieldOperand(dst, JSFunction::kContextOffset)); | 
| 2710 for (int i = 1; i < context_chain_length; i++) { | 2773 for (int i = 1; i < context_chain_length; i++) { | 
| 2711 movq(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); | 2774 movq(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); | 
| 2712 movq(dst, FieldOperand(dst, JSFunction::kContextOffset)); | 2775 movq(dst, FieldOperand(dst, JSFunction::kContextOffset)); | 
| 2713 } | 2776 } | 
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2857 CPU::FlushICache(address_, size_); | 2920 CPU::FlushICache(address_, size_); | 
| 2858 | 2921 | 
| 2859 // Check that the code was patched as expected. | 2922 // Check that the code was patched as expected. | 
| 2860 ASSERT(masm_.pc_ == address_ + size_); | 2923 ASSERT(masm_.pc_ == address_ + size_); | 
| 2861 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 2924 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 
| 2862 } | 2925 } | 
| 2863 | 2926 | 
| 2864 } } // namespace v8::internal | 2927 } } // namespace v8::internal | 
| 2865 | 2928 | 
| 2866 #endif // V8_TARGET_ARCH_X64 | 2929 #endif // V8_TARGET_ARCH_X64 | 
| OLD | NEW |