1 /*
2  *  Initialize built-in objects.  Current thread must have a valstack
3  *  and initialization errors may longjmp, so a setjmp() catch point
4  *  must exist.
5  */
6 
7 #include "duk_internal.h"
8 
9 /*
10  *  Encoding constants, must match genbuiltins.py
11  */
12 
13 #define DUK__CLASS_BITS                  5
14 #define DUK__BIDX_BITS                   7
15 #define DUK__STRIDX_BITS                 9  /* XXX: try to optimize to 8 (would now be possible, <200 used) */
16 #define DUK__NATIDX_BITS                 8
17 #define DUK__NUM_NORMAL_PROPS_BITS       6
18 #define DUK__NUM_FUNC_PROPS_BITS         6
19 #define DUK__PROP_FLAGS_BITS             3
20 #define DUK__STRING_LENGTH_BITS          8
21 #define DUK__STRING_CHAR_BITS            7
22 #define DUK__LENGTH_PROP_BITS            3
23 #define DUK__NARGS_BITS                  3
24 #define DUK__PROP_TYPE_BITS              3
25 #define DUK__MAGIC_BITS                  16
26 
27 #define DUK__NARGS_VARARGS_MARKER        0x07
28 #define DUK__NO_CLASS_MARKER             0x00   /* 0 = DUK_HOBJECT_CLASS_UNUSED */
29 #define DUK__NO_BIDX_MARKER              0x7f
30 #define DUK__NO_STRIDX_MARKER            0xff
31 
32 #define DUK__PROP_TYPE_DOUBLE            0
33 #define DUK__PROP_TYPE_STRING            1
34 #define DUK__PROP_TYPE_STRIDX            2
35 #define DUK__PROP_TYPE_BUILTIN           3
36 #define DUK__PROP_TYPE_UNDEFINED         4
37 #define DUK__PROP_TYPE_BOOLEAN_TRUE      5
38 #define DUK__PROP_TYPE_BOOLEAN_FALSE     6
39 #define DUK__PROP_TYPE_ACCESSOR          7
40 
41 /*
42  *  Create built-in objects by parsing an init bitstream generated
43  *  by genbuiltins.py.
44  */
45 
46 #if defined(DUK_USE_ROM_OBJECTS)
47 #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
duk__duplicate_ram_global_object(duk_hthread * thr)48 DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
49 	duk_context *ctx;
50 	duk_hobject *h1;
51 #if defined(DUK_USE_ROM_GLOBAL_CLONE)
52 	duk_hobject *h2;
53 	duk_uint8_t *props;
54 	duk_size_t alloc_size;
55 #endif
56 
57 	ctx = (duk_context *) thr;
58 
59 	/* XXX: refactor into internal helper, duk_clone_hobject() */
60 
61 #if defined(DUK_USE_ROM_GLOBAL_INHERIT)
62 	/* Inherit from ROM-based global object: less RAM usage, less transparent. */
63 	duk_push_object_helper(ctx,
64 	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
65 	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
66 	                       DUK_BIDX_GLOBAL);
67 	h1 = duk_get_hobject(ctx, -1);
68 	DUK_ASSERT(h1 != NULL);
69 #elif defined(DUK_USE_ROM_GLOBAL_CLONE)
70 	/* Clone the properties of the ROM-based global object to create a
71 	 * fully RAM-based global object.  Uses more memory than the inherit
72 	 * model but more compliant.
73 	 */
74 	duk_push_object_helper(ctx,
75 	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
76 	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
77 	                       DUK_BIDX_OBJECT_PROTOTYPE);
78 	h1 = duk_get_hobject(ctx, -1);
79 	DUK_ASSERT(h1 != NULL);
80 	h2 = thr->builtins[DUK_BIDX_GLOBAL];
81 	DUK_ASSERT(h2 != NULL);
82 
83 	/* Copy the property table verbatim; this handles attributes etc.
84 	 * For ROM objects it's not necessary (or possible) to update
85 	 * refcounts so leave them as is.
86 	 */
87 	alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2);
88 	DUK_ASSERT(alloc_size > 0);
89 	props = DUK_ALLOC(thr->heap, alloc_size);
90 	if (!props) {
91 		DUK_ERROR_ALLOC_DEFMSG(thr);
92 		return;
93 	}
94 	DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL);
95 	DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size);
96 
97 	/* XXX: keep property attributes or tweak them here?
98 	 * Properties will now be non-configurable even when they're
99 	 * normally configurable for the global object.
100 	 */
101 
102 	DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL);
103 	DUK_HOBJECT_SET_PROPS(thr->heap, h1, props);
104 	DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2));
105 	DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2));
106 	DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2));
107 	DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2));
108 #else
109 #error internal error in defines
110 #endif
111 
112 	duk_hobject_compact_props(thr, h1);
113 	DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
114 	DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL]));  /* no need to decref */
115 	thr->builtins[DUK_BIDX_GLOBAL] = h1;
116 	DUK_HOBJECT_INCREF(thr, h1);
117 	DUK_D(DUK_DPRINT("duplicated global object: %!O", h1));
118 
119 
120 	/* Create a fresh object environment for the global scope.  This is
121 	 * needed so that the global scope points to the newly created RAM-based
122 	 * global object.
123 	 */
124 	duk_push_object_helper(ctx,
125 	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
126 	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
127 	                       -1);  /* no prototype */
128 	h1 = duk_get_hobject(ctx, -1);
129 	DUK_ASSERT(h1 != NULL);
130 	duk_dup(ctx, -2);
131 	duk_dup(ctx, -1);  /* -> [ ... new_global new_globalenv new_global new_global ] */
132 	duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
133 	duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);  /* always provideThis=true */
134 
135 	duk_hobject_compact_props(thr, h1);
136 	DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
137 	DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV]));  /* no need to decref */
138 	thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1;
139 	DUK_HOBJECT_INCREF(thr, h1);
140 	DUK_D(DUK_DPRINT("duplicated global env: %!O", h1));
141 
142 	duk_pop_2(ctx);
143 }
144 #endif  /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
145 
duk_hthread_create_builtin_objects(duk_hthread * thr)146 DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
147 	/* Setup builtins from ROM objects.  All heaps/threads will share
148 	 * the same readonly objects.
149 	 */
150 	duk_small_uint_t i;
151 
152 	for (i = 0; i < DUK_NUM_BUILTINS; i++) {
153 		duk_hobject *h;
154 		h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
155 		DUK_ASSERT(h != NULL);
156 		thr->builtins[i] = h;
157 	}
158 
159 #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
160 	/* By default the global object is read-only which is often much
161 	 * more of an issue than having read-only built-in objects (like
162 	 * RegExp, Date, etc).  Use a RAM-based copy of the global object
163 	 * and the global environment object for convenience.
164 	 */
165 	duk__duplicate_ram_global_object(thr);
166 #endif
167 }
168 #else  /* DUK_USE_ROM_OBJECTS */
duk__push_stridx(duk_context * ctx,duk_bitdecoder_ctx * bd)169 DUK_LOCAL void duk__push_stridx(duk_context *ctx, duk_bitdecoder_ctx *bd) {
170 	duk_small_uint_t n;
171 
172 	n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS);
173 	DUK_ASSERT_DISABLE(n >= 0);  /* unsigned */
174 	DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
175 	duk_push_hstring_stridx(ctx, n);
176 }
duk__push_string(duk_context * ctx,duk_bitdecoder_ctx * bd)177 DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
178 	duk_small_uint_t n;
179 	duk_small_uint_t i;
180 	duk_uint8_t *p;
181 
182 	n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRING_LENGTH_BITS);
183 	p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, n);
184 	for (i = 0; i < n; i++) {
185 		*p++ = (duk_uint8_t) duk_bd_decode(bd, DUK__STRING_CHAR_BITS);
186 	}
187 	duk_to_string(ctx, -1);
188 }
duk__push_stridx_or_string(duk_context * ctx,duk_bitdecoder_ctx * bd)189 DUK_LOCAL void duk__push_stridx_or_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
190 	if (duk_bd_decode_flag(bd)) {
191 		duk__push_string(ctx, bd);
192 	} else {
193 		duk__push_stridx(ctx, bd);
194 	}
195 }
duk__push_double(duk_context * ctx,duk_bitdecoder_ctx * bd)196 DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
197 	duk_double_union du;
198 	duk_small_uint_t i;
199 
200 	for (i = 0; i < 8; i++) {
201 		/* Encoding endianness must match target memory layout,
202 		 * build scripts and genbuiltins.py must ensure this.
203 		 */
204 		du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
205 	}
206 
207 	duk_push_number(ctx, du.d);  /* push operation normalizes NaNs */
208 }
209 
duk_hthread_create_builtin_objects(duk_hthread * thr)210 DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
211 	duk_context *ctx = (duk_context *) thr;
212 	duk_bitdecoder_ctx bd_ctx;
213 	duk_bitdecoder_ctx *bd = &bd_ctx;  /* convenience */
214 	duk_hobject *h;
215 	duk_small_uint_t i, j;
216 
217 	DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
218 
219 	DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
220 	bd->data = (const duk_uint8_t *) duk_builtins_data;
221 	bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
222 
223 	/*
224 	 *  First create all built-in bare objects on the empty valstack.
225 	 *
226 	 *  Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
227 	 *  stack indices matching their eventual thr->builtins[] index.
228 	 *
229 	 *  Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
230 	 *  will exist on the value stack during init but won't be placed
231 	 *  into thr->builtins[].  These are objects referenced in some way
232 	 *  from thr->builtins[] roots but which don't need to be indexed by
233 	 *  Duktape through thr->builtins[] (e.g. user custom objects).
234 	 */
235 
236 	duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS);
237 
238 	DUK_DD(DUK_DDPRINT("create empty built-ins"));
239 	DUK_ASSERT_TOP(ctx, 0);
240 	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
241 		duk_small_uint_t class_num;
242 		duk_small_int_t len = -1;  /* must be signed */
243 
244 		class_num = (duk_small_uint_t) duk_bd_decode(bd, DUK__CLASS_BITS);
245 		len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
246 
247 		if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
248 			duk_small_uint_t natidx;
249 			duk_int_t c_nargs;  /* must hold DUK_VARARGS */
250 			duk_c_function c_func;
251 			duk_int16_t magic;
252 
253 			DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
254 			DUK_ASSERT(len >= 0);
255 
256 			natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
257 			c_func = duk_bi_native_functions[natidx];
258 
259 			c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/);
260 			if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
261 				c_nargs = DUK_VARARGS;
262 			}
263 
264 			/* XXX: set magic directly here? (it could share the c_nargs arg) */
265 			duk_push_c_function_noexotic(ctx, c_func, c_nargs);
266 
267 			h = duk_require_hobject(ctx, -1);
268 			DUK_ASSERT(h != NULL);
269 
270 			/* Currently all built-in native functions are strict.
271 			 * duk_push_c_function() now sets strict flag, so
272 			 * assert for it.
273 			 */
274 			DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
275 
276 			/* XXX: function properties */
277 
278 			/* Built-in 'name' is not writable by default.  Function '.name'
279 			 * is writable to allow user code to set a '.name' on a native
280 			 * function.
281 			 */
282 			duk__push_stridx_or_string(ctx, bd);
283 			duk_xdef_prop_stridx(ctx,
284 			                     -2,
285 			                     DUK_STRIDX_NAME,
286 			                     (i == DUK_BIDX_FUNCTION_PROTOTYPE) ?
287 			                         DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE);
288 
289 			/* Almost all global level Function objects are constructable
290 			 * but not all: Function.prototype is a non-constructable,
291 			 * callable Function.
292 			 */
293 			if (duk_bd_decode_flag(bd)) {
294 				DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
295 			} else {
296 				DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
297 			}
298 
299 			/* Cast converts magic to 16-bit signed value */
300 			magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/);
301 			((duk_hnativefunction *) h)->magic = magic;
302 		} else {
303 			/* XXX: ARRAY_PART for Array prototype? */
304 
305 			duk_push_object_helper(ctx,
306 			                       DUK_HOBJECT_FLAG_EXTENSIBLE,
307 			                       -1);  /* no prototype or class yet */
308 
309 			h = duk_require_hobject(ctx, -1);
310 			DUK_ASSERT(h != NULL);
311 		}
312 
313 		DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
314 
315 		if (i < DUK_NUM_BUILTINS) {
316 			thr->builtins[i] = h;
317 			DUK_HOBJECT_INCREF(thr, &h->hdr);
318 		}
319 
320 		if (len >= 0) {
321 			/*
322 			 *  For top-level objects, 'length' property has the following
323 			 *  default attributes: non-writable, non-enumerable, non-configurable
324 			 *  (E5 Section 15).
325 			 *
326 			 *  However, 'length' property for Array.prototype has attributes
327 			 *  expected of an Array instance which are different: writable,
328 			 *  non-enumerable, non-configurable (E5 Section 15.4.5.2).
329 			 *
330 			 *  This is currently determined implicitly based on class; there are
331 			 *  no attribute flags in the init data.
332 			 */
333 
334 			duk_push_int(ctx, len);
335 			duk_xdef_prop_stridx(ctx,
336 			                     -2,
337 			                     DUK_STRIDX_LENGTH,
338 			                     (class_num == DUK_HOBJECT_CLASS_ARRAY ?  /* only Array.prototype matches */
339 			                      DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE));
340 		}
341 
342 		/* enable exotic behaviors last */
343 
344 		if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
345 			DUK_HOBJECT_SET_EXOTIC_ARRAY(h);
346 		}
347 		if (class_num == DUK_HOBJECT_CLASS_STRING) {
348 			DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
349 		}
350 
351 		/* some assertions */
352 
353 		DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
354 		/* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
355 		DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h));
356 		DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h));
357 		/* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */
358 		DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h));
359 		DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h));       /* currently, even for Array.prototype */
360 		/* DUK_HOBJECT_FLAG_STRICT varies */
361 		DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) ||  /* all native functions have NEWENV */
362 		           DUK_HOBJECT_HAS_NEWENV(h));
363 		DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
364 		DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
365 		DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h));
366 		/* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
367 		/* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
368 		DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
369 
370 		DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
371 	}
372 
373 	/*
374 	 *  Then decode the builtins init data (see genbuiltins.py) to
375 	 *  init objects
376 	 */
377 
378 	DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
379 	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
380 		duk_small_uint_t t;
381 		duk_small_uint_t num;
382 
383 		DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
384 		h = duk_require_hobject(ctx, i);
385 		DUK_ASSERT(h != NULL);
386 
387 		t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
388 		if (t != DUK__NO_BIDX_MARKER) {
389 			DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
390 			DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_require_hobject(ctx, t));
391 		}
392 
393 		t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
394 		if (t != DUK__NO_BIDX_MARKER) {
395 			/* 'prototype' property for all built-in objects (which have it) has attributes:
396 			 *  [[Writable]] = false,
397 			 *  [[Enumerable]] = false,
398 			 *  [[Configurable]] = false
399 			 */
400 			DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
401 			duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
402 		}
403 
404 		t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
405 		if (t != DUK__NO_BIDX_MARKER) {
406 			/* 'constructor' property for all built-in objects (which have it) has attributes:
407 			 *  [[Writable]] = true,
408 			 *  [[Enumerable]] = false,
409 			 *  [[Configurable]] = true
410 			 */
411 			DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
412 			duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
413 		}
414 
415 		/* normal valued properties */
416 		num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS);
417 		DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
418 		for (j = 0; j < num; j++) {
419 			duk_small_uint_t prop_flags;
420 
421 			duk__push_stridx_or_string(ctx, bd);
422 
423 			/*
424 			 *  Property attribute defaults are defined in E5 Section 15 (first
425 			 *  few pages); there is a default for all properties and a special
426 			 *  default for 'length' properties.  Variation from the defaults is
427 			 *  signaled using a single flag bit in the bitstream.
428 			 */
429 
430 			if (duk_bd_decode_flag(bd)) {
431 				prop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
432 			} else {
433 				prop_flags = DUK_PROPDESC_FLAGS_WC;
434 			}
435 
436 			t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
437 
438 			DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
439 			                     (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) prop_flags, (long) t));
440 
441 			switch (t) {
442 			case DUK__PROP_TYPE_DOUBLE: {
443 				duk__push_double(ctx, bd);
444 				break;
445 			}
446 			case DUK__PROP_TYPE_STRING: {
447 				duk__push_string(ctx, bd);
448 				break;
449 			}
450 			case DUK__PROP_TYPE_STRIDX: {
451 				duk__push_stridx(ctx, bd);
452 				break;
453 			}
454 			case DUK__PROP_TYPE_BUILTIN: {
455 				duk_small_uint_t bidx;
456 
457 				bidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
458 				DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER);
459 				duk_dup(ctx, (duk_idx_t) bidx);
460 				break;
461 			}
462 			case DUK__PROP_TYPE_UNDEFINED: {
463 				duk_push_undefined(ctx);
464 				break;
465 			}
466 			case DUK__PROP_TYPE_BOOLEAN_TRUE: {
467 				duk_push_true(ctx);
468 				break;
469 			}
470 			case DUK__PROP_TYPE_BOOLEAN_FALSE: {
471 				duk_push_false(ctx);
472 				break;
473 			}
474 			case DUK__PROP_TYPE_ACCESSOR: {
475 				duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
476 				duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
477 				duk_c_function c_func_getter;
478 				duk_c_function c_func_setter;
479 
480 				/* XXX: this is a bit awkward because there is no exposed helper
481 				 * in the API style, only this internal helper.
482 				 */
483 				DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
484 				                     (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags));
485 
486 				c_func_getter = duk_bi_native_functions[natidx_getter];
487 				c_func_setter = duk_bi_native_functions[natidx_setter];
488 				duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0);  /* always 0 args */
489 				duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1);  /* always 1 arg */
490 
491 				/* XXX: magic for getter/setter? use duk_def_prop()? */
492 
493 				DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0);  /* genbuiltins.py ensures */
494 
495 				prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR;  /* accessor flag not encoded explicitly */
496 				duk_hobject_define_accessor_internal(thr,
497 				                                     duk_require_hobject(ctx, i),
498 				                                     duk_get_hstring(ctx, -3),
499 				                                     duk_require_hobject(ctx, -2),
500 				                                     duk_require_hobject(ctx, -1),
501 				                                     prop_flags);
502 				duk_pop_3(ctx);  /* key, getter and setter, now reachable through object */
503 				goto skip_value;
504 			}
505 			default: {
506 				/* exhaustive */
507 				DUK_UNREACHABLE();
508 			}
509 			}
510 
511 			DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0);
512 			duk_xdef_prop(ctx, i, prop_flags);
513 
514 		 skip_value:
515 			continue;  /* avoid empty label at the end of a compound statement */
516 		}
517 
518 		/* native function properties */
519 		num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS);
520 		DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
521 		for (j = 0; j < num; j++) {
522 			duk_hstring *h_key;
523 			duk_small_uint_t natidx;
524 			duk_int_t c_nargs;  /* must hold DUK_VARARGS */
525 			duk_small_uint_t c_length;
526 			duk_int16_t magic;
527 			duk_c_function c_func;
528 			duk_hnativefunction *h_func;
529 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
530 			duk_small_int_t lightfunc_eligible;
531 #endif
532 
533 			duk__push_stridx_or_string(ctx, bd);
534 			h_key = duk_get_hstring(ctx, -1);
535 			DUK_ASSERT(h_key != NULL);
536 			DUK_UNREF(h_key);
537 			natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
538 
539 			c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
540 			c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
541 			if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
542 				c_nargs = DUK_VARARGS;
543 			}
544 
545 			c_func = duk_bi_native_functions[natidx];
546 
547 			DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
548 			                     (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length,
549 			                     (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
550 
551 			/* Cast converts magic to 16-bit signed value */
552 			magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0);
553 
554 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
555 			lightfunc_eligible =
556 				((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
557 				(c_length <= DUK_LFUNC_LENGTH_MAX) &&
558 				(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
559 
560 			if (h_key == DUK_HTHREAD_STRING_EVAL(thr) ||
561 			    h_key == DUK_HTHREAD_STRING_YIELD(thr) ||
562 			    h_key == DUK_HTHREAD_STRING_RESUME(thr) ||
563 			    h_key == DUK_HTHREAD_STRING_REQUIRE(thr)) {
564 				/* These functions have trouble working as lightfuncs.
565 				 * Some of them have specific asserts and some may have
566 			         * additional properties (e.g. 'require.id' may be written).
567 				 */
568 				DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j));
569 				lightfunc_eligible = 0;
570 			}
571 
572 			if (lightfunc_eligible) {
573 				duk_tval tv_lfunc;
574 				duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
575 				duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
576 				DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
577 				duk_push_tval(ctx, &tv_lfunc);
578 				DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(ctx, -1)));
579 				goto lightfunc_skip;
580 			}
581 
582 			DUK_D(DUK_DPRINT("built-in function NOT ELIGIBLE as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic));
583 #endif  /* DUK_USE_LIGHTFUNC_BUILTINS */
584 
585 			/* [ (builtin objects) name ] */
586 
587 			duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs);
588 			h_func = duk_require_hnativefunction(ctx, -1);
589 			DUK_UNREF(h_func);
590 
591 			/* Currently all built-in native functions are strict.
592 			 * This doesn't matter for many functions, but e.g.
593 			 * String.prototype.charAt (and other string functions)
594 			 * rely on being strict so that their 'this' binding is
595 			 * not automatically coerced.
596 			 */
597 			DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
598 
599 			/* No built-in functions are constructable except the top
600 			 * level ones (Number, etc).
601 			 */
602 			DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
603 
604 			/* XXX: any way to avoid decoding magic bit; there are quite
605 			 * many function properties and relatively few with magic values.
606 			 */
607 			h_func->magic = magic;
608 
609 			/* [ (builtin objects) name func ] */
610 
611 			duk_push_int(ctx, c_length);
612 			duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
613 
614 			duk_dup(ctx, -2);
615 			duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
616 
617 			/* XXX: other properties of function instances; 'arguments', 'caller'. */
618 
619 			DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
620 			                   (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1)));
621 
622 			/* [ (builtin objects) name func ] */
623 
624 			/*
625 			 *  The default property attributes are correct for all
626 			 *  function valued properties of built-in objects now.
627 			 */
628 
629 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
630 		 lightfunc_skip:
631 #endif
632 
633 			duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC);
634 
635 			/* [ (builtin objects) ] */
636 		}
637 	}
638 
639 	/*
640 	 *  Special post-tweaks, for cases not covered by the init data format.
641 	 *
642 	 *  - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
643 	 *    toGMTString is required to have the same Function object as
644 	 *    toUTCString in E5 Section B.2.6.  Note that while Smjs respects
645 	 *    this, V8 does not (the Function objects are distinct).
646 	 *
647 	 *  - Make DoubleError non-extensible.
648 	 *
649 	 *  - Add info about most important effective compile options to Duktape.
650 	 *
651 	 *  - Possibly remove some properties (values or methods) which are not
652 	 *    desirable with current feature options but are not currently
653 	 *    conditional in init data.
654 	 */
655 
656 	duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
657 	duk_xdef_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
658 
659 	h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
660 	DUK_ASSERT(h != NULL);
661 	DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
662 
663 #if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
664 	DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
665 	(void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW);
666 #endif
667 
668 #if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
669 	DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
670 	(void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW);
671 #endif
672 
673 	/* XXX: relocate */
674 	duk_push_string(ctx,
675 			/* Endianness indicator */
676 #if defined(DUK_USE_INTEGER_LE)
677 	                "l"
678 #elif defined(DUK_USE_INTEGER_BE)
679 	                "b"
680 #elif defined(DUK_USE_INTEGER_ME)  /* integer mixed endian not really used now */
681 	                "m"
682 #else
683 	                "?"
684 #endif
685 #if defined(DUK_USE_DOUBLE_LE)
686 	                "l"
687 #elif defined(DUK_USE_DOUBLE_BE)
688 	                "b"
689 #elif defined(DUK_USE_DOUBLE_ME)
690 	                "m"
691 #else
692 	                "?"
693 #endif
694 	                " "
695 			/* Packed or unpacked tval */
696 #if defined(DUK_USE_PACKED_TVAL)
697 	                "p"
698 #else
699 	                "u"
700 #endif
701 #if defined(DUK_USE_FASTINT)
702 			"f"
703 #endif
704 			" "
705 			/* Low memory options */
706 #if defined(DUK_USE_STRTAB_CHAIN)
707 			"c"  /* chain */
708 #elif defined(DUK_USE_STRTAB_PROBE)
709 			"p"  /* probe */
710 #else
711 			"?"
712 #endif
713 #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
714 			"n"
715 #endif
716 #if defined(DUK_USE_HEAPPTR16)
717 			"h"
718 #endif
719 #if defined(DUK_USE_DATAPTR16)
720 			"d"
721 #endif
722 #if defined(DUK_USE_FUNCPTR16)
723 			"f"
724 #endif
725 #if defined(DUK_USE_REFCOUNT16)
726 			"R"
727 #endif
728 #if defined(DUK_USE_STRHASH16)
729 			"H"
730 #endif
731 #if defined(DUK_USE_STRLEN16)
732 			"S"
733 #endif
734 #if defined(DUK_USE_BUFLEN16)
735 			"B"
736 #endif
737 #if defined(DUK_USE_OBJSIZES16)
738 			"O"
739 #endif
740 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
741 			"L"
742 #endif
743 #if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
744 			/* XXX: This won't be shown in practice now
745 			 * because this code is not run when builtins
746 			 * are in ROM.
747 			 */
748 			"Z"
749 #endif
750 	                " "
751 			/* Object property allocation layout */
752 #if defined(DUK_USE_HOBJECT_LAYOUT_1)
753 			"p1"
754 #elif defined(DUK_USE_HOBJECT_LAYOUT_2)
755 			"p2"
756 #elif defined(DUK_USE_HOBJECT_LAYOUT_3)
757 			"p3"
758 #else
759 			"p?"
760 #endif
761 			" "
762 			/* Alignment guarantee */
763 #if (DUK_USE_ALIGN_BY == 4)
764 			"a4"
765 #elif (DUK_USE_ALIGN_BY == 8)
766 			"a8"
767 #elif (DUK_USE_ALIGN_BY == 1)
768 			"a1"
769 #else
770 #error invalid DUK_USE_ALIGN_BY
771 #endif
772 			" "
773 			/* Architecture, OS, and compiler strings */
774 	                DUK_USE_ARCH_STRING
775 			" "
776 	                DUK_USE_OS_STRING
777 			" "
778 	                DUK_USE_COMPILER_STRING);
779 	duk_xdef_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
780 
781 	/*
782 	 *  InitJS code - Ecmascript code evaluated from a built-in source
783 	 *  which provides e.g. backward compatibility.  User can also provide
784 	 *  JS code to be evaluated at startup.
785 	 */
786 
787 #ifdef DUK_USE_BUILTIN_INITJS
788 	/* XXX: compression */
789 	DUK_DD(DUK_DDPRINT("running built-in initjs"));
790 	duk_eval_string(ctx, (const char *) duk_initjs_data);  /* initjs data is NUL terminated */
791 	duk_pop(ctx);
792 #endif  /* DUK_USE_BUILTIN_INITJS */
793 
794 #ifdef DUK_USE_USER_INITJS
795 	/* XXX: compression (as an option) */
796 	DUK_DD(DUK_DDPRINT("running user initjs"));
797 	duk_eval_string_noresult(ctx, (const char *) DUK_USE_USER_INITJS);
798 #endif  /* DUK_USE_USER_INITJS */
799 
800 	/*
801 	 *  Since built-ins are not often extended, compact them.
802 	 */
803 
804 	DUK_DD(DUK_DDPRINT("compact built-ins"));
805 	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
806 		duk_hobject_compact_props(thr, duk_require_hobject(ctx, i));
807 	}
808 
809 	DUK_D(DUK_DPRINT("INITBUILTINS END"));
810 
811 #ifdef DUK_USE_DDPRINT
812 	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
813 		DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
814 		                   (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i)));
815 	}
816 #endif
817 
818 	/*
819 	 *  Pop built-ins from stack: they are now INCREF'd and
820 	 *  reachable from the builtins[] array or indirectly
821 	 *  through builtins[].
822 	 */
823 
824 	duk_set_top(ctx, 0);
825 	DUK_ASSERT_TOP(ctx, 0);
826 }
827 #endif  /* DUK_USE_ROM_OBJECTS */
828 
duk_hthread_copy_builtin_objects(duk_hthread * thr_from,duk_hthread * thr_to)829 DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
830 	duk_small_uint_t i;
831 
832 	for (i = 0; i < DUK_NUM_BUILTINS; i++) {
833 		thr_to->builtins[i] = thr_from->builtins[i];
834 		DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]);  /* side effect free */
835 	}
836 }
837