| 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 1025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1036 ASSERT(environment->HasBeenRegistered()); | 1036 ASSERT(environment->HasBeenRegistered()); |
| 1037 int id = environment->deoptimization_index(); | 1037 int id = environment->deoptimization_index(); |
| 1038 ASSERT(info()->IsOptimizing() || info()->IsStub()); | 1038 ASSERT(info()->IsOptimizing() || info()->IsStub()); |
| 1039 Address entry = | 1039 Address entry = |
| 1040 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); | 1040 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); |
| 1041 if (entry == NULL) { | 1041 if (entry == NULL) { |
| 1042 Abort(kBailoutWasNotPrepared); | 1042 Abort(kBailoutWasNotPrepared); |
| 1043 return; | 1043 return; |
| 1044 } | 1044 } |
| 1045 | 1045 |
| 1046 if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) { | 1046 if (DeoptEveryNTimes()) { |
| 1047 ExternalReference count = ExternalReference::stress_deopt_count(isolate()); | 1047 ExternalReference count = ExternalReference::stress_deopt_count(isolate()); |
| 1048 Label no_deopt; | 1048 Label no_deopt; |
| 1049 __ pushfd(); | 1049 __ pushfd(); |
| 1050 __ push(eax); | 1050 __ push(eax); |
| 1051 __ mov(eax, Operand::StaticVariable(count)); | 1051 __ mov(eax, Operand::StaticVariable(count)); |
| 1052 __ sub(eax, Immediate(1)); | 1052 __ sub(eax, Immediate(1)); |
| 1053 __ j(not_zero, &no_deopt, Label::kNear); | 1053 __ j(not_zero, &no_deopt, Label::kNear); |
| 1054 if (FLAG_trap_on_deopt) __ int3(); | 1054 if (FLAG_trap_on_deopt) __ int3(); |
| 1055 __ mov(eax, Immediate(FLAG_deopt_every_n_times)); | 1055 __ mov(eax, Immediate(FLAG_deopt_every_n_times)); |
| 1056 __ mov(Operand::StaticVariable(count), eax); | 1056 __ mov(Operand::StaticVariable(count), eax); |
| (...skipping 894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1951 __ pinsrd(res, Operand(temp), 1); | 1951 __ pinsrd(res, Operand(temp), 1); |
| 1952 } | 1952 } |
| 1953 } else { | 1953 } else { |
| 1954 __ Set(temp, Immediate(upper)); | 1954 __ Set(temp, Immediate(upper)); |
| 1955 __ movd(res, Operand(temp)); | 1955 __ movd(res, Operand(temp)); |
| 1956 __ psllq(res, 32); | 1956 __ psllq(res, 32); |
| 1957 if (lower != 0) { | 1957 if (lower != 0) { |
| 1958 XMMRegister xmm_scratch = double_scratch0(); | 1958 XMMRegister xmm_scratch = double_scratch0(); |
| 1959 __ Set(temp, Immediate(lower)); | 1959 __ Set(temp, Immediate(lower)); |
| 1960 __ movd(xmm_scratch, Operand(temp)); | 1960 __ movd(xmm_scratch, Operand(temp)); |
| 1961 __ por(res, xmm_scratch); | 1961 __ orps(res, xmm_scratch); |
| 1962 } | 1962 } |
| 1963 } | 1963 } |
| 1964 } | 1964 } |
| 1965 } | 1965 } |
| 1966 } | 1966 } |
| 1967 | 1967 |
| 1968 | 1968 |
| 1969 void LCodeGen::DoConstantE(LConstantE* instr) { | 1969 void LCodeGen::DoConstantE(LConstantE* instr) { |
| 1970 __ lea(ToRegister(instr->result()), Operand::StaticVariable(instr->value())); | 1970 __ lea(ToRegister(instr->result()), Operand::StaticVariable(instr->value())); |
| 1971 } | 1971 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2040 if (index->value() == 0) { | 2040 if (index->value() == 0) { |
| 2041 __ mov(result, FieldOperand(object, JSDate::kValueOffset)); | 2041 __ mov(result, FieldOperand(object, JSDate::kValueOffset)); |
| 2042 } else { | 2042 } else { |
| 2043 if (index->value() < JSDate::kFirstUncachedField) { | 2043 if (index->value() < JSDate::kFirstUncachedField) { |
| 2044 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); | 2044 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); |
| 2045 __ mov(scratch, Operand::StaticVariable(stamp)); | 2045 __ mov(scratch, Operand::StaticVariable(stamp)); |
| 2046 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset)); | 2046 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset)); |
| 2047 __ j(not_equal, &runtime, Label::kNear); | 2047 __ j(not_equal, &runtime, Label::kNear); |
| 2048 __ mov(result, FieldOperand(object, JSDate::kValueOffset + | 2048 __ mov(result, FieldOperand(object, JSDate::kValueOffset + |
| 2049 kPointerSize * index->value())); | 2049 kPointerSize * index->value())); |
| 2050 __ jmp(&done); | 2050 __ jmp(&done, Label::kNear); |
| 2051 } | 2051 } |
| 2052 __ bind(&runtime); | 2052 __ bind(&runtime); |
| 2053 __ PrepareCallCFunction(2, scratch); | 2053 __ PrepareCallCFunction(2, scratch); |
| 2054 __ mov(Operand(esp, 0), object); | 2054 __ mov(Operand(esp, 0), object); |
| 2055 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index)); | 2055 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index)); |
| 2056 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); | 2056 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); |
| 2057 __ bind(&done); | 2057 __ bind(&done); |
| 2058 } | 2058 } |
| 2059 } | 2059 } |
| 2060 | 2060 |
| 2061 | 2061 |
| 2062 Operand LCodeGen::BuildSeqStringOperand(Register string, |
| 2063 LOperand* index, |
| 2064 String::Encoding encoding) { |
| 2065 if (index->IsConstantOperand()) { |
| 2066 int offset = ToRepresentation(LConstantOperand::cast(index), |
| 2067 Representation::Integer32()); |
| 2068 if (encoding == String::TWO_BYTE_ENCODING) { |
| 2069 offset *= kUC16Size; |
| 2070 } |
| 2071 STATIC_ASSERT(kCharSize == 1); |
| 2072 return FieldOperand(string, SeqString::kHeaderSize + offset); |
| 2073 } |
| 2074 return FieldOperand( |
| 2075 string, ToRegister(index), |
| 2076 encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2, |
| 2077 SeqString::kHeaderSize); |
| 2078 } |
| 2079 |
| 2080 |
| 2081 void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) { |
| 2082 String::Encoding encoding = instr->hydrogen()->encoding(); |
| 2083 Register result = ToRegister(instr->result()); |
| 2084 Register string = ToRegister(instr->string()); |
| 2085 |
| 2086 if (FLAG_debug_code) { |
| 2087 __ push(string); |
| 2088 __ mov(string, FieldOperand(string, HeapObject::kMapOffset)); |
| 2089 __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset)); |
| 2090 |
| 2091 __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask)); |
| 2092 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 2093 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 2094 __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING |
| 2095 ? one_byte_seq_type : two_byte_seq_type)); |
| 2096 __ Check(equal, kUnexpectedStringType); |
| 2097 __ pop(string); |
| 2098 } |
| 2099 |
| 2100 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding); |
| 2101 if (encoding == String::ONE_BYTE_ENCODING) { |
| 2102 __ movzx_b(result, operand); |
| 2103 } else { |
| 2104 __ movzx_w(result, operand); |
| 2105 } |
| 2106 } |
| 2107 |
| 2108 |
| 2062 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { | 2109 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { |
| 2110 String::Encoding encoding = instr->hydrogen()->encoding(); |
| 2063 Register string = ToRegister(instr->string()); | 2111 Register string = ToRegister(instr->string()); |
| 2064 Register index = ToRegister(instr->index()); | |
| 2065 Register value = ToRegister(instr->value()); | |
| 2066 String::Encoding encoding = instr->encoding(); | |
| 2067 | 2112 |
| 2068 if (FLAG_debug_code) { | 2113 if (FLAG_debug_code) { |
| 2069 __ push(value); | 2114 __ push(string); |
| 2070 __ mov(value, FieldOperand(string, HeapObject::kMapOffset)); | 2115 __ mov(string, FieldOperand(string, HeapObject::kMapOffset)); |
| 2071 __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset)); | 2116 __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset)); |
| 2072 | 2117 |
| 2073 __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); | 2118 __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask)); |
| 2074 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 2119 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 2075 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 2120 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 2076 __ cmp(value, Immediate(encoding == String::ONE_BYTE_ENCODING | 2121 __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING |
| 2077 ? one_byte_seq_type : two_byte_seq_type)); | 2122 ? one_byte_seq_type : two_byte_seq_type)); |
| 2078 __ Check(equal, kUnexpectedStringType); | 2123 __ Check(equal, kUnexpectedStringType); |
| 2079 __ pop(value); | 2124 __ pop(string); |
| 2080 } | 2125 } |
| 2081 | 2126 |
| 2082 if (encoding == String::ONE_BYTE_ENCODING) { | 2127 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding); |
| 2083 __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize), | 2128 if (instr->value()->IsConstantOperand()) { |
| 2084 value); | 2129 int value = ToRepresentation(LConstantOperand::cast(instr->value()), |
| 2130 Representation::Integer32()); |
| 2131 ASSERT_LE(0, value); |
| 2132 if (encoding == String::ONE_BYTE_ENCODING) { |
| 2133 ASSERT_LE(value, String::kMaxOneByteCharCode); |
| 2134 __ mov_b(operand, static_cast<int8_t>(value)); |
| 2135 } else { |
| 2136 ASSERT_LE(value, String::kMaxUtf16CodeUnit); |
| 2137 __ mov_w(operand, static_cast<int16_t>(value)); |
| 2138 } |
| 2085 } else { | 2139 } else { |
| 2086 __ mov_w(FieldOperand(string, index, times_2, SeqString::kHeaderSize), | 2140 Register value = ToRegister(instr->value()); |
| 2087 value); | 2141 if (encoding == String::ONE_BYTE_ENCODING) { |
| 2142 __ mov_b(operand, value); |
| 2143 } else { |
| 2144 __ mov_w(operand, value); |
| 2145 } |
| 2088 } | 2146 } |
| 2089 } | 2147 } |
| 2090 | 2148 |
| 2091 | 2149 |
| 2092 void LCodeGen::DoThrow(LThrow* instr) { | 2150 void LCodeGen::DoThrow(LThrow* instr) { |
| 2093 __ push(ToOperand(instr->value())); | 2151 __ push(ToOperand(instr->value())); |
| 2094 ASSERT(ToRegister(instr->context()).is(esi)); | 2152 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2095 CallRuntime(Runtime::kThrow, 1, instr); | 2153 CallRuntime(Runtime::kThrow, 1, instr); |
| 2096 | 2154 |
| 2097 if (FLAG_debug_code) { | 2155 if (FLAG_debug_code) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2177 } else { | 2235 } else { |
| 2178 // Since we operate on +0 and/or -0, addsd and andsd have the same effect. | 2236 // Since we operate on +0 and/or -0, addsd and andsd have the same effect. |
| 2179 __ addsd(left_reg, right_reg); | 2237 __ addsd(left_reg, right_reg); |
| 2180 } | 2238 } |
| 2181 __ jmp(&return_left, Label::kNear); | 2239 __ jmp(&return_left, Label::kNear); |
| 2182 | 2240 |
| 2183 __ bind(&check_nan_left); | 2241 __ bind(&check_nan_left); |
| 2184 __ ucomisd(left_reg, left_reg); // NaN check. | 2242 __ ucomisd(left_reg, left_reg); // NaN check. |
| 2185 __ j(parity_even, &return_left, Label::kNear); // left == NaN. | 2243 __ j(parity_even, &return_left, Label::kNear); // left == NaN. |
| 2186 __ bind(&return_right); | 2244 __ bind(&return_right); |
| 2187 __ movsd(left_reg, right_reg); | 2245 __ movaps(left_reg, right_reg); |
| 2188 | 2246 |
| 2189 __ bind(&return_left); | 2247 __ bind(&return_left); |
| 2190 } | 2248 } |
| 2191 } | 2249 } |
| 2192 | 2250 |
| 2193 | 2251 |
| 2194 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { | 2252 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
| 2195 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { | 2253 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
| 2196 CpuFeatureScope scope(masm(), SSE2); | 2254 CpuFeatureScope scope(masm(), SSE2); |
| 2197 XMMRegister left = ToDoubleRegister(instr->left()); | 2255 XMMRegister left = ToDoubleRegister(instr->left()); |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2582 __ ucomisd(input_reg, input_reg); | 2640 __ ucomisd(input_reg, input_reg); |
| 2583 EmitFalseBranch(instr, parity_odd); | 2641 EmitFalseBranch(instr, parity_odd); |
| 2584 } else { | 2642 } else { |
| 2585 // Put the value to the top of stack | 2643 // Put the value to the top of stack |
| 2586 X87Register src = ToX87Register(instr->object()); | 2644 X87Register src = ToX87Register(instr->object()); |
| 2587 X87LoadForUsage(src); | 2645 X87LoadForUsage(src); |
| 2588 __ fld(0); | 2646 __ fld(0); |
| 2589 __ fld(0); | 2647 __ fld(0); |
| 2590 __ FCmp(); | 2648 __ FCmp(); |
| 2591 Label ok; | 2649 Label ok; |
| 2592 __ j(parity_even, &ok); | 2650 __ j(parity_even, &ok, Label::kNear); |
| 2593 __ fstp(0); | 2651 __ fstp(0); |
| 2594 EmitFalseBranch(instr, no_condition); | 2652 EmitFalseBranch(instr, no_condition); |
| 2595 __ bind(&ok); | 2653 __ bind(&ok); |
| 2596 } | 2654 } |
| 2597 | 2655 |
| 2598 | 2656 |
| 2599 __ sub(esp, Immediate(kDoubleSize)); | 2657 __ sub(esp, Immediate(kDoubleSize)); |
| 2600 if (use_sse2) { | 2658 if (use_sse2) { |
| 2601 CpuFeatureScope scope(masm(), SSE2); | 2659 CpuFeatureScope scope(masm(), SSE2); |
| 2602 XMMRegister input_reg = ToDoubleRegister(instr->object()); | 2660 XMMRegister input_reg = ToDoubleRegister(instr->object()); |
| 2603 __ movsd(MemOperand(esp, 0), input_reg); | 2661 __ movsd(MemOperand(esp, 0), input_reg); |
| 2604 } else { | 2662 } else { |
| 2605 __ fstp_d(MemOperand(esp, 0)); | 2663 __ fstp_d(MemOperand(esp, 0)); |
| 2606 } | 2664 } |
| 2607 | 2665 |
| 2608 __ add(esp, Immediate(kDoubleSize)); | 2666 __ add(esp, Immediate(kDoubleSize)); |
| 2609 int offset = sizeof(kHoleNanUpper32); | 2667 int offset = sizeof(kHoleNanUpper32); |
| 2610 __ cmp(MemOperand(esp, -offset), Immediate(kHoleNanUpper32)); | 2668 __ cmp(MemOperand(esp, -offset), Immediate(kHoleNanUpper32)); |
| 2611 EmitBranch(instr, equal); | 2669 EmitBranch(instr, equal); |
| 2612 } | 2670 } |
| 2613 | 2671 |
| 2614 | 2672 |
| 2673 void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) { |
| 2674 Representation rep = instr->hydrogen()->value()->representation(); |
| 2675 ASSERT(!rep.IsInteger32()); |
| 2676 Register scratch = ToRegister(instr->temp()); |
| 2677 |
| 2678 if (rep.IsDouble()) { |
| 2679 CpuFeatureScope use_sse2(masm(), SSE2); |
| 2680 XMMRegister value = ToDoubleRegister(instr->value()); |
| 2681 XMMRegister xmm_scratch = double_scratch0(); |
| 2682 __ xorps(xmm_scratch, xmm_scratch); |
| 2683 __ ucomisd(xmm_scratch, value); |
| 2684 EmitFalseBranch(instr, not_equal); |
| 2685 __ movmskpd(scratch, value); |
| 2686 __ test(scratch, Immediate(1)); |
| 2687 EmitBranch(instr, not_zero); |
| 2688 } else { |
| 2689 Register value = ToRegister(instr->value()); |
| 2690 Handle<Map> map = masm()->isolate()->factory()->heap_number_map(); |
| 2691 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK); |
| 2692 __ cmp(FieldOperand(value, HeapNumber::kExponentOffset), |
| 2693 Immediate(0x80000000)); |
| 2694 EmitFalseBranch(instr, not_equal); |
| 2695 __ cmp(FieldOperand(value, HeapNumber::kMantissaOffset), |
| 2696 Immediate(0x00000000)); |
| 2697 EmitBranch(instr, equal); |
| 2698 } |
| 2699 } |
| 2700 |
| 2701 |
| 2615 Condition LCodeGen::EmitIsObject(Register input, | 2702 Condition LCodeGen::EmitIsObject(Register input, |
| 2616 Register temp1, | 2703 Register temp1, |
| 2617 Label* is_not_object, | 2704 Label* is_not_object, |
| 2618 Label* is_object) { | 2705 Label* is_object) { |
| 2619 __ JumpIfSmi(input, is_not_object); | 2706 __ JumpIfSmi(input, is_not_object); |
| 2620 | 2707 |
| 2621 __ cmp(input, isolate()->factory()->null_value()); | 2708 __ cmp(input, isolate()->factory()->null_value()); |
| 2622 __ j(equal, is_object); | 2709 __ j(equal, is_object); |
| 2623 | 2710 |
| 2624 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset)); | 2711 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset)); |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2906 }; | 2993 }; |
| 2907 | 2994 |
| 2908 DeferredInstanceOfKnownGlobal* deferred; | 2995 DeferredInstanceOfKnownGlobal* deferred; |
| 2909 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr, x87_stack_); | 2996 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr, x87_stack_); |
| 2910 | 2997 |
| 2911 Label done, false_result; | 2998 Label done, false_result; |
| 2912 Register object = ToRegister(instr->value()); | 2999 Register object = ToRegister(instr->value()); |
| 2913 Register temp = ToRegister(instr->temp()); | 3000 Register temp = ToRegister(instr->temp()); |
| 2914 | 3001 |
| 2915 // A Smi is not an instance of anything. | 3002 // A Smi is not an instance of anything. |
| 2916 __ JumpIfSmi(object, &false_result); | 3003 __ JumpIfSmi(object, &false_result, Label::kNear); |
| 2917 | 3004 |
| 2918 // This is the inlined call site instanceof cache. The two occurences of the | 3005 // This is the inlined call site instanceof cache. The two occurences of the |
| 2919 // hole value will be patched to the last map/result pair generated by the | 3006 // hole value will be patched to the last map/result pair generated by the |
| 2920 // instanceof stub. | 3007 // instanceof stub. |
| 2921 Label cache_miss; | 3008 Label cache_miss; |
| 2922 Register map = ToRegister(instr->temp()); | 3009 Register map = ToRegister(instr->temp()); |
| 2923 __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); | 3010 __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); |
| 2924 __ bind(deferred->map_check()); // Label for calculating code patching. | 3011 __ bind(deferred->map_check()); // Label for calculating code patching. |
| 2925 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value()); | 3012 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value()); |
| 2926 __ cmp(map, Operand::ForCell(cache_cell)); // Patched to cached map. | 3013 __ cmp(map, Operand::ForCell(cache_cell)); // Patched to cached map. |
| 2927 __ j(not_equal, &cache_miss, Label::kNear); | 3014 __ j(not_equal, &cache_miss, Label::kNear); |
| 2928 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false. | 3015 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false. |
| 2929 __ jmp(&done); | 3016 __ jmp(&done, Label::kNear); |
| 2930 | 3017 |
| 2931 // The inlined call site cache did not match. Check for null and string | 3018 // The inlined call site cache did not match. Check for null and string |
| 2932 // before calling the deferred code. | 3019 // before calling the deferred code. |
| 2933 __ bind(&cache_miss); | 3020 __ bind(&cache_miss); |
| 2934 // Null is not an instance of anything. | 3021 // Null is not an instance of anything. |
| 2935 __ cmp(object, factory()->null_value()); | 3022 __ cmp(object, factory()->null_value()); |
| 2936 __ j(equal, &false_result); | 3023 __ j(equal, &false_result, Label::kNear); |
| 2937 | 3024 |
| 2938 // String values are not instances of anything. | 3025 // String values are not instances of anything. |
| 2939 Condition is_string = masm_->IsObjectStringType(object, temp, temp); | 3026 Condition is_string = masm_->IsObjectStringType(object, temp, temp); |
| 2940 __ j(is_string, &false_result); | 3027 __ j(is_string, &false_result, Label::kNear); |
| 2941 | 3028 |
| 2942 // Go to the deferred code. | 3029 // Go to the deferred code. |
| 2943 __ jmp(deferred->entry()); | 3030 __ jmp(deferred->entry()); |
| 2944 | 3031 |
| 2945 __ bind(&false_result); | 3032 __ bind(&false_result); |
| 2946 __ mov(ToRegister(instr->result()), factory()->false_value()); | 3033 __ mov(ToRegister(instr->result()), factory()->false_value()); |
| 2947 | 3034 |
| 2948 // Here result has either true or false. Deferred code also produces true or | 3035 // Here result has either true or false. Deferred code also produces true or |
| 2949 // false object. | 3036 // false object. |
| 2950 __ bind(deferred->exit()); | 3037 __ bind(deferred->exit()); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3075 } | 3162 } |
| 3076 int no_frame_start = -1; | 3163 int no_frame_start = -1; |
| 3077 if (NeedsEagerFrame()) { | 3164 if (NeedsEagerFrame()) { |
| 3078 __ mov(esp, ebp); | 3165 __ mov(esp, ebp); |
| 3079 __ pop(ebp); | 3166 __ pop(ebp); |
| 3080 no_frame_start = masm_->pc_offset(); | 3167 no_frame_start = masm_->pc_offset(); |
| 3081 } | 3168 } |
| 3082 if (dynamic_frame_alignment_) { | 3169 if (dynamic_frame_alignment_) { |
| 3083 Label no_padding; | 3170 Label no_padding; |
| 3084 __ cmp(edx, Immediate(kNoAlignmentPadding)); | 3171 __ cmp(edx, Immediate(kNoAlignmentPadding)); |
| 3085 __ j(equal, &no_padding); | 3172 __ j(equal, &no_padding, Label::kNear); |
| 3086 | 3173 |
| 3087 EmitReturn(instr, true); | 3174 EmitReturn(instr, true); |
| 3088 __ bind(&no_padding); | 3175 __ bind(&no_padding); |
| 3089 } | 3176 } |
| 3090 | 3177 |
| 3091 EmitReturn(instr, false); | 3178 EmitReturn(instr, false); |
| 3092 if (no_frame_start != -1) { | 3179 if (no_frame_start != -1) { |
| 3093 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset()); | 3180 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset()); |
| 3094 } | 3181 } |
| 3095 } | 3182 } |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3208 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 3295 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 3209 HObjectAccess access = instr->hydrogen()->access(); | 3296 HObjectAccess access = instr->hydrogen()->access(); |
| 3210 int offset = access.offset(); | 3297 int offset = access.offset(); |
| 3211 | 3298 |
| 3212 if (access.IsExternalMemory()) { | 3299 if (access.IsExternalMemory()) { |
| 3213 Register result = ToRegister(instr->result()); | 3300 Register result = ToRegister(instr->result()); |
| 3214 MemOperand operand = instr->object()->IsConstantOperand() | 3301 MemOperand operand = instr->object()->IsConstantOperand() |
| 3215 ? MemOperand::StaticVariable(ToExternalReference( | 3302 ? MemOperand::StaticVariable(ToExternalReference( |
| 3216 LConstantOperand::cast(instr->object()))) | 3303 LConstantOperand::cast(instr->object()))) |
| 3217 : MemOperand(ToRegister(instr->object()), offset); | 3304 : MemOperand(ToRegister(instr->object()), offset); |
| 3218 if (access.representation().IsByte()) { | 3305 __ Load(result, operand, access.representation()); |
| 3219 ASSERT(instr->hydrogen()->representation().IsInteger32()); | |
| 3220 __ movzx_b(result, operand); | |
| 3221 } else { | |
| 3222 __ mov(result, operand); | |
| 3223 } | |
| 3224 return; | 3306 return; |
| 3225 } | 3307 } |
| 3226 | 3308 |
| 3227 Register object = ToRegister(instr->object()); | 3309 Register object = ToRegister(instr->object()); |
| 3228 if (FLAG_track_double_fields && | 3310 if (FLAG_track_double_fields && |
| 3229 instr->hydrogen()->representation().IsDouble()) { | 3311 instr->hydrogen()->representation().IsDouble()) { |
| 3230 if (CpuFeatures::IsSupported(SSE2)) { | 3312 if (CpuFeatures::IsSupported(SSE2)) { |
| 3231 CpuFeatureScope scope(masm(), SSE2); | 3313 CpuFeatureScope scope(masm(), SSE2); |
| 3232 XMMRegister result = ToDoubleRegister(instr->result()); | 3314 XMMRegister result = ToDoubleRegister(instr->result()); |
| 3233 __ movsd(result, FieldOperand(object, offset)); | 3315 __ movsd(result, FieldOperand(object, offset)); |
| 3234 } else { | 3316 } else { |
| 3235 X87Mov(ToX87Register(instr->result()), FieldOperand(object, offset)); | 3317 X87Mov(ToX87Register(instr->result()), FieldOperand(object, offset)); |
| 3236 } | 3318 } |
| 3237 return; | 3319 return; |
| 3238 } | 3320 } |
| 3239 | 3321 |
| 3240 Register result = ToRegister(instr->result()); | 3322 Register result = ToRegister(instr->result()); |
| 3241 if (!access.IsInobject()) { | 3323 if (!access.IsInobject()) { |
| 3242 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); | 3324 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 3243 object = result; | 3325 object = result; |
| 3244 } | 3326 } |
| 3245 if (access.representation().IsByte()) { | 3327 __ Load(result, FieldOperand(object, offset), access.representation()); |
| 3246 ASSERT(instr->hydrogen()->representation().IsInteger32()); | |
| 3247 __ movzx_b(result, FieldOperand(object, offset)); | |
| 3248 } else { | |
| 3249 __ mov(result, FieldOperand(object, offset)); | |
| 3250 } | |
| 3251 } | 3328 } |
| 3252 | 3329 |
| 3253 | 3330 |
| 3254 void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { | 3331 void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { |
| 3255 ASSERT(!operand->IsDoubleRegister()); | 3332 ASSERT(!operand->IsDoubleRegister()); |
| 3256 if (operand->IsConstantOperand()) { | 3333 if (operand->IsConstantOperand()) { |
| 3257 Handle<Object> object = ToHandle(LConstantOperand::cast(operand)); | 3334 Handle<Object> object = ToHandle(LConstantOperand::cast(operand)); |
| 3258 AllowDeferredHandleDereference smi_check; | 3335 AllowDeferredHandleDereference smi_check; |
| 3259 if (object->IsSmi()) { | 3336 if (object->IsSmi()) { |
| 3260 __ Push(Handle<Smi>::cast(object)); | 3337 __ Push(Handle<Smi>::cast(object)); |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3593 | 3670 |
| 3594 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { | 3671 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { |
| 3595 Register receiver = ToRegister(instr->receiver()); | 3672 Register receiver = ToRegister(instr->receiver()); |
| 3596 Register function = ToRegister(instr->function()); | 3673 Register function = ToRegister(instr->function()); |
| 3597 Register scratch = ToRegister(instr->temp()); | 3674 Register scratch = ToRegister(instr->temp()); |
| 3598 | 3675 |
| 3599 // If the receiver is null or undefined, we have to pass the global | 3676 // If the receiver is null or undefined, we have to pass the global |
| 3600 // object as a receiver to normal functions. Values have to be | 3677 // object as a receiver to normal functions. Values have to be |
| 3601 // passed unchanged to builtins and strict-mode functions. | 3678 // passed unchanged to builtins and strict-mode functions. |
| 3602 Label global_object, receiver_ok; | 3679 Label global_object, receiver_ok; |
| 3680 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; |
| 3603 | 3681 |
| 3604 // Do not transform the receiver to object for strict mode | 3682 // Do not transform the receiver to object for strict mode |
| 3605 // functions. | 3683 // functions. |
| 3606 __ mov(scratch, | 3684 __ mov(scratch, |
| 3607 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); | 3685 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); |
| 3608 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset), | 3686 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset), |
| 3609 1 << SharedFunctionInfo::kStrictModeBitWithinByte); | 3687 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
| 3610 __ j(not_equal, &receiver_ok); // A near jump is not sufficient here! | 3688 __ j(not_equal, &receiver_ok, dist); |
| 3611 | 3689 |
| 3612 // Do not transform the receiver to object for builtins. | 3690 // Do not transform the receiver to object for builtins. |
| 3613 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset), | 3691 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset), |
| 3614 1 << SharedFunctionInfo::kNativeBitWithinByte); | 3692 1 << SharedFunctionInfo::kNativeBitWithinByte); |
| 3615 __ j(not_equal, &receiver_ok); | 3693 __ j(not_equal, &receiver_ok, dist); |
| 3616 | 3694 |
| 3617 // Normal function. Replace undefined or null with global receiver. | 3695 // Normal function. Replace undefined or null with global receiver. |
| 3618 __ cmp(receiver, factory()->null_value()); | 3696 __ cmp(receiver, factory()->null_value()); |
| 3619 __ j(equal, &global_object, Label::kNear); | 3697 __ j(equal, &global_object, Label::kNear); |
| 3620 __ cmp(receiver, factory()->undefined_value()); | 3698 __ cmp(receiver, factory()->undefined_value()); |
| 3621 __ j(equal, &global_object, Label::kNear); | 3699 __ j(equal, &global_object, Label::kNear); |
| 3622 | 3700 |
| 3623 // The receiver should be a JS object. | 3701 // The receiver should be a JS object. |
| 3624 __ test(receiver, Immediate(kSmiTagMask)); | 3702 __ test(receiver, Immediate(kSmiTagMask)); |
| 3625 DeoptimizeIf(equal, instr->environment()); | 3703 DeoptimizeIf(equal, instr->environment()); |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3814 | 3892 |
| 3815 // Preserve the value of all registers. | 3893 // Preserve the value of all registers. |
| 3816 PushSafepointRegistersScope scope(this); | 3894 PushSafepointRegistersScope scope(this); |
| 3817 | 3895 |
| 3818 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | 3896 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); |
| 3819 // Check the sign of the argument. If the argument is positive, just | 3897 // Check the sign of the argument. If the argument is positive, just |
| 3820 // return it. We do not need to patch the stack since |input| and | 3898 // return it. We do not need to patch the stack since |input| and |
| 3821 // |result| are the same register and |input| will be restored | 3899 // |result| are the same register and |input| will be restored |
| 3822 // unchanged by popping safepoint registers. | 3900 // unchanged by popping safepoint registers. |
| 3823 __ test(tmp, Immediate(HeapNumber::kSignMask)); | 3901 __ test(tmp, Immediate(HeapNumber::kSignMask)); |
| 3824 __ j(zero, &done); | 3902 __ j(zero, &done, Label::kNear); |
| 3825 | 3903 |
| 3826 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow); | 3904 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow); |
| 3827 __ jmp(&allocated, Label::kNear); | 3905 __ jmp(&allocated, Label::kNear); |
| 3828 | 3906 |
| 3829 // Slow case: Call the runtime system to do the number allocation. | 3907 // Slow case: Call the runtime system to do the number allocation. |
| 3830 __ bind(&slow); | 3908 __ bind(&slow); |
| 3831 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, | 3909 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, |
| 3832 instr, instr->context()); | 3910 instr, instr->context()); |
| 3833 // Set the pointer to the new heap number in tmp. | 3911 // Set the pointer to the new heap number in tmp. |
| 3834 if (!tmp.is(eax)) __ mov(tmp, eax); | 3912 if (!tmp.is(eax)) __ mov(tmp, eax); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3876 | 3954 |
| 3877 ASSERT(instr->value()->Equals(instr->result())); | 3955 ASSERT(instr->value()->Equals(instr->result())); |
| 3878 Representation r = instr->hydrogen()->value()->representation(); | 3956 Representation r = instr->hydrogen()->value()->representation(); |
| 3879 | 3957 |
| 3880 CpuFeatureScope scope(masm(), SSE2); | 3958 CpuFeatureScope scope(masm(), SSE2); |
| 3881 if (r.IsDouble()) { | 3959 if (r.IsDouble()) { |
| 3882 XMMRegister scratch = double_scratch0(); | 3960 XMMRegister scratch = double_scratch0(); |
| 3883 XMMRegister input_reg = ToDoubleRegister(instr->value()); | 3961 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 3884 __ xorps(scratch, scratch); | 3962 __ xorps(scratch, scratch); |
| 3885 __ subsd(scratch, input_reg); | 3963 __ subsd(scratch, input_reg); |
| 3886 __ pand(input_reg, scratch); | 3964 __ andps(input_reg, scratch); |
| 3887 } else if (r.IsSmiOrInteger32()) { | 3965 } else if (r.IsSmiOrInteger32()) { |
| 3888 EmitIntegerMathAbs(instr); | 3966 EmitIntegerMathAbs(instr); |
| 3889 } else { // Tagged case. | 3967 } else { // Tagged case. |
| 3890 DeferredMathAbsTaggedHeapNumber* deferred = | 3968 DeferredMathAbsTaggedHeapNumber* deferred = |
| 3891 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr, x87_stack_); | 3969 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr, x87_stack_); |
| 3892 Register input_reg = ToRegister(instr->value()); | 3970 Register input_reg = ToRegister(instr->value()); |
| 3893 // Smi check. | 3971 // Smi check. |
| 3894 __ JumpIfNotSmi(input_reg, deferred->entry()); | 3972 __ JumpIfNotSmi(input_reg, deferred->entry()); |
| 3895 EmitIntegerMathAbs(instr); | 3973 EmitIntegerMathAbs(instr); |
| 3896 __ bind(deferred->exit()); | 3974 __ bind(deferred->exit()); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3968 CpuFeatureScope scope(masm(), SSE2); | 4046 CpuFeatureScope scope(masm(), SSE2); |
| 3969 Register output_reg = ToRegister(instr->result()); | 4047 Register output_reg = ToRegister(instr->result()); |
| 3970 XMMRegister input_reg = ToDoubleRegister(instr->value()); | 4048 XMMRegister input_reg = ToDoubleRegister(instr->value()); |
| 3971 XMMRegister xmm_scratch = double_scratch0(); | 4049 XMMRegister xmm_scratch = double_scratch0(); |
| 3972 XMMRegister input_temp = ToDoubleRegister(instr->temp()); | 4050 XMMRegister input_temp = ToDoubleRegister(instr->temp()); |
| 3973 ExternalReference one_half = ExternalReference::address_of_one_half(); | 4051 ExternalReference one_half = ExternalReference::address_of_one_half(); |
| 3974 ExternalReference minus_one_half = | 4052 ExternalReference minus_one_half = |
| 3975 ExternalReference::address_of_minus_one_half(); | 4053 ExternalReference::address_of_minus_one_half(); |
| 3976 | 4054 |
| 3977 Label done, round_to_zero, below_one_half, do_not_compensate; | 4055 Label done, round_to_zero, below_one_half, do_not_compensate; |
| 4056 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; |
| 4057 |
| 3978 __ movsd(xmm_scratch, Operand::StaticVariable(one_half)); | 4058 __ movsd(xmm_scratch, Operand::StaticVariable(one_half)); |
| 3979 __ ucomisd(xmm_scratch, input_reg); | 4059 __ ucomisd(xmm_scratch, input_reg); |
| 3980 __ j(above, &below_one_half); | 4060 __ j(above, &below_one_half, Label::kNear); |
| 3981 | 4061 |
| 3982 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). | 4062 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x). |
| 3983 __ addsd(xmm_scratch, input_reg); | 4063 __ addsd(xmm_scratch, input_reg); |
| 3984 __ cvttsd2si(output_reg, Operand(xmm_scratch)); | 4064 __ cvttsd2si(output_reg, Operand(xmm_scratch)); |
| 3985 // Overflow is signalled with minint. | 4065 // Overflow is signalled with minint. |
| 3986 __ cmp(output_reg, 0x80000000u); | 4066 __ cmp(output_reg, 0x80000000u); |
| 3987 __ RecordComment("D2I conversion overflow"); | 4067 __ RecordComment("D2I conversion overflow"); |
| 3988 DeoptimizeIf(equal, instr->environment()); | 4068 DeoptimizeIf(equal, instr->environment()); |
| 3989 __ jmp(&done); | 4069 __ jmp(&done, dist); |
| 3990 | 4070 |
| 3991 __ bind(&below_one_half); | 4071 __ bind(&below_one_half); |
| 3992 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half)); | 4072 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half)); |
| 3993 __ ucomisd(xmm_scratch, input_reg); | 4073 __ ucomisd(xmm_scratch, input_reg); |
| 3994 __ j(below_equal, &round_to_zero); | 4074 __ j(below_equal, &round_to_zero, Label::kNear); |
| 3995 | 4075 |
| 3996 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then | 4076 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then |
| 3997 // compare and compensate. | 4077 // compare and compensate. |
| 3998 __ movsd(input_temp, input_reg); // Do not alter input_reg. | 4078 __ movaps(input_temp, input_reg); // Do not alter input_reg. |
| 3999 __ subsd(input_temp, xmm_scratch); | 4079 __ subsd(input_temp, xmm_scratch); |
| 4000 __ cvttsd2si(output_reg, Operand(input_temp)); | 4080 __ cvttsd2si(output_reg, Operand(input_temp)); |
| 4001 // Catch minint due to overflow, and to prevent overflow when compensating. | 4081 // Catch minint due to overflow, and to prevent overflow when compensating. |
| 4002 __ cmp(output_reg, 0x80000000u); | 4082 __ cmp(output_reg, 0x80000000u); |
| 4003 __ RecordComment("D2I conversion overflow"); | 4083 __ RecordComment("D2I conversion overflow"); |
| 4004 DeoptimizeIf(equal, instr->environment()); | 4084 DeoptimizeIf(equal, instr->environment()); |
| 4005 | 4085 |
| 4006 __ Cvtsi2sd(xmm_scratch, output_reg); | 4086 __ Cvtsi2sd(xmm_scratch, output_reg); |
| 4007 __ ucomisd(xmm_scratch, input_temp); | 4087 __ ucomisd(xmm_scratch, input_temp); |
| 4008 __ j(equal, &done); | 4088 __ j(equal, &done, dist); |
| 4009 __ sub(output_reg, Immediate(1)); | 4089 __ sub(output_reg, Immediate(1)); |
| 4010 // No overflow because we already ruled out minint. | 4090 // No overflow because we already ruled out minint. |
| 4011 __ jmp(&done); | 4091 __ jmp(&done, dist); |
| 4012 | 4092 |
| 4013 __ bind(&round_to_zero); | 4093 __ bind(&round_to_zero); |
| 4014 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if | 4094 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if |
| 4015 // we can ignore the difference between a result of -0 and +0. | 4095 // we can ignore the difference between a result of -0 and +0. |
| 4016 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 4096 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 4017 // If the sign is positive, we return +0. | 4097 // If the sign is positive, we return +0. |
| 4018 __ movmskpd(output_reg, input_reg); | 4098 __ movmskpd(output_reg, input_reg); |
| 4019 __ test(output_reg, Immediate(1)); | 4099 __ test(output_reg, Immediate(1)); |
| 4020 __ RecordComment("Minus zero"); | 4100 __ RecordComment("Minus zero"); |
| 4021 DeoptimizeIf(not_zero, instr->environment()); | 4101 DeoptimizeIf(not_zero, instr->environment()); |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4356 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode); | 4436 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode); |
| 4357 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4437 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4358 } else if (instr->arity() == 1) { | 4438 } else if (instr->arity() == 1) { |
| 4359 Label done; | 4439 Label done; |
| 4360 if (IsFastPackedElementsKind(kind)) { | 4440 if (IsFastPackedElementsKind(kind)) { |
| 4361 Label packed_case; | 4441 Label packed_case; |
| 4362 // We might need a change here | 4442 // We might need a change here |
| 4363 // look at the first argument | 4443 // look at the first argument |
| 4364 __ mov(ecx, Operand(esp, 0)); | 4444 __ mov(ecx, Operand(esp, 0)); |
| 4365 __ test(ecx, ecx); | 4445 __ test(ecx, ecx); |
| 4366 __ j(zero, &packed_case); | 4446 __ j(zero, &packed_case, Label::kNear); |
| 4367 | 4447 |
| 4368 ElementsKind holey_kind = GetHoleyElementsKind(kind); | 4448 ElementsKind holey_kind = GetHoleyElementsKind(kind); |
| 4369 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode, | 4449 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode, |
| 4370 override_mode); | 4450 override_mode); |
| 4371 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4451 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4372 __ jmp(&done); | 4452 __ jmp(&done, Label::kNear); |
| 4373 __ bind(&packed_case); | 4453 __ bind(&packed_case); |
| 4374 } | 4454 } |
| 4375 | 4455 |
| 4376 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode); | 4456 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode); |
| 4377 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4457 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4378 __ bind(&done); | 4458 __ bind(&done); |
| 4379 } else { | 4459 } else { |
| 4380 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode); | 4460 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode); |
| 4381 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4461 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4382 } | 4462 } |
| 4383 } | 4463 } |
| 4384 | 4464 |
| 4385 | 4465 |
| 4386 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { | 4466 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { |
| 4467 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4387 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles()); | 4468 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles()); |
| 4388 } | 4469 } |
| 4389 | 4470 |
| 4390 | 4471 |
| 4391 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) { | 4472 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) { |
| 4392 Register function = ToRegister(instr->function()); | 4473 Register function = ToRegister(instr->function()); |
| 4393 Register code_object = ToRegister(instr->code_object()); | 4474 Register code_object = ToRegister(instr->code_object()); |
| 4394 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize)); | 4475 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize)); |
| 4395 __ mov(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object); | 4476 __ mov(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object); |
| 4396 } | 4477 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 4409 HObjectAccess access = instr->hydrogen()->access(); | 4490 HObjectAccess access = instr->hydrogen()->access(); |
| 4410 int offset = access.offset(); | 4491 int offset = access.offset(); |
| 4411 | 4492 |
| 4412 if (access.IsExternalMemory()) { | 4493 if (access.IsExternalMemory()) { |
| 4413 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); | 4494 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
| 4414 MemOperand operand = instr->object()->IsConstantOperand() | 4495 MemOperand operand = instr->object()->IsConstantOperand() |
| 4415 ? MemOperand::StaticVariable( | 4496 ? MemOperand::StaticVariable( |
| 4416 ToExternalReference(LConstantOperand::cast(instr->object()))) | 4497 ToExternalReference(LConstantOperand::cast(instr->object()))) |
| 4417 : MemOperand(ToRegister(instr->object()), offset); | 4498 : MemOperand(ToRegister(instr->object()), offset); |
| 4418 if (instr->value()->IsConstantOperand()) { | 4499 if (instr->value()->IsConstantOperand()) { |
| 4419 ASSERT(!representation.IsByte()); | |
| 4420 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); | 4500 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); |
| 4421 __ mov(operand, Immediate(ToInteger32(operand_value))); | 4501 __ mov(operand, Immediate(ToInteger32(operand_value))); |
| 4422 } else { | 4502 } else { |
| 4423 Register value = ToRegister(instr->value()); | 4503 Register value = ToRegister(instr->value()); |
| 4424 if (representation.IsByte()) { | 4504 __ Store(value, operand, representation); |
| 4425 __ mov_b(operand, value); | |
| 4426 } else { | |
| 4427 __ mov(operand, value); | |
| 4428 } | |
| 4429 } | 4505 } |
| 4430 return; | 4506 return; |
| 4431 } | 4507 } |
| 4432 | 4508 |
| 4433 Register object = ToRegister(instr->object()); | 4509 Register object = ToRegister(instr->object()); |
| 4434 Handle<Map> transition = instr->transition(); | 4510 Handle<Map> transition = instr->transition(); |
| 4435 | 4511 |
| 4436 if (FLAG_track_fields && representation.IsSmi()) { | 4512 if (FLAG_track_fields && representation.IsSmi()) { |
| 4437 if (instr->value()->IsConstantOperand()) { | 4513 if (instr->value()->IsConstantOperand()) { |
| 4438 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); | 4514 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4496 if (!access.IsInobject()) { | 4572 if (!access.IsInobject()) { |
| 4497 write_register = ToRegister(instr->temp()); | 4573 write_register = ToRegister(instr->temp()); |
| 4498 __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset)); | 4574 __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 4499 } | 4575 } |
| 4500 | 4576 |
| 4501 MemOperand operand = FieldOperand(write_register, offset); | 4577 MemOperand operand = FieldOperand(write_register, offset); |
| 4502 if (instr->value()->IsConstantOperand()) { | 4578 if (instr->value()->IsConstantOperand()) { |
| 4503 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); | 4579 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); |
| 4504 if (operand_value->IsRegister()) { | 4580 if (operand_value->IsRegister()) { |
| 4505 Register value = ToRegister(operand_value); | 4581 Register value = ToRegister(operand_value); |
| 4506 if (representation.IsByte()) { | 4582 __ Store(value, operand, representation); |
| 4507 __ mov_b(operand, value); | 4583 } else if (representation.IsInteger32()) { |
| 4508 } else { | 4584 Immediate immediate = ToImmediate(operand_value, representation); |
| 4509 __ mov(operand, value); | 4585 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
| 4510 } | 4586 __ mov(operand, immediate); |
| 4511 } else { | 4587 } else { |
| 4512 Handle<Object> handle_value = ToHandle(operand_value); | 4588 Handle<Object> handle_value = ToHandle(operand_value); |
| 4513 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); | 4589 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
| 4514 __ mov(operand, handle_value); | 4590 __ mov(operand, handle_value); |
| 4515 } | 4591 } |
| 4516 } else { | 4592 } else { |
| 4517 Register value = ToRegister(instr->value()); | 4593 Register value = ToRegister(instr->value()); |
| 4518 if (representation.IsByte()) { | 4594 __ Store(value, operand, representation); |
| 4519 __ mov_b(operand, value); | |
| 4520 } else { | |
| 4521 __ mov(operand, value); | |
| 4522 } | |
| 4523 } | 4595 } |
| 4524 | 4596 |
| 4525 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4597 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4526 Register value = ToRegister(instr->value()); | 4598 Register value = ToRegister(instr->value()); |
| 4527 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object; | 4599 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object; |
| 4528 // Update the write barrier for the object for in-object properties. | 4600 // Update the write barrier for the object for in-object properties. |
| 4529 __ RecordWriteField(write_register, | 4601 __ RecordWriteField(write_register, |
| 4530 offset, | 4602 offset, |
| 4531 value, | 4603 value, |
| 4532 temp, | 4604 temp, |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4659 instr->additional_index()); | 4731 instr->additional_index()); |
| 4660 | 4732 |
| 4661 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { | 4733 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { |
| 4662 CpuFeatureScope scope(masm(), SSE2); | 4734 CpuFeatureScope scope(masm(), SSE2); |
| 4663 XMMRegister value = ToDoubleRegister(instr->value()); | 4735 XMMRegister value = ToDoubleRegister(instr->value()); |
| 4664 | 4736 |
| 4665 if (instr->NeedsCanonicalization()) { | 4737 if (instr->NeedsCanonicalization()) { |
| 4666 Label have_value; | 4738 Label have_value; |
| 4667 | 4739 |
| 4668 __ ucomisd(value, value); | 4740 __ ucomisd(value, value); |
| 4669 __ j(parity_odd, &have_value); // NaN. | 4741 __ j(parity_odd, &have_value, Label::kNear); // NaN. |
| 4670 | 4742 |
| 4671 __ movsd(value, Operand::StaticVariable(canonical_nan_reference)); | 4743 __ movsd(value, Operand::StaticVariable(canonical_nan_reference)); |
| 4672 __ bind(&have_value); | 4744 __ bind(&have_value); |
| 4673 } | 4745 } |
| 4674 | 4746 |
| 4675 __ movsd(double_store_operand, value); | 4747 __ movsd(double_store_operand, value); |
| 4676 } else { | 4748 } else { |
| 4677 // Can't use SSE2 in the serializer | 4749 // Can't use SSE2 in the serializer |
| 4678 if (instr->hydrogen()->IsConstantHoleStore()) { | 4750 if (instr->hydrogen()->IsConstantHoleStore()) { |
| 4679 // This means we should store the (double) hole. No floating point | 4751 // This means we should store the (double) hole. No floating point |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4695 } else { | 4767 } else { |
| 4696 Label no_special_nan_handling; | 4768 Label no_special_nan_handling; |
| 4697 X87Register value = ToX87Register(instr->value()); | 4769 X87Register value = ToX87Register(instr->value()); |
| 4698 X87Fxch(value); | 4770 X87Fxch(value); |
| 4699 | 4771 |
| 4700 if (instr->NeedsCanonicalization()) { | 4772 if (instr->NeedsCanonicalization()) { |
| 4701 __ fld(0); | 4773 __ fld(0); |
| 4702 __ fld(0); | 4774 __ fld(0); |
| 4703 __ FCmp(); | 4775 __ FCmp(); |
| 4704 | 4776 |
| 4705 __ j(parity_odd, &no_special_nan_handling); | 4777 __ j(parity_odd, &no_special_nan_handling, Label::kNear); |
| 4706 __ sub(esp, Immediate(kDoubleSize)); | 4778 __ sub(esp, Immediate(kDoubleSize)); |
| 4707 __ fst_d(MemOperand(esp, 0)); | 4779 __ fst_d(MemOperand(esp, 0)); |
| 4708 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)), | 4780 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)), |
| 4709 Immediate(kHoleNanUpper32)); | 4781 Immediate(kHoleNanUpper32)); |
| 4710 __ add(esp, Immediate(kDoubleSize)); | 4782 __ add(esp, Immediate(kDoubleSize)); |
| 4711 Label canonicalize; | 4783 Label canonicalize; |
| 4712 __ j(not_equal, &canonicalize); | 4784 __ j(not_equal, &canonicalize, Label::kNear); |
| 4713 __ jmp(&no_special_nan_handling); | 4785 __ jmp(&no_special_nan_handling, Label::kNear); |
| 4714 __ bind(&canonicalize); | 4786 __ bind(&canonicalize); |
| 4715 __ fstp(0); | 4787 __ fstp(0); |
| 4716 __ fld_d(Operand::StaticVariable(canonical_nan_reference)); | 4788 __ fld_d(Operand::StaticVariable(canonical_nan_reference)); |
| 4717 } | 4789 } |
| 4718 | 4790 |
| 4719 __ bind(&no_special_nan_handling); | 4791 __ bind(&no_special_nan_handling); |
| 4720 __ fst_d(double_store_operand); | 4792 __ fst_d(double_store_operand); |
| 4721 } | 4793 } |
| 4722 } | 4794 } |
| 4723 } | 4795 } |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4950 | 5022 |
| 4951 PushSafepointRegistersScope scope(this); | 5023 PushSafepointRegistersScope scope(this); |
| 4952 __ SmiTag(char_code); | 5024 __ SmiTag(char_code); |
| 4953 __ push(char_code); | 5025 __ push(char_code); |
| 4954 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context()); | 5026 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context()); |
| 4955 __ StoreToSafepointRegisterSlot(result, eax); | 5027 __ StoreToSafepointRegisterSlot(result, eax); |
| 4956 } | 5028 } |
| 4957 | 5029 |
| 4958 | 5030 |
| 4959 void LCodeGen::DoStringAdd(LStringAdd* instr) { | 5031 void LCodeGen::DoStringAdd(LStringAdd* instr) { |
| 4960 EmitPushTaggedOperand(instr->left()); | 5032 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4961 EmitPushTaggedOperand(instr->right()); | 5033 if (FLAG_new_string_add) { |
| 4962 StringAddStub stub(instr->hydrogen()->flags()); | 5034 ASSERT(ToRegister(instr->left()).is(edx)); |
| 4963 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 5035 ASSERT(ToRegister(instr->right()).is(eax)); |
| 5036 NewStringAddStub stub(instr->hydrogen()->flags(), |
| 5037 isolate()->heap()->GetPretenureMode()); |
| 5038 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 5039 } else { |
| 5040 EmitPushTaggedOperand(instr->left()); |
| 5041 EmitPushTaggedOperand(instr->right()); |
| 5042 StringAddStub stub(instr->hydrogen()->flags()); |
| 5043 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 5044 } |
| 4964 } | 5045 } |
| 4965 | 5046 |
| 4966 | 5047 |
| 4967 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { | 5048 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
| 4968 LOperand* input = instr->value(); | 5049 LOperand* input = instr->value(); |
| 4969 LOperand* output = instr->result(); | 5050 LOperand* output = instr->result(); |
| 4970 ASSERT(input->IsRegister() || input->IsStackSlot()); | 5051 ASSERT(input->IsRegister() || input->IsStackSlot()); |
| 4971 ASSERT(output->IsDoubleRegister()); | 5052 ASSERT(output->IsDoubleRegister()); |
| 4972 if (CpuFeatures::IsSupported(SSE2)) { | 5053 if (CpuFeatures::IsSupported(SSE2)) { |
| 4973 CpuFeatureScope scope(masm(), SSE2); | 5054 CpuFeatureScope scope(masm(), SSE2); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5005 ToDoubleRegister(temp)); | 5086 ToDoubleRegister(temp)); |
| 5006 } else { | 5087 } else { |
| 5007 X87Register res = ToX87Register(output); | 5088 X87Register res = ToX87Register(output); |
| 5008 X87PrepareToWrite(res); | 5089 X87PrepareToWrite(res); |
| 5009 __ LoadUint32NoSSE2(ToRegister(input)); | 5090 __ LoadUint32NoSSE2(ToRegister(input)); |
| 5010 X87CommitWrite(res); | 5091 X87CommitWrite(res); |
| 5011 } | 5092 } |
| 5012 } | 5093 } |
| 5013 | 5094 |
| 5014 | 5095 |
| 5096 void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) { |
| 5097 Register input = ToRegister(instr->value()); |
| 5098 if (!instr->hydrogen()->value()->HasRange() || |
| 5099 !instr->hydrogen()->value()->range()->IsInSmiRange()) { |
| 5100 __ test(input, Immediate(0xc0000000)); |
| 5101 DeoptimizeIf(not_zero, instr->environment()); |
| 5102 } |
| 5103 __ SmiTag(input); |
| 5104 } |
| 5105 |
| 5106 |
| 5015 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { | 5107 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
| 5016 class DeferredNumberTagI V8_FINAL : public LDeferredCode { | 5108 class DeferredNumberTagI V8_FINAL : public LDeferredCode { |
| 5017 public: | 5109 public: |
| 5018 DeferredNumberTagI(LCodeGen* codegen, | 5110 DeferredNumberTagI(LCodeGen* codegen, |
| 5019 LNumberTagI* instr, | 5111 LNumberTagI* instr, |
| 5020 const X87Stack& x87_stack) | 5112 const X87Stack& x87_stack) |
| 5021 : LDeferredCode(codegen, x87_stack), instr_(instr) { } | 5113 : LDeferredCode(codegen, x87_stack), instr_(instr) { } |
| 5022 virtual void Generate() V8_OVERRIDE { | 5114 virtual void Generate() V8_OVERRIDE { |
| 5023 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32); | 5115 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32); |
| 5024 } | 5116 } |
| (...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5672 DeferredCheckMaps* deferred = NULL; | 5764 DeferredCheckMaps* deferred = NULL; |
| 5673 if (instr->hydrogen()->has_migration_target()) { | 5765 if (instr->hydrogen()->has_migration_target()) { |
| 5674 deferred = new(zone()) DeferredCheckMaps(this, instr, reg, x87_stack_); | 5766 deferred = new(zone()) DeferredCheckMaps(this, instr, reg, x87_stack_); |
| 5675 __ bind(deferred->check_maps()); | 5767 __ bind(deferred->check_maps()); |
| 5676 } | 5768 } |
| 5677 | 5769 |
| 5678 UniqueSet<Map> map_set = instr->hydrogen()->map_set(); | 5770 UniqueSet<Map> map_set = instr->hydrogen()->map_set(); |
| 5679 Label success; | 5771 Label success; |
| 5680 for (int i = 0; i < map_set.size() - 1; i++) { | 5772 for (int i = 0; i < map_set.size() - 1; i++) { |
| 5681 Handle<Map> map = map_set.at(i).handle(); | 5773 Handle<Map> map = map_set.at(i).handle(); |
| 5682 __ CompareMap(reg, map, &success); | 5774 __ CompareMap(reg, map); |
| 5683 __ j(equal, &success); | 5775 __ j(equal, &success, Label::kNear); |
| 5684 } | 5776 } |
| 5685 | 5777 |
| 5686 Handle<Map> map = map_set.at(map_set.size() - 1).handle(); | 5778 Handle<Map> map = map_set.at(map_set.size() - 1).handle(); |
| 5687 __ CompareMap(reg, map, &success); | 5779 __ CompareMap(reg, map); |
| 5688 if (instr->hydrogen()->has_migration_target()) { | 5780 if (instr->hydrogen()->has_migration_target()) { |
| 5689 __ j(not_equal, deferred->entry()); | 5781 __ j(not_equal, deferred->entry()); |
| 5690 } else { | 5782 } else { |
| 5691 DeoptimizeIf(not_equal, instr->environment()); | 5783 DeoptimizeIf(not_equal, instr->environment()); |
| 5692 } | 5784 } |
| 5693 | 5785 |
| 5694 __ bind(&success); | 5786 __ bind(&success); |
| 5695 } | 5787 } |
| 5696 | 5788 |
| 5697 | 5789 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5755 Register scratch2 = ToRegister(instr->scratch2()); | 5847 Register scratch2 = ToRegister(instr->scratch2()); |
| 5756 Register scratch3 = ToRegister(instr->scratch3()); | 5848 Register scratch3 = ToRegister(instr->scratch3()); |
| 5757 Label is_smi, done, heap_number, valid_exponent, | 5849 Label is_smi, done, heap_number, valid_exponent, |
| 5758 largest_value, zero_result, maybe_nan_or_infinity; | 5850 largest_value, zero_result, maybe_nan_or_infinity; |
| 5759 | 5851 |
| 5760 __ JumpIfSmi(input_reg, &is_smi); | 5852 __ JumpIfSmi(input_reg, &is_smi); |
| 5761 | 5853 |
| 5762 // Check for heap number | 5854 // Check for heap number |
| 5763 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 5855 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 5764 factory()->heap_number_map()); | 5856 factory()->heap_number_map()); |
| 5765 __ j(equal, &heap_number, Label::kFar); | 5857 __ j(equal, &heap_number, Label::kNear); |
| 5766 | 5858 |
| 5767 // Check for undefined. Undefined is converted to zero for clamping | 5859 // Check for undefined. Undefined is converted to zero for clamping |
| 5768 // conversions. | 5860 // conversions. |
| 5769 __ cmp(input_reg, factory()->undefined_value()); | 5861 __ cmp(input_reg, factory()->undefined_value()); |
| 5770 DeoptimizeIf(not_equal, instr->environment()); | 5862 DeoptimizeIf(not_equal, instr->environment()); |
| 5771 __ jmp(&zero_result); | 5863 __ jmp(&zero_result, Label::kNear); |
| 5772 | 5864 |
| 5773 // Heap number | 5865 // Heap number |
| 5774 __ bind(&heap_number); | 5866 __ bind(&heap_number); |
| 5775 | 5867 |
| 5776 // Surprisingly, all of the hand-crafted bit-manipulations below are much | 5868 // Surprisingly, all of the hand-crafted bit-manipulations below are much |
| 5777 // faster than the x86 FPU built-in instruction, especially since "banker's | 5869 // faster than the x86 FPU built-in instruction, especially since "banker's |
| 5778 // rounding" would be additionally very expensive | 5870 // rounding" would be additionally very expensive |
| 5779 | 5871 |
| 5780 // Get exponent word. | 5872 // Get exponent word. |
| 5781 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | 5873 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset)); |
| 5782 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); | 5874 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); |
| 5783 | 5875 |
| 5784 // Test for negative values --> clamp to zero | 5876 // Test for negative values --> clamp to zero |
| 5785 __ test(scratch, scratch); | 5877 __ test(scratch, scratch); |
| 5786 __ j(negative, &zero_result); | 5878 __ j(negative, &zero_result, Label::kNear); |
| 5787 | 5879 |
| 5788 // Get exponent alone in scratch2. | 5880 // Get exponent alone in scratch2. |
| 5789 __ mov(scratch2, scratch); | 5881 __ mov(scratch2, scratch); |
| 5790 __ and_(scratch2, HeapNumber::kExponentMask); | 5882 __ and_(scratch2, HeapNumber::kExponentMask); |
| 5791 __ shr(scratch2, HeapNumber::kExponentShift); | 5883 __ shr(scratch2, HeapNumber::kExponentShift); |
| 5792 __ j(zero, &zero_result); | 5884 __ j(zero, &zero_result, Label::kNear); |
| 5793 __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1)); | 5885 __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1)); |
| 5794 __ j(negative, &zero_result); | 5886 __ j(negative, &zero_result, Label::kNear); |
| 5795 | 5887 |
| 5796 const uint32_t non_int8_exponent = 7; | 5888 const uint32_t non_int8_exponent = 7; |
| 5797 __ cmp(scratch2, Immediate(non_int8_exponent + 1)); | 5889 __ cmp(scratch2, Immediate(non_int8_exponent + 1)); |
| 5798 // If the exponent is too big, check for special values. | 5890 // If the exponent is too big, check for special values. |
| 5799 __ j(greater, &maybe_nan_or_infinity, Label::kNear); | 5891 __ j(greater, &maybe_nan_or_infinity, Label::kNear); |
| 5800 | 5892 |
| 5801 __ bind(&valid_exponent); | 5893 __ bind(&valid_exponent); |
| 5802 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent | 5894 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent |
| 5803 // < 7. The shift bias is the number of bits to shift the mantissa such that | 5895 // < 7. The shift bias is the number of bits to shift the mantissa such that |
| 5804 // with an exponent of 7 such the that top-most one is in bit 30, allowing | 5896 // with an exponent of 7 such the that top-most one is in bit 30, allowing |
| (...skipping 10 matching lines...) Expand all Loading... |
| 5815 __ shl_cl(scratch); | 5907 __ shl_cl(scratch); |
| 5816 // Use "banker's rounding" to spec: If fractional part of number is 0.5, then | 5908 // Use "banker's rounding" to spec: If fractional part of number is 0.5, then |
| 5817 // use the bit in the "ones" place and add it to the "halves" place, which has | 5909 // use the bit in the "ones" place and add it to the "halves" place, which has |
| 5818 // the effect of rounding to even. | 5910 // the effect of rounding to even. |
| 5819 __ mov(scratch2, scratch); | 5911 __ mov(scratch2, scratch); |
| 5820 const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8; | 5912 const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8; |
| 5821 const uint32_t one_bit_shift = one_half_bit_shift + 1; | 5913 const uint32_t one_bit_shift = one_half_bit_shift + 1; |
| 5822 __ and_(scratch2, Immediate((1 << one_bit_shift) - 1)); | 5914 __ and_(scratch2, Immediate((1 << one_bit_shift) - 1)); |
| 5823 __ cmp(scratch2, Immediate(1 << one_half_bit_shift)); | 5915 __ cmp(scratch2, Immediate(1 << one_half_bit_shift)); |
| 5824 Label no_round; | 5916 Label no_round; |
| 5825 __ j(less, &no_round); | 5917 __ j(less, &no_round, Label::kNear); |
| 5826 Label round_up; | 5918 Label round_up; |
| 5827 __ mov(scratch2, Immediate(1 << one_half_bit_shift)); | 5919 __ mov(scratch2, Immediate(1 << one_half_bit_shift)); |
| 5828 __ j(greater, &round_up); | 5920 __ j(greater, &round_up, Label::kNear); |
| 5829 __ test(scratch3, scratch3); | 5921 __ test(scratch3, scratch3); |
| 5830 __ j(not_zero, &round_up); | 5922 __ j(not_zero, &round_up, Label::kNear); |
| 5831 __ mov(scratch2, scratch); | 5923 __ mov(scratch2, scratch); |
| 5832 __ and_(scratch2, Immediate(1 << one_bit_shift)); | 5924 __ and_(scratch2, Immediate(1 << one_bit_shift)); |
| 5833 __ shr(scratch2, 1); | 5925 __ shr(scratch2, 1); |
| 5834 __ bind(&round_up); | 5926 __ bind(&round_up); |
| 5835 __ add(scratch, scratch2); | 5927 __ add(scratch, scratch2); |
| 5836 __ j(overflow, &largest_value); | 5928 __ j(overflow, &largest_value, Label::kNear); |
| 5837 __ bind(&no_round); | 5929 __ bind(&no_round); |
| 5838 __ shr(scratch, 23); | 5930 __ shr(scratch, 23); |
| 5839 __ mov(result_reg, scratch); | 5931 __ mov(result_reg, scratch); |
| 5840 __ jmp(&done, Label::kNear); | 5932 __ jmp(&done, Label::kNear); |
| 5841 | 5933 |
| 5842 __ bind(&maybe_nan_or_infinity); | 5934 __ bind(&maybe_nan_or_infinity); |
| 5843 // Check for NaN/Infinity, all other values map to 255 | 5935 // Check for NaN/Infinity, all other values map to 255 |
| 5844 __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1)); | 5936 __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1)); |
| 5845 __ j(not_equal, &largest_value, Label::kNear); | 5937 __ j(not_equal, &largest_value, Label::kNear); |
| 5846 | 5938 |
| 5847 // Check for NaN, which differs from Infinity in that at least one mantissa | 5939 // Check for NaN, which differs from Infinity in that at least one mantissa |
| 5848 // bit is set. | 5940 // bit is set. |
| 5849 __ and_(scratch, HeapNumber::kMantissaMask); | 5941 __ and_(scratch, HeapNumber::kMantissaMask); |
| 5850 __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); | 5942 __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); |
| 5851 __ j(not_zero, &zero_result); // M!=0 --> NaN | 5943 __ j(not_zero, &zero_result, Label::kNear); // M!=0 --> NaN |
| 5852 // Infinity -> Fall through to map to 255. | 5944 // Infinity -> Fall through to map to 255. |
| 5853 | 5945 |
| 5854 __ bind(&largest_value); | 5946 __ bind(&largest_value); |
| 5855 __ mov(result_reg, Immediate(255)); | 5947 __ mov(result_reg, Immediate(255)); |
| 5856 __ jmp(&done, Label::kNear); | 5948 __ jmp(&done, Label::kNear); |
| 5857 | 5949 |
| 5858 __ bind(&zero_result); | 5950 __ bind(&zero_result); |
| 5859 __ xor_(result_reg, result_reg); | 5951 __ xor_(result_reg, result_reg); |
| 5860 __ jmp(&done); | 5952 __ jmp(&done, Label::kNear); |
| 5861 | 5953 |
| 5862 // smi | 5954 // smi |
| 5863 __ bind(&is_smi); | 5955 __ bind(&is_smi); |
| 5864 if (!input_reg.is(result_reg)) { | 5956 if (!input_reg.is(result_reg)) { |
| 5865 __ mov(result_reg, input_reg); | 5957 __ mov(result_reg, input_reg); |
| 5866 } | 5958 } |
| 5867 __ SmiUntag(result_reg); | 5959 __ SmiUntag(result_reg); |
| 5868 __ ClampUint8(result_reg); | 5960 __ ClampUint8(result_reg); |
| 5869 __ bind(&done); | 5961 __ bind(&done); |
| 5870 } | 5962 } |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5998 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); | 6090 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); |
| 5999 __ push(Immediate(instr->hydrogen()->pattern())); | 6091 __ push(Immediate(instr->hydrogen()->pattern())); |
| 6000 __ push(Immediate(instr->hydrogen()->flags())); | 6092 __ push(Immediate(instr->hydrogen()->flags())); |
| 6001 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); | 6093 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); |
| 6002 __ mov(ebx, eax); | 6094 __ mov(ebx, eax); |
| 6003 | 6095 |
| 6004 __ bind(&materialized); | 6096 __ bind(&materialized); |
| 6005 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; | 6097 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
| 6006 Label allocated, runtime_allocate; | 6098 Label allocated, runtime_allocate; |
| 6007 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT); | 6099 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT); |
| 6008 __ jmp(&allocated); | 6100 __ jmp(&allocated, Label::kNear); |
| 6009 | 6101 |
| 6010 __ bind(&runtime_allocate); | 6102 __ bind(&runtime_allocate); |
| 6011 __ push(ebx); | 6103 __ push(ebx); |
| 6012 __ push(Immediate(Smi::FromInt(size))); | 6104 __ push(Immediate(Smi::FromInt(size))); |
| 6013 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); | 6105 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); |
| 6014 __ pop(ebx); | 6106 __ pop(ebx); |
| 6015 | 6107 |
| 6016 __ bind(&allocated); | 6108 __ bind(&allocated); |
| 6017 // Copy the content into the newly allocated memory. | 6109 // Copy the content into the newly allocated memory. |
| 6018 // (Unroll copy loop once for better throughput). | 6110 // (Unroll copy loop once for better throughput). |
| (...skipping 24 matching lines...) Expand all Loading... |
| 6043 __ push(esi); | 6135 __ push(esi); |
| 6044 __ push(Immediate(instr->hydrogen()->shared_info())); | 6136 __ push(Immediate(instr->hydrogen()->shared_info())); |
| 6045 __ push(Immediate(pretenure ? factory()->true_value() | 6137 __ push(Immediate(pretenure ? factory()->true_value() |
| 6046 : factory()->false_value())); | 6138 : factory()->false_value())); |
| 6047 CallRuntime(Runtime::kNewClosure, 3, instr); | 6139 CallRuntime(Runtime::kNewClosure, 3, instr); |
| 6048 } | 6140 } |
| 6049 } | 6141 } |
| 6050 | 6142 |
| 6051 | 6143 |
| 6052 void LCodeGen::DoTypeof(LTypeof* instr) { | 6144 void LCodeGen::DoTypeof(LTypeof* instr) { |
| 6145 ASSERT(ToRegister(instr->context()).is(esi)); |
| 6053 LOperand* input = instr->value(); | 6146 LOperand* input = instr->value(); |
| 6054 EmitPushTaggedOperand(input); | 6147 EmitPushTaggedOperand(input); |
| 6055 CallRuntime(Runtime::kTypeof, 1, instr); | 6148 CallRuntime(Runtime::kTypeof, 1, instr); |
| 6056 } | 6149 } |
| 6057 | 6150 |
| 6058 | 6151 |
| 6059 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 6152 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 6060 Register input = ToRegister(instr->value()); | 6153 Register input = ToRegister(instr->value()); |
| 6061 | 6154 |
| 6062 Condition final_branch_condition = | 6155 Condition final_branch_condition = |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6198 // now identical. When LAZY is eventually completely folded into EAGER, remove | 6291 // now identical. When LAZY is eventually completely folded into EAGER, remove |
| 6199 // the special case below. | 6292 // the special case below. |
| 6200 if (info()->IsStub() && type == Deoptimizer::EAGER) { | 6293 if (info()->IsStub() && type == Deoptimizer::EAGER) { |
| 6201 type = Deoptimizer::LAZY; | 6294 type = Deoptimizer::LAZY; |
| 6202 } | 6295 } |
| 6203 Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); | 6296 Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); |
| 6204 DeoptimizeIf(no_condition, instr->environment(), type); | 6297 DeoptimizeIf(no_condition, instr->environment(), type); |
| 6205 } | 6298 } |
| 6206 | 6299 |
| 6207 | 6300 |
| 6301 void LCodeGen::DoDummy(LDummy* instr) { |
| 6302 // Nothing to see here, move on! |
| 6303 } |
| 6304 |
| 6305 |
| 6208 void LCodeGen::DoDummyUse(LDummyUse* instr) { | 6306 void LCodeGen::DoDummyUse(LDummyUse* instr) { |
| 6209 // Nothing to see here, move on! | 6307 // Nothing to see here, move on! |
| 6210 } | 6308 } |
| 6211 | 6309 |
| 6212 | 6310 |
| 6213 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { | 6311 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { |
| 6214 PushSafepointRegistersScope scope(this); | 6312 PushSafepointRegistersScope scope(this); |
| 6215 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 6313 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 6216 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); | 6314 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); |
| 6217 RecordSafepointWithLazyDeopt( | 6315 RecordSafepointWithLazyDeopt( |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6287 // If the environment were already registered, we would have no way of | 6385 // If the environment were already registered, we would have no way of |
| 6288 // backpatching it with the spill slot operands. | 6386 // backpatching it with the spill slot operands. |
| 6289 ASSERT(!environment->HasBeenRegistered()); | 6387 ASSERT(!environment->HasBeenRegistered()); |
| 6290 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); | 6388 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| 6291 | 6389 |
| 6292 GenerateOsrPrologue(); | 6390 GenerateOsrPrologue(); |
| 6293 } | 6391 } |
| 6294 | 6392 |
| 6295 | 6393 |
| 6296 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { | 6394 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { |
| 6395 ASSERT(ToRegister(instr->context()).is(esi)); |
| 6297 __ cmp(eax, isolate()->factory()->undefined_value()); | 6396 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 6298 DeoptimizeIf(equal, instr->environment()); | 6397 DeoptimizeIf(equal, instr->environment()); |
| 6299 | 6398 |
| 6300 __ cmp(eax, isolate()->factory()->null_value()); | 6399 __ cmp(eax, isolate()->factory()->null_value()); |
| 6301 DeoptimizeIf(equal, instr->environment()); | 6400 DeoptimizeIf(equal, instr->environment()); |
| 6302 | 6401 |
| 6303 __ test(eax, Immediate(kSmiTagMask)); | 6402 __ test(eax, Immediate(kSmiTagMask)); |
| 6304 DeoptimizeIf(zero, instr->environment()); | 6403 DeoptimizeIf(zero, instr->environment()); |
| 6305 | 6404 |
| 6306 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 6405 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 6324 __ bind(&use_cache); | 6423 __ bind(&use_cache); |
| 6325 } | 6424 } |
| 6326 | 6425 |
| 6327 | 6426 |
| 6328 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { | 6427 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { |
| 6329 Register map = ToRegister(instr->map()); | 6428 Register map = ToRegister(instr->map()); |
| 6330 Register result = ToRegister(instr->result()); | 6429 Register result = ToRegister(instr->result()); |
| 6331 Label load_cache, done; | 6430 Label load_cache, done; |
| 6332 __ EnumLength(result, map); | 6431 __ EnumLength(result, map); |
| 6333 __ cmp(result, Immediate(Smi::FromInt(0))); | 6432 __ cmp(result, Immediate(Smi::FromInt(0))); |
| 6334 __ j(not_equal, &load_cache); | 6433 __ j(not_equal, &load_cache, Label::kNear); |
| 6335 __ mov(result, isolate()->factory()->empty_fixed_array()); | 6434 __ mov(result, isolate()->factory()->empty_fixed_array()); |
| 6336 __ jmp(&done); | 6435 __ jmp(&done, Label::kNear); |
| 6337 | 6436 |
| 6338 __ bind(&load_cache); | 6437 __ bind(&load_cache); |
| 6339 __ LoadInstanceDescriptors(map, result); | 6438 __ LoadInstanceDescriptors(map, result); |
| 6340 __ mov(result, | 6439 __ mov(result, |
| 6341 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); | 6440 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); |
| 6342 __ mov(result, | 6441 __ mov(result, |
| 6343 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); | 6442 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); |
| 6344 __ bind(&done); | 6443 __ bind(&done); |
| 6345 __ test(result, result); | 6444 __ test(result, result); |
| 6346 DeoptimizeIf(equal, instr->environment()); | 6445 DeoptimizeIf(equal, instr->environment()); |
| 6347 } | 6446 } |
| 6348 | 6447 |
| 6349 | 6448 |
| 6350 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { | 6449 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { |
| 6351 Register object = ToRegister(instr->value()); | 6450 Register object = ToRegister(instr->value()); |
| 6352 __ cmp(ToRegister(instr->map()), | 6451 __ cmp(ToRegister(instr->map()), |
| 6353 FieldOperand(object, HeapObject::kMapOffset)); | 6452 FieldOperand(object, HeapObject::kMapOffset)); |
| 6354 DeoptimizeIf(not_equal, instr->environment()); | 6453 DeoptimizeIf(not_equal, instr->environment()); |
| 6355 } | 6454 } |
| 6356 | 6455 |
| 6357 | 6456 |
| 6358 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { | 6457 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { |
| 6359 Register object = ToRegister(instr->object()); | 6458 Register object = ToRegister(instr->object()); |
| 6360 Register index = ToRegister(instr->index()); | 6459 Register index = ToRegister(instr->index()); |
| 6361 | 6460 |
| 6362 Label out_of_object, done; | 6461 Label out_of_object, done; |
| 6363 __ cmp(index, Immediate(0)); | 6462 __ cmp(index, Immediate(0)); |
| 6364 __ j(less, &out_of_object); | 6463 __ j(less, &out_of_object, Label::kNear); |
| 6365 __ mov(object, FieldOperand(object, | 6464 __ mov(object, FieldOperand(object, |
| 6366 index, | 6465 index, |
| 6367 times_half_pointer_size, | 6466 times_half_pointer_size, |
| 6368 JSObject::kHeaderSize)); | 6467 JSObject::kHeaderSize)); |
| 6369 __ jmp(&done, Label::kNear); | 6468 __ jmp(&done, Label::kNear); |
| 6370 | 6469 |
| 6371 __ bind(&out_of_object); | 6470 __ bind(&out_of_object); |
| 6372 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset)); | 6471 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 6373 __ neg(index); | 6472 __ neg(index); |
| 6374 // Index is now equal to out of object property index plus 1. | 6473 // Index is now equal to out of object property index plus 1. |
| 6375 __ mov(object, FieldOperand(object, | 6474 __ mov(object, FieldOperand(object, |
| 6376 index, | 6475 index, |
| 6377 times_half_pointer_size, | 6476 times_half_pointer_size, |
| 6378 FixedArray::kHeaderSize - kPointerSize)); | 6477 FixedArray::kHeaderSize - kPointerSize)); |
| 6379 __ bind(&done); | 6478 __ bind(&done); |
| 6380 } | 6479 } |
| 6381 | 6480 |
| 6382 | 6481 |
| 6383 #undef __ | 6482 #undef __ |
| 6384 | 6483 |
| 6385 } } // namespace v8::internal | 6484 } } // namespace v8::internal |
| 6386 | 6485 |
| 6387 #endif // V8_TARGET_ARCH_IA32 | 6486 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |