OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 <math.h> | 5 #include <math.h> |
6 | 6 |
7 #include "vm/bootstrap_natives.h" | 7 #include "vm/bootstrap_natives.h" |
8 | 8 |
9 #include "vm/bigint_operations.h" | 9 #include "vm/bigint_operations.h" |
10 #include "vm/double_conversion.h" | 10 #include "vm/double_conversion.h" |
11 #include "vm/exceptions.h" | 11 #include "vm/exceptions.h" |
12 #include "vm/native_entry.h" | 12 #include "vm/native_entry.h" |
13 #include "vm/object.h" | 13 #include "vm/object.h" |
14 | 14 |
15 namespace dart { | 15 namespace dart { |
16 | 16 |
17 DEFINE_NATIVE_ENTRY(Double_doubleFromInteger, 2) { | 17 DEFINE_NATIVE_ENTRY(Double_doubleFromInteger, 2) { |
18 ASSERT(AbstractTypeArguments::CheckedHandle(arguments->At(0)).IsNull()); | 18 ASSERT(AbstractTypeArguments::CheckedHandle(arguments->At(0)).IsNull()); |
19 const Integer& value = Integer::CheckedHandle(arguments->At(1)); | 19 const Integer& value = Integer::CheckedHandle(arguments->At(1)); |
20 const Double& result = Double::Handle(Double::New(value.AsDoubleValue())); | 20 return Double::New(value.AsDoubleValue()); |
21 arguments->SetReturn(result); | |
22 } | 21 } |
23 | 22 |
24 | 23 |
25 DEFINE_NATIVE_ENTRY(Double_add, 2) { | 24 DEFINE_NATIVE_ENTRY(Double_add, 2) { |
26 double left = Double::CheckedHandle(arguments->At(0)).value(); | 25 double left = Double::CheckedHandle(arguments->At(0)).value(); |
27 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); | 26 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); |
28 double right = right_object.value(); | 27 double right = right_object.value(); |
29 const Double& result = Double::Handle(Double::New(left + right)); | 28 return Double::New(left + right); |
30 arguments->SetReturn(result); | |
31 } | 29 } |
32 | 30 |
33 | 31 |
34 DEFINE_NATIVE_ENTRY(Double_sub, 2) { | 32 DEFINE_NATIVE_ENTRY(Double_sub, 2) { |
35 double left = Double::CheckedHandle(arguments->At(0)).value(); | 33 double left = Double::CheckedHandle(arguments->At(0)).value(); |
36 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); | 34 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); |
37 double right = right_object.value(); | 35 double right = right_object.value(); |
38 const Double& result = Double::Handle(Double::New(left - right)); | 36 return Double::New(left - right); |
39 arguments->SetReturn(result); | |
40 } | 37 } |
41 | 38 |
42 | 39 |
43 DEFINE_NATIVE_ENTRY(Double_mul, 2) { | 40 DEFINE_NATIVE_ENTRY(Double_mul, 2) { |
44 double left = Double::CheckedHandle(arguments->At(0)).value(); | 41 double left = Double::CheckedHandle(arguments->At(0)).value(); |
45 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); | 42 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); |
46 double right = right_object.value(); | 43 double right = right_object.value(); |
47 const Double& result = Double::Handle(Double::New(left * right)); | 44 return Double::New(left * right); |
48 arguments->SetReturn(result); | |
49 } | 45 } |
50 | 46 |
51 | 47 |
52 DEFINE_NATIVE_ENTRY(Double_div, 2) { | 48 DEFINE_NATIVE_ENTRY(Double_div, 2) { |
53 double left = Double::CheckedHandle(arguments->At(0)).value(); | 49 double left = Double::CheckedHandle(arguments->At(0)).value(); |
54 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); | 50 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); |
55 double right = right_object.value(); | 51 double right = right_object.value(); |
56 const Double& result = Double::Handle(Double::New(left / right)); | 52 return Double::New(left / right); |
57 arguments->SetReturn(result); | |
58 } | 53 } |
59 | 54 |
60 | 55 |
61 DEFINE_NATIVE_ENTRY(Double_trunc_div, 2) { | 56 DEFINE_NATIVE_ENTRY(Double_trunc_div, 2) { |
62 double left = Double::CheckedHandle(arguments->At(0)).value(); | 57 double left = Double::CheckedHandle(arguments->At(0)).value(); |
63 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); | 58 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); |
64 double right = right_object.value(); | 59 double right = right_object.value(); |
65 const Double& result = Double::Handle(Double::New(trunc(left / right))); | 60 return Double::New(trunc(left / right)); |
66 arguments->SetReturn(result); | |
67 } | 61 } |
68 | 62 |
69 | 63 |
70 DEFINE_NATIVE_ENTRY(Double_modulo, 2) { | 64 DEFINE_NATIVE_ENTRY(Double_modulo, 2) { |
71 double left = Double::CheckedHandle(arguments->At(0)).value(); | 65 double left = Double::CheckedHandle(arguments->At(0)).value(); |
72 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); | 66 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); |
73 double right = right_object.value(); | 67 double right = right_object.value(); |
74 double remainder = fmod(left, right); | 68 double remainder = fmod(left, right); |
75 if (remainder == 0.0) { | 69 if (remainder == 0.0) { |
76 // We explicitely switch to the positive 0.0 (just in case it was negative). | 70 // We explicitely switch to the positive 0.0 (just in case it was negative). |
77 remainder = +0.0; | 71 remainder = +0.0; |
78 } else if (remainder < 0) { | 72 } else if (remainder < 0) { |
79 if (right < 0) { | 73 if (right < 0) { |
80 remainder -= right; | 74 remainder -= right; |
81 } else { | 75 } else { |
82 remainder += right; | 76 remainder += right; |
83 } | 77 } |
84 } | 78 } |
85 const Double& result = Double::Handle(Double::New(remainder)); | 79 return Double::New(remainder); |
86 arguments->SetReturn(result); | |
87 } | 80 } |
88 | 81 |
89 | 82 |
90 DEFINE_NATIVE_ENTRY(Double_remainder, 2) { | 83 DEFINE_NATIVE_ENTRY(Double_remainder, 2) { |
91 double left = Double::CheckedHandle(arguments->At(0)).value(); | 84 double left = Double::CheckedHandle(arguments->At(0)).value(); |
92 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); | 85 GET_NATIVE_ARGUMENT(Double, right_object, arguments->At(1)); |
93 double right = right_object.value(); | 86 double right = right_object.value(); |
94 const Double& result = Double::Handle(Double::New(fmod(left, right))); | 87 return Double::New(fmod(left, right)); |
95 arguments->SetReturn(result); | |
96 } | 88 } |
97 | 89 |
98 | 90 |
99 DEFINE_NATIVE_ENTRY(Double_greaterThan, 2) { | 91 DEFINE_NATIVE_ENTRY(Double_greaterThan, 2) { |
100 const Double& left = Double::CheckedHandle(arguments->At(0)); | 92 const Double& left = Double::CheckedHandle(arguments->At(0)); |
101 GET_NATIVE_ARGUMENT(Double, right, arguments->At(1)); | 93 GET_NATIVE_ARGUMENT(Double, right, arguments->At(1)); |
102 bool result = right.IsNull() ? false : (left.value() > right.value()); | 94 bool result = right.IsNull() ? false : (left.value() > right.value()); |
103 arguments->SetReturn(Bool::Handle(Bool::Get(result))); | 95 return Bool::Get(result); |
104 } | 96 } |
105 | 97 |
106 | 98 |
107 DEFINE_NATIVE_ENTRY(Double_greaterThanFromInteger, 2) { | 99 DEFINE_NATIVE_ENTRY(Double_greaterThanFromInteger, 2) { |
108 const Double& right = Double::CheckedHandle(arguments->At(0)); | 100 const Double& right = Double::CheckedHandle(arguments->At(0)); |
109 GET_NATIVE_ARGUMENT(Integer, left, arguments->At(1)); | 101 GET_NATIVE_ARGUMENT(Integer, left, arguments->At(1)); |
110 const Bool& result = Bool::Handle(Bool::Get( | 102 return Bool::Get(left.AsDoubleValue() > right.value()); |
111 left.AsDoubleValue() > right.value())); | |
112 arguments->SetReturn(result); | |
113 } | 103 } |
114 | 104 |
115 | 105 |
116 DEFINE_NATIVE_ENTRY(Double_equal, 2) { | 106 DEFINE_NATIVE_ENTRY(Double_equal, 2) { |
117 const Double& left = Double::CheckedHandle(arguments->At(0)); | 107 const Double& left = Double::CheckedHandle(arguments->At(0)); |
118 GET_NATIVE_ARGUMENT(Double, right, arguments->At(1)); | 108 GET_NATIVE_ARGUMENT(Double, right, arguments->At(1)); |
119 bool result = right.IsNull() ? false : (left.value() == right.value()); | 109 bool result = right.IsNull() ? false : (left.value() == right.value()); |
120 arguments->SetReturn(Bool::Handle(Bool::Get(result))); | 110 return Bool::Get(result); |
121 } | 111 } |
122 | 112 |
123 | 113 |
124 DEFINE_NATIVE_ENTRY(Double_equalToInteger, 2) { | 114 DEFINE_NATIVE_ENTRY(Double_equalToInteger, 2) { |
125 const Double& left = Double::CheckedHandle(arguments->At(0)); | 115 const Double& left = Double::CheckedHandle(arguments->At(0)); |
126 GET_NATIVE_ARGUMENT(Integer, right, arguments->At(1)); | 116 GET_NATIVE_ARGUMENT(Integer, right, arguments->At(1)); |
127 const Bool& result = | 117 return Bool::Get(left.value() == right.AsDoubleValue()); |
128 Bool::Handle(Bool::Get(left.value() == right.AsDoubleValue())); | |
129 arguments->SetReturn(result); | |
130 } | 118 } |
131 | 119 |
132 | 120 |
133 DEFINE_NATIVE_ENTRY(Double_round, 1) { | 121 DEFINE_NATIVE_ENTRY(Double_round, 1) { |
134 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 122 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
135 arguments->SetReturn(Double::Handle(Double::New(round(arg.value())))); | 123 return Double::New(round(arg.value())); |
136 } | 124 } |
137 | 125 |
138 DEFINE_NATIVE_ENTRY(Double_floor, 1) { | 126 DEFINE_NATIVE_ENTRY(Double_floor, 1) { |
139 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 127 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
140 arguments->SetReturn(Double::Handle(Double::New(floor(arg.value())))); | 128 return Double::New(floor(arg.value())); |
141 } | 129 } |
142 | 130 |
143 DEFINE_NATIVE_ENTRY(Double_ceil, 1) { | 131 DEFINE_NATIVE_ENTRY(Double_ceil, 1) { |
144 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 132 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
145 arguments->SetReturn(Double::Handle(Double::New(ceil(arg.value())))); | 133 return Double::New(ceil(arg.value())); |
146 } | 134 } |
147 | 135 |
148 | 136 |
149 DEFINE_NATIVE_ENTRY(Double_truncate, 1) { | 137 DEFINE_NATIVE_ENTRY(Double_truncate, 1) { |
150 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 138 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
151 arguments->SetReturn(Double::Handle(Double::New(trunc(arg.value())))); | 139 return Double::New(trunc(arg.value())); |
152 } | 140 } |
153 | 141 |
154 | 142 |
155 DEFINE_NATIVE_ENTRY(Double_pow, 2) { | 143 DEFINE_NATIVE_ENTRY(Double_pow, 2) { |
156 const double operand = Double::CheckedHandle(arguments->At(0)).value(); | 144 const double operand = Double::CheckedHandle(arguments->At(0)).value(); |
157 GET_NATIVE_ARGUMENT(Double, exponent_object, arguments->At(1)); | 145 GET_NATIVE_ARGUMENT(Double, exponent_object, arguments->At(1)); |
158 const double exponent = exponent_object.value(); | 146 const double exponent = exponent_object.value(); |
159 arguments->SetReturn(Double::Handle(Double::New(pow(operand, exponent)))); | 147 return Double::New(pow(operand, exponent)); |
160 } | 148 } |
161 | 149 |
162 | 150 |
163 #if defined(TARGET_OS_MACOS) | 151 #if defined(TARGET_OS_MACOS) |
164 // MAC OSX math library produces old style cast warning. | 152 // MAC OSX math library produces old style cast warning. |
165 #pragma GCC diagnostic ignored "-Wold-style-cast" | 153 #pragma GCC diagnostic ignored "-Wold-style-cast" |
166 #endif | 154 #endif |
167 | 155 |
168 DEFINE_NATIVE_ENTRY(Double_toInt, 1) { | 156 DEFINE_NATIVE_ENTRY(Double_toInt, 1) { |
169 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 157 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
170 if (isinf(arg.value()) || isnan(arg.value())) { | 158 if (isinf(arg.value()) || isnan(arg.value())) { |
171 GrowableArray<const Object*> args; | 159 GrowableArray<const Object*> args; |
172 args.Add(&String::ZoneHandle(String::New( | 160 args.Add(&String::ZoneHandle(String::New( |
173 "Infinity or NaN toInt"))); | 161 "Infinity or NaN toInt"))); |
174 Exceptions::ThrowByType(Exceptions::kFormat, args); | 162 Exceptions::ThrowByType(Exceptions::kFormat, args); |
175 } | 163 } |
176 double result = trunc(arg.value()); | 164 double result = trunc(arg.value()); |
177 if ((Smi::kMinValue <= result) && (result <= Smi::kMaxValue)) { | 165 if ((Smi::kMinValue <= result) && (result <= Smi::kMaxValue)) { |
178 arguments->SetReturn(Smi::Handle(Smi::New(static_cast<intptr_t>(result)))); | 166 return Smi::New(static_cast<intptr_t>(result)); |
179 } else if ((Mint::kMinValue <= result) && (result <= Mint::kMaxValue)) { | 167 } else if ((Mint::kMinValue <= result) && (result <= Mint::kMaxValue)) { |
180 arguments->SetReturn(Mint::Handle(Mint::New(static_cast<int64_t>(result)))); | 168 return Mint::New(static_cast<int64_t>(result)); |
181 } else { | 169 } else { |
182 arguments->SetReturn( | 170 return BigintOperations::NewFromDouble(result); |
183 Bigint::Handle(BigintOperations::NewFromDouble(result))); | |
184 } | 171 } |
185 } | 172 } |
186 | 173 |
187 | 174 |
188 DEFINE_NATIVE_ENTRY(Double_toStringAsFixed, 2) { | 175 DEFINE_NATIVE_ENTRY(Double_toStringAsFixed, 2) { |
189 // The boundaries are exclusive. | 176 // The boundaries are exclusive. |
190 static const double kLowerBoundary = -1e21; | 177 static const double kLowerBoundary = -1e21; |
191 static const double kUpperBoundary = 1e21; | 178 static const double kUpperBoundary = 1e21; |
192 | 179 |
193 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 180 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
194 GET_NATIVE_ARGUMENT(Smi, fraction_digits, arguments->At(1)); | 181 GET_NATIVE_ARGUMENT(Smi, fraction_digits, arguments->At(1)); |
195 double d = arg.value(); | 182 double d = arg.value(); |
196 intptr_t fraction_digits_value = fraction_digits.Value(); | 183 intptr_t fraction_digits_value = fraction_digits.Value(); |
197 if (0 <= fraction_digits_value && fraction_digits_value <= 20 | 184 if (0 <= fraction_digits_value && fraction_digits_value <= 20 |
198 && kLowerBoundary < d && d < kUpperBoundary) { | 185 && kLowerBoundary < d && d < kUpperBoundary) { |
199 String& result = String::Handle(); | 186 return DoubleToStringAsFixed(d, static_cast<int>(fraction_digits_value)); |
200 result = DoubleToStringAsFixed(d, static_cast<int>(fraction_digits_value)); | |
201 arguments->SetReturn(result); | |
202 } else { | 187 } else { |
203 GrowableArray<const Object*> args; | 188 GrowableArray<const Object*> args; |
204 args.Add(&String::ZoneHandle(String::New( | 189 args.Add(&String::ZoneHandle(String::New( |
205 "Illegal arguments to double.toStringAsFixed"))); | 190 "Illegal arguments to double.toStringAsFixed"))); |
206 Exceptions::ThrowByType(Exceptions::kIllegalArgument, args); | 191 Exceptions::ThrowByType(Exceptions::kIllegalArgument, args); |
| 192 return Object::null(); |
207 } | 193 } |
208 } | 194 } |
209 | 195 |
210 | 196 |
211 DEFINE_NATIVE_ENTRY(Double_toStringAsExponential, 2) { | 197 DEFINE_NATIVE_ENTRY(Double_toStringAsExponential, 2) { |
212 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 198 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
213 GET_NATIVE_ARGUMENT(Smi, fraction_digits, arguments->At(1)); | 199 GET_NATIVE_ARGUMENT(Smi, fraction_digits, arguments->At(1)); |
214 double d = arg.value(); | 200 double d = arg.value(); |
215 intptr_t fraction_digits_value = fraction_digits.Value(); | 201 intptr_t fraction_digits_value = fraction_digits.Value(); |
216 if (-1 <= fraction_digits_value && fraction_digits_value <= 20) { | 202 if (-1 <= fraction_digits_value && fraction_digits_value <= 20) { |
217 String& result = String::Handle(); | 203 return DoubleToStringAsExponential( |
218 result = DoubleToStringAsExponential( | |
219 d, static_cast<int>(fraction_digits_value)); | 204 d, static_cast<int>(fraction_digits_value)); |
220 arguments->SetReturn(result); | |
221 } else { | 205 } else { |
222 GrowableArray<const Object*> args; | 206 GrowableArray<const Object*> args; |
223 args.Add(&String::ZoneHandle(String::New( | 207 args.Add(&String::ZoneHandle(String::New( |
224 "Illegal arguments to double.toStringAsExponential"))); | 208 "Illegal arguments to double.toStringAsExponential"))); |
225 Exceptions::ThrowByType(Exceptions::kIllegalArgument, args); | 209 Exceptions::ThrowByType(Exceptions::kIllegalArgument, args); |
| 210 return Object::null(); |
226 } | 211 } |
227 } | 212 } |
228 | 213 |
229 | 214 |
230 DEFINE_NATIVE_ENTRY(Double_toStringAsPrecision, 2) { | 215 DEFINE_NATIVE_ENTRY(Double_toStringAsPrecision, 2) { |
231 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 216 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
232 GET_NATIVE_ARGUMENT(Smi, precision, arguments->At(1)); | 217 GET_NATIVE_ARGUMENT(Smi, precision, arguments->At(1)); |
233 double d = arg.value(); | 218 double d = arg.value(); |
234 intptr_t precision_value = precision.Value(); | 219 intptr_t precision_value = precision.Value(); |
235 if (1 <= precision_value && precision_value <= 21) { | 220 if (1 <= precision_value && precision_value <= 21) { |
236 String& result = String::Handle(); | 221 return DoubleToStringAsPrecision(d, static_cast<int>(precision_value)); |
237 result = DoubleToStringAsPrecision(d, static_cast<int>(precision_value)); | |
238 arguments->SetReturn(result); | |
239 } else { | 222 } else { |
240 GrowableArray<const Object*> args; | 223 GrowableArray<const Object*> args; |
241 args.Add(&String::ZoneHandle(String::New( | 224 args.Add(&String::ZoneHandle(String::New( |
242 "Illegal arguments to double.toStringAsPrecision"))); | 225 "Illegal arguments to double.toStringAsPrecision"))); |
243 Exceptions::ThrowByType(Exceptions::kIllegalArgument, args); | 226 Exceptions::ThrowByType(Exceptions::kIllegalArgument, args); |
| 227 return Object::null(); |
244 } | 228 } |
245 } | 229 } |
246 | 230 |
247 | 231 |
248 DEFINE_NATIVE_ENTRY(Double_isInfinite, 1) { | 232 DEFINE_NATIVE_ENTRY(Double_isInfinite, 1) { |
249 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 233 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
250 if (isinf(arg.value())) { | 234 return Bool::Get(isinf(arg.value())); |
251 arguments->SetReturn(Bool::Handle(Bool::True())); | |
252 } else { | |
253 arguments->SetReturn(Bool::Handle(Bool::False())); | |
254 } | |
255 } | 235 } |
256 | 236 |
257 | 237 |
258 DEFINE_NATIVE_ENTRY(Double_isNaN, 1) { | 238 DEFINE_NATIVE_ENTRY(Double_isNaN, 1) { |
259 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 239 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
260 if (isnan(arg.value())) { | 240 return Bool::Get(isnan(arg.value())); |
261 arguments->SetReturn(Bool::Handle(Bool::True())); | |
262 } else { | |
263 arguments->SetReturn(Bool::Handle(Bool::False())); | |
264 } | |
265 } | 241 } |
266 | 242 |
267 | 243 |
268 DEFINE_NATIVE_ENTRY(Double_isNegative, 1) { | 244 DEFINE_NATIVE_ENTRY(Double_isNegative, 1) { |
269 const Double& arg = Double::CheckedHandle(arguments->At(0)); | 245 const Double& arg = Double::CheckedHandle(arguments->At(0)); |
270 // Include negative zero, infinity. | 246 // Include negative zero, infinity. |
271 if (signbit(arg.value()) && !isnan(arg.value())) { | 247 return Bool::Get(signbit(arg.value()) && !isnan(arg.value())); |
272 arguments->SetReturn(Bool::Handle(Bool::True())); | |
273 } else { | |
274 arguments->SetReturn(Bool::Handle(Bool::False())); | |
275 } | |
276 } | 248 } |
277 | 249 |
278 // Add here only functions using/referring to old-style casts. | 250 // Add here only functions using/referring to old-style casts. |
279 | 251 |
280 } // namespace dart | 252 } // namespace dart |
OLD | NEW |