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 | |
17 | namespace 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. |
23 | static 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 | |
31 | DEFINE_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 | |
44 | DEFINE_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 | |
57 | DEFINE_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 | |
70 | DEFINE_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 | |
83 | DEFINE_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 | |
96 | DEFINE_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 | |
109 | DEFINE_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 | |
119 | DEFINE_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 | |
136 | DEFINE_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 | |
149 | DEFINE_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 | |
161 | static 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 | |
182 | DEFINE_NATIVE_ENTRY(Integer_parse, 0, 1) { |
183 | GET_NON_NULL_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0)); |
184 | return ParseInteger(value); |
185 | } |
186 | |
187 | DEFINE_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 | |
205 | static 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 | |
214 | DEFINE_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 | |
227 | DEFINE_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 | |
240 | DEFINE_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 | |
252 | DEFINE_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 | |
262 | DEFINE_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 | |
275 | DEFINE_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 | |
285 | DEFINE_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 | |