OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/bootstrap_natives.h" | 5 #include "vm/bootstrap_natives.h" |
6 | 6 |
7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
8 #include "vm/dart_entry.h" | 8 #include "vm/dart_entry.h" |
9 #include "vm/exceptions.h" | 9 #include "vm/exceptions.h" |
10 #include "vm/native_entry.h" | 10 #include "vm/native_entry.h" |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 return big.raw(); | 61 return big.raw(); |
62 } | 62 } |
63 } | 63 } |
64 | 64 |
65 | 65 |
66 static bool Are64bitOperands(const Integer& op1, const Integer& op2) { | 66 static bool Are64bitOperands(const Integer& op1, const Integer& op2) { |
67 return !op1.IsBigint() && !op2.IsBigint(); | 67 return !op1.IsBigint() && !op2.IsBigint(); |
68 } | 68 } |
69 | 69 |
70 | 70 |
71 static bool Are63bitOperands(const Integer& op1, const Integer& op2) { | |
72 if (op1.IsBigint() || op2.IsBigint()) { | |
73 return false; | |
74 } | |
75 const int64_t limit = (static_cast<int64_t>(1)) << 62; | |
76 const int64_t value1 = op1.AsInt64Value(); | |
77 if ((-limit > value1) || (value1 >= limit)) { | |
78 return false; | |
79 } | |
80 const int64_t value2 = op2.AsInt64Value(); | |
81 return (-limit <= value2) && (value2 < limit); | |
82 } | |
83 | |
84 | |
85 static RawInteger* IntegerBitOperation(Token::Kind kind, | 71 static RawInteger* IntegerBitOperation(Token::Kind kind, |
86 const Integer& op1_int, | 72 const Integer& op1_int, |
87 const Integer& op2_int) { | 73 const Integer& op2_int) { |
88 if (op1_int.IsSmi() && op2_int.IsSmi()) { | 74 if (op1_int.IsSmi() && op2_int.IsSmi()) { |
89 Smi& op1 = Smi::Handle(); | 75 Smi& op1 = Smi::Handle(); |
90 Smi& op2 = Smi::Handle(); | 76 Smi& op2 = Smi::Handle(); |
91 op1 ^= op1_int.raw(); | 77 op1 ^= op1_int.raw(); |
92 op2 ^= op2_int.raw(); | 78 op2 ^= op2_int.raw(); |
93 intptr_t result = 0; | 79 intptr_t result = 0; |
94 switch (kind) { | 80 switch (kind) { |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 default: | 219 default: |
234 UNIMPLEMENTED(); | 220 UNIMPLEMENTED(); |
235 return Bigint::null(); | 221 return Bigint::null(); |
236 } | 222 } |
237 } | 223 } |
238 | 224 |
239 | 225 |
240 static RawInteger* IntegerBinopHelper(Token::Kind operation, | 226 static RawInteger* IntegerBinopHelper(Token::Kind operation, |
241 const Integer& left_int, | 227 const Integer& left_int, |
242 const Integer& right_int) { | 228 const Integer& right_int) { |
243 // The result of any operation (except multiplication in 64-bit mode) between | 229 // In 32-bit mode, the result of any operation between two Smis will fit in a |
244 // two Smis will always fit in a 64-bit signed result (no overflow). | 230 // 32-bit signed result, except the product of two Smis, which will be 64-bit. |
245 if (((Smi::kBits < 32) || (operation != Token::kMUL)) && | 231 // In 64-bit mode, the result of any operation between two Smis will fit in a |
246 left_int.IsSmi() && right_int.IsSmi()) { | 232 // 64-bit signed result, except the product of two Smis (unless the Smis are |
| 233 // 32-bit or less). |
| 234 if (left_int.IsSmi() && right_int.IsSmi()) { |
247 Smi& left_smi = Smi::Handle(); | 235 Smi& left_smi = Smi::Handle(); |
248 Smi& right_smi = Smi::Handle(); | 236 Smi& right_smi = Smi::Handle(); |
249 left_smi ^= left_int.raw(); | 237 left_smi ^= left_int.raw(); |
250 right_smi ^= right_int.raw(); | 238 right_smi ^= right_int.raw(); |
251 const intptr_t left_value = left_smi.Value(); | 239 const intptr_t left_value = left_smi.Value(); |
252 const intptr_t right_value = right_smi.Value(); | 240 const intptr_t right_value = right_smi.Value(); |
253 switch (operation) { | 241 switch (operation) { |
254 case Token::kADD: | 242 case Token::kADD: |
255 return Integer::New(left_value + right_value); | 243 return Integer::New(left_value + right_value); |
256 case Token::kSUB: | 244 case Token::kSUB: |
257 return Integer::New(left_value - right_value); | 245 return Integer::New(left_value - right_value); |
258 case Token::kMUL: { | 246 case Token::kMUL: { |
259 ASSERT(Smi::kBits < 32); // Do not use this code in 64-bit mode. | 247 if (Smi::kBits < 32) { |
260 return Integer::New(static_cast<int64_t>(left_value) * | 248 // In 32-bit mode, the product of two Smis fits in a 64-bit result. |
261 static_cast<int64_t>(right_value)); | 249 return Integer::New(static_cast<int64_t>(left_value) * |
| 250 static_cast<int64_t>(right_value)); |
| 251 } else { |
| 252 // In 64-bit mode, the product of two 32-bit signed integers fits in a |
| 253 // 64-bit result. |
| 254 ASSERT(sizeof(intptr_t) == sizeof(int64_t)); |
| 255 if (Utils::IsInt(32, left_value) && Utils::IsInt(32, right_value)) { |
| 256 return Integer::New(left_value * right_value); |
| 257 } |
| 258 } |
| 259 // Perform a Bigint multiplication below. |
| 260 break; |
262 } | 261 } |
263 case Token::kTRUNCDIV: | 262 case Token::kTRUNCDIV: |
264 return Integer::New(left_value / right_value); | 263 return Integer::New(left_value / right_value); |
265 case Token::kMOD: { | 264 case Token::kMOD: { |
266 const intptr_t remainder = left_value % right_value; | 265 const intptr_t remainder = left_value % right_value; |
267 if (remainder < 0) { | 266 if (remainder < 0) { |
268 if (right_value < 0) { | 267 if (right_value < 0) { |
269 return Integer::New(remainder - right_value); | 268 return Integer::New(remainder - right_value); |
270 } else { | 269 } else { |
271 return Integer::New(remainder + right_value); | 270 return Integer::New(remainder + right_value); |
272 } | 271 } |
273 } else { | |
274 return Integer::New(remainder); | |
275 } | 272 } |
| 273 return Integer::New(remainder); |
276 } | 274 } |
277 default: | 275 default: |
278 UNIMPLEMENTED(); | 276 UNIMPLEMENTED(); |
279 } | 277 } |
280 UNREACHABLE(); | |
281 return Integer::null(); | |
282 } | 278 } |
283 // The result of any operation (except multiplication) between two 63-bit | 279 // In 32-bit mode, the result of any operation between two 63-bit signed |
284 // signed integers will fit in a 64-bit signed result. | 280 // integers (or 32-bit for multiplication) will fit in a 64-bit signed result. |
285 // In 64-bit mode, this case was already handled above. | 281 // In 64-bit mode, 63-bit signed integers are Smis, already processed above. |
286 if ((Smi::kBits < 32) && (operation != Token::kMUL) && | 282 if ((Smi::kBits < 32) && !left_int.IsBigint() && !right_int.IsBigint()) { |
287 Are63bitOperands(left_int, right_int)) { | |
288 const int64_t left_value = left_int.AsInt64Value(); | 283 const int64_t left_value = left_int.AsInt64Value(); |
289 const int64_t right_value = right_int.AsInt64Value(); | 284 if (Utils::IsInt(63, left_value)) { |
290 switch (operation) { | 285 const int64_t right_value = right_int.AsInt64Value(); |
291 case Token::kADD: | 286 if (Utils::IsInt(63, right_value)) { |
292 return Integer::New(left_value + right_value); | 287 switch (operation) { |
293 case Token::kSUB: | 288 case Token::kADD: |
294 return Integer::New(left_value - right_value); | 289 return Integer::New(left_value + right_value); |
295 case Token::kTRUNCDIV: | 290 case Token::kSUB: |
296 return Integer::New(left_value / right_value); | 291 return Integer::New(left_value - right_value); |
297 case Token::kMOD: { | 292 case Token::kMUL: { |
298 const int64_t remainder = left_value % right_value; | 293 if (Utils::IsInt(32, left_value) && Utils::IsInt(32, right_value)) { |
299 if (remainder < 0) { | 294 return Integer::New(left_value * right_value); |
300 if (right_value < 0) { | |
301 return Integer::New(remainder - right_value); | |
302 } else { | |
303 return Integer::New(remainder + right_value); | |
304 } | 295 } |
305 } else { | 296 // Perform a Bigint multiplication below. |
| 297 break; |
| 298 } |
| 299 case Token::kTRUNCDIV: |
| 300 return Integer::New(left_value / right_value); |
| 301 case Token::kMOD: { |
| 302 const int64_t remainder = left_value % right_value; |
| 303 if (remainder < 0) { |
| 304 if (right_value < 0) { |
| 305 return Integer::New(remainder - right_value); |
| 306 } else { |
| 307 return Integer::New(remainder + right_value); |
| 308 } |
| 309 } |
306 return Integer::New(remainder); | 310 return Integer::New(remainder); |
307 } | 311 } |
| 312 default: |
| 313 UNIMPLEMENTED(); |
| 314 } |
308 } | 315 } |
309 default: | |
310 UNIMPLEMENTED(); | |
311 } | 316 } |
312 UNREACHABLE(); | |
313 return Integer::null(); | |
314 } | 317 } |
315 const Bigint& left_big = Bigint::Handle(AsBigint(left_int)); | 318 const Bigint& left_big = Bigint::Handle(AsBigint(left_int)); |
316 const Bigint& right_big = Bigint::Handle(AsBigint(right_int)); | 319 const Bigint& right_big = Bigint::Handle(AsBigint(right_int)); |
317 const Bigint& result = | 320 const Bigint& result = |
318 Bigint::Handle(BinaryOpWithTwoBigints(operation, left_big, right_big)); | 321 Bigint::Handle(BinaryOpWithTwoBigints(operation, left_big, right_big)); |
319 return Integer::Handle(AsInteger(result)).raw(); | 322 return Integer::Handle(AsInteger(result)).raw(); |
320 } | 323 } |
321 | 324 |
322 | 325 |
323 DEFINE_NATIVE_ENTRY(Integer_addFromInteger, 2) { | 326 DEFINE_NATIVE_ENTRY(Integer_addFromInteger, 2) { |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 | 578 |
576 DEFINE_NATIVE_ENTRY(Bigint_bitNegate, 1) { | 579 DEFINE_NATIVE_ENTRY(Bigint_bitNegate, 1) { |
577 const Bigint& value = Bigint::CheckedHandle(arguments->At(0)); | 580 const Bigint& value = Bigint::CheckedHandle(arguments->At(0)); |
578 const Bigint& result = Bigint::Handle(BigintOperations::BitNot(value)); | 581 const Bigint& result = Bigint::Handle(BigintOperations::BitNot(value)); |
579 ASSERT(CheckInteger(value)); | 582 ASSERT(CheckInteger(value)); |
580 ASSERT(CheckInteger(result)); | 583 ASSERT(CheckInteger(result)); |
581 arguments->SetReturn(Integer::Handle(AsInteger(result))); | 584 arguments->SetReturn(Integer::Handle(AsInteger(result))); |
582 } | 585 } |
583 | 586 |
584 } // namespace dart | 587 } // namespace dart |
OLD | NEW |