| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 2134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2145 FLAG_optimization_counter_threshold * (loop_depth() + 1); | 2145 FLAG_optimization_counter_threshold * (loop_depth() + 1); |
| 2146 __ cmpq(FieldAddress(temp, Function::usage_counter_offset()), | 2146 __ cmpq(FieldAddress(temp, Function::usage_counter_offset()), |
| 2147 Immediate(threshold)); | 2147 Immediate(threshold)); |
| 2148 __ j(GREATER_EQUAL, slow_path->entry_label()); | 2148 __ j(GREATER_EQUAL, slow_path->entry_label()); |
| 2149 } | 2149 } |
| 2150 __ Bind(slow_path->exit_label()); | 2150 __ Bind(slow_path->exit_label()); |
| 2151 } | 2151 } |
| 2152 | 2152 |
| 2153 | 2153 |
| 2154 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, | 2154 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, |
| 2155 Range* range, |
| 2155 Label* overflow, | 2156 Label* overflow, |
| 2156 Register result) { | 2157 Register result) { |
| 2157 if (FLAG_throw_on_javascript_int_overflow) { | 2158 if (!range->IsWithin(-0x20000000000000LL, 0x20000000000000LL)) { |
| 2158 ASSERT(overflow != NULL); | 2159 ASSERT(overflow != NULL); |
| 2159 __ cmpq(result, Immediate(-0x20000000000000)); | 2160 __ cmpq(result, Immediate(-0x20000000000000LL)); |
| 2160 __ j(LESS, overflow); | 2161 __ j(LESS, overflow); |
| 2161 __ cmpq(result, Immediate(0x20000000000000)); | 2162 __ cmpq(result, Immediate(0x20000000000000LL)); |
| 2162 __ j(GREATER, overflow); | 2163 __ j(GREATER, overflow); |
| 2163 } | 2164 } |
| 2164 } | 2165 } |
| 2165 | 2166 |
| 2166 | 2167 |
| 2167 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2168 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
| 2168 BinarySmiOpInstr* shift_left) { | 2169 BinarySmiOpInstr* shift_left) { |
| 2169 const bool is_truncating = shift_left->is_truncating(); | 2170 const bool is_truncating = shift_left->is_truncating(); |
| 2170 const LocationSummary& locs = *shift_left->locs(); | 2171 const LocationSummary& locs = *shift_left->locs(); |
| 2171 Register left = locs.in(0).reg(); | 2172 Register left = locs.in(0).reg(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2196 Register temp = locs.temp(0).reg(); | 2197 Register temp = locs.temp(0).reg(); |
| 2197 __ movq(temp, left); | 2198 __ movq(temp, left); |
| 2198 __ shlq(left, Immediate(value)); | 2199 __ shlq(left, Immediate(value)); |
| 2199 __ sarq(left, Immediate(value)); | 2200 __ sarq(left, Immediate(value)); |
| 2200 __ cmpq(left, temp); | 2201 __ cmpq(left, temp); |
| 2201 __ j(NOT_EQUAL, deopt); // Overflow. | 2202 __ j(NOT_EQUAL, deopt); // Overflow. |
| 2202 } | 2203 } |
| 2203 // Shift for result now we know there is no overflow. | 2204 // Shift for result now we know there is no overflow. |
| 2204 __ shlq(left, Immediate(value)); | 2205 __ shlq(left, Immediate(value)); |
| 2205 } | 2206 } |
| 2206 EmitJavascriptOverflowCheck(compiler, deopt, result); | 2207 if (FLAG_throw_on_javascript_int_overflow) { |
| 2208 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2209 } |
| 2207 return; | 2210 return; |
| 2208 } | 2211 } |
| 2209 | 2212 |
| 2210 // Right (locs.in(1)) is not constant. | 2213 // Right (locs.in(1)) is not constant. |
| 2211 Register right = locs.in(1).reg(); | 2214 Register right = locs.in(1).reg(); |
| 2212 Range* right_range = shift_left->right()->definition()->range(); | 2215 Range* right_range = shift_left->right()->definition()->range(); |
| 2213 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2216 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
| 2214 // TODO(srdjan): Implement code below for is_truncating(). | 2217 // TODO(srdjan): Implement code below for is_truncating(). |
| 2215 // If left is constant, we know the maximal allowed size for right. | 2218 // If left is constant, we know the maximal allowed size for right. |
| 2216 const Object& obj = shift_left->left()->BoundConstant(); | 2219 const Object& obj = shift_left->left()->BoundConstant(); |
| 2217 if (obj.IsSmi()) { | 2220 if (obj.IsSmi()) { |
| 2218 const intptr_t left_int = Smi::Cast(obj).Value(); | 2221 const intptr_t left_int = Smi::Cast(obj).Value(); |
| 2219 if (left_int == 0) { | 2222 if (left_int == 0) { |
| 2220 __ cmpq(right, Immediate(0)); | 2223 __ cmpq(right, Immediate(0)); |
| 2221 __ j(NEGATIVE, deopt); | 2224 __ j(NEGATIVE, deopt); |
| 2222 return; | 2225 return; |
| 2223 } | 2226 } |
| 2224 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); | 2227 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); |
| 2225 const bool right_needs_check = | 2228 const bool right_needs_check = |
| 2226 (right_range == NULL) || | 2229 (right_range == NULL) || |
| 2227 !right_range->IsWithin(0, max_right - 1); | 2230 !right_range->IsWithin(0, max_right - 1); |
| 2228 if (right_needs_check) { | 2231 if (right_needs_check) { |
| 2229 __ cmpq(right, | 2232 __ cmpq(right, |
| 2230 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); | 2233 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); |
| 2231 __ j(ABOVE_EQUAL, deopt); | 2234 __ j(ABOVE_EQUAL, deopt); |
| 2232 } | 2235 } |
| 2233 __ SmiUntag(right); | 2236 __ SmiUntag(right); |
| 2234 __ shlq(left, right); | 2237 __ shlq(left, right); |
| 2235 } | 2238 } |
| 2236 EmitJavascriptOverflowCheck(compiler, deopt, result); | 2239 if (FLAG_throw_on_javascript_int_overflow) { |
| 2240 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2241 } |
| 2237 return; | 2242 return; |
| 2238 } | 2243 } |
| 2239 | 2244 |
| 2240 const bool right_needs_check = | 2245 const bool right_needs_check = |
| 2241 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | 2246 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
| 2242 ASSERT(right == RCX); // Count must be in RCX | 2247 ASSERT(right == RCX); // Count must be in RCX |
| 2243 if (is_truncating) { | 2248 if (is_truncating) { |
| 2244 if (right_needs_check) { | 2249 if (right_needs_check) { |
| 2245 const bool right_may_be_negative = | 2250 const bool right_may_be_negative = |
| 2246 (right_range == NULL) || | 2251 (right_range == NULL) || |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2277 __ movq(temp, left); | 2282 __ movq(temp, left); |
| 2278 __ SmiUntag(right); | 2283 __ SmiUntag(right); |
| 2279 // Overflow test (preserve temp and right); | 2284 // Overflow test (preserve temp and right); |
| 2280 __ shlq(left, right); | 2285 __ shlq(left, right); |
| 2281 __ sarq(left, right); | 2286 __ sarq(left, right); |
| 2282 __ cmpq(left, temp); | 2287 __ cmpq(left, temp); |
| 2283 __ j(NOT_EQUAL, deopt); // Overflow. | 2288 __ j(NOT_EQUAL, deopt); // Overflow. |
| 2284 // Shift for result now we know there is no overflow. | 2289 // Shift for result now we know there is no overflow. |
| 2285 __ shlq(left, right); | 2290 __ shlq(left, right); |
| 2286 } | 2291 } |
| 2287 EmitJavascriptOverflowCheck(compiler, deopt, result); | 2292 if (FLAG_throw_on_javascript_int_overflow) { |
| 2293 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2294 } |
| 2288 } | 2295 } |
| 2289 | 2296 |
| 2290 | 2297 |
| 2291 static bool CanBeImmediate(const Object& constant) { | 2298 static bool CanBeImmediate(const Object& constant) { |
| 2292 return constant.IsSmi() && | 2299 return constant.IsSmi() && |
| 2293 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); | 2300 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); |
| 2294 } | 2301 } |
| 2295 | 2302 |
| 2296 | 2303 |
| 2297 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2304 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2476 | 2483 |
| 2477 __ sarq(left, Immediate(value)); | 2484 __ sarq(left, Immediate(value)); |
| 2478 __ SmiTag(left); | 2485 __ SmiTag(left); |
| 2479 break; | 2486 break; |
| 2480 } | 2487 } |
| 2481 | 2488 |
| 2482 default: | 2489 default: |
| 2483 UNREACHABLE(); | 2490 UNREACHABLE(); |
| 2484 break; | 2491 break; |
| 2485 } | 2492 } |
| 2486 EmitJavascriptOverflowCheck(compiler, deopt, result); | 2493 if (FLAG_throw_on_javascript_int_overflow) { |
| 2494 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2495 } |
| 2487 return; | 2496 return; |
| 2488 } // locs()->in(1).IsConstant(). | 2497 } // locs()->in(1).IsConstant(). |
| 2489 | 2498 |
| 2490 | 2499 |
| 2491 if (locs()->in(1).IsStackSlot()) { | 2500 if (locs()->in(1).IsStackSlot()) { |
| 2492 const Address& right = locs()->in(1).ToStackSlotAddress(); | 2501 const Address& right = locs()->in(1).ToStackSlotAddress(); |
| 2493 switch (op_kind()) { | 2502 switch (op_kind()) { |
| 2494 case Token::kADD: { | 2503 case Token::kADD: { |
| 2495 __ addq(left, right); | 2504 __ addq(left, right); |
| 2496 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2505 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2519 } | 2528 } |
| 2520 case Token::kBIT_XOR: { | 2529 case Token::kBIT_XOR: { |
| 2521 // No overflow check. | 2530 // No overflow check. |
| 2522 __ xorq(left, right); | 2531 __ xorq(left, right); |
| 2523 break; | 2532 break; |
| 2524 } | 2533 } |
| 2525 default: | 2534 default: |
| 2526 UNREACHABLE(); | 2535 UNREACHABLE(); |
| 2527 break; | 2536 break; |
| 2528 } | 2537 } |
| 2529 EmitJavascriptOverflowCheck(compiler, deopt, result); | 2538 if (FLAG_throw_on_javascript_int_overflow) { |
| 2539 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2540 } |
| 2530 return; | 2541 return; |
| 2531 } // locs()->in(1).IsStackSlot(). | 2542 } // locs()->in(1).IsStackSlot(). |
| 2532 | 2543 |
| 2533 // if locs()->in(1).IsRegister. | 2544 // if locs()->in(1).IsRegister. |
| 2534 Register right = locs()->in(1).reg(); | 2545 Register right = locs()->in(1).reg(); |
| 2535 switch (op_kind()) { | 2546 switch (op_kind()) { |
| 2536 case Token::kADD: { | 2547 case Token::kADD: { |
| 2537 __ addq(left, right); | 2548 __ addq(left, right); |
| 2538 if (deopt != NULL) __ j(OVERFLOW, deopt); | 2549 if (deopt != NULL) __ j(OVERFLOW, deopt); |
| 2539 break; | 2550 break; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2649 case Token::kAND: { | 2660 case Token::kAND: { |
| 2650 // Flow graph builder has dissected this operation to guarantee correct | 2661 // Flow graph builder has dissected this operation to guarantee correct |
| 2651 // behavior (short-circuit evaluation). | 2662 // behavior (short-circuit evaluation). |
| 2652 UNREACHABLE(); | 2663 UNREACHABLE(); |
| 2653 break; | 2664 break; |
| 2654 } | 2665 } |
| 2655 default: | 2666 default: |
| 2656 UNREACHABLE(); | 2667 UNREACHABLE(); |
| 2657 break; | 2668 break; |
| 2658 } | 2669 } |
| 2659 EmitJavascriptOverflowCheck(compiler, deopt, result); | 2670 if (FLAG_throw_on_javascript_int_overflow) { |
| 2671 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2672 } |
| 2660 } | 2673 } |
| 2661 | 2674 |
| 2662 | 2675 |
| 2663 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { | 2676 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { |
| 2664 intptr_t left_cid = left()->Type()->ToCid(); | 2677 intptr_t left_cid = left()->Type()->ToCid(); |
| 2665 intptr_t right_cid = right()->Type()->ToCid(); | 2678 intptr_t right_cid = right()->Type()->ToCid(); |
| 2666 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); | 2679 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); |
| 2667 const intptr_t kNumInputs = 2; | 2680 const intptr_t kNumInputs = 2; |
| 2668 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); | 2681 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); |
| 2669 const intptr_t kNumTemps = need_temp ? 1 : 0; | 2682 const intptr_t kNumTemps = need_temp ? 1 : 0; |
| (...skipping 1157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3827 | 3840 |
| 3828 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3841 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3829 Register value = locs()->in(0).reg(); | 3842 Register value = locs()->in(0).reg(); |
| 3830 ASSERT(value == locs()->out().reg()); | 3843 ASSERT(value == locs()->out().reg()); |
| 3831 switch (op_kind()) { | 3844 switch (op_kind()) { |
| 3832 case Token::kNEGATE: { | 3845 case Token::kNEGATE: { |
| 3833 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 3846 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 3834 kDeoptUnaryOp); | 3847 kDeoptUnaryOp); |
| 3835 __ negq(value); | 3848 __ negq(value); |
| 3836 __ j(OVERFLOW, deopt); | 3849 __ j(OVERFLOW, deopt); |
| 3837 EmitJavascriptOverflowCheck(compiler, deopt, value); | 3850 if (FLAG_throw_on_javascript_int_overflow) { |
| 3851 EmitJavascriptOverflowCheck(compiler, range(), deopt, value); |
| 3852 } |
| 3838 break; | 3853 break; |
| 3839 } | 3854 } |
| 3840 case Token::kBIT_NOT: | 3855 case Token::kBIT_NOT: |
| 3841 __ notq(value); | 3856 __ notq(value); |
| 3842 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 3857 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 3843 break; | 3858 break; |
| 3844 default: | 3859 default: |
| 3845 UNREACHABLE(); | 3860 UNREACHABLE(); |
| 3846 } | 3861 } |
| 3847 } | 3862 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3888 ASSERT(result != temp); | 3903 ASSERT(result != temp); |
| 3889 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset())); | 3904 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset())); |
| 3890 __ cvttsd2siq(result, value_double); | 3905 __ cvttsd2siq(result, value_double); |
| 3891 // Overflow is signalled with minint. | 3906 // Overflow is signalled with minint. |
| 3892 Label do_call, done; | 3907 Label do_call, done; |
| 3893 // Check for overflow and that it fits into Smi. | 3908 // Check for overflow and that it fits into Smi. |
| 3894 __ movq(temp, result); | 3909 __ movq(temp, result); |
| 3895 __ shlq(temp, Immediate(1)); | 3910 __ shlq(temp, Immediate(1)); |
| 3896 __ j(OVERFLOW, &do_call, Assembler::kNearJump); | 3911 __ j(OVERFLOW, &do_call, Assembler::kNearJump); |
| 3897 __ SmiTag(result); | 3912 __ SmiTag(result); |
| 3898 EmitJavascriptOverflowCheck(compiler, &do_call, result); | 3913 if (FLAG_throw_on_javascript_int_overflow) { |
| 3914 EmitJavascriptOverflowCheck(compiler, range(), &do_call, result); |
| 3915 } |
| 3899 __ jmp(&done); | 3916 __ jmp(&done); |
| 3900 __ Bind(&do_call); | 3917 __ Bind(&do_call); |
| 3901 ASSERT(instance_call()->HasICData()); | 3918 ASSERT(instance_call()->HasICData()); |
| 3902 const ICData& ic_data = *instance_call()->ic_data(); | 3919 const ICData& ic_data = *instance_call()->ic_data(); |
| 3903 ASSERT((ic_data.NumberOfChecks() == 1)); | 3920 ASSERT((ic_data.NumberOfChecks() == 1)); |
| 3904 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 3921 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 3905 | 3922 |
| 3906 const intptr_t kNumberOfArguments = 1; | 3923 const intptr_t kNumberOfArguments = 1; |
| 3907 __ pushq(value_obj); | 3924 __ pushq(value_obj); |
| 3908 compiler->GenerateStaticCall(deopt_id(), | 3925 compiler->GenerateStaticCall(deopt_id(), |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3934 Register temp = locs()->temp(0).reg(); | 3951 Register temp = locs()->temp(0).reg(); |
| 3935 | 3952 |
| 3936 __ cvttsd2siq(result, value); | 3953 __ cvttsd2siq(result, value); |
| 3937 // Overflow is signalled with minint. | 3954 // Overflow is signalled with minint. |
| 3938 Label do_call, done; | 3955 Label do_call, done; |
| 3939 // Check for overflow and that it fits into Smi. | 3956 // Check for overflow and that it fits into Smi. |
| 3940 __ movq(temp, result); | 3957 __ movq(temp, result); |
| 3941 __ shlq(temp, Immediate(1)); | 3958 __ shlq(temp, Immediate(1)); |
| 3942 __ j(OVERFLOW, deopt); | 3959 __ j(OVERFLOW, deopt); |
| 3943 __ SmiTag(result); | 3960 __ SmiTag(result); |
| 3944 EmitJavascriptOverflowCheck(compiler, deopt, result); | 3961 if (FLAG_throw_on_javascript_int_overflow) { |
| 3962 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 3963 } |
| 3945 } | 3964 } |
| 3946 | 3965 |
| 3947 | 3966 |
| 3948 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { | 3967 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { |
| 3949 const intptr_t kNumInputs = 1; | 3968 const intptr_t kNumInputs = 1; |
| 3950 const intptr_t kNumTemps = 0; | 3969 const intptr_t kNumTemps = 0; |
| 3951 LocationSummary* result = | 3970 LocationSummary* result = |
| 3952 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 3971 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3953 result->set_in(0, Location::RequiresFpuRegister()); | 3972 result->set_in(0, Location::RequiresFpuRegister()); |
| 3954 result->set_out(Location::RequiresFpuRegister()); | 3973 result->set_out(Location::RequiresFpuRegister()); |
| (...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4544 PcDescriptors::kOther, | 4563 PcDescriptors::kOther, |
| 4545 locs()); | 4564 locs()); |
| 4546 __ Drop(2); // Discard type arguments and receiver. | 4565 __ Drop(2); // Discard type arguments and receiver. |
| 4547 } | 4566 } |
| 4548 | 4567 |
| 4549 } // namespace dart | 4568 } // namespace dart |
| 4550 | 4569 |
| 4551 #undef __ | 4570 #undef __ |
| 4552 | 4571 |
| 4553 #endif // defined TARGET_ARCH_X64 | 4572 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |