2012-01-13 20:07:54 +00:00
|
|
|
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
2011-10-05 05:20:07 +00:00
|
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
2022-10-20 20:31:20 +00:00
|
|
|
#include "lib/integers.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/bootstrap_natives.h"
|
|
|
|
|
2013-10-31 05:46:57 +00:00
|
|
|
#include "include/dart_api.h"
|
|
|
|
#include "vm/dart_api_impl.h"
|
2017-07-13 15:08:33 +00:00
|
|
|
#include "vm/dart_entry.h"
|
2011-11-04 16:30:29 +00:00
|
|
|
#include "vm/exceptions.h"
|
2013-10-31 05:46:57 +00:00
|
|
|
#include "vm/isolate.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
#include "vm/native_entry.h"
|
|
|
|
#include "vm/object.h"
|
2013-07-25 19:28:53 +00:00
|
|
|
#include "vm/object_store.h"
|
2012-11-16 19:42:02 +00:00
|
|
|
#include "vm/symbols.h"
|
2011-10-05 05:20:07 +00:00
|
|
|
|
|
|
|
namespace dart {
|
|
|
|
|
|
|
|
// Smi natives.
|
|
|
|
|
2018-06-04 20:10:40 +00:00
|
|
|
// Returns false if integer is in wrong representation, e.g., as is a Mint
|
2011-10-05 05:20:07 +00:00
|
|
|
// when it could have been a Smi.
|
|
|
|
static bool CheckInteger(const Integer& i) {
|
|
|
|
if (i.IsMint()) {
|
2013-01-23 20:01:31 +00:00
|
|
|
const Mint& mint = Mint::Cast(i);
|
2014-06-24 13:41:48 +00:00
|
|
|
return !Smi::IsValid(mint.value());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_bitAndFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right));
|
|
|
|
ASSERT(CheckInteger(left));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_bitAndFromInteger %s & %s\n", right.ToCString(),
|
|
|
|
left.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return left.BitOp(Token::kBIT_AND, right);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_bitOrFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right));
|
|
|
|
ASSERT(CheckInteger(left));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_bitOrFromInteger %s | %s\n", left.ToCString(),
|
|
|
|
right.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return left.BitOp(Token::kBIT_OR, right);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_bitXorFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right));
|
|
|
|
ASSERT(CheckInteger(left));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_bitXorFromInteger %s ^ %s\n", left.ToCString(),
|
|
|
|
right.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return left.BitOp(Token::kBIT_XOR, right);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_addFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right_int =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right_int));
|
|
|
|
ASSERT(CheckInteger(left_int));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_addFromInteger %s + %s\n", left_int.ToCString(),
|
|
|
|
right_int.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return left_int.ArithmeticOp(Token::kADD, right_int);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_subFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right_int =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right_int));
|
|
|
|
ASSERT(CheckInteger(left_int));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_subFromInteger %s - %s\n", left_int.ToCString(),
|
|
|
|
right_int.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return left_int.ArithmeticOp(Token::kSUB, right_int);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_mulFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right_int =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right_int));
|
|
|
|
ASSERT(CheckInteger(left_int));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_mulFromInteger %s * %s\n", left_int.ToCString(),
|
|
|
|
right_int.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return left_int.ArithmeticOp(Token::kMUL, right_int);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_truncDivFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right_int =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right_int));
|
|
|
|
ASSERT(CheckInteger(left_int));
|
|
|
|
ASSERT(!right_int.IsZero());
|
2018-06-18 18:16:51 +00:00
|
|
|
return left_int.ArithmeticOp(Token::kTRUNCDIV, right_int);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_moduloFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right_int =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right_int));
|
2016-06-15 21:48:11 +00:00
|
|
|
ASSERT(CheckInteger(left_int));
|
2011-10-05 05:20:07 +00:00
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_moduloFromInteger %s mod %s\n", left_int.ToCString(),
|
|
|
|
right_int.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
if (right_int.IsZero()) {
|
|
|
|
// Should have been caught before calling into runtime.
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return left_int.ArithmeticOp(Token::kMOD, right_int);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_greaterThanFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& right =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(right));
|
|
|
|
ASSERT(CheckInteger(left));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_greaterThanFromInteger %s > %s\n", left.ToCString(),
|
|
|
|
right.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2021-01-15 23:32:02 +00:00
|
|
|
return Bool::Get(left.CompareWith(right) == 1).ptr();
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_equalToInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& left = Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2012-12-10 17:59:40 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, right, arguments->NativeArgAt(1));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(left));
|
|
|
|
ASSERT(CheckInteger(right));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Integer_equalToInteger %s == %s\n", left.ToCString(),
|
|
|
|
right.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2021-01-15 23:32:02 +00:00
|
|
|
return Bool::Get(left.CompareWith(right) == 0).ptr();
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2020-04-25 05:21:27 +00:00
|
|
|
static IntegerPtr ParseInteger(const String& value) {
|
2013-10-31 13:45:39 +00:00
|
|
|
// Used by both Integer_parse and Integer_fromEnvironment.
|
2013-02-25 18:32:46 +00:00
|
|
|
if (value.IsOneByteString()) {
|
|
|
|
// Quick conversion for unpadded integers in strings.
|
|
|
|
const intptr_t len = value.Length();
|
|
|
|
if (len > 0) {
|
|
|
|
const char* cstr = value.ToCString();
|
2023-03-30 19:28:28 +00:00
|
|
|
ASSERT(cstr != nullptr);
|
|
|
|
char* p_end = nullptr;
|
2013-04-19 23:19:15 +00:00
|
|
|
const int64_t int_value = strtoll(cstr, &p_end, 10);
|
|
|
|
if (p_end == (cstr + len)) {
|
|
|
|
if ((int_value != LLONG_MIN) && (int_value != LLONG_MAX)) {
|
|
|
|
return Integer::New(int_value);
|
2013-02-25 18:32:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 00:13:26 +00:00
|
|
|
return Integer::New(value);
|
2013-10-31 13:45:39 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_parse, 0, 1) {
|
2013-10-31 13:45:39 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0));
|
|
|
|
return ParseInteger(value);
|
2012-11-16 19:42:02 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_fromEnvironment, 0, 3) {
|
2013-10-31 05:46:57 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(1));
|
|
|
|
GET_NATIVE_ARGUMENT(Integer, default_value, arguments->NativeArgAt(2));
|
|
|
|
// Call the embedder to supply us with the environment.
|
2014-09-08 18:23:05 +00:00
|
|
|
const String& env_value =
|
2016-02-29 19:58:32 +00:00
|
|
|
String::Handle(Api::GetEnvironmentValue(thread, name));
|
2014-09-08 18:23:05 +00:00
|
|
|
if (!env_value.IsNull()) {
|
|
|
|
const Integer& result = Integer::Handle(ParseInteger(env_value));
|
|
|
|
if (!result.IsNull()) {
|
|
|
|
if (result.IsSmi()) {
|
2021-01-15 23:32:02 +00:00
|
|
|
return result.ptr();
|
2013-10-31 13:45:39 +00:00
|
|
|
}
|
2020-09-30 22:29:05 +00:00
|
|
|
return result.Canonicalize(thread);
|
2013-10-31 05:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-15 23:32:02 +00:00
|
|
|
return default_value.ptr();
|
2013-10-31 05:46:57 +00:00
|
|
|
}
|
|
|
|
|
2020-04-25 05:21:27 +00:00
|
|
|
static IntegerPtr ShiftOperationHelper(Token::Kind kind,
|
|
|
|
const Integer& value,
|
|
|
|
const Integer& amount) {
|
2018-06-18 18:16:51 +00:00
|
|
|
if (amount.AsInt64Value() < 0) {
|
2013-10-01 18:48:37 +00:00
|
|
|
Exceptions::ThrowArgumentError(amount);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return value.ShiftOp(kind, amount, Heap::kNew);
|
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_shrFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& amount =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2018-06-18 18:16:51 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
|
|
|
|
ASSERT(CheckInteger(amount));
|
|
|
|
ASSERT(CheckInteger(value));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
|
|
|
OS::PrintErr("Integer_shrFromInteger: %s >> %s\n", value.ToCString(),
|
|
|
|
amount.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return ShiftOperationHelper(Token::kSHR, value, amount);
|
|
|
|
}
|
|
|
|
|
2021-02-24 00:14:57 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_ushrFromInteger, 0, 2) {
|
|
|
|
const Integer& amount =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
|
|
|
|
ASSERT(CheckInteger(amount));
|
|
|
|
ASSERT(CheckInteger(value));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
|
|
|
OS::PrintErr("Integer_ushrFromInteger: %s >>> %s\n", value.ToCString(),
|
|
|
|
amount.ToCString());
|
|
|
|
}
|
|
|
|
return ShiftOperationHelper(Token::kUSHR, value, amount);
|
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Integer_shlFromInteger, 0, 2) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Integer& amount =
|
|
|
|
Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2018-06-18 18:16:51 +00:00
|
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
|
|
|
|
ASSERT(CheckInteger(amount));
|
|
|
|
ASSERT(CheckInteger(value));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
|
|
|
OS::PrintErr("Integer_shlFromInteger: %s << %s\n", value.ToCString(),
|
|
|
|
amount.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
2018-06-18 18:16:51 +00:00
|
|
|
return ShiftOperationHelper(Token::kSHL, value, amount);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Smi_bitNegate, 0, 1) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Smi& operand = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2011-10-05 05:20:07 +00:00
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Smi_bitNegate: %s\n", operand.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
intptr_t result = ~operand.Value();
|
|
|
|
ASSERT(Smi::IsValid(result));
|
2012-08-30 17:41:19 +00:00
|
|
|
return Smi::New(result);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Smi_bitLength, 0, 1) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Smi& operand = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2013-09-06 22:22:26 +00:00
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Smi_bitLength: %s\n", operand.ToCString());
|
2013-09-06 22:22:26 +00:00
|
|
|
}
|
|
|
|
int64_t value = operand.AsInt64Value();
|
2014-11-11 14:51:10 +00:00
|
|
|
intptr_t result = Utils::BitLength(value);
|
2013-09-06 22:22:26 +00:00
|
|
|
ASSERT(Smi::IsValid(result));
|
|
|
|
return Smi::New(result);
|
|
|
|
}
|
|
|
|
|
2022-11-17 02:28:37 +00:00
|
|
|
// Should be kept in sync with il_*.cc EmitHashIntegerCodeSequence
|
2022-10-20 20:31:20 +00:00
|
|
|
uint32_t Multiply64Hash(int64_t ivalue) {
|
|
|
|
const uint64_t magic_constant = /*0x1b873593cc9e*/ 0x2d51;
|
|
|
|
uint64_t value = static_cast<uint64_t>(ivalue);
|
|
|
|
#if defined(ARCH_IS_64_BIT)
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
__int64 hi = __umulh(value, magic_constant);
|
|
|
|
uint64_t lo = value * magic_constant;
|
|
|
|
uint64_t hash = lo ^ hi;
|
|
|
|
#else
|
|
|
|
const __int128 res = static_cast<__int128>(value) * magic_constant;
|
|
|
|
uint64_t hash = res ^ static_cast<int64_t>(res >> 64);
|
|
|
|
#endif
|
|
|
|
hash = hash ^ (hash >> 32);
|
|
|
|
#else
|
|
|
|
uint64_t prod_lo64 = value * magic_constant;
|
|
|
|
|
|
|
|
uint64_t value_lo32 = value & 0xffffffff;
|
|
|
|
uint64_t value_hi32 = value >> 32;
|
|
|
|
uint64_t carry = (((value_hi32 * magic_constant) & 0xffffffff) +
|
|
|
|
((value_lo32 * magic_constant) >> 32)) >>
|
|
|
|
32;
|
|
|
|
uint64_t prod_hi64 = ((value_hi32 * magic_constant) >> 32) + carry;
|
|
|
|
uint64_t hash = prod_hi64 ^ prod_lo64;
|
|
|
|
hash = hash ^ (hash >> 32);
|
|
|
|
#endif
|
|
|
|
return hash & 0x3fffffff;
|
|
|
|
}
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
// Mint natives.
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Mint_bitNegate, 0, 1) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Mint& operand = Mint::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2011-10-05 05:20:07 +00:00
|
|
|
ASSERT(CheckInteger(operand));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Mint_bitNegate: %s\n", operand.ToCString());
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
int64_t result = ~operand.value();
|
2012-08-30 17:41:19 +00:00
|
|
|
return Integer::New(result);
|
2011-10-05 05:20:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 19:29:26 +00:00
|
|
|
DEFINE_NATIVE_ENTRY(Mint_bitLength, 0, 1) {
|
2018-11-08 02:02:39 +00:00
|
|
|
const Mint& operand = Mint::CheckedHandle(zone, arguments->NativeArgAt(0));
|
2013-09-06 22:22:26 +00:00
|
|
|
ASSERT(CheckInteger(operand));
|
|
|
|
if (FLAG_trace_intrinsified_natives) {
|
2018-06-13 19:51:40 +00:00
|
|
|
OS::PrintErr("Mint_bitLength: %s\n", operand.ToCString());
|
2013-09-06 22:22:26 +00:00
|
|
|
}
|
|
|
|
int64_t value = operand.AsInt64Value();
|
2014-11-11 14:51:10 +00:00
|
|
|
intptr_t result = Utils::BitLength(value);
|
2013-09-06 22:22:26 +00:00
|
|
|
ASSERT(Smi::IsValid(result));
|
|
|
|
return Smi::New(result);
|
|
|
|
}
|
|
|
|
|
2011-10-05 05:20:07 +00:00
|
|
|
} // namespace dart
|