| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 21 matching lines...) Expand all Loading... |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "codegen.h" | 34 #include "codegen.h" |
| 35 #include "regexp-macro-assembler.h" | 35 #include "regexp-macro-assembler.h" |
| 36 #include "stub-cache.h" | 36 #include "stub-cache.h" |
| 37 | 37 |
| 38 namespace v8 { | 38 namespace v8 { |
| 39 namespace internal { | 39 namespace internal { |
| 40 | 40 |
| 41 | 41 |
| 42 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor( |
| 43 Isolate* isolate, |
| 44 CodeStubInterfaceDescriptor* descriptor) { |
| 45 static Register registers[] = { a3, a2, a1, a0 }; |
| 46 descriptor->register_param_count_ = 4; |
| 47 descriptor->register_params_ = registers; |
| 48 descriptor->stack_parameter_count_ = NULL; |
| 49 descriptor->deoptimization_handler_ = |
| 50 Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry; |
| 51 } |
| 52 |
| 53 |
| 42 void KeyedLoadFastElementStub::InitializeInterfaceDescriptor( | 54 void KeyedLoadFastElementStub::InitializeInterfaceDescriptor( |
| 43 Isolate* isolate, | 55 Isolate* isolate, |
| 44 CodeStubInterfaceDescriptor* descriptor) { | 56 CodeStubInterfaceDescriptor* descriptor) { |
| 45 static Register registers[] = { a1, a0 }; | 57 static Register registers[] = { a1, a0 }; |
| 46 descriptor->register_param_count_ = 2; | 58 descriptor->register_param_count_ = 2; |
| 47 descriptor->register_params_ = registers; | 59 descriptor->register_params_ = registers; |
| 48 descriptor->deoptimization_handler_ = | 60 descriptor->deoptimization_handler_ = |
| 49 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure); | 61 FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure); |
| 50 } | 62 } |
| 51 | 63 |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 &slow_case); | 503 &slow_case); |
| 492 | 504 |
| 493 // Return and remove the on-stack parameters. | 505 // Return and remove the on-stack parameters. |
| 494 __ DropAndRet(3); | 506 __ DropAndRet(3); |
| 495 | 507 |
| 496 __ bind(&slow_case); | 508 __ bind(&slow_case); |
| 497 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 509 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 498 } | 510 } |
| 499 | 511 |
| 500 | 512 |
| 501 void FastCloneShallowObjectStub::Generate(MacroAssembler* masm) { | |
| 502 // Stack layout on entry: | |
| 503 // | |
| 504 // [sp]: object literal flags. | |
| 505 // [sp + kPointerSize]: constant properties. | |
| 506 // [sp + (2 * kPointerSize)]: literal index. | |
| 507 // [sp + (3 * kPointerSize)]: literals array. | |
| 508 | |
| 509 // Load boilerplate object into a3 and check if we need to create a | |
| 510 // boilerplate. | |
| 511 Label slow_case; | |
| 512 __ lw(a3, MemOperand(sp, 3 * kPointerSize)); | |
| 513 __ lw(a0, MemOperand(sp, 2 * kPointerSize)); | |
| 514 __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 515 __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize); | |
| 516 __ Addu(a3, t0, a3); | |
| 517 __ lw(a3, MemOperand(a3)); | |
| 518 __ LoadRoot(t0, Heap::kUndefinedValueRootIndex); | |
| 519 __ Branch(&slow_case, eq, a3, Operand(t0)); | |
| 520 | |
| 521 // Check that the boilerplate contains only fast properties and we can | |
| 522 // statically determine the instance size. | |
| 523 int size = JSObject::kHeaderSize + length_ * kPointerSize; | |
| 524 __ lw(a0, FieldMemOperand(a3, HeapObject::kMapOffset)); | |
| 525 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceSizeOffset)); | |
| 526 __ Branch(&slow_case, ne, a0, Operand(size >> kPointerSizeLog2)); | |
| 527 | |
| 528 // Allocate the JS object and copy header together with all in-object | |
| 529 // properties from the boilerplate. | |
| 530 __ AllocateInNewSpace(size, v0, a1, a2, &slow_case, TAG_OBJECT); | |
| 531 for (int i = 0; i < size; i += kPointerSize) { | |
| 532 __ lw(a1, FieldMemOperand(a3, i)); | |
| 533 __ sw(a1, FieldMemOperand(v0, i)); | |
| 534 } | |
| 535 | |
| 536 // Return and remove the on-stack parameters. | |
| 537 __ DropAndRet(4); | |
| 538 | |
| 539 __ bind(&slow_case); | |
| 540 __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1); | |
| 541 } | |
| 542 | |
| 543 | |
| 544 // Takes a Smi and converts to an IEEE 64 bit floating point value in two | 513 // Takes a Smi and converts to an IEEE 64 bit floating point value in two |
| 545 // registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and | 514 // registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and |
| 546 // 52 fraction bits (20 in the first word, 32 in the second). Zeros is a | 515 // 52 fraction bits (20 in the first word, 32 in the second). Zeros is a |
| 547 // scratch register. Destroys the source register. No GC occurs during this | 516 // scratch register. Destroys the source register. No GC occurs during this |
| 548 // stub so you don't have to set up the frame. | 517 // stub so you don't have to set up the frame. |
| 549 class ConvertToDoubleStub : public PlatformCodeStub { | 518 class ConvertToDoubleStub : public PlatformCodeStub { |
| 550 public: | 519 public: |
| 551 ConvertToDoubleStub(Register result_reg_1, | 520 ConvertToDoubleStub(Register result_reg_1, |
| 552 Register result_reg_2, | 521 Register result_reg_2, |
| 553 Register source_reg, | 522 Register source_reg, |
| (...skipping 1254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1808 | 1777 |
| 1809 | 1778 |
| 1810 static void ICCompareStub_CheckInputType(MacroAssembler* masm, | 1779 static void ICCompareStub_CheckInputType(MacroAssembler* masm, |
| 1811 Register input, | 1780 Register input, |
| 1812 Register scratch, | 1781 Register scratch, |
| 1813 CompareIC::State expected, | 1782 CompareIC::State expected, |
| 1814 Label* fail) { | 1783 Label* fail) { |
| 1815 Label ok; | 1784 Label ok; |
| 1816 if (expected == CompareIC::SMI) { | 1785 if (expected == CompareIC::SMI) { |
| 1817 __ JumpIfNotSmi(input, fail); | 1786 __ JumpIfNotSmi(input, fail); |
| 1818 } else if (expected == CompareIC::HEAP_NUMBER) { | 1787 } else if (expected == CompareIC::NUMBER) { |
| 1819 __ JumpIfSmi(input, &ok); | 1788 __ JumpIfSmi(input, &ok); |
| 1820 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, | 1789 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, |
| 1821 DONT_DO_SMI_CHECK); | 1790 DONT_DO_SMI_CHECK); |
| 1822 } | 1791 } |
| 1823 // We could be strict about symbol/string here, but as long as | 1792 // We could be strict about symbol/string here, but as long as |
| 1824 // hydrogen doesn't care, the stub doesn't have to care either. | 1793 // hydrogen doesn't care, the stub doesn't have to care either. |
| 1825 __ bind(&ok); | 1794 __ bind(&ok); |
| 1826 } | 1795 } |
| 1827 | 1796 |
| 1828 | 1797 |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2167 | 2136 |
| 2168 // TODO(svenpanne): Use virtual functions instead of switch. | 2137 // TODO(svenpanne): Use virtual functions instead of switch. |
| 2169 void UnaryOpStub::Generate(MacroAssembler* masm) { | 2138 void UnaryOpStub::Generate(MacroAssembler* masm) { |
| 2170 switch (operand_type_) { | 2139 switch (operand_type_) { |
| 2171 case UnaryOpIC::UNINITIALIZED: | 2140 case UnaryOpIC::UNINITIALIZED: |
| 2172 GenerateTypeTransition(masm); | 2141 GenerateTypeTransition(masm); |
| 2173 break; | 2142 break; |
| 2174 case UnaryOpIC::SMI: | 2143 case UnaryOpIC::SMI: |
| 2175 GenerateSmiStub(masm); | 2144 GenerateSmiStub(masm); |
| 2176 break; | 2145 break; |
| 2177 case UnaryOpIC::HEAP_NUMBER: | 2146 case UnaryOpIC::NUMBER: |
| 2178 GenerateHeapNumberStub(masm); | 2147 GenerateNumberStub(masm); |
| 2179 break; | 2148 break; |
| 2180 case UnaryOpIC::GENERIC: | 2149 case UnaryOpIC::GENERIC: |
| 2181 GenerateGenericStub(masm); | 2150 GenerateGenericStub(masm); |
| 2182 break; | 2151 break; |
| 2183 } | 2152 } |
| 2184 } | 2153 } |
| 2185 | 2154 |
| 2186 | 2155 |
| 2187 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 2156 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 2188 // Argument is in a0 and v0 at this point, so we can overwrite a0. | 2157 // Argument is in a0 and v0 at this point, so we can overwrite a0. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2248 __ JumpIfNotSmi(a0, non_smi); | 2217 __ JumpIfNotSmi(a0, non_smi); |
| 2249 | 2218 |
| 2250 // Flip bits and revert inverted smi-tag. | 2219 // Flip bits and revert inverted smi-tag. |
| 2251 __ Neg(v0, a0); | 2220 __ Neg(v0, a0); |
| 2252 __ And(v0, v0, ~kSmiTagMask); | 2221 __ And(v0, v0, ~kSmiTagMask); |
| 2253 __ Ret(); | 2222 __ Ret(); |
| 2254 } | 2223 } |
| 2255 | 2224 |
| 2256 | 2225 |
| 2257 // TODO(svenpanne): Use virtual functions instead of switch. | 2226 // TODO(svenpanne): Use virtual functions instead of switch. |
| 2258 void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 2227 void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) { |
| 2259 switch (op_) { | 2228 switch (op_) { |
| 2260 case Token::SUB: | 2229 case Token::SUB: |
| 2261 GenerateHeapNumberStubSub(masm); | 2230 GenerateNumberStubSub(masm); |
| 2262 break; | 2231 break; |
| 2263 case Token::BIT_NOT: | 2232 case Token::BIT_NOT: |
| 2264 GenerateHeapNumberStubBitNot(masm); | 2233 GenerateNumberStubBitNot(masm); |
| 2265 break; | 2234 break; |
| 2266 default: | 2235 default: |
| 2267 UNREACHABLE(); | 2236 UNREACHABLE(); |
| 2268 } | 2237 } |
| 2269 } | 2238 } |
| 2270 | 2239 |
| 2271 | 2240 |
| 2272 void UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { | 2241 void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) { |
| 2273 Label non_smi, slow, call_builtin; | 2242 Label non_smi, slow, call_builtin; |
| 2274 GenerateSmiCodeSub(masm, &non_smi, &call_builtin); | 2243 GenerateSmiCodeSub(masm, &non_smi, &call_builtin); |
| 2275 __ bind(&non_smi); | 2244 __ bind(&non_smi); |
| 2276 GenerateHeapNumberCodeSub(masm, &slow); | 2245 GenerateHeapNumberCodeSub(masm, &slow); |
| 2277 __ bind(&slow); | 2246 __ bind(&slow); |
| 2278 GenerateTypeTransition(masm); | 2247 GenerateTypeTransition(masm); |
| 2279 __ bind(&call_builtin); | 2248 __ bind(&call_builtin); |
| 2280 GenerateGenericCodeFallback(masm); | 2249 GenerateGenericCodeFallback(masm); |
| 2281 } | 2250 } |
| 2282 | 2251 |
| 2283 | 2252 |
| 2284 void UnaryOpStub::GenerateHeapNumberStubBitNot(MacroAssembler* masm) { | 2253 void UnaryOpStub::GenerateNumberStubBitNot(MacroAssembler* masm) { |
| 2285 Label non_smi, slow; | 2254 Label non_smi, slow; |
| 2286 GenerateSmiCodeBitNot(masm, &non_smi); | 2255 GenerateSmiCodeBitNot(masm, &non_smi); |
| 2287 __ bind(&non_smi); | 2256 __ bind(&non_smi); |
| 2288 GenerateHeapNumberCodeBitNot(masm, &slow); | 2257 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 2289 __ bind(&slow); | 2258 __ bind(&slow); |
| 2290 GenerateTypeTransition(masm); | 2259 GenerateTypeTransition(masm); |
| 2291 } | 2260 } |
| 2292 | 2261 |
| 2293 | 2262 |
| 2294 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, | 2263 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2689 // Load the operands. | 2658 // Load the operands. |
| 2690 if (smi_operands) { | 2659 if (smi_operands) { |
| 2691 FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); | 2660 FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); |
| 2692 } else { | 2661 } else { |
| 2693 // Load right operand to f14 or a2/a3. | 2662 // Load right operand to f14 or a2/a3. |
| 2694 if (right_type == BinaryOpIC::INT32) { | 2663 if (right_type == BinaryOpIC::INT32) { |
| 2695 FloatingPointHelper::LoadNumberAsInt32Double( | 2664 FloatingPointHelper::LoadNumberAsInt32Double( |
| 2696 masm, right, destination, f14, f16, a2, a3, heap_number_map, | 2665 masm, right, destination, f14, f16, a2, a3, heap_number_map, |
| 2697 scratch1, scratch2, f2, miss); | 2666 scratch1, scratch2, f2, miss); |
| 2698 } else { | 2667 } else { |
| 2699 Label* fail = (right_type == BinaryOpIC::HEAP_NUMBER) ? miss | 2668 Label* fail = (right_type == BinaryOpIC::NUMBER) ? miss : not_numbers; |
| 2700 : not_numbers; | |
| 2701 FloatingPointHelper::LoadNumber( | 2669 FloatingPointHelper::LoadNumber( |
| 2702 masm, destination, right, f14, a2, a3, heap_number_map, | 2670 masm, destination, right, f14, a2, a3, heap_number_map, |
| 2703 scratch1, scratch2, fail); | 2671 scratch1, scratch2, fail); |
| 2704 } | 2672 } |
| 2705 // Load left operand to f12 or a0/a1. This keeps a0/a1 intact if it | 2673 // Load left operand to f12 or a0/a1. This keeps a0/a1 intact if it |
| 2706 // jumps to |miss|. | 2674 // jumps to |miss|. |
| 2707 if (left_type == BinaryOpIC::INT32) { | 2675 if (left_type == BinaryOpIC::INT32) { |
| 2708 FloatingPointHelper::LoadNumberAsInt32Double( | 2676 FloatingPointHelper::LoadNumberAsInt32Double( |
| 2709 masm, left, destination, f12, f16, a0, a1, heap_number_map, | 2677 masm, left, destination, f12, f16, a0, a1, heap_number_map, |
| 2710 scratch1, scratch2, f2, miss); | 2678 scratch1, scratch2, f2, miss); |
| 2711 } else { | 2679 } else { |
| 2712 Label* fail = (left_type == BinaryOpIC::HEAP_NUMBER) ? miss | 2680 Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers; |
| 2713 : not_numbers; | |
| 2714 FloatingPointHelper::LoadNumber( | 2681 FloatingPointHelper::LoadNumber( |
| 2715 masm, destination, left, f12, a0, a1, heap_number_map, | 2682 masm, destination, left, f12, a0, a1, heap_number_map, |
| 2716 scratch1, scratch2, fail); | 2683 scratch1, scratch2, fail); |
| 2717 } | 2684 } |
| 2718 } | 2685 } |
| 2719 | 2686 |
| 2720 // Calculate the result. | 2687 // Calculate the result. |
| 2721 if (destination == FloatingPointHelper::kFPURegisters) { | 2688 if (destination == FloatingPointHelper::kFPURegisters) { |
| 2722 // Using FPU registers: | 2689 // Using FPU registers: |
| 2723 // f12: Left value. | 2690 // f12: Left value. |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3102 // Tag the result and return. | 3069 // Tag the result and return. |
| 3103 __ SmiTag(v0, scratch1); | 3070 __ SmiTag(v0, scratch1); |
| 3104 __ Ret(); | 3071 __ Ret(); |
| 3105 } else { | 3072 } else { |
| 3106 // DIV just falls through to allocating a heap number. | 3073 // DIV just falls through to allocating a heap number. |
| 3107 } | 3074 } |
| 3108 | 3075 |
| 3109 __ bind(&return_heap_number); | 3076 __ bind(&return_heap_number); |
| 3110 // Return a heap number, or fall through to type transition or runtime | 3077 // Return a heap number, or fall through to type transition or runtime |
| 3111 // call if we can't. | 3078 // call if we can't. |
| 3112 if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER | 3079 if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::NUMBER |
| 3113 : BinaryOpIC::INT32)) { | 3080 : BinaryOpIC::INT32)) { |
| 3114 // We are using FPU registers so s0 is available. | 3081 // We are using FPU registers so s0 is available. |
| 3115 heap_number_result = s0; | 3082 heap_number_result = s0; |
| 3116 BinaryOpStub_GenerateHeapResultAllocation(masm, | 3083 BinaryOpStub_GenerateHeapResultAllocation(masm, |
| 3117 heap_number_result, | 3084 heap_number_result, |
| 3118 heap_number_map, | 3085 heap_number_map, |
| 3119 scratch1, | 3086 scratch1, |
| 3120 scratch2, | 3087 scratch2, |
| 3121 &call_runtime, | 3088 &call_runtime, |
| 3122 mode_); | 3089 mode_); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3331 __ bind(&check); | 3298 __ bind(&check); |
| 3332 __ LoadRoot(t0, Heap::kUndefinedValueRootIndex); | 3299 __ LoadRoot(t0, Heap::kUndefinedValueRootIndex); |
| 3333 __ Branch(&done, ne, a0, Operand(t0)); | 3300 __ Branch(&done, ne, a0, Operand(t0)); |
| 3334 if (Token::IsBitOp(op_)) { | 3301 if (Token::IsBitOp(op_)) { |
| 3335 __ li(a0, Operand(Smi::FromInt(0))); | 3302 __ li(a0, Operand(Smi::FromInt(0))); |
| 3336 } else { | 3303 } else { |
| 3337 __ LoadRoot(a0, Heap::kNanValueRootIndex); | 3304 __ LoadRoot(a0, Heap::kNanValueRootIndex); |
| 3338 } | 3305 } |
| 3339 __ bind(&done); | 3306 __ bind(&done); |
| 3340 | 3307 |
| 3341 GenerateHeapNumberStub(masm); | 3308 GenerateNumberStub(masm); |
| 3342 } | 3309 } |
| 3343 | 3310 |
| 3344 | 3311 |
| 3345 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { | 3312 void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) { |
| 3346 Label call_runtime, transition; | 3313 Label call_runtime, transition; |
| 3347 BinaryOpStub_GenerateFPOperation( | 3314 BinaryOpStub_GenerateFPOperation( |
| 3348 masm, left_type_, right_type_, false, | 3315 masm, left_type_, right_type_, false, |
| 3349 &transition, &call_runtime, &transition, op_, mode_); | 3316 &transition, &call_runtime, &transition, op_, mode_); |
| 3350 | 3317 |
| 3351 __ bind(&transition); | 3318 __ bind(&transition); |
| 3352 GenerateTypeTransition(masm); | 3319 GenerateTypeTransition(masm); |
| 3353 | 3320 |
| 3354 __ bind(&call_runtime); | 3321 __ bind(&call_runtime); |
| 3355 GenerateRegisterArgsPush(masm); | 3322 GenerateRegisterArgsPush(masm); |
| (...skipping 1781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5137 // sp[8]: subject string | 5104 // sp[8]: subject string |
| 5138 // sp[12]: JSRegExp object | 5105 // sp[12]: JSRegExp object |
| 5139 | 5106 |
| 5140 const int kLastMatchInfoOffset = 0 * kPointerSize; | 5107 const int kLastMatchInfoOffset = 0 * kPointerSize; |
| 5141 const int kPreviousIndexOffset = 1 * kPointerSize; | 5108 const int kPreviousIndexOffset = 1 * kPointerSize; |
| 5142 const int kSubjectOffset = 2 * kPointerSize; | 5109 const int kSubjectOffset = 2 * kPointerSize; |
| 5143 const int kJSRegExpOffset = 3 * kPointerSize; | 5110 const int kJSRegExpOffset = 3 * kPointerSize; |
| 5144 | 5111 |
| 5145 Isolate* isolate = masm->isolate(); | 5112 Isolate* isolate = masm->isolate(); |
| 5146 | 5113 |
| 5147 Label runtime, invoke_regexp; | 5114 Label runtime; |
| 5148 | |
| 5149 // Allocation of registers for this function. These are in callee save | 5115 // Allocation of registers for this function. These are in callee save |
| 5150 // registers and will be preserved by the call to the native RegExp code, as | 5116 // registers and will be preserved by the call to the native RegExp code, as |
| 5151 // this code is called using the normal C calling convention. When calling | 5117 // this code is called using the normal C calling convention. When calling |
| 5152 // directly from generated code the native RegExp code will not do a GC and | 5118 // directly from generated code the native RegExp code will not do a GC and |
| 5153 // therefore the content of these registers are safe to use after the call. | 5119 // therefore the content of these registers are safe to use after the call. |
| 5154 // MIPS - using s0..s2, since we are not using CEntry Stub. | 5120 // MIPS - using s0..s2, since we are not using CEntry Stub. |
| 5155 Register subject = s0; | 5121 Register subject = s0; |
| 5156 Register regexp_data = s1; | 5122 Register regexp_data = s1; |
| 5157 Register last_match_info_elements = s2; | 5123 Register last_match_info_elements = s2; |
| 5158 | 5124 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5190 | 5156 |
| 5191 // regexp_data: RegExp data (FixedArray) | 5157 // regexp_data: RegExp data (FixedArray) |
| 5192 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 5158 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
| 5193 __ lw(a0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | 5159 __ lw(a0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); |
| 5194 __ Branch(&runtime, ne, a0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); | 5160 __ Branch(&runtime, ne, a0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); |
| 5195 | 5161 |
| 5196 // regexp_data: RegExp data (FixedArray) | 5162 // regexp_data: RegExp data (FixedArray) |
| 5197 // Check that the number of captures fit in the static offsets vector buffer. | 5163 // Check that the number of captures fit in the static offsets vector buffer. |
| 5198 __ lw(a2, | 5164 __ lw(a2, |
| 5199 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | 5165 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
| 5200 // Calculate number of capture registers (number_of_captures + 1) * 2. This | 5166 // Check (number_of_captures + 1) * 2 <= offsets vector size |
| 5201 // uses the asumption that smis are 2 * their untagged value. | 5167 // Or number_of_captures * 2 <= offsets vector size - 2 |
| 5168 // Multiplying by 2 comes for free since a2 is smi-tagged. |
| 5202 STATIC_ASSERT(kSmiTag == 0); | 5169 STATIC_ASSERT(kSmiTag == 0); |
| 5203 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 5170 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
| 5204 __ Addu(a2, a2, Operand(2)); // a2 was a smi. | 5171 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
| 5205 // Check that the static offsets vector buffer is large enough. | |
| 5206 __ Branch( | 5172 __ Branch( |
| 5207 &runtime, hi, a2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize)); | 5173 &runtime, hi, a2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2)); |
| 5208 | |
| 5209 // a2: Number of capture registers | |
| 5210 // regexp_data: RegExp data (FixedArray) | |
| 5211 // Check that the second argument is a string. | |
| 5212 __ lw(subject, MemOperand(sp, kSubjectOffset)); | |
| 5213 __ JumpIfSmi(subject, &runtime); | |
| 5214 __ GetObjectType(subject, a0, a0); | |
| 5215 __ And(a0, a0, Operand(kIsNotStringMask)); | |
| 5216 STATIC_ASSERT(kStringTag == 0); | |
| 5217 __ Branch(&runtime, ne, a0, Operand(zero_reg)); | |
| 5218 | |
| 5219 // Get the length of the string to r3. | |
| 5220 __ lw(a3, FieldMemOperand(subject, String::kLengthOffset)); | |
| 5221 | |
| 5222 // a2: Number of capture registers | |
| 5223 // a3: Length of subject string as a smi | |
| 5224 // subject: Subject string | |
| 5225 // regexp_data: RegExp data (FixedArray) | |
| 5226 // Check that the third argument is a positive smi less than the subject | |
| 5227 // string length. A negative value will be greater (unsigned comparison). | |
| 5228 __ lw(a0, MemOperand(sp, kPreviousIndexOffset)); | |
| 5229 __ JumpIfNotSmi(a0, &runtime); | |
| 5230 __ Branch(&runtime, ls, a3, Operand(a0)); | |
| 5231 | |
| 5232 // a2: Number of capture registers | |
| 5233 // subject: Subject string | |
| 5234 // regexp_data: RegExp data (FixedArray) | |
| 5235 // Check that the fourth object is a JSArray object. | |
| 5236 __ lw(a0, MemOperand(sp, kLastMatchInfoOffset)); | |
| 5237 __ JumpIfSmi(a0, &runtime); | |
| 5238 __ GetObjectType(a0, a1, a1); | |
| 5239 __ Branch(&runtime, ne, a1, Operand(JS_ARRAY_TYPE)); | |
| 5240 // Check that the JSArray is in fast case. | |
| 5241 __ lw(last_match_info_elements, | |
| 5242 FieldMemOperand(a0, JSArray::kElementsOffset)); | |
| 5243 __ lw(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); | |
| 5244 __ Branch(&runtime, ne, a0, Operand( | |
| 5245 isolate->factory()->fixed_array_map())); | |
| 5246 // Check that the last match info has space for the capture registers and the | |
| 5247 // additional information. | |
| 5248 __ lw(a0, | |
| 5249 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); | |
| 5250 __ Addu(a2, a2, Operand(RegExpImpl::kLastMatchOverhead)); | |
| 5251 __ sra(at, a0, kSmiTagSize); // Untag length for comparison. | |
| 5252 __ Branch(&runtime, gt, a2, Operand(at)); | |
| 5253 | 5174 |
| 5254 // Reset offset for possibly sliced string. | 5175 // Reset offset for possibly sliced string. |
| 5255 __ mov(t0, zero_reg); | 5176 __ mov(t0, zero_reg); |
| 5256 // subject: Subject string | 5177 __ lw(subject, MemOperand(sp, kSubjectOffset)); |
| 5257 // regexp_data: RegExp data (FixedArray) | 5178 __ JumpIfSmi(subject, &runtime); |
| 5258 // Check the representation and encoding of the subject string. | 5179 __ mov(a3, subject); // Make a copy of the original subject string. |
| 5259 Label seq_string; | |
| 5260 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 5180 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
| 5261 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); | 5181 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); |
| 5262 // First check for flat string. None of the following string type tests will | 5182 // subject: subject string |
| 5263 // succeed if subject is not a string or a short external string. | 5183 // a3: subject string |
| 5184 // a0: subject string instance type |
| 5185 // regexp_data: RegExp data (FixedArray) |
| 5186 // Handle subject string according to its encoding and representation: |
| 5187 // (1) Sequential string? If yes, go to (5). |
| 5188 // (2) Anything but sequential or cons? If yes, go to (6). |
| 5189 // (3) Cons string. If the string is flat, replace subject with first string. |
| 5190 // Otherwise bailout. |
| 5191 // (4) Is subject external? If yes, go to (7). |
| 5192 // (5) Sequential string. Load regexp code according to encoding. |
| 5193 // (E) Carry on. |
| 5194 /// [...] |
| 5195 |
| 5196 // Deferred code at the end of the stub: |
| 5197 // (6) Not a long external string? If yes, go to (8). |
| 5198 // (7) External string. Make it, offset-wise, look like a sequential string. |
| 5199 // Go to (5). |
| 5200 // (8) Short external string or not a string? If yes, bail out to runtime. |
| 5201 // (9) Sliced string. Replace subject with parent. Go to (4). |
| 5202 |
| 5203 Label seq_string /* 5 */, external_string /* 7 */, |
| 5204 check_underlying /* 4 */, not_seq_nor_cons /* 6 */, |
| 5205 not_long_external /* 8 */; |
| 5206 |
| 5207 // (1) Sequential string? If yes, go to (5). |
| 5264 __ And(a1, | 5208 __ And(a1, |
| 5265 a0, | 5209 a0, |
| 5266 Operand(kIsNotStringMask | | 5210 Operand(kIsNotStringMask | |
| 5267 kStringRepresentationMask | | 5211 kStringRepresentationMask | |
| 5268 kShortExternalStringMask)); | 5212 kShortExternalStringMask)); |
| 5269 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); | 5213 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); |
| 5270 __ Branch(&seq_string, eq, a1, Operand(zero_reg)); | 5214 __ Branch(&seq_string, eq, a1, Operand(zero_reg)); // Go to (5). |
| 5271 | 5215 |
| 5272 // subject: Subject string | 5216 // (2) Anything but sequential or cons? If yes, go to (6). |
| 5273 // a0: instance type if Subject string | |
| 5274 // regexp_data: RegExp data (FixedArray) | |
| 5275 // a1: whether subject is a string and if yes, its string representation | |
| 5276 // Check for flat cons string or sliced string. | |
| 5277 // A flat cons string is a cons string where the second part is the empty | |
| 5278 // string. In that case the subject string is just the first part of the cons | |
| 5279 // string. Also in this case the first part of the cons string is known to be | |
| 5280 // a sequential string or an external string. | |
| 5281 // In the case of a sliced string its offset has to be taken into account. | |
| 5282 Label cons_string, external_string, check_encoding; | |
| 5283 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | 5217 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
| 5284 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | 5218 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); |
| 5285 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | 5219 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); |
| 5286 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | 5220 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); |
| 5287 __ Branch(&cons_string, lt, a1, Operand(kExternalStringTag)); | 5221 // Go to (6). |
| 5288 __ Branch(&external_string, eq, a1, Operand(kExternalStringTag)); | 5222 __ Branch(¬_seq_nor_cons, ge, a1, Operand(kExternalStringTag)); |
| 5289 | 5223 |
| 5290 // Catch non-string subject or short external string. | 5224 // (3) Cons string. Check that it's flat. |
| 5291 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | 5225 // Replace subject with first string and reload instance type. |
| 5292 __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask)); | |
| 5293 __ Branch(&runtime, ne, at, Operand(zero_reg)); | |
| 5294 | |
| 5295 // String is sliced. | |
| 5296 __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset)); | |
| 5297 __ sra(t0, t0, kSmiTagSize); | |
| 5298 __ lw(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); | |
| 5299 // t5: offset of sliced string, smi-tagged. | |
| 5300 __ jmp(&check_encoding); | |
| 5301 // String is a cons string, check whether it is flat. | |
| 5302 __ bind(&cons_string); | |
| 5303 __ lw(a0, FieldMemOperand(subject, ConsString::kSecondOffset)); | 5226 __ lw(a0, FieldMemOperand(subject, ConsString::kSecondOffset)); |
| 5304 __ LoadRoot(a1, Heap::kEmptyStringRootIndex); | 5227 __ LoadRoot(a1, Heap::kEmptyStringRootIndex); |
| 5305 __ Branch(&runtime, ne, a0, Operand(a1)); | 5228 __ Branch(&runtime, ne, a0, Operand(a1)); |
| 5306 __ lw(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | 5229 __ lw(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); |
| 5307 // Is first part of cons or parent of slice a flat string? | 5230 |
| 5308 __ bind(&check_encoding); | 5231 // (4) Is subject external? If yes, go to (7). |
| 5232 __ bind(&check_underlying); |
| 5309 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 5233 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
| 5310 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); | 5234 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); |
| 5311 STATIC_ASSERT(kSeqStringTag == 0); | 5235 STATIC_ASSERT(kSeqStringTag == 0); |
| 5312 __ And(at, a0, Operand(kStringRepresentationMask)); | 5236 __ And(at, a0, Operand(kStringRepresentationMask)); |
| 5313 __ Branch(&external_string, ne, at, Operand(zero_reg)); | 5237 // The underlying external string is never a short external string. |
| 5238 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength); |
| 5239 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength); |
| 5240 __ Branch(&external_string, ne, at, Operand(zero_reg)); // Go to (7). |
| 5314 | 5241 |
| 5242 // (5) Sequential string. Load regexp code according to encoding. |
| 5315 __ bind(&seq_string); | 5243 __ bind(&seq_string); |
| 5316 // subject: Subject string | 5244 // subject: sequential subject string (or look-alike, external string) |
| 5317 // regexp_data: RegExp data (FixedArray) | 5245 // a3: original subject string |
| 5318 // a0: Instance type of subject string | 5246 // Load previous index and check range before a3 is overwritten. We have to |
| 5247 // use a3 instead of subject here because subject might have been only made |
| 5248 // to look like a sequential string when it actually is an external string. |
| 5249 __ lw(a1, MemOperand(sp, kPreviousIndexOffset)); |
| 5250 __ JumpIfNotSmi(a1, &runtime); |
| 5251 __ lw(a3, FieldMemOperand(a3, String::kLengthOffset)); |
| 5252 __ Branch(&runtime, ls, a3, Operand(a1)); |
| 5253 __ sra(a1, a1, kSmiTagSize); // Untag the Smi. |
| 5254 |
| 5319 STATIC_ASSERT(kStringEncodingMask == 4); | 5255 STATIC_ASSERT(kStringEncodingMask == 4); |
| 5320 STATIC_ASSERT(kOneByteStringTag == 4); | 5256 STATIC_ASSERT(kOneByteStringTag == 4); |
| 5321 STATIC_ASSERT(kTwoByteStringTag == 0); | 5257 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 5322 // Find the code object based on the assumptions above. | |
| 5323 __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ASCII. | 5258 __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ASCII. |
| 5324 __ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset)); | 5259 __ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset)); |
| 5325 __ sra(a3, a0, 2); // a3 is 1 for ASCII, 0 for UC16 (used below). | 5260 __ sra(a3, a0, 2); // a3 is 1 for ASCII, 0 for UC16 (used below). |
| 5326 __ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); | 5261 __ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); |
| 5327 __ Movz(t9, t1, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset. | 5262 __ Movz(t9, t1, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset. |
| 5328 | 5263 |
| 5264 // (E) Carry on. String handling is done. |
| 5265 // t9: irregexp code |
| 5329 // Check that the irregexp code has been generated for the actual string | 5266 // Check that the irregexp code has been generated for the actual string |
| 5330 // encoding. If it has, the field contains a code object otherwise it contains | 5267 // encoding. If it has, the field contains a code object otherwise it contains |
| 5331 // a smi (code flushing support). | 5268 // a smi (code flushing support). |
| 5332 __ JumpIfSmi(t9, &runtime); | 5269 __ JumpIfSmi(t9, &runtime); |
| 5333 | 5270 |
| 5334 // a3: encoding of subject string (1 if ASCII, 0 if two_byte); | |
| 5335 // t9: code | |
| 5336 // subject: Subject string | |
| 5337 // regexp_data: RegExp data (FixedArray) | |
| 5338 // Load used arguments before starting to push arguments for call to native | |
| 5339 // RegExp code to avoid handling changing stack height. | |
| 5340 __ lw(a1, MemOperand(sp, kPreviousIndexOffset)); | |
| 5341 __ sra(a1, a1, kSmiTagSize); // Untag the Smi. | |
| 5342 | |
| 5343 // a1: previous index | 5271 // a1: previous index |
| 5344 // a3: encoding of subject string (1 if ASCII, 0 if two_byte); | 5272 // a3: encoding of subject string (1 if ASCII, 0 if two_byte); |
| 5345 // t9: code | 5273 // t9: code |
| 5346 // subject: Subject string | 5274 // subject: Subject string |
| 5347 // regexp_data: RegExp data (FixedArray) | 5275 // regexp_data: RegExp data (FixedArray) |
| 5348 // All checks done. Now push arguments for native regexp code. | 5276 // All checks done. Now push arguments for native regexp code. |
| 5349 __ IncrementCounter(isolate->counters()->regexp_entry_native(), | 5277 __ IncrementCounter(isolate->counters()->regexp_entry_native(), |
| 5350 1, a0, a2); | 5278 1, a0, a2); |
| 5351 | 5279 |
| 5352 // Isolates: note we add an additional parameter here (isolate pointer). | 5280 // Isolates: note we add an additional parameter here (isolate pointer). |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5427 __ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag)); | 5355 __ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 5428 DirectCEntryStub stub; | 5356 DirectCEntryStub stub; |
| 5429 stub.GenerateCall(masm, t9); | 5357 stub.GenerateCall(masm, t9); |
| 5430 | 5358 |
| 5431 __ LeaveExitFrame(false, no_reg); | 5359 __ LeaveExitFrame(false, no_reg); |
| 5432 | 5360 |
| 5433 // v0: result | 5361 // v0: result |
| 5434 // subject: subject string (callee saved) | 5362 // subject: subject string (callee saved) |
| 5435 // regexp_data: RegExp data (callee saved) | 5363 // regexp_data: RegExp data (callee saved) |
| 5436 // last_match_info_elements: Last match info elements (callee saved) | 5364 // last_match_info_elements: Last match info elements (callee saved) |
| 5437 | |
| 5438 // Check the result. | 5365 // Check the result. |
| 5439 | |
| 5440 Label success; | 5366 Label success; |
| 5441 __ Branch(&success, eq, v0, Operand(1)); | 5367 __ Branch(&success, eq, v0, Operand(1)); |
| 5442 // We expect exactly one result since we force the called regexp to behave | 5368 // We expect exactly one result since we force the called regexp to behave |
| 5443 // as non-global. | 5369 // as non-global. |
| 5444 Label failure; | 5370 Label failure; |
| 5445 __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE)); | 5371 __ Branch(&failure, eq, v0, Operand(NativeRegExpMacroAssembler::FAILURE)); |
| 5446 // If not exception it can only be retry. Handle that in the runtime system. | 5372 // If not exception it can only be retry. Handle that in the runtime system. |
| 5447 __ Branch(&runtime, ne, v0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); | 5373 __ Branch(&runtime, ne, v0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); |
| 5448 // Result must now be exception. If there is no pending exception already a | 5374 // Result must now be exception. If there is no pending exception already a |
| 5449 // stack overflow (on the backtrack stack) was detected in RegExp code but | 5375 // stack overflow (on the backtrack stack) was detected in RegExp code but |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5470 __ bind(&failure); | 5396 __ bind(&failure); |
| 5471 // For failure and exception return null. | 5397 // For failure and exception return null. |
| 5472 __ li(v0, Operand(isolate->factory()->null_value())); | 5398 __ li(v0, Operand(isolate->factory()->null_value())); |
| 5473 __ DropAndRet(4); | 5399 __ DropAndRet(4); |
| 5474 | 5400 |
| 5475 // Process the result from the native regexp code. | 5401 // Process the result from the native regexp code. |
| 5476 __ bind(&success); | 5402 __ bind(&success); |
| 5477 __ lw(a1, | 5403 __ lw(a1, |
| 5478 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | 5404 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
| 5479 // Calculate number of capture registers (number_of_captures + 1) * 2. | 5405 // Calculate number of capture registers (number_of_captures + 1) * 2. |
| 5406 // Multiplying by 2 comes for free since r1 is smi-tagged. |
| 5480 STATIC_ASSERT(kSmiTag == 0); | 5407 STATIC_ASSERT(kSmiTag == 0); |
| 5481 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 5408 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
| 5482 __ Addu(a1, a1, Operand(2)); // a1 was a smi. | 5409 __ Addu(a1, a1, Operand(2)); // a1 was a smi. |
| 5483 | 5410 |
| 5411 __ lw(a0, MemOperand(sp, kLastMatchInfoOffset)); |
| 5412 __ JumpIfSmi(a0, &runtime); |
| 5413 __ GetObjectType(a0, a2, a2); |
| 5414 __ Branch(&runtime, ne, a2, Operand(JS_ARRAY_TYPE)); |
| 5415 // Check that the JSArray is in fast case. |
| 5416 __ lw(last_match_info_elements, |
| 5417 FieldMemOperand(a0, JSArray::kElementsOffset)); |
| 5418 __ lw(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); |
| 5419 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex); |
| 5420 __ Branch(&runtime, ne, a0, Operand(at)); |
| 5421 // Check that the last match info has space for the capture registers and the |
| 5422 // additional information. |
| 5423 __ lw(a0, |
| 5424 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); |
| 5425 __ Addu(a2, a1, Operand(RegExpImpl::kLastMatchOverhead)); |
| 5426 __ sra(at, a0, kSmiTagSize); |
| 5427 __ Branch(&runtime, gt, a2, Operand(at)); |
| 5428 |
| 5484 // a1: number of capture registers | 5429 // a1: number of capture registers |
| 5485 // subject: subject string | 5430 // subject: subject string |
| 5486 // Store the capture count. | 5431 // Store the capture count. |
| 5487 __ sll(a2, a1, kSmiTagSize + kSmiShiftSize); // To smi. | 5432 __ sll(a2, a1, kSmiTagSize + kSmiShiftSize); // To smi. |
| 5488 __ sw(a2, FieldMemOperand(last_match_info_elements, | 5433 __ sw(a2, FieldMemOperand(last_match_info_elements, |
| 5489 RegExpImpl::kLastCaptureCountOffset)); | 5434 RegExpImpl::kLastCaptureCountOffset)); |
| 5490 // Store last subject and last input. | 5435 // Store last subject and last input. |
| 5491 __ sw(subject, | 5436 __ sw(subject, |
| 5492 FieldMemOperand(last_match_info_elements, | 5437 FieldMemOperand(last_match_info_elements, |
| 5493 RegExpImpl::kLastSubjectOffset)); | 5438 RegExpImpl::kLastSubjectOffset)); |
| 5494 __ mov(a2, subject); | 5439 __ mov(a2, subject); |
| 5495 __ RecordWriteField(last_match_info_elements, | 5440 __ RecordWriteField(last_match_info_elements, |
| 5496 RegExpImpl::kLastSubjectOffset, | 5441 RegExpImpl::kLastSubjectOffset, |
| 5497 a2, | 5442 subject, |
| 5498 t3, | 5443 t3, |
| 5499 kRAHasNotBeenSaved, | 5444 kRAHasNotBeenSaved, |
| 5500 kDontSaveFPRegs); | 5445 kDontSaveFPRegs); |
| 5446 __ mov(subject, a2); |
| 5501 __ sw(subject, | 5447 __ sw(subject, |
| 5502 FieldMemOperand(last_match_info_elements, | 5448 FieldMemOperand(last_match_info_elements, |
| 5503 RegExpImpl::kLastInputOffset)); | 5449 RegExpImpl::kLastInputOffset)); |
| 5504 __ RecordWriteField(last_match_info_elements, | 5450 __ RecordWriteField(last_match_info_elements, |
| 5505 RegExpImpl::kLastInputOffset, | 5451 RegExpImpl::kLastInputOffset, |
| 5506 subject, | 5452 subject, |
| 5507 t3, | 5453 t3, |
| 5508 kRAHasNotBeenSaved, | 5454 kRAHasNotBeenSaved, |
| 5509 kDontSaveFPRegs); | 5455 kDontSaveFPRegs); |
| 5510 | 5456 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 5532 __ sw(a3, MemOperand(a0, 0)); | 5478 __ sw(a3, MemOperand(a0, 0)); |
| 5533 __ Branch(&next_capture, USE_DELAY_SLOT); | 5479 __ Branch(&next_capture, USE_DELAY_SLOT); |
| 5534 __ addiu(a0, a0, kPointerSize); // In branch delay slot. | 5480 __ addiu(a0, a0, kPointerSize); // In branch delay slot. |
| 5535 | 5481 |
| 5536 __ bind(&done); | 5482 __ bind(&done); |
| 5537 | 5483 |
| 5538 // Return last match info. | 5484 // Return last match info. |
| 5539 __ lw(v0, MemOperand(sp, kLastMatchInfoOffset)); | 5485 __ lw(v0, MemOperand(sp, kLastMatchInfoOffset)); |
| 5540 __ DropAndRet(4); | 5486 __ DropAndRet(4); |
| 5541 | 5487 |
| 5542 // External string. Short external strings have already been ruled out. | 5488 // Do the runtime call to execute the regexp. |
| 5543 // a0: scratch | 5489 __ bind(&runtime); |
| 5490 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 5491 |
| 5492 // Deferred code for string handling. |
| 5493 // (6) Not a long external string? If yes, go to (8). |
| 5494 __ bind(¬_seq_nor_cons); |
| 5495 // Go to (8). |
| 5496 __ Branch(¬_long_external, gt, a1, Operand(kExternalStringTag)); |
| 5497 |
| 5498 // (7) External string. Make it, offset-wise, look like a sequential string. |
| 5544 __ bind(&external_string); | 5499 __ bind(&external_string); |
| 5545 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 5500 __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
| 5546 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); | 5501 __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); |
| 5547 if (FLAG_debug_code) { | 5502 if (FLAG_debug_code) { |
| 5548 // Assert that we do not have a cons or slice (indirect strings) here. | 5503 // Assert that we do not have a cons or slice (indirect strings) here. |
| 5549 // Sequential strings have already been ruled out. | 5504 // Sequential strings have already been ruled out. |
| 5550 __ And(at, a0, Operand(kIsIndirectStringMask)); | 5505 __ And(at, a0, Operand(kIsIndirectStringMask)); |
| 5551 __ Assert(eq, | 5506 __ Assert(eq, |
| 5552 "external string expected, but not found", | 5507 "external string expected, but not found", |
| 5553 at, | 5508 at, |
| 5554 Operand(zero_reg)); | 5509 Operand(zero_reg)); |
| 5555 } | 5510 } |
| 5556 __ lw(subject, | 5511 __ lw(subject, |
| 5557 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); | 5512 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); |
| 5558 // Move the pointer so that offset-wise, it looks like a sequential string. | 5513 // Move the pointer so that offset-wise, it looks like a sequential string. |
| 5559 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 5514 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| 5560 __ Subu(subject, | 5515 __ Subu(subject, |
| 5561 subject, | 5516 subject, |
| 5562 SeqTwoByteString::kHeaderSize - kHeapObjectTag); | 5517 SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
| 5563 __ jmp(&seq_string); | 5518 __ jmp(&seq_string); // Go to (5). |
| 5564 | 5519 |
| 5565 // Do the runtime call to execute the regexp. | 5520 // (8) Short external string or not a string? If yes, bail out to runtime. |
| 5566 __ bind(&runtime); | 5521 __ bind(¬_long_external); |
| 5567 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 5522 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); |
| 5523 __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask)); |
| 5524 __ Branch(&runtime, ne, at, Operand(zero_reg)); |
| 5525 |
| 5526 // (9) Sliced string. Replace subject with parent. Go to (4). |
| 5527 // Load offset into t0 and replace subject string with parent. |
| 5528 __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset)); |
| 5529 __ sra(t0, t0, kSmiTagSize); |
| 5530 __ lw(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); |
| 5531 __ jmp(&check_underlying); // Go to (4). |
| 5568 #endif // V8_INTERPRETED_REGEXP | 5532 #endif // V8_INTERPRETED_REGEXP |
| 5569 } | 5533 } |
| 5570 | 5534 |
| 5571 | 5535 |
| 5572 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { | 5536 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { |
| 5573 const int kMaxInlineLength = 100; | 5537 const int kMaxInlineLength = 100; |
| 5574 Label slowcase; | 5538 Label slowcase; |
| 5575 Label done; | 5539 Label done; |
| 5576 __ lw(a1, MemOperand(sp, kPointerSize * 2)); | 5540 __ lw(a1, MemOperand(sp, kPointerSize * 2)); |
| 5577 STATIC_ASSERT(kSmiTag == 0); | 5541 STATIC_ASSERT(kSmiTag == 0); |
| (...skipping 1457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7035 __ SmiUntag(a0); | 6999 __ SmiUntag(a0); |
| 7036 __ Subu(v0, a1, a0); | 7000 __ Subu(v0, a1, a0); |
| 7037 } | 7001 } |
| 7038 __ Ret(); | 7002 __ Ret(); |
| 7039 | 7003 |
| 7040 __ bind(&miss); | 7004 __ bind(&miss); |
| 7041 GenerateMiss(masm); | 7005 GenerateMiss(masm); |
| 7042 } | 7006 } |
| 7043 | 7007 |
| 7044 | 7008 |
| 7045 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { | 7009 void ICCompareStub::GenerateNumbers(MacroAssembler* masm) { |
| 7046 ASSERT(state_ == CompareIC::HEAP_NUMBER); | 7010 ASSERT(state_ == CompareIC::NUMBER); |
| 7047 | 7011 |
| 7048 Label generic_stub; | 7012 Label generic_stub; |
| 7049 Label unordered, maybe_undefined1, maybe_undefined2; | 7013 Label unordered, maybe_undefined1, maybe_undefined2; |
| 7050 Label miss; | 7014 Label miss; |
| 7051 | 7015 |
| 7052 if (left_ == CompareIC::SMI) { | 7016 if (left_ == CompareIC::SMI) { |
| 7053 __ JumpIfNotSmi(a1, &miss); | 7017 __ JumpIfNotSmi(a1, &miss); |
| 7054 } | 7018 } |
| 7055 if (right_ == CompareIC::SMI) { | 7019 if (right_ == CompareIC::SMI) { |
| 7056 __ JumpIfNotSmi(a0, &miss); | 7020 __ JumpIfNotSmi(a0, &miss); |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7634 struct AheadOfTimeWriteBarrierStubList { | 7598 struct AheadOfTimeWriteBarrierStubList { |
| 7635 Register object, value, address; | 7599 Register object, value, address; |
| 7636 RememberedSetAction action; | 7600 RememberedSetAction action; |
| 7637 }; | 7601 }; |
| 7638 | 7602 |
| 7639 #define REG(Name) { kRegister_ ## Name ## _Code } | 7603 #define REG(Name) { kRegister_ ## Name ## _Code } |
| 7640 | 7604 |
| 7641 static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { | 7605 static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { |
| 7642 // Used in RegExpExecStub. | 7606 // Used in RegExpExecStub. |
| 7643 { REG(s2), REG(s0), REG(t3), EMIT_REMEMBERED_SET }, | 7607 { REG(s2), REG(s0), REG(t3), EMIT_REMEMBERED_SET }, |
| 7644 { REG(s2), REG(a2), REG(t3), EMIT_REMEMBERED_SET }, | |
| 7645 // Used in CompileArrayPushCall. | 7608 // Used in CompileArrayPushCall. |
| 7646 // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. | 7609 // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. |
| 7647 // Also used in KeyedStoreIC::GenerateGeneric. | 7610 // Also used in KeyedStoreIC::GenerateGeneric. |
| 7648 { REG(a3), REG(t0), REG(t1), EMIT_REMEMBERED_SET }, | 7611 { REG(a3), REG(t0), REG(t1), EMIT_REMEMBERED_SET }, |
| 7649 // Used in CompileStoreGlobal. | 7612 // Used in CompileStoreGlobal. |
| 7650 { REG(t0), REG(a1), REG(a2), OMIT_REMEMBERED_SET }, | 7613 { REG(t0), REG(a1), REG(a2), OMIT_REMEMBERED_SET }, |
| 7651 // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField. | 7614 // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField. |
| 7652 { REG(a1), REG(a2), REG(a3), EMIT_REMEMBERED_SET }, | 7615 { REG(a1), REG(a2), REG(a3), EMIT_REMEMBERED_SET }, |
| 7653 { REG(a3), REG(a2), REG(a1), EMIT_REMEMBERED_SET }, | 7616 { REG(a3), REG(a2), REG(a1), EMIT_REMEMBERED_SET }, |
| 7654 // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. | 7617 // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8059 __ Pop(ra, t1, a1); | 8022 __ Pop(ra, t1, a1); |
| 8060 __ Ret(); | 8023 __ Ret(); |
| 8061 } | 8024 } |
| 8062 | 8025 |
| 8063 | 8026 |
| 8064 #undef __ | 8027 #undef __ |
| 8065 | 8028 |
| 8066 } } // namespace v8::internal | 8029 } } // namespace v8::internal |
| 8067 | 8030 |
| 8068 #endif // V8_TARGET_ARCH_MIPS | 8031 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |