Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: runtime/vm/intermediate_language_x64.cc

Issue 21301003: Fixes javascript integer overflow check. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 2133 matching lines...) Expand 10 before | Expand all | Expand 10 after
2144 intptr_t threshold = 2144 intptr_t threshold =
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 Emit53BitOverflowCheck(FlowGraphCompiler* compiler, 2154 static void Emit54BitOverflowCheck(FlowGraphCompiler* compiler,
2155 Label* overflow, 2155 Label* overflow,
2156 Register result) { 2156 Register result) {
2157 if (FLAG_throw_on_javascript_int_overflow) { 2157 if (FLAG_throw_on_javascript_int_overflow) {
2158 ASSERT(overflow != NULL); 2158 ASSERT(overflow != NULL);
2159 __ movq(TMP, result); // result is a tagged Smi. 2159 __ movq(TMP, result); // result is a tagged Smi.
2160 // Bits 54...64 must be all 0 or all 1. (It would be bit 53, but result 2160 // Bits 55...64 must be all 0 or all 1. (It would be bit 54, but result
2161 // is tagged.) 2161 // is tagged.)
2162 __ shlq(result, Immediate(64 - 54)); 2162 __ shlq(result, Immediate(64 - 55));
2163 __ sarq(result, Immediate(64 - 54)); 2163 __ sarq(result, Immediate(64 - 55));
2164 __ cmpq(result, TMP); 2164 __ cmpq(result, TMP);
2165 __ j(NOT_EQUAL, overflow); // 53-bit overflow. 2165 __ j(NOT_EQUAL, overflow); // 54-bit overflow.
2166 __ cmpq(result, Immediate(-0x1FFFFFFFFFFFFF-1));
2167 __ j(EQUAL, overflow); // The most negative 54-bit int is also disallowed.
2166 } 2168 }
2167 } 2169 }
2168 2170
2169 2171
2170 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, 2172 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
2171 BinarySmiOpInstr* shift_left) { 2173 BinarySmiOpInstr* shift_left) {
2172 const bool is_truncating = shift_left->is_truncating(); 2174 const bool is_truncating = shift_left->is_truncating();
2173 const LocationSummary& locs = *shift_left->locs(); 2175 const LocationSummary& locs = *shift_left->locs();
2174 Register left = locs.in(0).reg(); 2176 Register left = locs.in(0).reg();
2175 Register result = locs.out().reg(); 2177 Register result = locs.out().reg();
(...skipping 23 matching lines...) Expand all
2199 Register temp = locs.temp(0).reg(); 2201 Register temp = locs.temp(0).reg();
2200 __ movq(temp, left); 2202 __ movq(temp, left);
2201 __ shlq(left, Immediate(value)); 2203 __ shlq(left, Immediate(value));
2202 __ sarq(left, Immediate(value)); 2204 __ sarq(left, Immediate(value));
2203 __ cmpq(left, temp); 2205 __ cmpq(left, temp);
2204 __ j(NOT_EQUAL, deopt); // Overflow. 2206 __ j(NOT_EQUAL, deopt); // Overflow.
2205 } 2207 }
2206 // Shift for result now we know there is no overflow. 2208 // Shift for result now we know there is no overflow.
2207 __ shlq(left, Immediate(value)); 2209 __ shlq(left, Immediate(value));
2208 } 2210 }
2209 Emit53BitOverflowCheck(compiler, deopt, result); 2211 Emit54BitOverflowCheck(compiler, deopt, result);
2210 return; 2212 return;
2211 } 2213 }
2212 2214
2213 // Right (locs.in(1)) is not constant. 2215 // Right (locs.in(1)) is not constant.
2214 Register right = locs.in(1).reg(); 2216 Register right = locs.in(1).reg();
2215 Range* right_range = shift_left->right()->definition()->range(); 2217 Range* right_range = shift_left->right()->definition()->range();
2216 if (shift_left->left()->BindsToConstant() && !is_truncating) { 2218 if (shift_left->left()->BindsToConstant() && !is_truncating) {
2217 // TODO(srdjan): Implement code below for is_truncating(). 2219 // TODO(srdjan): Implement code below for is_truncating().
2218 // If left is constant, we know the maximal allowed size for right. 2220 // If left is constant, we know the maximal allowed size for right.
2219 const Object& obj = shift_left->left()->BoundConstant(); 2221 const Object& obj = shift_left->left()->BoundConstant();
2220 if (obj.IsSmi()) { 2222 if (obj.IsSmi()) {
2221 const intptr_t left_int = Smi::Cast(obj).Value(); 2223 const intptr_t left_int = Smi::Cast(obj).Value();
2222 if (left_int == 0) { 2224 if (left_int == 0) {
2223 __ cmpq(right, Immediate(0)); 2225 __ cmpq(right, Immediate(0));
2224 __ j(NEGATIVE, deopt); 2226 __ j(NEGATIVE, deopt);
2225 return; 2227 return;
2226 } 2228 }
2227 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); 2229 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
2228 const bool right_needs_check = 2230 const bool right_needs_check =
2229 (right_range == NULL) || 2231 (right_range == NULL) ||
2230 !right_range->IsWithin(0, max_right - 1); 2232 !right_range->IsWithin(0, max_right - 1);
2231 if (right_needs_check) { 2233 if (right_needs_check) {
2232 __ cmpq(right, 2234 __ cmpq(right,
2233 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); 2235 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
2234 __ j(ABOVE_EQUAL, deopt); 2236 __ j(ABOVE_EQUAL, deopt);
2235 } 2237 }
2236 __ SmiUntag(right); 2238 __ SmiUntag(right);
2237 __ shlq(left, right); 2239 __ shlq(left, right);
2238 } 2240 }
2239 Emit53BitOverflowCheck(compiler, deopt, result); 2241 Emit54BitOverflowCheck(compiler, deopt, result);
2240 return; 2242 return;
2241 } 2243 }
2242 2244
2243 const bool right_needs_check = 2245 const bool right_needs_check =
2244 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); 2246 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
2245 ASSERT(right == RCX); // Count must be in RCX 2247 ASSERT(right == RCX); // Count must be in RCX
2246 if (is_truncating) { 2248 if (is_truncating) {
2247 if (right_needs_check) { 2249 if (right_needs_check) {
2248 const bool right_may_be_negative = 2250 const bool right_may_be_negative =
2249 (right_range == NULL) || 2251 (right_range == NULL) ||
(...skipping 30 matching lines...) Expand all
2280 __ movq(temp, left); 2282 __ movq(temp, left);
2281 __ SmiUntag(right); 2283 __ SmiUntag(right);
2282 // Overflow test (preserve temp and right); 2284 // Overflow test (preserve temp and right);
2283 __ shlq(left, right); 2285 __ shlq(left, right);
2284 __ sarq(left, right); 2286 __ sarq(left, right);
2285 __ cmpq(left, temp); 2287 __ cmpq(left, temp);
2286 __ j(NOT_EQUAL, deopt); // Overflow. 2288 __ j(NOT_EQUAL, deopt); // Overflow.
2287 // Shift for result now we know there is no overflow. 2289 // Shift for result now we know there is no overflow.
2288 __ shlq(left, right); 2290 __ shlq(left, right);
2289 } 2291 }
2290 Emit53BitOverflowCheck(compiler, deopt, result); 2292 Emit54BitOverflowCheck(compiler, deopt, result);
2291 } 2293 }
2292 2294
2293 2295
2294 static bool CanBeImmediate(const Object& constant) { 2296 static bool CanBeImmediate(const Object& constant) {
2295 return constant.IsSmi() && 2297 return constant.IsSmi() &&
2296 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); 2298 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
2297 } 2299 }
2298 2300
2299 2301
2300 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { 2302 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
2479 2481
2480 __ sarq(left, Immediate(value)); 2482 __ sarq(left, Immediate(value));
2481 __ SmiTag(left); 2483 __ SmiTag(left);
2482 break; 2484 break;
2483 } 2485 }
2484 2486
2485 default: 2487 default:
2486 UNREACHABLE(); 2488 UNREACHABLE();
2487 break; 2489 break;
2488 } 2490 }
2489 Emit53BitOverflowCheck(compiler, deopt, result); 2491 Emit54BitOverflowCheck(compiler, deopt, result);
2490 return; 2492 return;
2491 } // locs()->in(1).IsConstant(). 2493 } // locs()->in(1).IsConstant().
2492 2494
2493 2495
2494 if (locs()->in(1).IsStackSlot()) { 2496 if (locs()->in(1).IsStackSlot()) {
2495 const Address& right = locs()->in(1).ToStackSlotAddress(); 2497 const Address& right = locs()->in(1).ToStackSlotAddress();
2496 switch (op_kind()) { 2498 switch (op_kind()) {
2497 case Token::kADD: { 2499 case Token::kADD: {
2498 __ addq(left, right); 2500 __ addq(left, right);
2499 if (deopt != NULL) __ j(OVERFLOW, deopt); 2501 if (deopt != NULL) __ j(OVERFLOW, deopt);
(...skipping 22 matching lines...) Expand all
2522 } 2524 }
2523 case Token::kBIT_XOR: { 2525 case Token::kBIT_XOR: {
2524 // No overflow check. 2526 // No overflow check.
2525 __ xorq(left, right); 2527 __ xorq(left, right);
2526 break; 2528 break;
2527 } 2529 }
2528 default: 2530 default:
2529 UNREACHABLE(); 2531 UNREACHABLE();
2530 break; 2532 break;
2531 } 2533 }
2532 Emit53BitOverflowCheck(compiler, deopt, result); 2534 Emit54BitOverflowCheck(compiler, deopt, result);
2533 return; 2535 return;
2534 } // locs()->in(1).IsStackSlot(). 2536 } // locs()->in(1).IsStackSlot().
2535 2537
2536 // if locs()->in(1).IsRegister. 2538 // if locs()->in(1).IsRegister.
2537 Register right = locs()->in(1).reg(); 2539 Register right = locs()->in(1).reg();
2538 switch (op_kind()) { 2540 switch (op_kind()) {
2539 case Token::kADD: { 2541 case Token::kADD: {
2540 __ addq(left, right); 2542 __ addq(left, right);
2541 if (deopt != NULL) __ j(OVERFLOW, deopt); 2543 if (deopt != NULL) __ j(OVERFLOW, deopt);
2542 break; 2544 break;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
2652 case Token::kAND: { 2654 case Token::kAND: {
2653 // Flow graph builder has dissected this operation to guarantee correct 2655 // Flow graph builder has dissected this operation to guarantee correct
2654 // behavior (short-circuit evaluation). 2656 // behavior (short-circuit evaluation).
2655 UNREACHABLE(); 2657 UNREACHABLE();
2656 break; 2658 break;
2657 } 2659 }
2658 default: 2660 default:
2659 UNREACHABLE(); 2661 UNREACHABLE();
2660 break; 2662 break;
2661 } 2663 }
2662 Emit53BitOverflowCheck(compiler, deopt, result); 2664 Emit54BitOverflowCheck(compiler, deopt, result);
2663 } 2665 }
2664 2666
2665 2667
2666 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { 2668 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
2667 intptr_t left_cid = left()->Type()->ToCid(); 2669 intptr_t left_cid = left()->Type()->ToCid();
2668 intptr_t right_cid = right()->Type()->ToCid(); 2670 intptr_t right_cid = right()->Type()->ToCid();
2669 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); 2671 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
2670 const intptr_t kNumInputs = 2; 2672 const intptr_t kNumInputs = 2;
2671 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); 2673 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid);
2672 const intptr_t kNumTemps = need_temp ? 1 : 0; 2674 const intptr_t kNumTemps = need_temp ? 1 : 0;
(...skipping 1160 matching lines...) Expand 10 before | Expand all | Expand 10 after
3833 3835
3834 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3836 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
3835 Register value = locs()->in(0).reg(); 3837 Register value = locs()->in(0).reg();
3836 ASSERT(value == locs()->out().reg()); 3838 ASSERT(value == locs()->out().reg());
3837 switch (op_kind()) { 3839 switch (op_kind()) {
3838 case Token::kNEGATE: { 3840 case Token::kNEGATE: {
3839 Label* deopt = compiler->AddDeoptStub(deopt_id(), 3841 Label* deopt = compiler->AddDeoptStub(deopt_id(),
3840 kDeoptUnaryOp); 3842 kDeoptUnaryOp);
3841 __ negq(value); 3843 __ negq(value);
3842 __ j(OVERFLOW, deopt); 3844 __ j(OVERFLOW, deopt);
3843 Emit53BitOverflowCheck(compiler, deopt, value); 3845 Emit54BitOverflowCheck(compiler, deopt, value);
3844 break; 3846 break;
3845 } 3847 }
3846 case Token::kBIT_NOT: 3848 case Token::kBIT_NOT:
3847 __ notq(value); 3849 __ notq(value);
3848 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. 3850 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
3849 break; 3851 break;
3850 default: 3852 default:
3851 UNREACHABLE(); 3853 UNREACHABLE();
3852 } 3854 }
3853 } 3855 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
3894 ASSERT(result != temp); 3896 ASSERT(result != temp);
3895 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset())); 3897 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset()));
3896 __ cvttsd2siq(result, value_double); 3898 __ cvttsd2siq(result, value_double);
3897 // Overflow is signalled with minint. 3899 // Overflow is signalled with minint.
3898 Label do_call, done; 3900 Label do_call, done;
3899 // Check for overflow and that it fits into Smi. 3901 // Check for overflow and that it fits into Smi.
3900 __ movq(temp, result); 3902 __ movq(temp, result);
3901 __ shlq(temp, Immediate(1)); 3903 __ shlq(temp, Immediate(1));
3902 __ j(OVERFLOW, &do_call, Assembler::kNearJump); 3904 __ j(OVERFLOW, &do_call, Assembler::kNearJump);
3903 __ SmiTag(result); 3905 __ SmiTag(result);
3904 Emit53BitOverflowCheck(compiler, &do_call, result); 3906 Emit54BitOverflowCheck(compiler, &do_call, result);
3905 __ jmp(&done); 3907 __ jmp(&done);
3906 __ Bind(&do_call); 3908 __ Bind(&do_call);
3907 ASSERT(instance_call()->HasICData()); 3909 ASSERT(instance_call()->HasICData());
3908 const ICData& ic_data = *instance_call()->ic_data(); 3910 const ICData& ic_data = *instance_call()->ic_data();
3909 ASSERT((ic_data.NumberOfChecks() == 1)); 3911 ASSERT((ic_data.NumberOfChecks() == 1));
3910 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 3912 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
3911 3913
3912 const intptr_t kNumberOfArguments = 1; 3914 const intptr_t kNumberOfArguments = 1;
3913 __ pushq(value_obj); 3915 __ pushq(value_obj);
3914 compiler->GenerateStaticCall(deopt_id(), 3916 compiler->GenerateStaticCall(deopt_id(),
(...skipping 25 matching lines...) Expand all
3940 Register temp = locs()->temp(0).reg(); 3942 Register temp = locs()->temp(0).reg();
3941 3943
3942 __ cvttsd2siq(result, value); 3944 __ cvttsd2siq(result, value);
3943 // Overflow is signalled with minint. 3945 // Overflow is signalled with minint.
3944 Label do_call, done; 3946 Label do_call, done;
3945 // Check for overflow and that it fits into Smi. 3947 // Check for overflow and that it fits into Smi.
3946 __ movq(temp, result); 3948 __ movq(temp, result);
3947 __ shlq(temp, Immediate(1)); 3949 __ shlq(temp, Immediate(1));
3948 __ j(OVERFLOW, deopt); 3950 __ j(OVERFLOW, deopt);
3949 __ SmiTag(result); 3951 __ SmiTag(result);
3950 Emit53BitOverflowCheck(compiler, deopt, result); 3952 Emit54BitOverflowCheck(compiler, deopt, result);
3951 } 3953 }
3952 3954
3953 3955
3954 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { 3956 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
3955 const intptr_t kNumInputs = 1; 3957 const intptr_t kNumInputs = 1;
3956 const intptr_t kNumTemps = 0; 3958 const intptr_t kNumTemps = 0;
3957 LocationSummary* result = 3959 LocationSummary* result =
3958 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 3960 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
3959 result->set_in(0, Location::RequiresFpuRegister()); 3961 result->set_in(0, Location::RequiresFpuRegister());
3960 result->set_out(Location::RequiresFpuRegister()); 3962 result->set_out(Location::RequiresFpuRegister());
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after
4551 PcDescriptors::kOther, 4553 PcDescriptors::kOther,
4552 locs()); 4554 locs());
4553 __ Drop(2); // Discard type arguments and receiver. 4555 __ Drop(2); // Discard type arguments and receiver.
4554 } 4556 }
4555 4557
4556 } // namespace dart 4558 } // namespace dart
4557 4559
4558 #undef __ 4560 #undef __
4559 4561
4560 #endif // defined TARGET_ARCH_X64 4562 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/exceptions.cc ('k') | runtime/vm/object.h » ('j') | runtime/vm/object.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698