| 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 |