V8 Project
runtime-numbers.cc
Go to the documentation of this file.
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #include "src/arguments.h"
8 #include "src/codegen.h"
9 #include "src/misc-intrinsics.h"
10 #include "src/runtime/runtime.h"
12 
13 
14 #ifndef _STLP_VENDOR_CSTD
15 // STLPort doesn't import fpclassify and isless into the std namespace.
16 using std::fpclassify;
17 using std::isless;
18 #endif
19 
20 namespace v8 {
21 namespace internal {
22 
23 RUNTIME_FUNCTION(Runtime_NumberToRadixString) {
24  HandleScope scope(isolate);
25  DCHECK(args.length() == 2);
26  CONVERT_SMI_ARG_CHECKED(radix, 1);
27  RUNTIME_ASSERT(2 <= radix && radix <= 36);
28 
29  // Fast case where the result is a one character string.
30  if (args[0]->IsSmi()) {
31  int value = args.smi_at(0);
32  if (value >= 0 && value < radix) {
33  // Character array used for conversion.
34  static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
35  return *isolate->factory()->LookupSingleCharacterStringFromCode(
36  kCharTable[value]);
37  }
38  }
39 
40  // Slow case.
42  if (std::isnan(value)) {
43  return isolate->heap()->nan_string();
44  }
45  if (std::isinf(value)) {
46  if (value < 0) {
47  return isolate->heap()->minus_infinity_string();
48  }
49  return isolate->heap()->infinity_string();
50  }
51  char* str = DoubleToRadixCString(value, radix);
52  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
53  DeleteArray(str);
54  return *result;
55 }
56 
57 
58 RUNTIME_FUNCTION(Runtime_NumberToFixed) {
59  HandleScope scope(isolate);
60  DCHECK(args.length() == 2);
61 
63  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
64  int f = FastD2IChecked(f_number);
65  // See DoubleToFixedCString for these constants:
66  RUNTIME_ASSERT(f >= 0 && f <= 20);
67  RUNTIME_ASSERT(!Double(value).IsSpecial());
68  char* str = DoubleToFixedCString(value, f);
69  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
70  DeleteArray(str);
71  return *result;
72 }
73 
74 
75 RUNTIME_FUNCTION(Runtime_NumberToExponential) {
76  HandleScope scope(isolate);
77  DCHECK(args.length() == 2);
78 
80  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
81  int f = FastD2IChecked(f_number);
82  RUNTIME_ASSERT(f >= -1 && f <= 20);
83  RUNTIME_ASSERT(!Double(value).IsSpecial());
84  char* str = DoubleToExponentialCString(value, f);
85  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
86  DeleteArray(str);
87  return *result;
88 }
89 
90 
91 RUNTIME_FUNCTION(Runtime_NumberToPrecision) {
92  HandleScope scope(isolate);
93  DCHECK(args.length() == 2);
94 
96  CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
97  int f = FastD2IChecked(f_number);
98  RUNTIME_ASSERT(f >= 1 && f <= 21);
99  RUNTIME_ASSERT(!Double(value).IsSpecial());
100  char* str = DoubleToPrecisionCString(value, f);
101  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
102  DeleteArray(str);
103  return *result;
104 }
105 
106 
107 RUNTIME_FUNCTION(Runtime_IsValidSmi) {
108  SealHandleScope shs(isolate);
109  DCHECK(args.length() == 1);
110 
111  CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
112  return isolate->heap()->ToBoolean(Smi::IsValid(number));
113 }
114 
115 
116 static bool AreDigits(const uint8_t* s, int from, int to) {
117  for (int i = from; i < to; i++) {
118  if (s[i] < '0' || s[i] > '9') return false;
119  }
120 
121  return true;
122 }
123 
124 
125 static int ParseDecimalInteger(const uint8_t* s, int from, int to) {
126  DCHECK(to - from < 10); // Overflow is not possible.
127  DCHECK(from < to);
128  int d = s[from] - '0';
129 
130  for (int i = from + 1; i < to; i++) {
131  d = 10 * d + (s[i] - '0');
132  }
133 
134  return d;
135 }
136 
137 
138 RUNTIME_FUNCTION(Runtime_StringToNumber) {
139  HandleScope handle_scope(isolate);
140  DCHECK(args.length() == 1);
141  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
142  subject = String::Flatten(subject);
143 
144  // Fast case: short integer or some sorts of junk values.
145  if (subject->IsSeqOneByteString()) {
146  int len = subject->length();
147  if (len == 0) return Smi::FromInt(0);
148 
150  uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars();
151  bool minus = (data[0] == '-');
152  int start_pos = (minus ? 1 : 0);
153 
154  if (start_pos == len) {
155  return isolate->heap()->nan_value();
156  } else if (data[start_pos] > '9') {
157  // Fast check for a junk value. A valid string may start from a
158  // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit
159  // or the 'I' character ('Infinity'). All of that have codes not greater
160  // than '9' except 'I' and &nbsp;.
161  if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
162  return isolate->heap()->nan_value();
163  }
164  } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
165  // The maximal/minimal smi has 10 digits. If the string has less digits
166  // we know it will fit into the smi-data type.
167  int d = ParseDecimalInteger(data, start_pos, len);
168  if (minus) {
169  if (d == 0) return isolate->heap()->minus_zero_value();
170  d = -d;
171  } else if (!subject->HasHashCode() && len <= String::kMaxArrayIndexSize &&
172  (len == 1 || data[0] != '0')) {
173  // String hash is not calculated yet but all the data are present.
174  // Update the hash field to speed up sequential convertions.
176 #ifdef DEBUG
177  subject->Hash(); // Force hash calculation.
178  DCHECK_EQ(static_cast<int>(subject->hash_field()),
179  static_cast<int>(hash));
180 #endif
181  subject->set_hash_field(hash);
182  }
183  return Smi::FromInt(d);
184  }
185  }
186 
187  // Slower case.
188  int flags = ALLOW_HEX;
189  if (FLAG_harmony_numeric_literals) {
190  // The current spec draft has not updated "ToNumber Applied to the String
191  // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
193  }
194 
195  return *isolate->factory()->NewNumber(
196  StringToDouble(isolate->unicode_cache(), *subject, flags));
197 }
198 
199 
200 RUNTIME_FUNCTION(Runtime_StringParseInt) {
201  HandleScope handle_scope(isolate);
202  DCHECK(args.length() == 2);
203  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
204  CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]);
205  RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
206 
207  subject = String::Flatten(subject);
208  double value;
209 
210  {
212  String::FlatContent flat = subject->GetFlatContent();
213 
214  // ECMA-262 section 15.1.2.3, empty string is NaN
215  if (flat.IsOneByte()) {
216  value =
217  StringToInt(isolate->unicode_cache(), flat.ToOneByteVector(), radix);
218  } else {
219  value = StringToInt(isolate->unicode_cache(), flat.ToUC16Vector(), radix);
220  }
221  }
222 
223  return *isolate->factory()->NewNumber(value);
224 }
225 
226 
227 RUNTIME_FUNCTION(Runtime_StringParseFloat) {
228  HandleScope shs(isolate);
229  DCHECK(args.length() == 1);
230  CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
231 
232  subject = String::Flatten(subject);
233  double value = StringToDouble(isolate->unicode_cache(), *subject,
235 
236  return *isolate->factory()->NewNumber(value);
237 }
238 
239 
240 RUNTIME_FUNCTION(Runtime_NumberToStringRT) {
241  HandleScope scope(isolate);
242  DCHECK(args.length() == 1);
244 
245  return *isolate->factory()->NumberToString(number);
246 }
247 
248 
249 RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
250  HandleScope scope(isolate);
251  DCHECK(args.length() == 1);
253 
254  return *isolate->factory()->NumberToString(number, false);
255 }
256 
257 
258 RUNTIME_FUNCTION(Runtime_NumberToInteger) {
259  HandleScope scope(isolate);
260  DCHECK(args.length() == 1);
261 
262  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
263  return *isolate->factory()->NewNumber(DoubleToInteger(number));
264 }
265 
266 
267 RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) {
268  HandleScope scope(isolate);
269  DCHECK(args.length() == 1);
270 
271  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
272  double double_value = DoubleToInteger(number);
273  // Map both -0 and +0 to +0.
274  if (double_value == 0) double_value = 0;
275 
276  return *isolate->factory()->NewNumber(double_value);
277 }
278 
279 
280 RUNTIME_FUNCTION(Runtime_NumberToJSUint32) {
281  HandleScope scope(isolate);
282  DCHECK(args.length() == 1);
283 
284  CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
285  return *isolate->factory()->NewNumberFromUint(number);
286 }
287 
288 
289 RUNTIME_FUNCTION(Runtime_NumberToJSInt32) {
290  HandleScope scope(isolate);
291  DCHECK(args.length() == 1);
292 
293  CONVERT_DOUBLE_ARG_CHECKED(number, 0);
294  return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number));
295 }
296 
297 
298 // Converts a Number to a Smi, if possible. Returns NaN if the number is not
299 // a small integer.
300 RUNTIME_FUNCTION(Runtime_NumberToSmi) {
301  SealHandleScope shs(isolate);
302  DCHECK(args.length() == 1);
303  CONVERT_ARG_CHECKED(Object, obj, 0);
304  if (obj->IsSmi()) {
305  return obj;
306  }
307  if (obj->IsHeapNumber()) {
308  double value = HeapNumber::cast(obj)->value();
309  int int_value = FastD2I(value);
310  if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
311  return Smi::FromInt(int_value);
312  }
313  }
314  return isolate->heap()->nan_value();
315 }
316 
317 
318 RUNTIME_FUNCTION(Runtime_NumberAdd) {
319  HandleScope scope(isolate);
320  DCHECK(args.length() == 2);
321 
324  return *isolate->factory()->NewNumber(x + y);
325 }
326 
327 
328 RUNTIME_FUNCTION(Runtime_NumberSub) {
329  HandleScope scope(isolate);
330  DCHECK(args.length() == 2);
331 
334  return *isolate->factory()->NewNumber(x - y);
335 }
336 
337 
338 RUNTIME_FUNCTION(Runtime_NumberMul) {
339  HandleScope scope(isolate);
340  DCHECK(args.length() == 2);
341 
344  return *isolate->factory()->NewNumber(x * y);
345 }
346 
347 
348 RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) {
349  HandleScope scope(isolate);
350  DCHECK(args.length() == 1);
351 
353  return *isolate->factory()->NewNumber(-x);
354 }
355 
356 
357 RUNTIME_FUNCTION(Runtime_NumberDiv) {
358  HandleScope scope(isolate);
359  DCHECK(args.length() == 2);
360 
363  return *isolate->factory()->NewNumber(x / y);
364 }
365 
366 
367 RUNTIME_FUNCTION(Runtime_NumberMod) {
368  HandleScope scope(isolate);
369  DCHECK(args.length() == 2);
370 
373  return *isolate->factory()->NewNumber(modulo(x, y));
374 }
375 
376 
377 RUNTIME_FUNCTION(Runtime_NumberImul) {
378  HandleScope scope(isolate);
379  DCHECK(args.length() == 2);
380 
381  // We rely on implementation-defined behavior below, but at least not on
382  // undefined behavior.
383  CONVERT_NUMBER_CHECKED(uint32_t, x, Int32, args[0]);
385  int32_t product = static_cast<int32_t>(x * y);
386  return *isolate->factory()->NewNumberFromInt(product);
387 }
388 
389 
390 RUNTIME_FUNCTION(Runtime_NumberOr) {
391  HandleScope scope(isolate);
392  DCHECK(args.length() == 2);
393 
394  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
396  return *isolate->factory()->NewNumberFromInt(x | y);
397 }
398 
399 
400 RUNTIME_FUNCTION(Runtime_NumberAnd) {
401  HandleScope scope(isolate);
402  DCHECK(args.length() == 2);
403 
404  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
406  return *isolate->factory()->NewNumberFromInt(x & y);
407 }
408 
409 
410 RUNTIME_FUNCTION(Runtime_NumberXor) {
411  HandleScope scope(isolate);
412  DCHECK(args.length() == 2);
413 
414  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
416  return *isolate->factory()->NewNumberFromInt(x ^ y);
417 }
418 
419 
420 RUNTIME_FUNCTION(Runtime_NumberShl) {
421  HandleScope scope(isolate);
422  DCHECK(args.length() == 2);
423 
424  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
426  return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f));
427 }
428 
429 
430 RUNTIME_FUNCTION(Runtime_NumberShr) {
431  HandleScope scope(isolate);
432  DCHECK(args.length() == 2);
433 
434  CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
436  return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f));
437 }
438 
439 
440 RUNTIME_FUNCTION(Runtime_NumberSar) {
441  HandleScope scope(isolate);
442  DCHECK(args.length() == 2);
443 
444  CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
446  return *isolate->factory()->NewNumberFromInt(
447  ArithmeticShiftRight(x, y & 0x1f));
448 }
449 
450 
451 RUNTIME_FUNCTION(Runtime_NumberEquals) {
452  SealHandleScope shs(isolate);
453  DCHECK(args.length() == 2);
454 
457  if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
458  if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
459  if (x == y) return Smi::FromInt(EQUAL);
460  Object* result;
461  if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
462  result = Smi::FromInt(EQUAL);
463  } else {
464  result = Smi::FromInt(NOT_EQUAL);
465  }
466  return result;
467 }
468 
469 
470 RUNTIME_FUNCTION(Runtime_NumberCompare) {
471  SealHandleScope shs(isolate);
472  DCHECK(args.length() == 3);
473 
476  CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2)
477  if (std::isnan(x) || std::isnan(y)) return *uncomparable_result;
478  if (x == y) return Smi::FromInt(EQUAL);
479  if (isless(x, y)) return Smi::FromInt(LESS);
480  return Smi::FromInt(GREATER);
481 }
482 
483 
484 // Compare two Smis as if they were converted to strings and then
485 // compared lexicographically.
486 RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) {
487  SealHandleScope shs(isolate);
488  DCHECK(args.length() == 2);
489  CONVERT_SMI_ARG_CHECKED(x_value, 0);
490  CONVERT_SMI_ARG_CHECKED(y_value, 1);
491 
492  // If the integers are equal so are the string representations.
493  if (x_value == y_value) return Smi::FromInt(EQUAL);
494 
495  // If one of the integers is zero the normal integer order is the
496  // same as the lexicographic order of the string representations.
497  if (x_value == 0 || y_value == 0)
498  return Smi::FromInt(x_value < y_value ? LESS : GREATER);
499 
500  // If only one of the integers is negative the negative number is
501  // smallest because the char code of '-' is less than the char code
502  // of any digit. Otherwise, we make both values positive.
503 
504  // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
505  // architectures using 32-bit Smis.
506  uint32_t x_scaled = x_value;
507  uint32_t y_scaled = y_value;
508  if (x_value < 0 || y_value < 0) {
509  if (y_value >= 0) return Smi::FromInt(LESS);
510  if (x_value >= 0) return Smi::FromInt(GREATER);
511  x_scaled = -x_value;
512  y_scaled = -y_value;
513  }
514 
515  static const uint32_t kPowersOf10[] = {
516  1, 10, 100, 1000,
517  10 * 1000, 100 * 1000, 1000 * 1000, 10 * 1000 * 1000,
518  100 * 1000 * 1000, 1000 * 1000 * 1000};
519 
520  // If the integers have the same number of decimal digits they can be
521  // compared directly as the numeric order is the same as the
522  // lexicographic order. If one integer has fewer digits, it is scaled
523  // by some power of 10 to have the same number of digits as the longer
524  // integer. If the scaled integers are equal it means the shorter
525  // integer comes first in the lexicographic order.
526 
527  // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
528  int x_log2 = IntegerLog2(x_scaled);
529  int x_log10 = ((x_log2 + 1) * 1233) >> 12;
530  x_log10 -= x_scaled < kPowersOf10[x_log10];
531 
532  int y_log2 = IntegerLog2(y_scaled);
533  int y_log10 = ((y_log2 + 1) * 1233) >> 12;
534  y_log10 -= y_scaled < kPowersOf10[y_log10];
535 
536  int tie = EQUAL;
537 
538  if (x_log10 < y_log10) {
539  // X has fewer digits. We would like to simply scale up X but that
540  // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
541  // be scaled up to 9_000_000_000. So we scale up by the next
542  // smallest power and scale down Y to drop one digit. It is OK to
543  // drop one digit from the longer integer since the final digit is
544  // past the length of the shorter integer.
545  x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
546  y_scaled /= 10;
547  tie = LESS;
548  } else if (y_log10 < x_log10) {
549  y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
550  x_scaled /= 10;
551  tie = GREATER;
552  }
553 
554  if (x_scaled < y_scaled) return Smi::FromInt(LESS);
555  if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
556  return Smi::FromInt(tie);
557 }
558 
559 
560 RUNTIME_FUNCTION(RuntimeReference_NumberToString) {
561  SealHandleScope shs(isolate);
562  return __RT_impl_Runtime_NumberToStringRT(args, isolate);
563 }
564 }
565 } // namespace v8::internal
A JavaScript value representing a 32-bit signed integer.
Definition: v8.h:2191
A JavaScript value representing a 32-bit unsigned integer.
Definition: v8.h:2202
static double nan_value()
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static bool IsValid(intptr_t value)
Definition: objects-inl.h:1334
static uint32_t MakeArrayIndexHash(uint32_t value, int length)
Definition: objects.cc:8925
Vector< const uint8_t > ToOneByteVector()
Definition: objects.h:8639
Vector< const uc16 > ToUC16Vector()
Definition: objects.h:8645
static const int kMaxArrayIndexSize
Definition: objects.h:8807
static Handle< String > Flatten(Handle< String > string, PretenureFlag pretenure=NOT_TENURED)
Definition: objects-inl.h:3354
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in only print modified registers Trace simulator debug messages Implied by trace sim abort randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot A filename with extra code to be included in the A file to write the raw snapshot bytes to(mksnapshot only)") DEFINE_STRING(raw_context_file
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
int int32_t
Definition: unicode.cc:24
void DeleteArray(T *array)
Definition: allocation.h:68
char * DoubleToRadixCString(double value, int radix)
Definition: conversions.cc:414
char * DoubleToFixedCString(double value, int f)
Definition: conversions.cc:196
static int ParseDecimalInteger(const uint8_t *s, int from, int to)
double DoubleToInteger(double x)
int IntegerLog2(uint32_t value)
double modulo(double x, double y)
Definition: codegen.cc:50
char * DoubleToExponentialCString(double value, int f)
Definition: conversions.cc:299
static bool AreDigits(const uint8_t *s, int from, int to)
char * DoubleToPrecisionCString(double value, int p)
Definition: conversions.cc:344
double StringToInt(UnicodeCache *unicode_cache, Vector< const uint8_t > vector, int radix)
Definition: conversions.cc:105
double FastI2D(int x)
Definition: conversions.h:64
int ArithmeticShiftRight(int x, int s)
Definition: utils.h:90
int32_t DoubleToInt32(double x)
int FastD2I(double x)
Definition: conversions.h:57
double StringToDouble(UnicodeCache *unicode_cache, const char *str, int flags, double empty_string_val)
Definition: conversions.cc:70
int FastD2IChecked(double x)
Definition: conversions.h:46
@ RUNTIME_FUNCTION
Definition: serialize.h:23
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define CONVERT_ARG_CHECKED(Type, name, index)
Definition: runtime-utils.h:24
#define RUNTIME_ASSERT(value)
Definition: runtime-utils.h:12
#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index)
Definition: runtime-utils.h:28
#define CONVERT_NUMBER_CHECKED(type, name, Type, obj)
Definition: runtime-utils.h:60
#define CONVERT_DOUBLE_ARG_CHECKED(name, index)
Definition: runtime-utils.h:53
#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index)
Definition: runtime-utils.h:32
#define CONVERT_SMI_ARG_CHECKED(name, index)
Definition: runtime-utils.h:46
@ FP_ZERO
Definition: win32-math.h:22
int fpclassify(double x)
int isless(double x, double y)