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 2291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2302 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 2302 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
2303 ASSERT(ToRegister(instr->object()).is(rdx)); | 2303 ASSERT(ToRegister(instr->object()).is(rdx)); |
2304 ASSERT(ToRegister(instr->key()).is(rcx)); | 2304 ASSERT(ToRegister(instr->key()).is(rcx)); |
2305 ASSERT(ToRegister(instr->value()).is(rax)); | 2305 ASSERT(ToRegister(instr->value()).is(rax)); |
2306 | 2306 |
2307 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 2307 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
2308 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2308 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
2309 } | 2309 } |
2310 | 2310 |
2311 | 2311 |
2312 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | |
2313 class DeferredStringCharCodeAt: public LDeferredCode { | |
2314 public: | |
2315 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | |
2316 : LDeferredCode(codegen), instr_(instr) { } | |
2317 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } | |
2318 private: | |
2319 LStringCharCodeAt* instr_; | |
2320 }; | |
2321 | |
2322 Register string = ToRegister(instr->string()); | |
2323 Register index = no_reg; | |
2324 int const_index = -1; | |
2325 if (instr->index()->IsConstantOperand()) { | |
2326 const_index = ToInteger32(LConstantOperand::cast(instr->index())); | |
2327 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | |
2328 if (!Smi::IsValid(const_index)) { | |
2329 // Guaranteed to be out of bounds because of the assert above. | |
2330 // So the bounds check that must dominate this instruction must | |
2331 // have deoptimized already. | |
2332 if (FLAG_debug_code) { | |
2333 __ Abort("StringCharCodeAt: out of bounds index."); | |
2334 } | |
2335 // No code needs to be generated. | |
2336 return; | |
2337 } | |
2338 } else { | |
2339 index = ToRegister(instr->index()); | |
2340 } | |
2341 Register result = ToRegister(instr->result()); | |
2342 | |
2343 DeferredStringCharCodeAt* deferred = | |
2344 new DeferredStringCharCodeAt(this, instr); | |
2345 | |
2346 NearLabel flat_string, ascii_string, done; | |
2347 | |
2348 // Fetch the instance type of the receiver into result register. | |
2349 __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); | |
2350 __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); | |
2351 | |
2352 // We need special handling for non-flat strings. | |
Lasse Reichstein
2011/02/18 13:22:25
... special handling for non-sequential strings. (
Mads Ager (chromium)
2011/02/18 13:58:47
Done.
| |
2353 STATIC_ASSERT(kSeqStringTag == 0); | |
2354 __ testb(result, Immediate(kStringRepresentationMask)); | |
2355 __ j(zero, &flat_string); | |
2356 | |
2357 // Handle non-flat strings. | |
2358 __ testb(result, Immediate(kIsConsStringMask)); | |
2359 __ j(zero, deferred->entry()); | |
2360 | |
2361 // ConsString. | |
2362 // Check whether the right hand side is the empty string (i.e. if | |
2363 // this is really a flat string in a cons string). If that is not | |
2364 // the case we would rather go to the runtime system now to flatten | |
2365 // the string. | |
2366 __ CompareRoot(FieldOperand(string, ConsString::kSecondOffset), | |
2367 Heap::kEmptyStringRootIndex); | |
2368 __ j(not_equal, deferred->entry()); | |
2369 // Get the first of the two strings and load its instance type. | |
2370 __ movq(string, FieldOperand(string, ConsString::kFirstOffset)); | |
2371 __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); | |
2372 __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); | |
2373 // If the first cons component is also non-flat, then go to runtime. | |
2374 STATIC_ASSERT(kSeqStringTag == 0); | |
2375 __ testb(result, Immediate(kStringRepresentationMask)); | |
2376 __ j(not_zero, deferred->entry()); | |
2377 | |
2378 // Check for 1-byte or 2-byte string. | |
Lasse Reichstein
2011/02/18 13:22:25
You call it 1-byte string here and ASCII string be
Mads Ager (chromium)
2011/02/18 13:58:47
Done.
| |
2379 __ bind(&flat_string); | |
2380 STATIC_ASSERT(kAsciiStringTag != 0); | |
2381 __ testb(result, Immediate(kStringEncodingMask)); | |
2382 __ j(not_zero, &ascii_string); | |
2383 | |
2384 // 2-byte string. | |
2385 // Load the 2-byte character code into the result register. | |
2386 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | |
2387 if (instr->index()->IsConstantOperand()) { | |
2388 __ movzxwl(result, | |
2389 FieldOperand(string, | |
2390 SeqTwoByteString::kHeaderSize + 2 * const_index)); | |
Lasse Reichstein
2011/02/18 13:22:25
Use kUC16Size instead of 2.
Mads Ager (chromium)
2011/02/18 13:58:47
Done.
| |
2391 } else { | |
2392 __ movzxwl(result, FieldOperand(string, | |
2393 index, | |
2394 times_2, | |
2395 SeqTwoByteString::kHeaderSize)); | |
2396 } | |
2397 __ jmp(&done); | |
2398 | |
2399 // ASCII string. | |
2400 // Load the byte into the result register. | |
2401 __ bind(&ascii_string); | |
2402 if (instr->index()->IsConstantOperand()) { | |
2403 __ movzxbl(result, FieldOperand(string, | |
2404 SeqAsciiString::kHeaderSize + const_index)); | |
2405 } else { | |
2406 __ movzxbl(result, FieldOperand(string, | |
2407 index, | |
2408 times_1, | |
2409 SeqAsciiString::kHeaderSize)); | |
2410 } | |
2411 __ bind(&done); | |
2412 __ bind(deferred->exit()); | |
2413 } | |
2414 | |
2415 | |
2416 void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { | |
2417 Register string = ToRegister(instr->string()); | |
2418 Register result = ToRegister(instr->result()); | |
2419 | |
2420 // TODO(3095996): Get rid of this. For now, we need to make the | |
2421 // result register contain a valid pointer because it is already | |
2422 // contained in the register pointer map. | |
2423 __ Set(result, 0); | |
2424 | |
2425 __ PushSafepointRegisters(); | |
2426 __ push(string); | |
2427 // Push the index as a smi. This is safe because of the checks in | |
2428 // DoStringCharCodeAt above. | |
2429 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | |
2430 if (instr->index()->IsConstantOperand()) { | |
2431 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); | |
2432 __ Push(Smi::FromInt(const_index)); | |
2433 } else { | |
2434 Register index = ToRegister(instr->index()); | |
2435 __ Integer32ToSmi(index, index); | |
2436 __ push(index); | |
2437 } | |
2438 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
2439 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); | |
2440 RecordSafepointWithRegisters( | |
2441 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); | |
2442 if (FLAG_debug_code) { | |
2443 __ AbortIfNotSmi(rax); | |
2444 } | |
2445 __ Integer32ToSmi(rax, rax); | |
Lasse Reichstein
2011/02/18 13:22:25
Should be SmiToInteger32.
Mads Ager (chromium)
2011/02/18 13:58:47
Whoops! Done.
| |
2446 __ movq(Operand(rsp, Register::ToRspIndexForPushAll(result) * kPointerSize), | |
2447 rax); | |
2448 __ PopSafepointRegisters(); | |
Lasse Reichstein
2011/02/18 13:22:25
We could make an alternative version: PopSafepoint
Mads Ager (chromium)
2011/02/18 13:58:47
Don't think it will. Will leave that for a separat
| |
2449 } | |
2450 | |
2451 | |
2312 void LCodeGen::DoStringLength(LStringLength* instr) { | 2452 void LCodeGen::DoStringLength(LStringLength* instr) { |
2313 Register string = ToRegister(instr->string()); | 2453 Register string = ToRegister(instr->string()); |
2314 Register result = ToRegister(instr->result()); | 2454 Register result = ToRegister(instr->result()); |
2315 __ movq(result, FieldOperand(string, String::kLengthOffset)); | 2455 __ movq(result, FieldOperand(string, String::kLengthOffset)); |
2316 } | 2456 } |
2317 | 2457 |
2318 | 2458 |
2319 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { | 2459 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
2320 LOperand* input = instr->InputAt(0); | 2460 LOperand* input = instr->InputAt(0); |
2321 ASSERT(input->IsRegister() || input->IsStackSlot()); | 2461 ASSERT(input->IsRegister() || input->IsStackSlot()); |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2660 // Pick the right runtime function to call. | 2800 // Pick the right runtime function to call. |
2661 if (instr->hydrogen()->depth() > 1) { | 2801 if (instr->hydrogen()->depth() > 1) { |
2662 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); | 2802 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); |
2663 } else { | 2803 } else { |
2664 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); | 2804 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); |
2665 } | 2805 } |
2666 } | 2806 } |
2667 | 2807 |
2668 | 2808 |
2669 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { | 2809 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { |
2670 Abort("Unimplemented: %s", "DoRegExpLiteral"); | 2810 NearLabel materialized; |
2811 // Registers will be used as follows: | |
2812 // rdi = JS function. | |
2813 // rcx = literals array. | |
2814 // rbx = regexp literal. | |
2815 // rax = regexp literal clone. | |
2816 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | |
2817 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | |
2818 int literal_offset = FixedArray::kHeaderSize + | |
2819 instr->hydrogen()->literal_index() * kPointerSize; | |
2820 __ movq(rbx, FieldOperand(rcx, literal_offset)); | |
2821 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); | |
2822 __ j(not_equal, &materialized); | |
2823 | |
2824 // Create regexp literal using runtime function | |
2825 // Result will be in eax. | |
Lasse Reichstein
2011/02/18 13:22:25
eax->rax
Mads Ager (chromium)
2011/02/18 13:58:47
Done.
| |
2826 __ push(rcx); | |
2827 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); | |
2828 __ Push(instr->hydrogen()->pattern()); | |
2829 __ Push(instr->hydrogen()->flags()); | |
2830 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); | |
2831 __ movq(rbx, rax); | |
2832 | |
2833 __ bind(&materialized); | |
2834 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; | |
2835 Label allocated, runtime_allocate; | |
2836 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT); | |
2837 __ jmp(&allocated); | |
2838 | |
2839 __ bind(&runtime_allocate); | |
2840 __ push(rbx); | |
2841 __ Push(Smi::FromInt(size)); | |
2842 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); | |
2843 __ pop(rbx); | |
2844 | |
2845 __ bind(&allocated); | |
2846 // Copy the content into the newly allocated memory. | |
2847 // (Unroll copy loop once for better throughput). | |
2848 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { | |
2849 __ movq(rdx, FieldOperand(rbx, i)); | |
2850 __ movq(rcx, FieldOperand(rbx, i + kPointerSize)); | |
2851 __ movq(FieldOperand(rax, i), rdx); | |
2852 __ movq(FieldOperand(rax, i + kPointerSize), rcx); | |
2853 } | |
2854 if ((size % (2 * kPointerSize)) != 0) { | |
2855 __ movq(rdx, FieldOperand(rbx, size - kPointerSize)); | |
2856 __ movq(FieldOperand(rax, size - kPointerSize), rdx); | |
2857 } | |
2671 } | 2858 } |
2672 | 2859 |
2673 | 2860 |
2674 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { | 2861 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { |
2675 // Use the fast case closure allocation code that allocates in new | 2862 // Use the fast case closure allocation code that allocates in new |
2676 // space for nested functions that don't need literals cloning. | 2863 // space for nested functions that don't need literals cloning. |
2677 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); | 2864 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); |
2678 bool pretenure = instr->hydrogen()->pretenure(); | 2865 bool pretenure = instr->hydrogen()->pretenure(); |
2679 if (shared_info->num_literals() == 0 && !pretenure) { | 2866 if (shared_info->num_literals() == 0 && !pretenure) { |
2680 FastNewClosureStub stub; | 2867 FastNewClosureStub stub; |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2869 RegisterEnvironmentForDeoptimization(environment); | 3056 RegisterEnvironmentForDeoptimization(environment); |
2870 ASSERT(osr_pc_offset_ == -1); | 3057 ASSERT(osr_pc_offset_ == -1); |
2871 osr_pc_offset_ = masm()->pc_offset(); | 3058 osr_pc_offset_ = masm()->pc_offset(); |
2872 } | 3059 } |
2873 | 3060 |
2874 #undef __ | 3061 #undef __ |
2875 | 3062 |
2876 } } // namespace v8::internal | 3063 } } // namespace v8::internal |
2877 | 3064 |
2878 #endif // V8_TARGET_ARCH_X64 | 3065 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |