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