1 /*
2  *  Ecmascript specification algorithm and conversion helpers.
3  *
4  *  These helpers encapsulate the primitive Ecmascript operation
5  *  semantics, and are used by the bytecode executor and the API
6  *  (among other places).  Note that some primitives are only
7  *  implemented as part of the API and have no "internal" helper.
8  *  (This is the case when an internal helper would not really be
9  *  useful; e.g. the operation is rare, uses value stack heavily,
10  *  etc.)
11  *
12  *  The operation arguments depend on what is required to implement
13  *  the operation:
14  *
15  *    - If an operation is simple and stateless, and has no side
16  *      effects, it won't take an duk_hthread argument and its
17  *      arguments may be duk_tval pointers (which are safe as long
18  *      as no side effects take place).
19  *
20  *    - If complex coercions are required (e.g. a "ToNumber" coercion)
21  *      or errors may be thrown, the operation takes an duk_hthread
22  *      argument.  This also implies that the operation may have
23  *      arbitrary side effects, invalidating any duk_tval pointers.
24  *
25  *    - For operations with potential side effects, arguments can be
26  *      taken in several ways:
27  *
28  *      a) as duk_tval pointers, which makes sense if the "common case"
29  *         can be resolved without side effects (e.g. coercion); the
30  *         arguments are pushed to the valstack for coercion if
31  *         necessary
32  *
33  *      b) as duk_tval values
34  *
35  *      c) implicitly on value stack top
36  *
37  *      d) as indices to the value stack
38  *
39  *  Future work:
40  *
41  *     - Argument styles may not be the most sensible in every case now.
42  *
43  *     - In-place coercions might be useful for several operations, if
44  *       in-place coercion is OK for the bytecode executor and the API.
45  */
46 
47 #include "duk_internal.h"
48 
49 /*
50  *  [[DefaultValue]]  (E5 Section 8.12.8)
51  *
52  *  ==> implemented in the API.
53  */
54 
55 /*
56  *  ToPrimitive()  (E5 Section 9.1)
57  *
58  *  ==> implemented in the API.
59  */
60 
61 /*
62  *  ToBoolean()  (E5 Section 9.2)
63  */
64 
duk_js_toboolean(duk_tval * tv)65 DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
66 	switch (DUK_TVAL_GET_TAG(tv)) {
67 	case DUK_TAG_UNDEFINED:
68 	case DUK_TAG_NULL:
69 		return 0;
70 	case DUK_TAG_BOOLEAN:
71 		return DUK_TVAL_GET_BOOLEAN(tv);
72 	case DUK_TAG_STRING: {
73 		duk_hstring *h = DUK_TVAL_GET_STRING(tv);
74 		DUK_ASSERT(h != NULL);
75 		return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
76 	}
77 	case DUK_TAG_OBJECT: {
78 		return 1;
79 	}
80 	case DUK_TAG_BUFFER: {
81 		/* mimic semantics for strings */
82 		duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
83 		DUK_ASSERT(h != NULL);
84 		return (DUK_HBUFFER_GET_SIZE(h) > 0 ? 1 : 0);
85 	}
86 	case DUK_TAG_POINTER: {
87 		void *p = DUK_TVAL_GET_POINTER(tv);
88 		return (p != NULL ? 1 : 0);
89 	}
90 	case DUK_TAG_LIGHTFUNC: {
91 		return 1;
92 	}
93 #if defined(DUK_USE_FASTINT)
94 	case DUK_TAG_FASTINT:
95 		if (DUK_TVAL_GET_FASTINT(tv) != 0) {
96 			return 1;
97 		} else {
98 			return 0;
99 		}
100 #endif
101 	default: {
102 		/* number */
103 		duk_double_t d;
104 		int c;
105 		DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
106 		DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
107 		d = DUK_TVAL_GET_DOUBLE(tv);
108 		c = DUK_FPCLASSIFY((double) d);
109 		if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
110 			return 0;
111 		} else {
112 			return 1;
113 		}
114 	}
115 	}
116 	DUK_UNREACHABLE();
117 }
118 
119 /*
120  *  ToNumber()  (E5 Section 9.3)
121  *
122  *  Value to convert must be on stack top, and is popped before exit.
123  *
124  *  See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
125  *       http://www.cs.indiana.edu/~burger/fp/index.html
126  *
127  *  Notes on the conversion:
128  *
129  *    - There are specific requirements on the accuracy of the conversion
130  *      through a "Mathematical Value" (MV), so this conversion is not
131  *      trivial.
132  *
133  *    - Quick rejects (e.g. based on first char) are difficult because
134  *      the grammar allows leading and trailing white space.
135  *
136  *    - Quick reject based on string length is difficult even after
137  *      accounting for white space; there may be arbitrarily many
138  *      decimal digits.
139  *
140  *    - Standard grammar allows decimal values ("123"), hex values
141  *      ("0x123") and infinities
142  *
143  *    - Unlike source code literals, ToNumber() coerces empty strings
144  *      and strings with only whitespace to zero (not NaN).
145  */
146 
147 /* E5 Section 9.3.1 */
duk__tonumber_string_raw(duk_hthread * thr)148 DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
149 	duk_context *ctx = (duk_context *) thr;
150 	duk_small_uint_t s2n_flags;
151 	duk_double_t d;
152 
153 	/* Quite lenient, e.g. allow empty as zero, but don't allow trailing
154 	 * garbage.
155 	 */
156 	s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
157 	            DUK_S2N_FLAG_ALLOW_EXP |
158 	            DUK_S2N_FLAG_ALLOW_PLUS |
159 	            DUK_S2N_FLAG_ALLOW_MINUS |
160 	            DUK_S2N_FLAG_ALLOW_INF |
161 	            DUK_S2N_FLAG_ALLOW_FRAC |
162 	            DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
163 	            DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
164 	            DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
165 	            DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
166 	            DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
167 
168 	duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
169 	d = duk_get_number(ctx, -1);
170 	duk_pop(ctx);
171 
172 	return d;
173 }
174 
duk_js_tonumber(duk_hthread * thr,duk_tval * tv)175 DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
176 	duk_context *ctx = (duk_hthread *) thr;
177 
178 	DUK_ASSERT(thr != NULL);
179 	DUK_ASSERT(tv != NULL);
180 
181 	switch (DUK_TVAL_GET_TAG(tv)) {
182 	case DUK_TAG_UNDEFINED: {
183 		/* return a specific NaN (although not strictly necessary) */
184 		duk_double_union du;
185 		DUK_DBLUNION_SET_NAN(&du);
186 		DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
187 		return du.d;
188 	}
189 	case DUK_TAG_NULL: {
190 		/* +0.0 */
191 		return 0.0;
192 	}
193 	case DUK_TAG_BOOLEAN: {
194 		if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
195 			return 1.0;
196 		}
197 		return 0.0;
198 	}
199 	case DUK_TAG_STRING: {
200 		duk_hstring *h = DUK_TVAL_GET_STRING(tv);
201 		duk_push_hstring(ctx, h);
202 		return duk__tonumber_string_raw(thr);
203 	}
204 	case DUK_TAG_OBJECT: {
205 		/* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint),
206 		 * so use [[DefaultValue]] directly.
207 		 */
208 		duk_double_t d;
209 		duk_push_tval(ctx, tv);
210 		duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER);  /* 'tv' becomes invalid */
211 
212 		/* recursive call for a primitive value (guaranteed not to cause second
213 		 * recursion).
214 		 */
215 		d = duk_js_tonumber(thr, duk_require_tval(ctx, -1));
216 
217 		duk_pop(ctx);
218 		return d;
219 	}
220 	case DUK_TAG_BUFFER: {
221 		/* Coerce like a string.  This makes sense because addition also treats
222 		 * buffers like strings.
223 		 */
224 		duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
225 		duk_push_hbuffer(ctx, h);
226 		duk_to_string(ctx, -1);  /* XXX: expensive, but numconv now expects to see a string */
227 		return duk__tonumber_string_raw(thr);
228 	}
229 	case DUK_TAG_POINTER: {
230 		/* Coerce like boolean */
231 		void *p = DUK_TVAL_GET_POINTER(tv);
232 		return (p != NULL ? 1.0 : 0.0);
233 	}
234 	case DUK_TAG_LIGHTFUNC: {
235 		/* +(function(){}) -> NaN */
236 		return DUK_DOUBLE_NAN;
237 	}
238 #if defined(DUK_USE_FASTINT)
239 	case DUK_TAG_FASTINT:
240 		return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
241 #endif
242 	default: {
243 		/* number */
244 		DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
245 		DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
246 		return DUK_TVAL_GET_DOUBLE(tv);
247 	}
248 	}
249 
250 	DUK_UNREACHABLE();
251 }
252 
253 /*
254  *  ToInteger()  (E5 Section 9.4)
255  */
256 
257 /* exposed, used by e.g. duk_bi_date.c */
duk_js_tointeger_number(duk_double_t x)258 DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
259 	duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
260 
261 	if (c == DUK_FP_NAN) {
262 		return 0.0;
263 	} else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
264 		/* XXX: FP_ZERO check can be removed, the else clause handles it
265 		 * correctly (preserving sign).
266 		 */
267 		return x;
268 	} else {
269 		duk_small_int_t s = (duk_small_int_t) DUK_SIGNBIT(x);
270 		x = DUK_FLOOR(DUK_FABS(x));  /* truncate towards zero */
271 		if (s) {
272 			x = -x;
273 		}
274 		return x;
275 	}
276 }
277 
duk_js_tointeger(duk_hthread * thr,duk_tval * tv)278 DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
279 	/* XXX: fastint */
280 	duk_double_t d = duk_js_tonumber(thr, tv);  /* invalidates tv */
281 	return duk_js_tointeger_number(d);
282 }
283 
284 /*
285  *  ToInt32(), ToUint32(), ToUint16()  (E5 Sections 9.5, 9.6, 9.7)
286  */
287 
288 /* combined algorithm matching E5 Sections 9.5 and 9.6 */
duk__toint32_touint32_helper(duk_double_t x,duk_bool_t is_toint32)289 DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
290 	duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
291 	duk_small_int_t s;
292 
293 	if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
294 		return 0.0;
295 	}
296 
297 
298 	/* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
299 	s = (duk_small_int_t) DUK_SIGNBIT(x);
300 	x = DUK_FLOOR(DUK_FABS(x));
301 	if (s) {
302 		x = -x;
303 	}
304 
305 	/* NOTE: fmod(x) result sign is same as sign of x, which
306 	 * differs from what Javascript wants (see Section 9.6).
307 	 */
308 
309 	x = DUK_FMOD(x, DUK_DOUBLE_2TO32);    /* -> x in ]-2**32, 2**32[ */
310 
311 	if (x < 0.0) {
312 		x += DUK_DOUBLE_2TO32;
313 	}
314 	/* -> x in [0, 2**32[ */
315 
316 	if (is_toint32) {
317 		if (x >= DUK_DOUBLE_2TO31) {
318 			/* x in [2**31, 2**32[ */
319 
320 			x -= DUK_DOUBLE_2TO32;  /* -> x in [-2**31,2**31[ */
321 		}
322 	}
323 
324 	return x;
325 }
326 
duk_js_toint32(duk_hthread * thr,duk_tval * tv)327 DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
328 	duk_double_t d;
329 
330 #if defined(DUK_USE_FASTINT)
331 	if (DUK_TVAL_IS_FASTINT(tv)) {
332 		return DUK_TVAL_GET_FASTINT_I32(tv);
333 	}
334 #endif
335 
336 	d = duk_js_tonumber(thr, tv);  /* invalidates tv */
337 	d = duk__toint32_touint32_helper(d, 1);
338 	DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
339 	DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0);  /* [-0x80000000,0x7fffffff] */
340 	DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d)));  /* whole, won't clip */
341 	return (duk_int32_t) d;
342 }
343 
344 
duk_js_touint32(duk_hthread * thr,duk_tval * tv)345 DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
346 	duk_double_t d;
347 
348 #if defined(DUK_USE_FASTINT)
349 	if (DUK_TVAL_IS_FASTINT(tv)) {
350 		return DUK_TVAL_GET_FASTINT_U32(tv);
351 	}
352 #endif
353 
354 	d = duk_js_tonumber(thr, tv);  /* invalidates tv */
355 	d = duk__toint32_touint32_helper(d, 0);
356 	DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
357 	DUK_ASSERT(d >= 0.0 && d <= 4294967295.0);  /* [0x00000000, 0xffffffff] */
358 	DUK_ASSERT(d == ((duk_double_t) ((duk_uint32_t) d)));  /* whole, won't clip */
359 	return (duk_uint32_t) d;
360 
361 }
362 
duk_js_touint16(duk_hthread * thr,duk_tval * tv)363 DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
364 	/* should be a safe way to compute this */
365 	return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
366 }
367 
368 /*
369  *  ToString()  (E5 Section 9.8)
370  *
371  *  ==> implemented in the API.
372  */
373 
374 /*
375  *  ToObject()  (E5 Section 9.9)
376  *
377  *  ==> implemented in the API.
378  */
379 
380 /*
381  *  CheckObjectCoercible()  (E5 Section 9.10)
382  *
383  *  Note: no API equivalent now.
384  */
385 
386 #if 0  /* unused */
387 DUK_INTERNAL void duk_js_checkobjectcoercible(duk_hthread *thr, duk_tval *tv_x) {
388 	duk_small_uint_t tag = DUK_TVAL_GET_TAG(tv_x);
389 
390 	/* Note: this must match ToObject() behavior */
391 
392 	if (tag == DUK_TAG_UNDEFINED ||
393 	    tag == DUK_TAG_NULL ||
394 	    tag == DUK_TAG_POINTER ||
395 	    tag == DUK_TAG_BUFFER) {
396 		DUK_ERROR_TYPE(thr, "not object coercible");
397 	}
398 }
399 #endif
400 
401 /*
402  *  IsCallable()  (E5 Section 9.11)
403  *
404  *  XXX: API equivalent is a separate implementation now, and this has
405  *  currently no callers.
406  */
407 
408 #if 0  /* unused */
409 DUK_INTERNAL duk_bool_t duk_js_iscallable(duk_tval *tv_x) {
410 	duk_hobject *obj;
411 
412 	if (!DUK_TVAL_IS_OBJECT(tv_x)) {
413 		return 0;
414 	}
415 	obj = DUK_TVAL_GET_OBJECT(tv_x);
416 	DUK_ASSERT(obj != NULL);
417 
418 	return DUK_HOBJECT_IS_CALLABLE(obj);
419 }
420 #endif
421 
422 /*
423  *  Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
424  *  9.12).  These have much in common so they can share some helpers.
425  *
426  *  Future work notes:
427  *
428  *    - Current implementation (and spec definition) has recursion; this should
429  *      be fixed if possible.
430  *
431  *    - String-to-number coercion should be possible without going through the
432  *      value stack (and be more compact) if a shared helper is invoked.
433  */
434 
435 /* Note that this is the same operation for strict and loose equality:
436  *  - E5 Section 11.9.3, step 1.c (loose)
437  *  - E5 Section 11.9.6, step 4 (strict)
438  */
439 
duk__js_equals_number(duk_double_t x,duk_double_t y)440 DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) {
441 #if defined(DUK_USE_PARANOID_MATH)
442 	/* Straightforward algorithm, makes fewer compiler assumptions. */
443 	duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
444 	duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
445 	if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
446 		return 0;
447 	}
448 	if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
449 		return 1;
450 	}
451 	if (x == y) {
452 		return 1;
453 	}
454 	return 0;
455 #else  /* DUK_USE_PARANOID_MATH */
456 	/* Better equivalent algorithm.  If the compiler is compliant, C and
457 	 * Ecmascript semantics are identical for this particular comparison.
458 	 * In particular, NaNs must never compare equal and zeroes must compare
459 	 * equal regardless of sign.  Could also use a macro, but this inlines
460 	 * already nicely (no difference on gcc, for instance).
461 	 */
462 	if (x == y) {
463 		/* IEEE requires that NaNs compare false */
464 		DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
465 		DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
466 		return 1;
467 	} else {
468 		/* IEEE requires that zeros compare the same regardless
469 		 * of their signed, so if both x and y are zeroes, they
470 		 * are caught above.
471 		 */
472 		DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
473 		return 0;
474 	}
475 #endif  /* DUK_USE_PARANOID_MATH */
476 }
477 
duk__js_samevalue_number(duk_double_t x,duk_double_t y)478 DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
479 #if defined(DUK_USE_PARANOID_MATH)
480 	duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
481 	duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
482 
483 	if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
484 		/* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
485 		return 1;
486 	}
487 	if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
488 		/* Note: cannot assume that a non-zero return value of signbit() would
489 		 * always be the same -- hence cannot (portably) use something like:
490 		 *
491 		 *     signbit(x) == signbit(y)
492 		 */
493 		duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
494 		duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
495 		return (sx == sy);
496 	}
497 
498 	/* normal comparison; known:
499 	 *   - both x and y are not NaNs (but one of them can be)
500 	 *   - both x and y are not zero (but one of them can be)
501 	 *   - x and y may be denormal or infinite
502 	 */
503 
504 	return (x == y);
505 #else  /* DUK_USE_PARANOID_MATH */
506 	duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
507 	duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
508 
509 	if (x == y) {
510 		/* IEEE requires that NaNs compare false */
511 		DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
512 		DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
513 
514 		/* Using classification has smaller footprint than direct comparison. */
515 		if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
516 			/* Note: cannot assume that a non-zero return value of signbit() would
517 			 * always be the same -- hence cannot (portably) use something like:
518 			 *
519 			 *     signbit(x) == signbit(y)
520 			 */
521 			duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
522 			duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
523 			return (sx == sy);
524 		}
525 		return 1;
526 	} else {
527 		/* IEEE requires that zeros compare the same regardless
528 		 * of their signed, so if both x and y are zeroes, they
529 		 * are caught above.
530 		 */
531 		DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
532 
533 		/* Difference to non-strict/strict comparison is that NaNs compare
534 		 * equal and signed zero signs matter.
535 		 */
536 		if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
537 			/* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
538 			return 1;
539 		}
540 		return 0;
541 	}
542 #endif  /* DUK_USE_PARANOID_MATH */
543 }
544 
duk_js_equals_helper(duk_hthread * thr,duk_tval * tv_x,duk_tval * tv_y,duk_small_int_t flags)545 DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
546 	duk_context *ctx = (duk_context *) thr;
547 	duk_tval *tv_tmp;
548 
549 	/* If flags != 0 (strict or SameValue), thr can be NULL.  For loose
550 	 * equals comparison it must be != NULL.
551 	 */
552 	DUK_ASSERT(flags != 0 || thr != NULL);
553 
554 	/*
555 	 *  Same type?
556 	 *
557 	 *  Note: since number values have no explicit tag in the 8-byte
558 	 *  representation, need the awkward if + switch.
559 	 */
560 
561 #if defined(DUK_USE_FASTINT)
562 	if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
563 		if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
564 			return 1;
565 		} else {
566 			return 0;
567 		}
568 	}
569 	else
570 #endif
571 	if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
572 		/* Catches both doubles and cases where only one argument is a fastint */
573 		if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
574 			/* SameValue */
575 			return duk__js_samevalue_number(DUK_TVAL_GET_NUMBER(tv_x),
576 			                                DUK_TVAL_GET_NUMBER(tv_y));
577 		} else {
578 			/* equals and strict equals */
579 			return duk__js_equals_number(DUK_TVAL_GET_NUMBER(tv_x),
580 			                             DUK_TVAL_GET_NUMBER(tv_y));
581 		}
582 	} else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
583 		switch (DUK_TVAL_GET_TAG(tv_x)) {
584 		case DUK_TAG_UNDEFINED:
585 		case DUK_TAG_NULL: {
586 			return 1;
587 		}
588 		case DUK_TAG_BOOLEAN: {
589 			return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
590 		}
591 		case DUK_TAG_POINTER: {
592 			return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
593 		}
594 		case DUK_TAG_STRING:
595 		case DUK_TAG_OBJECT: {
596 			/* heap pointer comparison suffices */
597 			return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
598 		}
599 		case DUK_TAG_BUFFER: {
600 			if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
601 				/* heap pointer comparison suffices */
602 				return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
603 			} else {
604 				/* non-strict equality for buffers compares contents */
605 				duk_hbuffer *h_x = DUK_TVAL_GET_BUFFER(tv_x);
606 				duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
607 				duk_size_t len_x = DUK_HBUFFER_GET_SIZE(h_x);
608 				duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
609 				void *buf_x;
610 				void *buf_y;
611 				if (len_x != len_y) {
612 					return 0;
613 				}
614 				buf_x = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_x);
615 				buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
616 				/* if len_x == len_y == 0, buf_x and/or buf_y may
617 				 * be NULL, but that's OK.
618 				 */
619 				DUK_ASSERT(len_x == len_y);
620 				DUK_ASSERT(len_x == 0 || buf_x != NULL);
621 				DUK_ASSERT(len_y == 0 || buf_y != NULL);
622 				return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
623 			}
624 		}
625 		case DUK_TAG_LIGHTFUNC: {
626 			/* At least 'magic' has a significant impact on function
627 			 * identity.
628 			 */
629 			duk_small_uint_t lf_flags_x;
630 			duk_small_uint_t lf_flags_y;
631 			duk_c_function func_x;
632 			duk_c_function func_y;
633 
634 			DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
635 			DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
636 			return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
637 		}
638 #if defined(DUK_USE_FASTINT)
639 		case DUK_TAG_FASTINT:
640 #endif
641 		default: {
642 			DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
643 			DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y));
644 			DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
645 			DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
646 			DUK_UNREACHABLE();
647 			return 0;
648 		}
649 		}
650 	}
651 
652 	if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
653 		return 0;
654 	}
655 
656 	DUK_ASSERT(flags == 0);  /* non-strict equality from here on */
657 
658 	/*
659 	 *  Types are different; various cases for non-strict comparison
660 	 *
661 	 *  Since comparison is symmetric, we use a "swap trick" to reduce
662 	 *  code size.
663 	 */
664 
665 	/* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
666 	if ((DUK_TVAL_IS_UNDEFINED(tv_x) && DUK_TVAL_IS_NULL(tv_y)) ||
667 	    (DUK_TVAL_IS_NULL(tv_x) && DUK_TVAL_IS_UNDEFINED(tv_y))) {
668 		return 1;
669 	}
670 
671 	/* Number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
672 	if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
673 		/* the next 'if' is guaranteed to match after swap */
674 		tv_tmp = tv_x;
675 		tv_x = tv_y;
676 		tv_y = tv_tmp;
677 	}
678 	if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
679 		/* XXX: this is possible without resorting to the value stack */
680 		duk_double_t d1, d2;
681 		d2 = DUK_TVAL_GET_NUMBER(tv_y);
682 		duk_push_tval(ctx, tv_x);
683 		duk_to_string(ctx, -1);  /* buffer values are coerced first to string here */
684 		duk_to_number(ctx, -1);
685 		d1 = duk_require_number(ctx, -1);
686 		duk_pop(ctx);
687 		return duk__js_equals_number(d1, d2);
688 	}
689 
690 	/* Buffer/string -> compare contents. */
691 	if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
692 		tv_tmp = tv_x;
693 		tv_x = tv_y;
694 		tv_y = tv_tmp;
695 	}
696 	if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
697 		duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
698 		duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
699 		duk_size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
700 		duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
701 		const void *buf_x;
702 		const void *buf_y;
703 		if (len_x != len_y) {
704 			return 0;
705 		}
706 		buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x);
707 		buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
708 		/* if len_x == len_y == 0, buf_x and/or buf_y may
709 		 * be NULL, but that's OK.
710 		 */
711 		DUK_ASSERT(len_x == len_y);
712 		DUK_ASSERT(len_x == 0 || buf_x != NULL);
713 		DUK_ASSERT(len_y == 0 || buf_y != NULL);
714 		return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
715 	}
716 
717 	/* Boolean/any -> coerce boolean to number and try again.  If boolean is
718 	 * compared to a pointer, the final comparison after coercion now always
719 	 * yields false (as pointer vs. number compares to false), but this is
720 	 * not special cased.
721 	 */
722 	if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
723 		tv_tmp = tv_x;
724 		tv_x = tv_y;
725 		tv_y = tv_tmp;
726 	}
727 	if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
728 		/* ToNumber(bool) is +1.0 or 0.0.  Tagged boolean value is always 0 or 1. */
729 		duk_bool_t rc;
730 		DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
731 		duk_push_tval(ctx, tv_x);
732 		duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
733 		rc = duk_js_equals_helper(thr,
734 		                          DUK_GET_TVAL_NEGIDX(ctx, -2),
735 		                          DUK_GET_TVAL_NEGIDX(ctx, -1),
736 		                          0 /*flags:nonstrict*/);
737 		duk_pop_2(ctx);
738 		return rc;
739 	}
740 
741 	/* String-number-buffer/object -> coerce object to primitive (apparently without hint), then try again. */
742 	if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
743 	    DUK_TVAL_IS_OBJECT(tv_y)) {
744 		tv_tmp = tv_x;
745 		tv_x = tv_y;
746 		tv_y = tv_tmp;
747 	}
748 	if (DUK_TVAL_IS_OBJECT(tv_x) &&
749 	    (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
750 		duk_bool_t rc;
751 		duk_push_tval(ctx, tv_x);
752 		duk_push_tval(ctx, tv_y);
753 		duk_to_primitive(ctx, -2, DUK_HINT_NONE);  /* apparently no hint? */
754 		rc = duk_js_equals_helper(thr,
755 		                          DUK_GET_TVAL_NEGIDX(ctx, -2),
756 		                          DUK_GET_TVAL_NEGIDX(ctx, -1),
757 		                          0 /*flags:nonstrict*/);
758 		duk_pop_2(ctx);
759 		return rc;
760 	}
761 
762 	/* Nothing worked -> not equal. */
763 	return 0;
764 }
765 
766 /*
767  *  Comparisons (x >= y, x > y, x <= y, x < y)
768  *
769  *  E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
770  *  flags to get the rest.
771  */
772 
773 /* XXX: this should probably just operate on the stack top, because it
774  * needs to push stuff on the stack anyway...
775  */
776 
duk_js_data_compare(const duk_uint8_t * buf1,const duk_uint8_t * buf2,duk_size_t len1,duk_size_t len2)777 DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2) {
778 	duk_size_t prefix_len;
779 	duk_small_int_t rc;
780 
781 	prefix_len = (len1 <= len2 ? len1 : len2);
782 
783 	/* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length
784 	 * inputs so no zero length check is needed.
785 	 */
786 	rc = DUK_MEMCMP((const void *) buf1,
787 	                (const void *) buf2,
788 	                (size_t) prefix_len);
789 
790 	if (rc < 0) {
791 		return -1;
792 	} else if (rc > 0) {
793 		return 1;
794 	}
795 
796 	/* prefix matches, lengths matter now */
797 	if (len1 < len2) {
798 		/* e.g. "x" < "xx" */
799 		return -1;
800 	} else if (len1 > len2) {
801 		return 1;
802 	}
803 
804 	return 0;
805 }
806 
duk_js_string_compare(duk_hstring * h1,duk_hstring * h2)807 DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
808 	/*
809 	 *  String comparison (E5 Section 11.8.5, step 4), which
810 	 *  needs to compare codepoint by codepoint.
811 	 *
812 	 *  However, UTF-8 allows us to use strcmp directly: the shared
813 	 *  prefix will be encoded identically (UTF-8 has unique encoding)
814 	 *  and the first differing character can be compared with a simple
815 	 *  unsigned byte comparison (which strcmp does).
816 	 *
817 	 *  This will not work properly for non-xutf-8 strings, but this
818 	 *  is not an issue for compliance.
819 	 */
820 
821 	DUK_ASSERT(h1 != NULL);
822 	DUK_ASSERT(h2 != NULL);
823 
824 	return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1),
825 	                           (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2),
826 	                           (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1),
827 	                           (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2));
828 }
829 
830 #if 0  /* unused */
831 DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) {
832 	/* Similar to String comparison. */
833 
834 	DUK_ASSERT(h1 != NULL);
835 	DUK_ASSERT(h2 != NULL);
836 	DUK_UNREF(heap);
837 
838 	return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
839 	                           (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
840 	                           (duk_size_t) DUK_HBUFFER_GET_SIZE(h1),
841 	                           (duk_size_t) DUK_HBUFFER_GET_SIZE(h2));
842 }
843 #endif
844 
duk_js_compare_helper(duk_hthread * thr,duk_tval * tv_x,duk_tval * tv_y,duk_small_int_t flags)845 DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
846 	duk_context *ctx = (duk_context *) thr;
847 	duk_double_t d1, d2;
848 	duk_small_int_t c1, c2;
849 	duk_small_int_t s1, s2;
850 	duk_small_int_t rc;
851 	duk_bool_t retval;
852 
853 	/* Fast path for fastints */
854 #if defined(DUK_USE_FASTINT)
855 	if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
856 		duk_int64_t v1 = DUK_TVAL_GET_FASTINT(tv_x);
857 		duk_int64_t v2 = DUK_TVAL_GET_FASTINT(tv_y);
858 		if (v1 < v2) {
859 			/* 'lt is true' */
860 			retval = 1;
861 		} else {
862 			retval = 0;
863 		}
864 		if (flags & DUK_COMPARE_FLAG_NEGATE) {
865 			retval ^= 1;
866 		}
867 		return retval;
868 	}
869 #endif  /* DUK_USE_FASTINT */
870 
871 	/* Fast path for numbers (one of which may be a fastint) */
872 #if 1  /* XXX: make fast paths optional for size minimization? */
873 	if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
874 		d1 = DUK_TVAL_GET_NUMBER(tv_x);
875 		d2 = DUK_TVAL_GET_NUMBER(tv_y);
876 		c1 = DUK_FPCLASSIFY(d1);
877 		c2 = DUK_FPCLASSIFY(d2);
878 
879 		if (c1 == DUK_FP_NORMAL && c2 == DUK_FP_NORMAL) {
880 			/* XXX: this is a very narrow check, and doesn't cover
881 			 * zeroes, subnormals, infinities, which compare normally.
882 			 */
883 
884 			if (d1 < d2) {
885 				/* 'lt is true' */
886 				retval = 1;
887 			} else {
888 				retval = 0;
889 			}
890 			if (flags & DUK_COMPARE_FLAG_NEGATE) {
891 				retval ^= 1;
892 			}
893 			return retval;
894 		}
895 	}
896 #endif
897 
898 	/* Slow path */
899 
900 	duk_push_tval(ctx, tv_x);
901 	duk_push_tval(ctx, tv_y);
902 
903 	if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
904 		duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
905 		duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
906 	} else {
907 		duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
908 		duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
909 	}
910 
911 	/* Note: reuse variables */
912 	tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
913 	tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
914 
915 	if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
916 		duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
917 		duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
918 		DUK_ASSERT(h1 != NULL);
919 		DUK_ASSERT(h2 != NULL);
920 
921 		rc = duk_js_string_compare(h1, h2);
922 		if (rc < 0) {
923 			goto lt_true;
924 		} else {
925 			goto lt_false;
926 		}
927 	} else {
928 		/* Ordering should not matter (E5 Section 11.8.5, step 3.a) but
929 		 * preserve it just in case.
930 		 */
931 
932 		if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
933 			d1 = duk_to_number(ctx, -2);
934 			d2 = duk_to_number(ctx, -1);
935 		} else {
936 			d2 = duk_to_number(ctx, -1);
937 			d1 = duk_to_number(ctx, -2);
938 		}
939 
940 		c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
941 		s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
942 		c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
943 		s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
944 
945 		if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
946 			goto lt_undefined;
947 		}
948 
949 		if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
950 			/* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
951 			 * steps e, f, and g.
952 			 */
953 			goto lt_false;
954 		}
955 
956 		if (d1 == d2) {
957 			goto lt_false;
958 		}
959 
960 		if (c1 == DUK_FP_INFINITE && s1 == 0) {
961 			/* x == +Infinity */
962 			goto lt_false;
963 		}
964 
965 		if (c2 == DUK_FP_INFINITE && s2 == 0) {
966 			/* y == +Infinity */
967 			goto lt_true;
968 		}
969 
970 		if (c2 == DUK_FP_INFINITE && s2 != 0) {
971 			/* y == -Infinity */
972 			goto lt_false;
973 		}
974 
975 		if (c1 == DUK_FP_INFINITE && s1 != 0) {
976 			/* x == -Infinity */
977 			goto lt_true;
978 		}
979 
980 		if (d1 < d2) {
981 			goto lt_true;
982 		}
983 
984 		goto lt_false;
985 	}
986 
987  lt_undefined:
988 	/* Note: undefined from Section 11.8.5 always results in false
989 	 * return (see e.g. Section 11.8.3) - hence special treatment here.
990 	 */
991 	retval = 0;
992 	goto cleanup;
993 
994  lt_true:
995 	if (flags & DUK_COMPARE_FLAG_NEGATE) {
996 		retval = 0;
997 		goto cleanup;
998 	} else {
999 		retval = 1;
1000 		goto cleanup;
1001 	}
1002 	/* never here */
1003 
1004  lt_false:
1005 	if (flags & DUK_COMPARE_FLAG_NEGATE) {
1006 		retval = 1;
1007 		goto cleanup;
1008 	} else {
1009 		retval = 0;
1010 		goto cleanup;
1011 	}
1012 	/* never here */
1013 
1014  cleanup:
1015 	duk_pop_2(ctx);
1016 	return retval;
1017 }
1018 
1019 /*
1020  *  instanceof
1021  */
1022 
1023 /*
1024  *  E5 Section 11.8.6 describes the main algorithm, which uses
1025  *  [[HasInstance]].  [[HasInstance]] is defined for only
1026  *  function objects:
1027  *
1028  *    - Normal functions:
1029  *      E5 Section 15.3.5.3
1030  *    - Functions established with Function.prototype.bind():
1031  *      E5 Section 15.3.4.5.3
1032  *
1033  *  For other objects, a TypeError is thrown.
1034  *
1035  *  Limited Proxy support: don't support 'getPrototypeOf' trap but
1036  *  continue lookup in Proxy target if the value is a Proxy.
1037  */
1038 
duk_js_instanceof(duk_hthread * thr,duk_tval * tv_x,duk_tval * tv_y)1039 DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
1040 	duk_context *ctx = (duk_context *) thr;
1041 	duk_hobject *func;
1042 	duk_hobject *val;
1043 	duk_hobject *proto;
1044 	duk_uint_t sanity;
1045 
1046 	/*
1047 	 *  Get the values onto the stack first.  It would be possible to cover
1048 	 *  some normal cases without resorting to the value stack.
1049 	 *
1050 	 *  The right hand side could be a light function (as they generally
1051 	 *  behave like objects).  Light functions never have a 'prototype'
1052 	 *  property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
1053 	 *  Using duk_require_hobject() is thus correct (except for error msg).
1054 	 */
1055 
1056 	duk_push_tval(ctx, tv_x);
1057 	duk_push_tval(ctx, tv_y);
1058 	func = duk_require_hobject(ctx, -1);
1059 
1060 	/*
1061 	 *  For bound objects, [[HasInstance]] just calls the target function
1062 	 *  [[HasInstance]].  If that is again a bound object, repeat until
1063 	 *  we find a non-bound Function object.
1064 	 */
1065 
1066 	/* XXX: this bound function resolution also happens elsewhere,
1067 	 * move into a shared helper.
1068 	 */
1069 
1070 	sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
1071 	do {
1072 		/* check func supports [[HasInstance]] (this is checked for every function
1073 		 * in the bound chain, including the final one)
1074 		 */
1075 
1076 		if (!DUK_HOBJECT_IS_CALLABLE(func)) {
1077 			/*
1078 			 *  Note: of native Ecmascript objects, only Function instances
1079 			 *  have a [[HasInstance]] internal property.  Custom objects might
1080 			 *  also have it, but not in current implementation.
1081 			 *
1082 			 *  XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
1083 			 */
1084 			DUK_ERROR_TYPE(thr, "invalid instanceof rval");
1085 		}
1086 
1087 		if (!DUK_HOBJECT_HAS_BOUND(func)) {
1088 			break;
1089 		}
1090 
1091 		/* [ ... lval rval ] */
1092 
1093 		duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);         /* -> [ ... lval rval new_rval ] */
1094 		duk_replace(ctx, -1);                                        /* -> [ ... lval new_rval ] */
1095 		func = duk_require_hobject(ctx, -1);
1096 
1097 		/* func support for [[HasInstance]] checked in the beginning of the loop */
1098 	} while (--sanity > 0);
1099 
1100 	if (sanity == 0) {
1101 		DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
1102 	}
1103 
1104 	/*
1105 	 *  'func' is now a non-bound object which supports [[HasInstance]]
1106 	 *  (which here just means DUK_HOBJECT_FLAG_CALLABLE).  Move on
1107 	 *  to execute E5 Section 15.3.5.3.
1108 	 */
1109 
1110 	DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
1111 	DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
1112 
1113 	/* [ ... lval rval(func) ] */
1114 
1115 	/* Handle lightfuncs through object coercion for now. */
1116 	/* XXX: direct implementation */
1117 	val = duk_get_hobject_or_lfunc_coerce(ctx, -2);
1118 	if (!val) {
1119 		goto pop_and_false;
1120 	}
1121 
1122 	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE);  /* -> [ ... lval rval rval.prototype ] */
1123 	proto = duk_require_hobject(ctx, -1);
1124 	duk_pop(ctx);  /* -> [ ... lval rval ] */
1125 
1126 	DUK_ASSERT(val != NULL);
1127 
1128 #if defined(DUK_USE_ES6_PROXY)
1129 	val = duk_hobject_resolve_proxy_target(thr, val);
1130 	DUK_ASSERT(val != NULL);
1131 #endif
1132 
1133 	sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
1134 	do {
1135 		/*
1136 		 *  Note: prototype chain is followed BEFORE first comparison.  This
1137 		 *  means that the instanceof lval is never itself compared to the
1138 		 *  rval.prototype property.  This is apparently intentional, see E5
1139 		 *  Section 15.3.5.3, step 4.a.
1140 		 *
1141 		 *  Also note:
1142 		 *
1143 		 *      js> (function() {}) instanceof Function
1144 		 *      true
1145 		 *      js> Function instanceof Function
1146 		 *      true
1147 		 *
1148 		 *  For the latter, h_proto will be Function.prototype, which is the
1149 		 *  built-in Function prototype.  Because Function.[[Prototype]] is
1150 		 *  also the built-in Function prototype, the result is true.
1151 		 */
1152 
1153 		DUK_ASSERT(val != NULL);
1154 		val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
1155 
1156 		if (!val) {
1157 			goto pop_and_false;
1158 		}
1159 
1160 		DUK_ASSERT(val != NULL);
1161 #if defined(DUK_USE_ES6_PROXY)
1162 		val = duk_hobject_resolve_proxy_target(thr, val);
1163 #endif
1164 
1165 		if (val == proto) {
1166 			goto pop_and_true;
1167 		}
1168 
1169 		/* follow prototype chain */
1170 	} while (--sanity > 0);
1171 
1172 	if (sanity == 0) {
1173 		DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
1174 	}
1175 	DUK_UNREACHABLE();
1176 
1177  pop_and_false:
1178 	duk_pop_2(ctx);
1179 	return 0;
1180 
1181  pop_and_true:
1182 	duk_pop_2(ctx);
1183 	return 1;
1184 }
1185 
1186 /*
1187  *  in
1188  */
1189 
1190 /*
1191  *  E5 Sections 11.8.7, 8.12.6.
1192  *
1193  *  Basically just a property existence check using [[HasProperty]].
1194  */
1195 
duk_js_in(duk_hthread * thr,duk_tval * tv_x,duk_tval * tv_y)1196 DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
1197 	duk_context *ctx = (duk_context *) thr;
1198 	duk_bool_t retval;
1199 
1200 	/*
1201 	 *  Get the values onto the stack first.  It would be possible to cover
1202 	 *  some normal cases without resorting to the value stack (e.g. if
1203 	 *  lval is already a string).
1204 	 */
1205 
1206 	/* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
1207 	 * must be string coerced before the internal HasProperty() algorithm is
1208 	 * invoked.  A fast path skipping coercion could be safely implemented for
1209 	 * numbers (as number-to-string coercion has no side effects).  For ES6
1210 	 * proxy behavior, the trap 'key' argument must be in a string coerced
1211 	 * form (which is a shame).
1212 	 */
1213 
1214 	/* TypeError if rval is not an object (or lightfunc which should behave
1215 	 * like a Function instance).
1216 	 */
1217 	duk_push_tval(ctx, tv_x);
1218 	duk_push_tval(ctx, tv_y);
1219 	duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC);
1220 	duk_to_string(ctx, -2);               /* coerce lval with ToString() */
1221 
1222 	retval = duk_hobject_hasprop(thr,
1223 	                             DUK_GET_TVAL_NEGIDX(ctx, -1),
1224 	                             DUK_GET_TVAL_NEGIDX(ctx, -2));
1225 
1226 	duk_pop_2(ctx);
1227 	return retval;
1228 }
1229 
1230 /*
1231  *  typeof
1232  *
1233  *  E5 Section 11.4.3.
1234  *
1235  *  Very straightforward.  The only question is what to return for our
1236  *  non-standard tag / object types.
1237  *
1238  *  There is an unfortunate string constant define naming problem with
1239  *  typeof return values for e.g. "Object" and "object"; careful with
1240  *  the built-in string defines.  The LC_XXX defines are used for the
1241  *  lowercase variants now.
1242  */
1243 
duk_js_typeof(duk_hthread * thr,duk_tval * tv_x)1244 DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
1245 	duk_small_int_t stridx = 0;
1246 
1247 	DUK_UNREF(thr);
1248 
1249 	switch (DUK_TVAL_GET_TAG(tv_x)) {
1250 	case DUK_TAG_UNDEFINED: {
1251 		stridx = DUK_STRIDX_LC_UNDEFINED;
1252 		break;
1253 	}
1254 	case DUK_TAG_NULL: {
1255 		/* Note: not a typo, "object" is returned for a null value */
1256 		stridx = DUK_STRIDX_LC_OBJECT;
1257 		break;
1258 	}
1259 	case DUK_TAG_BOOLEAN: {
1260 		stridx = DUK_STRIDX_LC_BOOLEAN;
1261 		break;
1262 	}
1263 	case DUK_TAG_POINTER: {
1264 		/* implementation specific */
1265 		stridx = DUK_STRIDX_LC_POINTER;
1266 		break;
1267 	}
1268 	case DUK_TAG_STRING: {
1269 		stridx = DUK_STRIDX_LC_STRING;
1270 		break;
1271 	}
1272 	case DUK_TAG_OBJECT: {
1273 		duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
1274 		DUK_ASSERT(obj != NULL);
1275 		if (DUK_HOBJECT_IS_CALLABLE(obj)) {
1276 			stridx = DUK_STRIDX_LC_FUNCTION;
1277 		} else {
1278 			stridx = DUK_STRIDX_LC_OBJECT;
1279 		}
1280 		break;
1281 	}
1282 	case DUK_TAG_BUFFER: {
1283 		/* implementation specific */
1284 		stridx = DUK_STRIDX_LC_BUFFER;
1285 		break;
1286 	}
1287 	case DUK_TAG_LIGHTFUNC: {
1288 		stridx = DUK_STRIDX_LC_FUNCTION;
1289 		break;
1290 	}
1291 #if defined(DUK_USE_FASTINT)
1292 	case DUK_TAG_FASTINT:
1293 #endif
1294 	default: {
1295 		/* number */
1296 		DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
1297 		DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
1298 		stridx = DUK_STRIDX_LC_NUMBER;
1299 		break;
1300 	}
1301 	}
1302 
1303 	DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
1304 	return DUK_HTHREAD_GET_STRING(thr, stridx);
1305 }
1306 
1307 /*
1308  *  Array index and length
1309  *
1310  *  Array index: E5 Section 15.4
1311  *  Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
1312  *
1313  *  The DUK_HSTRING_GET_ARRIDX_SLOW() and DUK_HSTRING_GET_ARRIDX_FAST() macros
1314  *  call duk_js_to_arrayindex_string_helper().
1315  */
1316 
duk_js_to_arrayindex_raw_string(const duk_uint8_t * str,duk_uint32_t blen,duk_uarridx_t * out_idx)1317 DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) {
1318 	duk_uarridx_t res, new_res;
1319 
1320 	if (blen == 0 || blen > 10) {
1321 		goto parse_fail;
1322 	}
1323 	if (str[0] == (duk_uint8_t) '0' && blen > 1) {
1324 		goto parse_fail;
1325 	}
1326 
1327 	/* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
1328 	 * Leading zeroes are not accepted (zero index "0" is an exception
1329 	 * handled above).
1330 	 */
1331 
1332 	res = 0;
1333 	while (blen-- > 0) {
1334 		duk_uint8_t c = *str++;
1335 		if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') {
1336 			new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0');
1337 			if (new_res < res) {
1338 				/* overflow, more than 32 bits -> not an array index */
1339 				goto parse_fail;
1340 			}
1341 			res = new_res;
1342 		} else {
1343 			goto parse_fail;
1344 		}
1345 	}
1346 
1347 	*out_idx = res;
1348 	return 1;
1349 
1350  parse_fail:
1351 	*out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
1352 	return 0;
1353 }
1354 
1355 /* Called by duk_hstring.h macros */
duk_js_to_arrayindex_string_helper(duk_hstring * h)1356 DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
1357 	duk_uarridx_t res;
1358 	duk_small_int_t rc;
1359 
1360 	if (!DUK_HSTRING_HAS_ARRIDX(h)) {
1361 		return DUK_HSTRING_NO_ARRAY_INDEX;
1362 	}
1363 
1364 	rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h),
1365 	                                     DUK_HSTRING_GET_BYTELEN(h),
1366 	                                     &res);
1367 	DUK_UNREF(rc);
1368 	DUK_ASSERT(rc != 0);
1369 	return res;
1370 }
1371