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 "vm/bootstrap_natives.h"
6
7#include "include/dart_api.h"
8#include "vm/dart_api_impl.h"
9#include "vm/dart_entry.h"
10#include "vm/exceptions.h"
11#include "vm/isolate.h"
12#include "vm/native_entry.h"
13#include "vm/object.h"
14#include "vm/object_store.h"
15#include "vm/symbols.h"
16
17namespace dart {
18
19// Smi natives.
20
21// Returns false if integer is in wrong representation, e.g., as is a Mint
22// when it could have been a Smi.
23static bool CheckInteger(const Integer& i) {
24 if (i.IsMint()) {
25 const Mint& mint = Mint::Cast(i);
26 return !Smi::IsValid(mint.value());
27 }
28 return true;
29}
30
31DEFINE_NATIVE_ENTRY(Integer_bitAndFromInteger, 0, 2) {
32 const Integer& right =
33 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
34 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
35 ASSERT(CheckInteger(right));
36 ASSERT(CheckInteger(left));
37 if (FLAG_trace_intrinsified_natives) {
38 OS::PrintErr("Integer_bitAndFromInteger %s & %s\n", right.ToCString(),
39 left.ToCString());
40 }
41 return left.BitOp(Token::kBIT_AND, right);
42}
43
44DEFINE_NATIVE_ENTRY(Integer_bitOrFromInteger, 0, 2) {
45 const Integer& right =
46 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
47 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
48 ASSERT(CheckInteger(right));
49 ASSERT(CheckInteger(left));
50 if (FLAG_trace_intrinsified_natives) {
51 OS::PrintErr("Integer_bitOrFromInteger %s | %s\n", left.ToCString(),
52 right.ToCString());
53 }
54 return left.BitOp(Token::kBIT_OR, right);
55}
56
57DEFINE_NATIVE_ENTRY(Integer_bitXorFromInteger, 0, 2) {
58 const Integer& right =
59 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
60 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
61 ASSERT(CheckInteger(right));
62 ASSERT(CheckInteger(left));
63 if (FLAG_trace_intrinsified_natives) {
64 OS::PrintErr("Integer_bitXorFromInteger %s ^ %s\n", left.ToCString(),
65 right.ToCString());
66 }
67 return left.BitOp(Token::kBIT_XOR, right);
68}
69
70DEFINE_NATIVE_ENTRY(Integer_addFromInteger, 0, 2) {
71 const Integer& right_int =
72 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
73 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
74 ASSERT(CheckInteger(right_int));
75 ASSERT(CheckInteger(left_int));
76 if (FLAG_trace_intrinsified_natives) {
77 OS::PrintErr("Integer_addFromInteger %s + %s\n", left_int.ToCString(),
78 right_int.ToCString());
79 }
80 return left_int.ArithmeticOp(Token::kADD, right_int);
81}
82
83DEFINE_NATIVE_ENTRY(Integer_subFromInteger, 0, 2) {
84 const Integer& right_int =
85 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
86 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
87 ASSERT(CheckInteger(right_int));
88 ASSERT(CheckInteger(left_int));
89 if (FLAG_trace_intrinsified_natives) {
90 OS::PrintErr("Integer_subFromInteger %s - %s\n", left_int.ToCString(),
91 right_int.ToCString());
92 }
93 return left_int.ArithmeticOp(Token::kSUB, right_int);
94}
95
96DEFINE_NATIVE_ENTRY(Integer_mulFromInteger, 0, 2) {
97 const Integer& right_int =
98 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
99 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
100 ASSERT(CheckInteger(right_int));
101 ASSERT(CheckInteger(left_int));
102 if (FLAG_trace_intrinsified_natives) {
103 OS::PrintErr("Integer_mulFromInteger %s * %s\n", left_int.ToCString(),
104 right_int.ToCString());
105 }
106 return left_int.ArithmeticOp(Token::kMUL, right_int);
107}
108
109DEFINE_NATIVE_ENTRY(Integer_truncDivFromInteger, 0, 2) {
110 const Integer& right_int =
111 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
112 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
113 ASSERT(CheckInteger(right_int));
114 ASSERT(CheckInteger(left_int));
115 ASSERT(!right_int.IsZero());
116 return left_int.ArithmeticOp(Token::kTRUNCDIV, right_int);
117}
118
119DEFINE_NATIVE_ENTRY(Integer_moduloFromInteger, 0, 2) {
120 const Integer& right_int =
121 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
122 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left_int, arguments->NativeArgAt(1));
123 ASSERT(CheckInteger(right_int));
124 ASSERT(CheckInteger(left_int));
125 if (FLAG_trace_intrinsified_natives) {
126 OS::PrintErr("Integer_moduloFromInteger %s mod %s\n", left_int.ToCString(),
127 right_int.ToCString());
128 }
129 if (right_int.IsZero()) {
130 // Should have been caught before calling into runtime.
131 UNIMPLEMENTED();
132 }
133 return left_int.ArithmeticOp(Token::kMOD, right_int);
134}
135
136DEFINE_NATIVE_ENTRY(Integer_greaterThanFromInteger, 0, 2) {
137 const Integer& right =
138 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
139 GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
140 ASSERT(CheckInteger(right));
141 ASSERT(CheckInteger(left));
142 if (FLAG_trace_intrinsified_natives) {
143 OS::PrintErr("Integer_greaterThanFromInteger %s > %s\n", left.ToCString(),
144 right.ToCString());
145 }
146 return Bool::Get(left.CompareWith(right) == 1).raw();
147}
148
149DEFINE_NATIVE_ENTRY(Integer_equalToInteger, 0, 2) {
150 const Integer& left = Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
151 GET_NON_NULL_NATIVE_ARGUMENT(Integer, right, arguments->NativeArgAt(1));
152 ASSERT(CheckInteger(left));
153 ASSERT(CheckInteger(right));
154 if (FLAG_trace_intrinsified_natives) {
155 OS::PrintErr("Integer_equalToInteger %s == %s\n", left.ToCString(),
156 right.ToCString());
157 }
158 return Bool::Get(left.CompareWith(right) == 0).raw();
159}
160
161static IntegerPtr ParseInteger(const String& value) {
162 // Used by both Integer_parse and Integer_fromEnvironment.
163 if (value.IsOneByteString()) {
164 // Quick conversion for unpadded integers in strings.
165 const intptr_t len = value.Length();
166 if (len > 0) {
167 const char* cstr = value.ToCString();
168 ASSERT(cstr != NULL);
169 char* p_end = NULL;
170 const int64_t int_value = strtoll(cstr, &p_end, 10);
171 if (p_end == (cstr + len)) {
172 if ((int_value != LLONG_MIN) && (int_value != LLONG_MAX)) {
173 return Integer::New(int_value);
174 }
175 }
176 }
177 }
178
179 return Integer::New(value);
180}
181
182DEFINE_NATIVE_ENTRY(Integer_parse, 0, 1) {
183 GET_NON_NULL_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0));
184 return ParseInteger(value);
185}
186
187DEFINE_NATIVE_ENTRY(Integer_fromEnvironment, 0, 3) {
188 GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(1));
189 GET_NATIVE_ARGUMENT(Integer, default_value, arguments->NativeArgAt(2));
190 // Call the embedder to supply us with the environment.
191 const String& env_value =
192 String::Handle(Api::GetEnvironmentValue(thread, name));
193 if (!env_value.IsNull()) {
194 const Integer& result = Integer::Handle(ParseInteger(env_value));
195 if (!result.IsNull()) {
196 if (result.IsSmi()) {
197 return result.raw();
198 }
199 return result.CheckAndCanonicalize(thread, NULL);
200 }
201 }
202 return default_value.raw();
203}
204
205static IntegerPtr ShiftOperationHelper(Token::Kind kind,
206 const Integer& value,
207 const Integer& amount) {
208 if (amount.AsInt64Value() < 0) {
209 Exceptions::ThrowArgumentError(amount);
210 }
211 return value.ShiftOp(kind, amount, Heap::kNew);
212}
213
214DEFINE_NATIVE_ENTRY(Integer_shrFromInteger, 0, 2) {
215 const Integer& amount =
216 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
217 GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
218 ASSERT(CheckInteger(amount));
219 ASSERT(CheckInteger(value));
220 if (FLAG_trace_intrinsified_natives) {
221 OS::PrintErr("Integer_shrFromInteger: %s >> %s\n", value.ToCString(),
222 amount.ToCString());
223 }
224 return ShiftOperationHelper(Token::kSHR, value, amount);
225}
226
227DEFINE_NATIVE_ENTRY(Integer_shlFromInteger, 0, 2) {
228 const Integer& amount =
229 Integer::CheckedHandle(zone, arguments->NativeArgAt(0));
230 GET_NON_NULL_NATIVE_ARGUMENT(Integer, value, arguments->NativeArgAt(1));
231 ASSERT(CheckInteger(amount));
232 ASSERT(CheckInteger(value));
233 if (FLAG_trace_intrinsified_natives) {
234 OS::PrintErr("Integer_shlFromInteger: %s << %s\n", value.ToCString(),
235 amount.ToCString());
236 }
237 return ShiftOperationHelper(Token::kSHL, value, amount);
238}
239
240DEFINE_NATIVE_ENTRY(Smi_bitAndFromSmi, 0, 2) {
241 const Smi& left = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
242 GET_NON_NULL_NATIVE_ARGUMENT(Smi, right, arguments->NativeArgAt(1));
243 if (FLAG_trace_intrinsified_natives) {
244 OS::PrintErr("Smi_bitAndFromSmi %s & %s\n", left.ToCString(),
245 right.ToCString());
246 }
247 const Smi& left_value = Smi::Cast(left);
248 const Smi& right_value = Smi::Cast(right);
249 return Smi::New(left_value.Value() & right_value.Value());
250}
251
252DEFINE_NATIVE_ENTRY(Smi_bitNegate, 0, 1) {
253 const Smi& operand = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
254 if (FLAG_trace_intrinsified_natives) {
255 OS::PrintErr("Smi_bitNegate: %s\n", operand.ToCString());
256 }
257 intptr_t result = ~operand.Value();
258 ASSERT(Smi::IsValid(result));
259 return Smi::New(result);
260}
261
262DEFINE_NATIVE_ENTRY(Smi_bitLength, 0, 1) {
263 const Smi& operand = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
264 if (FLAG_trace_intrinsified_natives) {
265 OS::PrintErr("Smi_bitLength: %s\n", operand.ToCString());
266 }
267 int64_t value = operand.AsInt64Value();
268 intptr_t result = Utils::BitLength(value);
269 ASSERT(Smi::IsValid(result));
270 return Smi::New(result);
271}
272
273// Mint natives.
274
275DEFINE_NATIVE_ENTRY(Mint_bitNegate, 0, 1) {
276 const Mint& operand = Mint::CheckedHandle(zone, arguments->NativeArgAt(0));
277 ASSERT(CheckInteger(operand));
278 if (FLAG_trace_intrinsified_natives) {
279 OS::PrintErr("Mint_bitNegate: %s\n", operand.ToCString());
280 }
281 int64_t result = ~operand.value();
282 return Integer::New(result);
283}
284
285DEFINE_NATIVE_ENTRY(Mint_bitLength, 0, 1) {
286 const Mint& operand = Mint::CheckedHandle(zone, arguments->NativeArgAt(0));
287 ASSERT(CheckInteger(operand));
288 if (FLAG_trace_intrinsified_natives) {
289 OS::PrintErr("Mint_bitLength: %s\n", operand.ToCString());
290 }
291 int64_t value = operand.AsInt64Value();
292 intptr_t result = Utils::BitLength(value);
293 ASSERT(Smi::IsValid(result));
294 return Smi::New(result);
295}
296
297} // namespace dart
298