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

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

Issue 16398008: Implements checks for 53-bit overflow for x64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 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"
11 #include "vm/dart_entry.h" 11 #include "vm/dart_entry.h"
12 #include "vm/flow_graph_compiler.h" 12 #include "vm/flow_graph_compiler.h"
13 #include "vm/locations.h" 13 #include "vm/locations.h"
14 #include "vm/object_store.h" 14 #include "vm/object_store.h"
15 #include "vm/parser.h" 15 #include "vm/parser.h"
16 #include "vm/stack_frame.h" 16 #include "vm/stack_frame.h"
17 #include "vm/stub_code.h" 17 #include "vm/stub_code.h"
18 #include "vm/symbols.h" 18 #include "vm/symbols.h"
19 19
20 #define __ compiler->assembler()-> 20 #define __ compiler->assembler()->
21 21
22 namespace dart { 22 namespace dart {
23 23
24 DECLARE_FLAG(int, optimization_counter_threshold); 24 DECLARE_FLAG(int, optimization_counter_threshold);
25 DECLARE_FLAG(bool, propagate_ic_data); 25 DECLARE_FLAG(bool, propagate_ic_data);
26 DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
26 27
27 // Generic summary for call instructions that have all arguments pushed 28 // Generic summary for call instructions that have all arguments pushed
28 // on the stack and return the result in a fixed register RAX. 29 // on the stack and return the result in a fixed register RAX.
29 LocationSummary* Instruction::MakeCallSummary() { 30 LocationSummary* Instruction::MakeCallSummary() {
30 LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall); 31 LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall);
31 result->set_out(Location::RegisterLocation(RAX)); 32 result->set_out(Location::RegisterLocation(RAX));
32 return result; 33 return result;
33 } 34 }
34 35
35 36
(...skipping 2086 matching lines...) Expand 10 before | Expand all | Expand 10 after
2122 2123
2123 Register temp = locs()->temp(0).reg(); 2124 Register temp = locs()->temp(0).reg();
2124 // Generate stack overflow check. 2125 // Generate stack overflow check.
2125 __ movq(temp, Immediate(Isolate::Current()->stack_limit_address())); 2126 __ movq(temp, Immediate(Isolate::Current()->stack_limit_address()));
2126 __ cmpq(RSP, Address(temp, 0)); 2127 __ cmpq(RSP, Address(temp, 0));
2127 __ j(BELOW_EQUAL, slow_path->entry_label()); 2128 __ j(BELOW_EQUAL, slow_path->entry_label());
2128 __ Bind(slow_path->exit_label()); 2129 __ Bind(slow_path->exit_label());
2129 } 2130 }
2130 2131
2131 2132
2133 static void Emit53BitOverflowCheck(FlowGraphCompiler* compiler,
2134 Label* overflow,
2135 Register result) {
2136 if (FLAG_throw_on_javascript_int_overflow) {
2137 ASSERT(overflow != NULL);
2138 __ movq(TMP, result); // result is a tagged Smi.
2139 // Bits 54...64 must be all 0 or all 1. (It would be bit 53, but result
2140 // is tagged.)
2141 __ shlq(result, Immediate(64 - 54));
2142 __ sarq(result, Immediate(64 - 54));
2143 __ cmpq(result, TMP);
2144 __ j(NOT_EQUAL, overflow); // 53-bit overflow.
2145 }
2146 }
2147
2148
2132 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, 2149 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
2133 BinarySmiOpInstr* shift_left) { 2150 BinarySmiOpInstr* shift_left) {
2134 const bool is_truncating = shift_left->is_truncating(); 2151 const bool is_truncating = shift_left->is_truncating();
2135 const LocationSummary& locs = *shift_left->locs(); 2152 const LocationSummary& locs = *shift_left->locs();
2136 Register left = locs.in(0).reg(); 2153 Register left = locs.in(0).reg();
2137 Register result = locs.out().reg(); 2154 Register result = locs.out().reg();
2138 ASSERT(left == result); 2155 ASSERT(left == result);
2139 Label* deopt = shift_left->CanDeoptimize() ? 2156 Label* deopt = shift_left->CanDeoptimize() ?
2140 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL; 2157 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL;
2141 if (locs.in(1).IsConstant()) { 2158 if (locs.in(1).IsConstant()) {
(...skipping 19 matching lines...) Expand all
2161 Register temp = locs.temp(0).reg(); 2178 Register temp = locs.temp(0).reg();
2162 __ movq(temp, left); 2179 __ movq(temp, left);
2163 __ shlq(left, Immediate(value)); 2180 __ shlq(left, Immediate(value));
2164 __ sarq(left, Immediate(value)); 2181 __ sarq(left, Immediate(value));
2165 __ cmpq(left, temp); 2182 __ cmpq(left, temp);
2166 __ j(NOT_EQUAL, deopt); // Overflow. 2183 __ j(NOT_EQUAL, deopt); // Overflow.
2167 } 2184 }
2168 // Shift for result now we know there is no overflow. 2185 // Shift for result now we know there is no overflow.
2169 __ shlq(left, Immediate(value)); 2186 __ shlq(left, Immediate(value));
2170 } 2187 }
2188 Emit53BitOverflowCheck(compiler, deopt, result);
2171 return; 2189 return;
2172 } 2190 }
2173 2191
2174 // Right (locs.in(1)) is not constant. 2192 // Right (locs.in(1)) is not constant.
2175 Register right = locs.in(1).reg(); 2193 Register right = locs.in(1).reg();
2176 Range* right_range = shift_left->right()->definition()->range(); 2194 Range* right_range = shift_left->right()->definition()->range();
2177 if (shift_left->left()->BindsToConstant() && !is_truncating) { 2195 if (shift_left->left()->BindsToConstant() && !is_truncating) {
2178 // TODO(srdjan): Implement code below for is_truncating(). 2196 // TODO(srdjan): Implement code below for is_truncating().
2179 // If left is constant, we know the maximal allowed size for right. 2197 // If left is constant, we know the maximal allowed size for right.
2180 const Object& obj = shift_left->left()->BoundConstant(); 2198 const Object& obj = shift_left->left()->BoundConstant();
2181 if (obj.IsSmi()) { 2199 if (obj.IsSmi()) {
2182 const intptr_t left_int = Smi::Cast(obj).Value(); 2200 const intptr_t left_int = Smi::Cast(obj).Value();
2183 if (left_int == 0) { 2201 if (left_int == 0) {
2184 __ cmpq(right, Immediate(0)); 2202 __ cmpq(right, Immediate(0));
2185 __ j(NEGATIVE, deopt); 2203 __ j(NEGATIVE, deopt);
2186 return; 2204 return;
2187 } 2205 }
2188 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); 2206 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
2189 const bool right_needs_check = 2207 const bool right_needs_check =
2190 (right_range == NULL) || 2208 (right_range == NULL) ||
2191 !right_range->IsWithin(0, max_right - 1); 2209 !right_range->IsWithin(0, max_right - 1);
2192 if (right_needs_check) { 2210 if (right_needs_check) {
2193 __ cmpq(right, 2211 __ cmpq(right,
2194 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); 2212 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
2195 __ j(ABOVE_EQUAL, deopt); 2213 __ j(ABOVE_EQUAL, deopt);
2196 } 2214 }
2197 __ SmiUntag(right); 2215 __ SmiUntag(right);
2198 __ shlq(left, right); 2216 __ shlq(left, right);
2199 } 2217 }
2218 Emit53BitOverflowCheck(compiler, deopt, result);
2200 return; 2219 return;
2201 } 2220 }
2202 2221
2203 const bool right_needs_check = 2222 const bool right_needs_check =
2204 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); 2223 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
2205 ASSERT(right == RCX); // Count must be in RCX 2224 ASSERT(right == RCX); // Count must be in RCX
2206 if (is_truncating) { 2225 if (is_truncating) {
2207 if (right_needs_check) { 2226 if (right_needs_check) {
2208 const bool right_may_be_negative = 2227 const bool right_may_be_negative =
2209 (right_range == NULL) || 2228 (right_range == NULL) ||
(...skipping 30 matching lines...) Expand all
2240 __ movq(temp, left); 2259 __ movq(temp, left);
2241 __ SmiUntag(right); 2260 __ SmiUntag(right);
2242 // Overflow test (preserve temp and right); 2261 // Overflow test (preserve temp and right);
2243 __ shlq(left, right); 2262 __ shlq(left, right);
2244 __ sarq(left, right); 2263 __ sarq(left, right);
2245 __ cmpq(left, temp); 2264 __ cmpq(left, temp);
2246 __ j(NOT_EQUAL, deopt); // Overflow. 2265 __ j(NOT_EQUAL, deopt); // Overflow.
2247 // Shift for result now we know there is no overflow. 2266 // Shift for result now we know there is no overflow.
2248 __ shlq(left, right); 2267 __ shlq(left, right);
2249 } 2268 }
2269 Emit53BitOverflowCheck(compiler, deopt, result);
2250 } 2270 }
2251 2271
2252 2272
2253 static bool CanBeImmediate(const Object& constant) { 2273 static bool CanBeImmediate(const Object& constant) {
2254 return constant.IsSmi() && 2274 return constant.IsSmi() &&
2255 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); 2275 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
2256 } 2276 }
2257 2277
2258 2278
2259 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { 2279 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
2438 2458
2439 __ sarq(left, Immediate(value)); 2459 __ sarq(left, Immediate(value));
2440 __ SmiTag(left); 2460 __ SmiTag(left);
2441 break; 2461 break;
2442 } 2462 }
2443 2463
2444 default: 2464 default:
2445 UNREACHABLE(); 2465 UNREACHABLE();
2446 break; 2466 break;
2447 } 2467 }
2468 Emit53BitOverflowCheck(compiler, deopt, result);
2448 return; 2469 return;
2449 } // locs()->in(1).IsConstant(). 2470 } // locs()->in(1).IsConstant().
2450 2471
2451 2472
2452 if (locs()->in(1).IsStackSlot()) { 2473 if (locs()->in(1).IsStackSlot()) {
2453 const Address& right = locs()->in(1).ToStackSlotAddress(); 2474 const Address& right = locs()->in(1).ToStackSlotAddress();
2454 switch (op_kind()) { 2475 switch (op_kind()) {
2455 case Token::kADD: { 2476 case Token::kADD: {
2456 __ addq(left, right); 2477 __ addq(left, right);
2457 if (deopt != NULL) __ j(OVERFLOW, deopt); 2478 if (deopt != NULL) __ j(OVERFLOW, deopt);
(...skipping 22 matching lines...) Expand all
2480 } 2501 }
2481 case Token::kBIT_XOR: { 2502 case Token::kBIT_XOR: {
2482 // No overflow check. 2503 // No overflow check.
2483 __ xorq(left, right); 2504 __ xorq(left, right);
2484 break; 2505 break;
2485 } 2506 }
2486 default: 2507 default:
2487 UNREACHABLE(); 2508 UNREACHABLE();
2488 break; 2509 break;
2489 } 2510 }
2511 Emit53BitOverflowCheck(compiler, deopt, result);
2490 return; 2512 return;
2491 } // locs()->in(1).IsStackSlot(). 2513 } // locs()->in(1).IsStackSlot().
2492 2514
2493 // if locs()->in(1).IsRegister. 2515 // if locs()->in(1).IsRegister.
2494 Register right = locs()->in(1).reg(); 2516 Register right = locs()->in(1).reg();
2495 switch (op_kind()) { 2517 switch (op_kind()) {
2496 case Token::kADD: { 2518 case Token::kADD: {
2497 __ addq(left, right); 2519 __ addq(left, right);
2498 if (deopt != NULL) __ j(OVERFLOW, deopt); 2520 if (deopt != NULL) __ j(OVERFLOW, deopt);
2499 break; 2521 break;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
2609 case Token::kAND: { 2631 case Token::kAND: {
2610 // Flow graph builder has dissected this operation to guarantee correct 2632 // Flow graph builder has dissected this operation to guarantee correct
2611 // behavior (short-circuit evaluation). 2633 // behavior (short-circuit evaluation).
2612 UNREACHABLE(); 2634 UNREACHABLE();
2613 break; 2635 break;
2614 } 2636 }
2615 default: 2637 default:
2616 UNREACHABLE(); 2638 UNREACHABLE();
2617 break; 2639 break;
2618 } 2640 }
2641 Emit53BitOverflowCheck(compiler, deopt, result);
2619 } 2642 }
2620 2643
2621 2644
2622 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { 2645 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
2623 intptr_t left_cid = left()->Type()->ToCid(); 2646 intptr_t left_cid = left()->Type()->ToCid();
2624 intptr_t right_cid = right()->Type()->ToCid(); 2647 intptr_t right_cid = right()->Type()->ToCid();
2625 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); 2648 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
2626 const intptr_t kNumInputs = 2; 2649 const intptr_t kNumInputs = 2;
2627 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); 2650 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid);
2628 const intptr_t kNumTemps = need_temp ? 1 : 0; 2651 const intptr_t kNumTemps = need_temp ? 1 : 0;
(...skipping 1037 matching lines...) Expand 10 before | Expand all | Expand 10 after
3666 3689
3667 3690
3668 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3691 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
3669 Register value = locs()->in(0).reg(); 3692 Register value = locs()->in(0).reg();
3670 ASSERT(value == locs()->out().reg()); 3693 ASSERT(value == locs()->out().reg());
3671 switch (op_kind()) { 3694 switch (op_kind()) {
3672 case Token::kNEGATE: { 3695 case Token::kNEGATE: {
3673 Label* deopt = compiler->AddDeoptStub(deopt_id(), 3696 Label* deopt = compiler->AddDeoptStub(deopt_id(),
3674 kDeoptUnaryOp); 3697 kDeoptUnaryOp);
3675 __ negq(value); 3698 __ negq(value);
3676 __ j(OVERFLOW, deopt); 3699 __ j(OVERFLOW, deopt);
Florian Schneider 2013/06/07 07:33:15 What about this operation?
3677 break; 3700 break;
3678 } 3701 }
3679 case Token::kBIT_NOT: 3702 case Token::kBIT_NOT:
3680 __ notq(value); 3703 __ notq(value);
3681 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. 3704 __ andq(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
3682 break; 3705 break;
3683 default: 3706 default:
3684 UNREACHABLE(); 3707 UNREACHABLE();
3685 } 3708 }
3686 } 3709 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
3727 ASSERT(result != temp); 3750 ASSERT(result != temp);
3728 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset())); 3751 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset()));
3729 __ cvttsd2siq(result, value_double); 3752 __ cvttsd2siq(result, value_double);
3730 // Overflow is signalled with minint. 3753 // Overflow is signalled with minint.
3731 Label do_call, done; 3754 Label do_call, done;
3732 // Check for overflow and that it fits into Smi. 3755 // Check for overflow and that it fits into Smi.
3733 __ movq(temp, result); 3756 __ movq(temp, result);
3734 __ shlq(temp, Immediate(1)); 3757 __ shlq(temp, Immediate(1));
3735 __ j(OVERFLOW, &do_call, Assembler::kNearJump); 3758 __ j(OVERFLOW, &do_call, Assembler::kNearJump);
3736 __ SmiTag(result); 3759 __ SmiTag(result);
3760 Emit53BitOverflowCheck(compiler, &do_call, result);
3737 __ jmp(&done); 3761 __ jmp(&done);
3738 __ Bind(&do_call); 3762 __ Bind(&do_call);
3739 ASSERT(instance_call()->HasICData()); 3763 ASSERT(instance_call()->HasICData());
3740 const ICData& ic_data = *instance_call()->ic_data(); 3764 const ICData& ic_data = *instance_call()->ic_data();
3741 ASSERT((ic_data.NumberOfChecks() == 1)); 3765 ASSERT((ic_data.NumberOfChecks() == 1));
3742 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 3766 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
3743 3767
3744 const intptr_t kNumberOfArguments = 1; 3768 const intptr_t kNumberOfArguments = 1;
3745 __ pushq(value_obj); 3769 __ pushq(value_obj);
3746 compiler->GenerateStaticCall(deopt_id(), 3770 compiler->GenerateStaticCall(deopt_id(),
(...skipping 25 matching lines...) Expand all
3772 Register temp = locs()->temp(0).reg(); 3796 Register temp = locs()->temp(0).reg();
3773 3797
3774 __ cvttsd2siq(result, value); 3798 __ cvttsd2siq(result, value);
3775 // Overflow is signalled with minint. 3799 // Overflow is signalled with minint.
3776 Label do_call, done; 3800 Label do_call, done;
3777 // Check for overflow and that it fits into Smi. 3801 // Check for overflow and that it fits into Smi.
3778 __ movq(temp, result); 3802 __ movq(temp, result);
3779 __ shlq(temp, Immediate(1)); 3803 __ shlq(temp, Immediate(1));
3780 __ j(OVERFLOW, deopt); 3804 __ j(OVERFLOW, deopt);
3781 __ SmiTag(result); 3805 __ SmiTag(result);
3806 Emit53BitOverflowCheck(compiler, deopt, result);
3782 } 3807 }
3783 3808
3784 3809
3785 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { 3810 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
3786 const intptr_t kNumInputs = 1; 3811 const intptr_t kNumInputs = 1;
3787 const intptr_t kNumTemps = 0; 3812 const intptr_t kNumTemps = 0;
3788 LocationSummary* result = 3813 LocationSummary* result =
3789 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 3814 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
3790 result->set_in(0, Location::RequiresFpuRegister()); 3815 result->set_in(0, Location::RequiresFpuRegister());
3791 result->set_out(Location::RequiresFpuRegister()); 3816 result->set_out(Location::RequiresFpuRegister());
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
4389 PcDescriptors::kOther, 4414 PcDescriptors::kOther,
4390 locs()); 4415 locs());
4391 __ Drop(2); // Discard type arguments and receiver. 4416 __ Drop(2); // Discard type arguments and receiver.
4392 } 4417 }
4393 4418
4394 } // namespace dart 4419 } // namespace dart
4395 4420
4396 #undef __ 4421 #undef __
4397 4422
4398 #endif // defined TARGET_ARCH_X64 4423 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698