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

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
« no previous file with comments | « no previous file | runtime/vm/intrinsifier.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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) {
srdjan 2013/06/06 21:59:02 I think that it should be ASSERT(overflow != NULL)
Ivan Posva 2013/06/06 22:10:18 Actually if that flag is set we should just assume
2137 if (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
2149
2132 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, 2150 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
2133 BinarySmiOpInstr* shift_left) { 2151 BinarySmiOpInstr* shift_left) {
2134 const bool is_truncating = shift_left->is_truncating(); 2152 const bool is_truncating = shift_left->is_truncating();
2135 const LocationSummary& locs = *shift_left->locs(); 2153 const LocationSummary& locs = *shift_left->locs();
2136 Register left = locs.in(0).reg(); 2154 Register left = locs.in(0).reg();
2137 Register result = locs.out().reg(); 2155 Register result = locs.out().reg();
2138 ASSERT(left == result); 2156 ASSERT(left == result);
2139 Label* deopt = shift_left->CanDeoptimize() ? 2157 Label* deopt = shift_left->CanDeoptimize() ?
Ivan Posva 2013/06/06 22:10:18 For example here we should assume that we can alwa
2140 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL; 2158 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL;
2141 if (locs.in(1).IsConstant()) { 2159 if (locs.in(1).IsConstant()) {
2142 const Object& constant = locs.in(1).constant(); 2160 const Object& constant = locs.in(1).constant();
2143 ASSERT(constant.IsSmi()); 2161 ASSERT(constant.IsSmi());
2144 // shlq operation masks the count to 6 bits. 2162 // shlq operation masks the count to 6 bits.
2145 const intptr_t kCountLimit = 0x3F; 2163 const intptr_t kCountLimit = 0x3F;
2146 const intptr_t value = Smi::Cast(constant).Value(); 2164 const intptr_t value = Smi::Cast(constant).Value();
2147 if (value == 0) { 2165 if (value == 0) {
2148 // No code needed. 2166 // No code needed.
2149 } else if ((value < 0) || (value >= kCountLimit)) { 2167 } else if ((value < 0) || (value >= kCountLimit)) {
(...skipping 11 matching lines...) Expand all
2161 Register temp = locs.temp(0).reg(); 2179 Register temp = locs.temp(0).reg();
2162 __ movq(temp, left); 2180 __ movq(temp, left);
2163 __ shlq(left, Immediate(value)); 2181 __ shlq(left, Immediate(value));
2164 __ sarq(left, Immediate(value)); 2182 __ sarq(left, Immediate(value));
2165 __ cmpq(left, temp); 2183 __ cmpq(left, temp);
2166 __ j(NOT_EQUAL, deopt); // Overflow. 2184 __ j(NOT_EQUAL, deopt); // Overflow.
2167 } 2185 }
2168 // Shift for result now we know there is no overflow. 2186 // Shift for result now we know there is no overflow.
2169 __ shlq(left, Immediate(value)); 2187 __ shlq(left, Immediate(value));
2170 } 2188 }
2189 Emit53BitOverflowCheck(compiler, deopt, result);
2171 return; 2190 return;
2172 } 2191 }
2173 2192
2174 // Right (locs.in(1)) is not constant. 2193 // Right (locs.in(1)) is not constant.
2175 Register right = locs.in(1).reg(); 2194 Register right = locs.in(1).reg();
2176 Range* right_range = shift_left->right()->definition()->range(); 2195 Range* right_range = shift_left->right()->definition()->range();
2177 if (shift_left->left()->BindsToConstant() && !is_truncating) { 2196 if (shift_left->left()->BindsToConstant() && !is_truncating) {
2178 // TODO(srdjan): Implement code below for is_truncating(). 2197 // TODO(srdjan): Implement code below for is_truncating().
2179 // If left is constant, we know the maximal allowed size for right. 2198 // If left is constant, we know the maximal allowed size for right.
2180 const Object& obj = shift_left->left()->BoundConstant(); 2199 const Object& obj = shift_left->left()->BoundConstant();
2181 if (obj.IsSmi()) { 2200 if (obj.IsSmi()) {
2182 const intptr_t left_int = Smi::Cast(obj).Value(); 2201 const intptr_t left_int = Smi::Cast(obj).Value();
2183 if (left_int == 0) { 2202 if (left_int == 0) {
2184 __ cmpq(right, Immediate(0)); 2203 __ cmpq(right, Immediate(0));
2185 __ j(NEGATIVE, deopt); 2204 __ j(NEGATIVE, deopt);
2186 return; 2205 return;
2187 } 2206 }
2188 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int); 2207 const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
2189 const bool right_needs_check = 2208 const bool right_needs_check =
2190 (right_range == NULL) || 2209 (right_range == NULL) ||
2191 !right_range->IsWithin(0, max_right - 1); 2210 !right_range->IsWithin(0, max_right - 1);
2192 if (right_needs_check) { 2211 if (right_needs_check) {
2193 __ cmpq(right, 2212 __ cmpq(right,
2194 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right)))); 2213 Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
2195 __ j(ABOVE_EQUAL, deopt); 2214 __ j(ABOVE_EQUAL, deopt);
2196 } 2215 }
2197 __ SmiUntag(right); 2216 __ SmiUntag(right);
2198 __ shlq(left, right); 2217 __ shlq(left, right);
2199 } 2218 }
2219 Emit53BitOverflowCheck(compiler, deopt, result);
2200 return; 2220 return;
2201 } 2221 }
2202 2222
2203 const bool right_needs_check = 2223 const bool right_needs_check =
2204 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); 2224 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
2205 ASSERT(right == RCX); // Count must be in RCX 2225 ASSERT(right == RCX); // Count must be in RCX
2206 if (is_truncating) { 2226 if (is_truncating) {
2207 if (right_needs_check) { 2227 if (right_needs_check) {
2208 const bool right_may_be_negative = 2228 const bool right_may_be_negative =
2209 (right_range == NULL) || 2229 (right_range == NULL) ||
(...skipping 30 matching lines...) Expand all
2240 __ movq(temp, left); 2260 __ movq(temp, left);
2241 __ SmiUntag(right); 2261 __ SmiUntag(right);
2242 // Overflow test (preserve temp and right); 2262 // Overflow test (preserve temp and right);
2243 __ shlq(left, right); 2263 __ shlq(left, right);
2244 __ sarq(left, right); 2264 __ sarq(left, right);
2245 __ cmpq(left, temp); 2265 __ cmpq(left, temp);
2246 __ j(NOT_EQUAL, deopt); // Overflow. 2266 __ j(NOT_EQUAL, deopt); // Overflow.
2247 // Shift for result now we know there is no overflow. 2267 // Shift for result now we know there is no overflow.
2248 __ shlq(left, right); 2268 __ shlq(left, right);
2249 } 2269 }
2270 Emit53BitOverflowCheck(compiler, deopt, result);
2250 } 2271 }
2251 2272
2252 2273
2253 static bool CanBeImmediate(const Object& constant) { 2274 static bool CanBeImmediate(const Object& constant) {
2254 return constant.IsSmi() && 2275 return constant.IsSmi() &&
2255 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32(); 2276 Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
2256 } 2277 }
2257 2278
2258 2279
2259 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { 2280 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
2332 if (op_kind() == Token::kSHL) { 2353 if (op_kind() == Token::kSHL) {
2333 EmitSmiShiftLeft(compiler, this); 2354 EmitSmiShiftLeft(compiler, this);
2334 return; 2355 return;
2335 } 2356 }
2336 2357
2337 ASSERT(!is_truncating()); 2358 ASSERT(!is_truncating());
2338 Register left = locs()->in(0).reg(); 2359 Register left = locs()->in(0).reg();
2339 Register result = locs()->out().reg(); 2360 Register result = locs()->out().reg();
2340 ASSERT(left == result); 2361 ASSERT(left == result);
2341 Label* deopt = NULL; 2362 Label* deopt = NULL;
2342 if (CanDeoptimize()) { 2363 if (CanDeoptimize()) {
Ivan Posva 2013/06/06 22:10:18 For example right here.
2343 deopt = compiler->AddDeoptStub(deopt_id(), 2364 deopt = compiler->AddDeoptStub(deopt_id(),
2344 kDeoptBinarySmiOp); 2365 kDeoptBinarySmiOp);
2345 } 2366 }
2346 2367
2347 if (locs()->in(1).IsConstant()) { 2368 if (locs()->in(1).IsConstant()) {
2348 const Object& constant = locs()->in(1).constant(); 2369 const Object& constant = locs()->in(1).constant();
2349 ASSERT(constant.IsSmi()); 2370 ASSERT(constant.IsSmi());
2350 const int64_t imm = 2371 const int64_t imm =
2351 reinterpret_cast<int64_t>(constant.raw()); 2372 reinterpret_cast<int64_t>(constant.raw());
2352 switch (op_kind()) { 2373 switch (op_kind()) {
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
2438 2459
2439 __ sarq(left, Immediate(value)); 2460 __ sarq(left, Immediate(value));
2440 __ SmiTag(left); 2461 __ SmiTag(left);
2441 break; 2462 break;
2442 } 2463 }
2443 2464
2444 default: 2465 default:
2445 UNREACHABLE(); 2466 UNREACHABLE();
2446 break; 2467 break;
2447 } 2468 }
2469 Emit53BitOverflowCheck(compiler, deopt, result);
2448 return; 2470 return;
2449 } // locs()->in(1).IsConstant(). 2471 } // locs()->in(1).IsConstant().
2450 2472
2451 2473
2452 if (locs()->in(1).IsStackSlot()) { 2474 if (locs()->in(1).IsStackSlot()) {
2453 const Address& right = locs()->in(1).ToStackSlotAddress(); 2475 const Address& right = locs()->in(1).ToStackSlotAddress();
2454 switch (op_kind()) { 2476 switch (op_kind()) {
2455 case Token::kADD: { 2477 case Token::kADD: {
2456 __ addq(left, right); 2478 __ addq(left, right);
2457 if (deopt != NULL) __ j(OVERFLOW, deopt); 2479 if (deopt != NULL) __ j(OVERFLOW, deopt);
(...skipping 22 matching lines...) Expand all
2480 } 2502 }
2481 case Token::kBIT_XOR: { 2503 case Token::kBIT_XOR: {
2482 // No overflow check. 2504 // No overflow check.
2483 __ xorq(left, right); 2505 __ xorq(left, right);
2484 break; 2506 break;
2485 } 2507 }
2486 default: 2508 default:
2487 UNREACHABLE(); 2509 UNREACHABLE();
2488 break; 2510 break;
2489 } 2511 }
2512 Emit53BitOverflowCheck(compiler, deopt, result);
2490 return; 2513 return;
2491 } // locs()->in(1).IsStackSlot(). 2514 } // locs()->in(1).IsStackSlot().
2492 2515
2493 // if locs()->in(1).IsRegister. 2516 // if locs()->in(1).IsRegister.
2494 Register right = locs()->in(1).reg(); 2517 Register right = locs()->in(1).reg();
2495 switch (op_kind()) { 2518 switch (op_kind()) {
2496 case Token::kADD: { 2519 case Token::kADD: {
2497 __ addq(left, right); 2520 __ addq(left, right);
2498 if (deopt != NULL) __ j(OVERFLOW, deopt); 2521 if (deopt != NULL) __ j(OVERFLOW, deopt);
2499 break; 2522 break;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
2609 case Token::kAND: { 2632 case Token::kAND: {
2610 // Flow graph builder has dissected this operation to guarantee correct 2633 // Flow graph builder has dissected this operation to guarantee correct
2611 // behavior (short-circuit evaluation). 2634 // behavior (short-circuit evaluation).
2612 UNREACHABLE(); 2635 UNREACHABLE();
2613 break; 2636 break;
2614 } 2637 }
2615 default: 2638 default:
2616 UNREACHABLE(); 2639 UNREACHABLE();
2617 break; 2640 break;
2618 } 2641 }
2642 Emit53BitOverflowCheck(compiler, deopt, result);
2619 } 2643 }
2620 2644
2621 2645
2622 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const { 2646 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
2623 intptr_t left_cid = left()->Type()->ToCid(); 2647 intptr_t left_cid = left()->Type()->ToCid();
2624 intptr_t right_cid = right()->Type()->ToCid(); 2648 intptr_t right_cid = right()->Type()->ToCid();
2625 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); 2649 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
2626 const intptr_t kNumInputs = 2; 2650 const intptr_t kNumInputs = 2;
2627 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid); 2651 const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid);
2628 const intptr_t kNumTemps = need_temp ? 1 : 0; 2652 const intptr_t kNumTemps = need_temp ? 1 : 0;
(...skipping 1098 matching lines...) Expand 10 before | Expand all | Expand 10 after
3727 ASSERT(result != temp); 3751 ASSERT(result != temp);
3728 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset())); 3752 __ movsd(value_double, FieldAddress(value_obj, Double::value_offset()));
3729 __ cvttsd2siq(result, value_double); 3753 __ cvttsd2siq(result, value_double);
3730 // Overflow is signalled with minint. 3754 // Overflow is signalled with minint.
3731 Label do_call, done; 3755 Label do_call, done;
3732 // Check for overflow and that it fits into Smi. 3756 // Check for overflow and that it fits into Smi.
3733 __ movq(temp, result); 3757 __ movq(temp, result);
3734 __ shlq(temp, Immediate(1)); 3758 __ shlq(temp, Immediate(1));
3735 __ j(OVERFLOW, &do_call, Assembler::kNearJump); 3759 __ j(OVERFLOW, &do_call, Assembler::kNearJump);
3736 __ SmiTag(result); 3760 __ SmiTag(result);
3761 Emit53BitOverflowCheck(compiler, &do_call, result);
3737 __ jmp(&done); 3762 __ jmp(&done);
3738 __ Bind(&do_call); 3763 __ Bind(&do_call);
3739 ASSERT(instance_call()->HasICData()); 3764 ASSERT(instance_call()->HasICData());
3740 const ICData& ic_data = *instance_call()->ic_data(); 3765 const ICData& ic_data = *instance_call()->ic_data();
3741 ASSERT((ic_data.NumberOfChecks() == 1)); 3766 ASSERT((ic_data.NumberOfChecks() == 1));
3742 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 3767 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
3743 3768
3744 const intptr_t kNumberOfArguments = 1; 3769 const intptr_t kNumberOfArguments = 1;
3745 __ pushq(value_obj); 3770 __ pushq(value_obj);
3746 compiler->GenerateStaticCall(deopt_id(), 3771 compiler->GenerateStaticCall(deopt_id(),
(...skipping 25 matching lines...) Expand all
3772 Register temp = locs()->temp(0).reg(); 3797 Register temp = locs()->temp(0).reg();
3773 3798
3774 __ cvttsd2siq(result, value); 3799 __ cvttsd2siq(result, value);
3775 // Overflow is signalled with minint. 3800 // Overflow is signalled with minint.
3776 Label do_call, done; 3801 Label do_call, done;
3777 // Check for overflow and that it fits into Smi. 3802 // Check for overflow and that it fits into Smi.
3778 __ movq(temp, result); 3803 __ movq(temp, result);
3779 __ shlq(temp, Immediate(1)); 3804 __ shlq(temp, Immediate(1));
3780 __ j(OVERFLOW, deopt); 3805 __ j(OVERFLOW, deopt);
3781 __ SmiTag(result); 3806 __ SmiTag(result);
3807 Emit53BitOverflowCheck(compiler, deopt, result);
3782 } 3808 }
3783 3809
3784 3810
3785 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { 3811 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
3786 const intptr_t kNumInputs = 1; 3812 const intptr_t kNumInputs = 1;
3787 const intptr_t kNumTemps = 0; 3813 const intptr_t kNumTemps = 0;
3788 LocationSummary* result = 3814 LocationSummary* result =
3789 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 3815 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
3790 result->set_in(0, Location::RequiresFpuRegister()); 3816 result->set_in(0, Location::RequiresFpuRegister());
3791 result->set_out(Location::RequiresFpuRegister()); 3817 result->set_out(Location::RequiresFpuRegister());
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
4389 PcDescriptors::kOther, 4415 PcDescriptors::kOther,
4390 locs()); 4416 locs());
4391 __ Drop(2); // Discard type arguments and receiver. 4417 __ Drop(2); // Discard type arguments and receiver.
4392 } 4418 }
4393 4419
4394 } // namespace dart 4420 } // namespace dart
4395 4421
4396 #undef __ 4422 #undef __
4397 4423
4398 #endif // defined TARGET_ARCH_X64 4424 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intrinsifier.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698