Flutter Engine
The Flutter Engine
integers.cc
Go to the documentation of this 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
3// BSD-style license that can be found in the LICENSE file.
4
5#include "lib/integers.h"
7
8#include "include/dart_api.h"
9#include "vm/dart_api_impl.h"
10#include "vm/dart_entry.h"
11#include "vm/exceptions.h"
12#include "vm/isolate.h"
13#include "vm/native_entry.h"
14#include "vm/object.h"
15#include "vm/object_store.h"
16#include "vm/symbols.h"
17
18namespace dart {
19
20// Smi natives.
21
22// Returns false if integer is in wrong representation, e.g., as is a Mint
23// when it could have been a Smi.
24static bool CheckInteger(const Integer& i) {
25 if (i.IsMint()) {
26 const Mint& mint = Mint::Cast(i);
27 return !Smi::IsValid(mint.value());
28 }
29 return true;
30}
31
32DEFINE_NATIVE_ENTRY(Integer_bitAndFromInteger, 0, 2) {
33 const Integer& right =
34 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
35 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
36 ASSERT(CheckInteger(right));
37 ASSERT(CheckInteger(left));
38 if (FLAG_trace_intrinsified_natives) {
39 OS::PrintErr("Integer_bitAndFromInteger %s & %s\n", right.ToCString(),
40 left.ToCString());
41 }
42 return left.BitOp(Token::kBIT_AND, right);
43}
44
45DEFINE_NATIVE_ENTRY(Integer_bitOrFromInteger, 0, 2) {
46 const Integer& right =
47 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
48 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
49 ASSERT(CheckInteger(right));
50 ASSERT(CheckInteger(left));
51 if (FLAG_trace_intrinsified_natives) {
52 OS::PrintErr("Integer_bitOrFromInteger %s | %s\n", left.ToCString(),
53 right.ToCString());
54 }
55 return left.BitOp(Token::kBIT_OR, right);
56}
57
58DEFINE_NATIVE_ENTRY(Integer_bitXorFromInteger, 0, 2) {
59 const Integer& right =
60 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
61 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
62 ASSERT(CheckInteger(right));
63 ASSERT(CheckInteger(left));
64 if (FLAG_trace_intrinsified_natives) {
65 OS::PrintErr("Integer_bitXorFromInteger %s ^ %s\n", left.ToCString(),
66 right.ToCString());
67 }
68 return left.BitOp(Token::kBIT_XOR, right);
69}
70
71DEFINE_NATIVE_ENTRY(Integer_addFromInteger, 0, 2) {
72 const Integer& right_int =
73 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
74 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
75 ASSERT(CheckInteger(right_int));
76 ASSERT(CheckInteger(left_int));
77 if (FLAG_trace_intrinsified_natives) {
78 OS::PrintErr("Integer_addFromInteger %s + %s\n", left_int.ToCString(),
79 right_int.ToCString());
80 }
81 return left_int.ArithmeticOp(Token::kADD, right_int);
82}
83
84DEFINE_NATIVE_ENTRY(Integer_subFromInteger, 0, 2) {
85 const Integer& right_int =
86 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
87 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
88 ASSERT(CheckInteger(right_int));
89 ASSERT(CheckInteger(left_int));
90 if (FLAG_trace_intrinsified_natives) {
91 OS::PrintErr("Integer_subFromInteger %s - %s\n", left_int.ToCString(),
92 right_int.ToCString());
93 }
94 return left_int.ArithmeticOp(Token::kSUB, right_int);
95}
96
97DEFINE_NATIVE_ENTRY(Integer_mulFromInteger, 0, 2) {
98 const Integer& right_int =
99 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
100 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
101 ASSERT(CheckInteger(right_int));
102 ASSERT(CheckInteger(left_int));
103 if (FLAG_trace_intrinsified_natives) {
104 OS::PrintErr("Integer_mulFromInteger %s * %s\n", left_int.ToCString(),
105 right_int.ToCString());
106 }
107 return left_int.ArithmeticOp(Token::kMUL, right_int);
108}
109
110DEFINE_NATIVE_ENTRY(Integer_truncDivFromInteger, 0, 2) {
111 const Integer& right_int =
112 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
113 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
114 ASSERT(CheckInteger(right_int));
115 ASSERT(CheckInteger(left_int));
116 ASSERT(!right_int.IsZero());
117 return left_int.ArithmeticOp(Token::kTRUNCDIV, right_int);
118}
119
120DEFINE_NATIVE_ENTRY(Integer_moduloFromInteger, 0, 2) {
121 const Integer& right_int =
122 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
123 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
124 ASSERT(CheckInteger(right_int));
125 ASSERT(CheckInteger(left_int));
126 if (FLAG_trace_intrinsified_natives) {
127 OS::PrintErr("Integer_moduloFromInteger %s mod %s\n", left_int.ToCString(),
128 right_int.ToCString());
129 }
130 if (right_int.IsZero()) {
131 // Should have been caught before calling into runtime.
133 }
134 return left_int.ArithmeticOp(Token::kMOD, right_int);
135}
136
137DEFINE_NATIVE_ENTRY(Integer_greaterThanFromInteger, 0, 2) {
138 const Integer& right =
139 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
140 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
141 ASSERT(CheckInteger(right));
142 ASSERT(CheckInteger(left));
143 if (FLAG_trace_intrinsified_natives) {
144 OS::PrintErr("Integer_greaterThanFromInteger %s > %s\n", left.ToCString(),
145 right.ToCString());
146 }
147 return Bool::Get(left.CompareWith(right) == 1).ptr();
148}
149
150DEFINE_NATIVE_ENTRY(Integer_equalToInteger, 0, 2) {
151 const Integer& left = Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
152 GET_NON_NULL_NATIVE_ARGUMENT(Integer, right, arguments->NativeArgAt(1));
153 ASSERT(CheckInteger(left));
154 ASSERT(CheckInteger(right));
155 if (FLAG_trace_intrinsified_natives) {
156 OS::PrintErr("Integer_equalToInteger %s == %s\n", left.ToCString(),
157 right.ToCString());
158 }
159 return Bool::Get(left.CompareWith(right) == 0).ptr();
160}
161
162static IntegerPtr ParseInteger(const String& value) {
163 // Used by both Integer_parse and Integer_fromEnvironment.
164 if (value.IsOneByteString()) {
165 // Quick conversion for unpadded integers in strings.
166 const intptr_t len = value.Length();
167 if (len > 0) {
168 const char* cstr = value.ToCString();
169 ASSERT(cstr != nullptr);
170 char* p_end = nullptr;
171 const int64_t int_value = strtoll(cstr, &p_end, 10);
172 if (p_end == (cstr + len)) {
173 if ((int_value != LLONG_MIN) && (int_value != LLONG_MAX)) {
174 return Integer::New(int_value);
175 }
176 }
177 }
178 }
179
180 return Integer::New(value);
181}
182
183DEFINE_NATIVE_ENTRY(Integer_parse, 0, 1) {
184 GET_NON_NULL_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0));
185 return ParseInteger(value);
186}
187
188DEFINE_NATIVE_ENTRY(Integer_fromEnvironment, 0, 3) {
189 GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(1));
190 GET_NATIVE_ARGUMENT(Integer, default_value, arguments->NativeArgAt(2));
191 // Call the embedder to supply us with the environment.
192 const String& env_value =
194 if (!env_value.IsNull()) {
195 const Integer& result = Integer::Handle(ParseInteger(env_value));
196 if (!result.IsNull()) {
197 if (result.IsSmi()) {
198 return result.ptr();
199 }
200 return result.Canonicalize(thread);
201 }
202 }
203 return default_value.ptr();
204}
205
206static IntegerPtr ShiftOperationHelper(Token::Kind kind,
207 const Integer& value,
208 const Integer& amount) {
209 if (amount.AsInt64Value() < 0) {
211 }
212 return value.ShiftOp(kind, amount, Heap::kNew);
213}
214
215DEFINE_NATIVE_ENTRY(Integer_shrFromInteger, 0, 2) {
216 const Integer& amount =
217 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
218 GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
219 ASSERT(CheckInteger(amount));
221 if (FLAG_trace_intrinsified_natives) {
222 OS::PrintErr("Integer_shrFromInteger: %s >> %s\n", value.ToCString(),
223 amount.ToCString());
224 }
225 return ShiftOperationHelper(Token::kSHR, value, amount);
226}
227
228DEFINE_NATIVE_ENTRY(Integer_ushrFromInteger, 0, 2) {
229 const Integer& amount =
230 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
231 GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
232 ASSERT(CheckInteger(amount));
234 if (FLAG_trace_intrinsified_natives) {
235 OS::PrintErr("Integer_ushrFromInteger: %s >>> %s\n", value.ToCString(),
236 amount.ToCString());
237 }
238 return ShiftOperationHelper(Token::kUSHR, value, amount);
239}
240
241DEFINE_NATIVE_ENTRY(Integer_shlFromInteger, 0, 2) {
242 const Integer& amount =
243 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
244 GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
245 ASSERT(CheckInteger(amount));
247 if (FLAG_trace_intrinsified_natives) {
248 OS::PrintErr("Integer_shlFromInteger: %s << %s\n", value.ToCString(),
249 amount.ToCString());
250 }
251 return ShiftOperationHelper(Token::kSHL, value, amount);
252}
253
254DEFINE_NATIVE_ENTRY(Smi_bitNegate, 0, 1) {
255 const Smi& operand = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
256 if (FLAG_trace_intrinsified_natives) {
257 OS::PrintErr("Smi_bitNegate: %s\n", operand.ToCString());
258 }
259 intptr_t result = ~operand.Value();
261 return Smi::New(result);
262}
263
264DEFINE_NATIVE_ENTRY(Smi_bitLength, 0, 1) {
265 const Smi& operand = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
266 if (FLAG_trace_intrinsified_natives) {
267 OS::PrintErr("Smi_bitLength: %s\n", operand.ToCString());
268 }
269 int64_t value = operand.AsInt64Value();
270 intptr_t result = Utils::BitLength(value);
272 return Smi::New(result);
273}
274
275// Should be kept in sync with il_*.cc EmitHashIntegerCodeSequence
276uint32_t Multiply64Hash(int64_t ivalue) {
277 const uint64_t magic_constant = /*0x1b873593cc9e*/ 0x2d51;
278 uint64_t value = static_cast<uint64_t>(ivalue);
279#if defined(ARCH_IS_64_BIT)
280#ifdef _MSC_VER
281 __int64 hi = __umulh(value, magic_constant);
282 uint64_t lo = value * magic_constant;
283 uint64_t hash = lo ^ hi;
284#else
285 const __int128 res = static_cast<__int128>(value) * magic_constant;
286 uint64_t hash = res ^ static_cast<int64_t>(res >> 64);
287#endif
288 hash = hash ^ (hash >> 32);
289#else
290 uint64_t prod_lo64 = value * magic_constant;
291
292 uint64_t value_lo32 = value & 0xffffffff;
293 uint64_t value_hi32 = value >> 32;
294 uint64_t carry = (((value_hi32 * magic_constant) & 0xffffffff) +
295 ((value_lo32 * magic_constant) >> 32)) >>
296 32;
297 uint64_t prod_hi64 = ((value_hi32 * magic_constant) >> 32) + carry;
298 uint64_t hash = prod_hi64 ^ prod_lo64;
299 hash = hash ^ (hash >> 32);
300#endif
301 return hash & 0x3fffffff;
302}
303
304// Mint natives.
305
306DEFINE_NATIVE_ENTRY(Mint_bitNegate, 0, 1) {
307 const Mint& operand = Mint::CheckedHandle(zone, arguments->NativeArgAt(0));
308 ASSERT(CheckInteger(operand));
309 if (FLAG_trace_intrinsified_natives) {
310 OS::PrintErr("Mint_bitNegate: %s\n", operand.ToCString());
311 }
312 int64_t result = ~operand.value();
313 return Integer::New(result);
314}
315
316DEFINE_NATIVE_ENTRY(Mint_bitLength, 0, 1) {
317 const Mint& operand = Mint::CheckedHandle(zone, arguments->NativeArgAt(0));
318 ASSERT(CheckInteger(operand));
319 if (FLAG_trace_intrinsified_natives) {
320 OS::PrintErr("Mint_bitLength: %s\n", operand.ToCString());
321 }
322 int64_t value = operand.AsInt64Value();
323 intptr_t result = Utils::BitLength(value);
325 return Smi::New(result);
326}
327
328} // namespace dart
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static StringPtr GetEnvironmentValue(Thread *thread, const String &name)
static const Bool & Get(bool value)
Definition: object.h:10801
static DART_NORETURN void ThrowArgumentError(const Instance &arg)
Definition: exceptions.cc:1082
@ kNew
Definition: heap.h:38
static IntegerPtr New(const String &str, Heap::Space space=Heap::kNew)
Definition: object.cc:22984
virtual int64_t AsInt64Value() const
Definition: object.cc:23058
virtual bool IsZero() const
Definition: object.cc:23040
virtual int64_t AsInt64Value() const
Definition: object.cc:23336
int64_t value() const
Definition: object.h:10073
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
ObjectPtr ptr() const
Definition: object.h:332
virtual const char * ToCString() const
Definition: object.h:366
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static SmiPtr New(intptr_t value)
Definition: object.h:10006
virtual int64_t AsInt64Value() const
Definition: object.cc:23262
static bool IsValid(int64_t value)
Definition: object.h:10026
static constexpr size_t BitLength(int64_t value)
Definition: utils.h:213
#define UNIMPLEMENTED
#define ASSERT(E)
uint8_t value
GAsyncResult * result
Definition: dart_vm.cc:33
const char *const name
static IntegerPtr ShiftOperationHelper(Token::Kind kind, const Integer &value, const Integer &amount)
Definition: integers.cc:206
uint32_t Multiply64Hash(int64_t ivalue)
Definition: integers.cc:276
static IntegerPtr ParseInteger(const String &value)
Definition: integers.cc:162
DEFINE_NATIVE_ENTRY(List_allocate, 0, 2)
Definition: array.cc:13
static bool CheckInteger(const Integer &i)
Definition: integers.cc:24
string magic_constant
Definition: mskp_parser.py:24
#define GET_NATIVE_ARGUMENT(type, name, value)
Definition: native_entry.h:84
#define GET_NON_NULL_NATIVE_ARGUMENT(type, name, value)
Definition: native_entry.h:74