File: duk_hthread_builtins.c

package info (click to toggle)
duktape 2.7.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 21,160 kB
  • sloc: ansic: 215,359; python: 5,961; javascript: 4,555; makefile: 477; cpp: 205
file content (886 lines) | stat: -rw-r--r-- 31,114 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
/*
 *  Initialize built-in objects.  Current thread must have a valstack
 *  and initialization errors may longjmp, so a setjmp() catch point
 *  must exist.
 */

#include "duk_internal.h"

/*
 *  Encoding constants, must match genbuiltins.py
 */

#define DUK__PROP_FLAGS_BITS  3
#define DUK__LENGTH_PROP_BITS 3
#define DUK__NARGS_BITS       3
#define DUK__PROP_TYPE_BITS   3

#define DUK__NARGS_VARARGS_MARKER 0x07

#define DUK__PROP_TYPE_DOUBLE        0
#define DUK__PROP_TYPE_STRING        1
#define DUK__PROP_TYPE_STRIDX        2
#define DUK__PROP_TYPE_BUILTIN       3
#define DUK__PROP_TYPE_UNDEFINED     4
#define DUK__PROP_TYPE_BOOLEAN_TRUE  5
#define DUK__PROP_TYPE_BOOLEAN_FALSE 6
#define DUK__PROP_TYPE_ACCESSOR      7

/*
 *  Create built-in objects by parsing an init bitstream generated
 *  by genbuiltins.py.
 */

#if defined(DUK_USE_ROM_OBJECTS)
#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
	duk_hobject *h_global;
#if defined(DUK_USE_ROM_GLOBAL_CLONE)
	duk_hobject *h_oldglobal;
	duk_uint8_t *props;
	duk_size_t alloc_size;
#endif
	duk_hobject *h_objenv;

	/* XXX: refactor into internal helper, duk_clone_hobject() */

#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
	/* Inherit from ROM-based global object: less RAM usage, less transparent. */
	h_global = duk_push_object_helper(thr,
	                                  DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_FASTREFS |
	                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
	                                  DUK_BIDX_GLOBAL);
	DUK_ASSERT(h_global != NULL);
#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
	/* Clone the properties of the ROM-based global object to create a
	 * fully RAM-based global object.  Uses more memory than the inherit
	 * model but more compliant.
	 */
	h_global = duk_push_object_helper(thr,
	                                  DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_FASTREFS |
	                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
	                                  DUK_BIDX_OBJECT_PROTOTYPE);
	DUK_ASSERT(h_global != NULL);
	h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL];
	DUK_ASSERT(h_oldglobal != NULL);

	/* Copy the property table verbatim; this handles attributes etc.
	 * For ROM objects it's not necessary (or possible) to update
	 * refcounts so leave them as is.
	 */
	alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal);
	DUK_ASSERT(alloc_size > 0);
	props = DUK_ALLOC_CHECKED(thr, alloc_size);
	DUK_ASSERT(props != NULL);
	DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL);
	duk_memcpy((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size);

	/* XXX: keep property attributes or tweak them here?
	 * Properties will now be non-configurable even when they're
	 * normally configurable for the global object.
	 */

	DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL);
	DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props);
	DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal));
	DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal));
	DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal));
	DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal));
#else
#error internal error in config defines
#endif

	duk_hobject_compact_props(thr, h_global);
	DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
	DUK_ASSERT(
	    !DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */
	thr->builtins[DUK_BIDX_GLOBAL] = h_global;
	DUK_HOBJECT_INCREF(thr, h_global);
	DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global));

	/* Create a fresh object environment for the global scope.  This is
	 * needed so that the global scope points to the newly created RAM-based
	 * global object.
	 */
	h_objenv =
	    (duk_hobject *) duk_hobjenv_alloc(thr,
	                                      DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
	DUK_ASSERT(h_objenv != NULL);
	DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL);
	duk_push_hobject(thr, h_objenv);

	DUK_ASSERT(h_global != NULL);
	((duk_hobjenv *) h_objenv)->target = h_global;
	DUK_HOBJECT_INCREF(thr, h_global);
	DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0);

	DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
	DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(
	    (duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */
	thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv;
	DUK_HOBJECT_INCREF(thr, h_objenv);
	DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv));

	DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) h_objenv);

	duk_pop_2(thr); /* Pop global object and global env. */
}
#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */

DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
	/* Setup builtins from ROM objects.  All heaps/threads will share
	 * the same readonly objects.
	 */
	duk_small_uint_t i;

	for (i = 0; i < DUK_NUM_BUILTINS; i++) {
		duk_hobject *h;
		h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
		DUK_ASSERT(h != NULL);
		thr->builtins[i] = h;
	}

#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
	/* By default the global object is read-only which is often much
	 * more of an issue than having read-only built-in objects (like
	 * RegExp, Date, etc).  Use a RAM-based copy of the global object
	 * and the global environment object for convenience.
	 */
	duk__duplicate_ram_global_object(thr);
#endif
}
#else /* DUK_USE_ROM_OBJECTS */
DUK_LOCAL void duk__push_stridx(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
	duk_small_uint_t n;

	n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
	DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
	DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
	duk_push_hstring_stridx(thr, n);
}
DUK_LOCAL void duk__push_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
	/* XXX: built-ins data could provide a maximum length that is
	 * actually needed; bitpacked max length is now 256 bytes.
	 */
	duk_uint8_t tmp[DUK_BD_BITPACKED_STRING_MAXLEN];
	duk_small_uint_t len;

	len = duk_bd_decode_bitpacked_string(bd, tmp);
	duk_push_lstring(thr, (const char *) tmp, (duk_size_t) len);
}
DUK_LOCAL void duk__push_stridx_or_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
	duk_small_uint_t n;

	n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
	if (n == 0) {
		duk__push_string(thr, bd);
	} else {
		n--;
		DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
		duk_push_hstring_stridx(thr, n);
	}
}
DUK_LOCAL void duk__push_double(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
	duk_double_union du;
	duk_small_uint_t i;

	for (i = 0; i < 8; i++) {
		/* Encoding endianness must match target memory layout,
		 * build scripts and genbuiltins.py must ensure this.
		 */
		du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
	}

	duk_push_number(thr, du.d); /* push operation normalizes NaNs */
}

DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
	duk_bitdecoder_ctx bd_ctx;
	duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
	duk_hobject *h;
	duk_small_uint_t i, j;

	DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d",
	                 (int) DUK_NUM_BUILTINS,
	                 (int) DUK_NUM_ALL_BUILTINS));

	duk_memzero(&bd_ctx, sizeof(bd_ctx));
	bd->data = (const duk_uint8_t *) duk_builtins_data;
	bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;

	/*
	 *  First create all built-in bare objects on the empty valstack.
	 *
	 *  Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
	 *  stack indices matching their eventual thr->builtins[] index.
	 *
	 *  Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
	 *  will exist on the value stack during init but won't be placed
	 *  into thr->builtins[].  These are objects referenced in some way
	 *  from thr->builtins[] roots but which don't need to be indexed by
	 *  Duktape through thr->builtins[] (e.g. user custom objects).
	 *
	 *  Internal prototypes will be incorrect (NULL) at this stage.
	 */

	duk_require_stack(thr, DUK_NUM_ALL_BUILTINS);

	DUK_DD(DUK_DDPRINT("create empty built-ins"));
	DUK_ASSERT_TOP(thr, 0);
	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
		duk_small_uint_t class_num;
		duk_small_int_t len = -1; /* must be signed */

		class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
		len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);

		if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
			duk_small_uint_t natidx;
			duk_small_int_t c_nargs; /* must hold DUK_VARARGS */
			duk_c_function c_func;
			duk_int16_t magic;

			DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
			DUK_ASSERT(len >= 0);

			natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
			DUK_ASSERT(natidx != 0);
			c_func = duk_bi_native_functions[natidx];
			DUK_ASSERT(c_func != NULL);

			c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/);
			if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
				c_nargs = DUK_VARARGS;
			}

			/* XXX: set magic directly here? (it could share the c_nargs arg) */
			(void) duk_push_c_function_builtin(thr, c_func, c_nargs);
			h = duk_known_hobject(thr, -1);

			/* Currently all built-in native functions are strict.
			 * duk_push_c_function() now sets strict flag, so
			 * assert for it.
			 */
			DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));

			/* XXX: function properties */

			duk__push_stridx_or_string(thr, bd);
#if defined(DUK_USE_FUNC_NAME_PROPERTY)
			duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
#else
			duk_pop(thr); /* Not very ideal but good enough for now. */
#endif

			/* Almost all global level Function objects are constructable
			 * but not all: Function.prototype is a non-constructable,
			 * callable Function.
			 */
			if (duk_bd_decode_flag(bd)) {
				DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
			} else {
				DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
			}

			/* Cast converts magic to 16-bit signed value */
			magic = (duk_int16_t) duk_bd_decode_varuint(bd);
			((duk_hnatfunc *) h)->magic = magic;
		} else if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
			duk_push_array(thr);
		} else if (class_num == DUK_HOBJECT_CLASS_OBJENV) {
			duk_hobjenv *env;
			duk_hobject *global;

			DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV);
			DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL);

			env = duk_hobjenv_alloc(thr,
			                        DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
			DUK_ASSERT(env->target == NULL);
			duk_push_hobject(thr, (duk_hobject *) env);

			global = duk_known_hobject(thr, DUK_BIDX_GLOBAL);
			DUK_ASSERT(global != NULL);
			env->target = global;
			DUK_HOBJECT_INCREF(thr, global);
			DUK_ASSERT(env->has_this == 0);

			DUK_HOBJENV_ASSERT_VALID(env);
		} else {
			DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV);

			(void) duk_push_object_helper(thr,
			                              DUK_HOBJECT_FLAG_FASTREFS | DUK_HOBJECT_FLAG_EXTENSIBLE,
			                              -1); /* no prototype or class yet */
		}

		h = duk_known_hobject(thr, -1);
		DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);

		if (i < DUK_NUM_BUILTINS) {
			thr->builtins[i] = h;
			DUK_HOBJECT_INCREF(thr, &h->hdr);
		}

		if (len >= 0) {
			/* In ES2015+ built-in function object .length property
			 * has property attributes C (configurable only):
			 * http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-standard-built-in-objects
			 *
			 * Array.prototype remains an Array instance in ES2015+
			 * and its length has attributes W (writable only).
			 * Because .length is now virtual for duk_harray, it is
			 * not encoded explicitly in init data.
			 */

			DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */
			duk_push_int(thr, len);
			duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
		}

		/* enable exotic behaviors last */

		if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
			DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)); /* set by duk_push_array() */
		}
		if (class_num == DUK_HOBJECT_CLASS_STRING) {
			DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
		}

		/* some assertions */

		DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
		/* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
		DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h));
		DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h));
		/* DUK_HOBJECT_FLAG_NATFUNC varies */
		DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h));
		DUK_ASSERT(!DUK_HOBJECT_IS_PROXY(h));
		DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY);
		/* DUK_HOBJECT_FLAG_STRICT varies */
		DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */
		           DUK_HOBJECT_HAS_NEWENV(h));
		DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
		DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
		/* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
		/* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
		DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));

		DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
	}

	/*
	 *  Then decode the builtins init data (see genbuiltins.py) to
	 *  init objects.  Internal prototypes are set at this stage,
	 *  with thr->builtins[] populated.
	 */

	DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
		duk_small_uint_t t;
		duk_small_uint_t num;

		DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
		h = duk_known_hobject(thr, (duk_idx_t) i);

		t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
		if (t > 0) {
			t--;
			DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
			DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(thr, (duk_idx_t) t));
		} else if (DUK_HOBJECT_IS_NATFUNC(h)) {
			/* Standard native built-ins cannot inherit from
			 * %NativeFunctionPrototype%, they are required to
			 * inherit from Function.prototype directly.
			 */
			DUK_ASSERT(thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE] != NULL);
			DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
		}

		t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
		if (t > 0) {
			/* 'prototype' property for all built-in objects (which have it) has attributes:
			 *  [[Writable]] = false,
			 *  [[Enumerable]] = false,
			 *  [[Configurable]] = false
			 */
			t--;
			DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
			duk_dup(thr, (duk_idx_t) t);
			duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_NONE);
		}

		t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
		if (t > 0) {
			/* 'constructor' property for all built-in objects (which have it) has attributes:
			 *  [[Writable]] = true,
			 *  [[Enumerable]] = false,
			 *  [[Configurable]] = true
			 */
			t--;
			DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
			duk_dup(thr, (duk_idx_t) t);
			duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);
		}

		/* normal valued properties */
		num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
		DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
		for (j = 0; j < num; j++) {
			duk_small_uint_t defprop_flags;

			duk__push_stridx_or_string(thr, bd);

			/*
			 *  Property attribute defaults are defined in E5 Section 15 (first
			 *  few pages); there is a default for all properties and a special
			 *  default for 'length' properties.  Variation from the defaults is
			 *  signaled using a single flag bit in the bitstream.
			 */

			defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
			                                                         DUK__PROP_FLAGS_BITS,
			                                                         (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
			defprop_flags |= DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE |
			                 DUK_DEFPROP_HAVE_ENUMERABLE |
			                 DUK_DEFPROP_HAVE_CONFIGURABLE; /* Defaults for data properties. */

			/* The writable, enumerable, configurable flags in prop_flags
			 * match both duk_def_prop() and internal property flags.
			 */
			DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
			DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
			DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);

			t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);

			DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
			                     (long) i,
			                     (long) j,
			                     duk_get_tval(thr, -1),
			                     (unsigned long) defprop_flags,
			                     (long) t));

			switch (t) {
			case DUK__PROP_TYPE_DOUBLE: {
				duk__push_double(thr, bd);
				break;
			}
			case DUK__PROP_TYPE_STRING: {
				duk__push_string(thr, bd);
				break;
			}
			case DUK__PROP_TYPE_STRIDX: {
				duk__push_stridx(thr, bd);
				break;
			}
			case DUK__PROP_TYPE_BUILTIN: {
				duk_small_uint_t bidx;

				bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
				duk_dup(thr, (duk_idx_t) bidx);
				break;
			}
			case DUK__PROP_TYPE_UNDEFINED: {
				duk_push_undefined(thr);
				break;
			}
			case DUK__PROP_TYPE_BOOLEAN_TRUE: {
				duk_push_true(thr);
				break;
			}
			case DUK__PROP_TYPE_BOOLEAN_FALSE: {
				duk_push_false(thr);
				break;
			}
			case DUK__PROP_TYPE_ACCESSOR: {
				duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
				duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
				duk_small_uint_t accessor_magic = (duk_small_uint_t) duk_bd_decode_varuint(bd);
				duk_c_function c_func_getter;
				duk_c_function c_func_setter;

				DUK_DDD(DUK_DDDPRINT(
				    "built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
				    (long) i,
				    duk_get_tval(thr, -1),
				    (long) natidx_getter,
				    (long) natidx_setter,
				    (unsigned long) defprop_flags));

				c_func_getter = duk_bi_native_functions[natidx_getter];
				if (c_func_getter != NULL) {
					duk_push_c_function_builtin_noconstruct(thr, c_func_getter, 0); /* always 0 args */
					duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
					defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
				}
				c_func_setter = duk_bi_native_functions[natidx_setter];
				if (c_func_setter != NULL) {
					duk_push_c_function_builtin_noconstruct(thr, c_func_setter, 1); /* always 1 arg */
					duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
					defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
				}

				/* Writable flag doesn't make sense for an accessor. */
				DUK_ASSERT((defprop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */

				defprop_flags &= ~(DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
				defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE;
				break;
			}
			default: {
				/* exhaustive */
				DUK_UNREACHABLE();
			}
			}

			duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
			DUK_ASSERT_TOP(thr, DUK_NUM_ALL_BUILTINS);
		}

		/* native function properties */
		num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
		DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
		for (j = 0; j < num; j++) {
			duk_hstring *h_key;
			duk_small_uint_t natidx;
			duk_int_t c_nargs; /* must hold DUK_VARARGS */
			duk_small_uint_t c_length;
			duk_int16_t magic;
			duk_c_function c_func;
			duk_hnatfunc *h_func;
#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
			duk_small_int_t lightfunc_eligible;
#endif
			duk_small_uint_t defprop_flags;

			duk__push_stridx_or_string(thr, bd);
			h_key = duk_known_hstring(thr, -1);
			DUK_UNREF(h_key);
			natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);

			c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
			c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_uint32_t) c_length /*def_value*/);
			if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
				c_nargs = DUK_VARARGS;
			}

			c_func = duk_bi_native_functions[natidx];

			DUK_DDD(
			    DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
			                 (long) i,
			                 (long) j,
			                 (duk_heaphdr *) h_key,
			                 (long) natidx,
			                 (long) c_length,
			                 (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));

			/* Cast converts magic to 16-bit signed value */
			magic = (duk_int16_t) duk_bd_decode_varuint(bd);

#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
			lightfunc_eligible =
			    ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
			    (c_length <= DUK_LFUNC_LENGTH_MAX) && (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);

			/* These functions have trouble working as lightfuncs.
			 * Some of them have specific asserts and some may have
			 * additional properties (e.g. 'require.id' may be written).
			 */
			if (c_func == duk_bi_global_object_eval) {
				lightfunc_eligible = 0;
			}
#if defined(DUK_USE_COROUTINE_SUPPORT)
			if (c_func == duk_bi_thread_yield || c_func == duk_bi_thread_resume) {
				lightfunc_eligible = 0;
			}
#endif
			if (c_func == duk_bi_function_prototype_call || c_func == duk_bi_function_prototype_apply ||
			    c_func == duk_bi_reflect_apply || c_func == duk_bi_reflect_construct) {
				lightfunc_eligible = 0;
			}

			if (lightfunc_eligible) {
				duk_tval tv_lfunc;
				duk_small_uint_t lf_nargs =
				    (duk_small_uint_t) (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
				duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
				DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
				duk_push_tval(thr, &tv_lfunc);
				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(thr, -1)));
				goto lightfunc_skip;
			}

			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));
#endif /* DUK_USE_LIGHTFUNC_BUILTINS */

			/* [ (builtin objects) name ] */

			duk_push_c_function_builtin_noconstruct(thr, c_func, c_nargs);
			h_func = duk_known_hnatfunc(thr, -1);
			DUK_UNREF(h_func);

			/* XXX: add into init data? */

			/* Special call handling, not described in init data. */
			if (c_func == duk_bi_global_object_eval || c_func == duk_bi_function_prototype_call ||
			    c_func == duk_bi_function_prototype_apply || c_func == duk_bi_reflect_apply ||
			    c_func == duk_bi_reflect_construct) {
				DUK_HOBJECT_SET_SPECIAL_CALL((duk_hobject *) h_func);
			}

			/* Currently all built-in native functions are strict.
			 * This doesn't matter for many functions, but e.g.
			 * String.prototype.charAt (and other string functions)
			 * rely on being strict so that their 'this' binding is
			 * not automatically coerced.
			 */
			DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);

			/* No built-in functions are constructable except the top
			 * level ones (Number, etc).
			 */
			DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));

			/* XXX: any way to avoid decoding magic bit; there are quite
			 * many function properties and relatively few with magic values.
			 */
			h_func->magic = magic;

			/* [ (builtin objects) name func ] */

			duk_push_uint(thr, c_length);
			duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);

			duk_dup_m2(thr);
			duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);

			/* XXX: other properties of function instances; 'arguments', 'caller'. */

			DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
			                   (long) i,
			                   (long) j,
			                   (duk_tval *) duk_get_tval(thr, -1)));

			/* [ (builtin objects) name func ] */

			/*
			 *  The default property attributes are correct for all
			 *  function valued properties of built-in objects now.
			 */

#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
		lightfunc_skip:
#endif

			defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
			                                                         DUK__PROP_FLAGS_BITS,
			                                                         (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
			defprop_flags |= DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE |
			                 DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE;
			DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
			DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
			DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);

			duk_def_prop(thr, (duk_idx_t) i, defprop_flags);

			/* [ (builtin objects) ] */
		}
	}

	/*
	 *  Special post-tweaks, for cases not covered by the init data format.
	 *
	 *  - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
	 *    toGMTString is required to have the same Function object as
	 *    toUTCString in E5 Section B.2.6.  Note that while Smjs respects
	 *    this, V8 does not (the Function objects are distinct).
	 *
	 *  - Make DoubleError non-extensible.
	 *
	 *  - Add info about most important effective compile options to Duktape.
	 *
	 *  - Possibly remove some properties (values or methods) which are not
	 *    desirable with current feature options but are not currently
	 *    conditional in init data.
	 */

#if defined(DUK_USE_DATE_BUILTIN)
	duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
	duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
#endif

	h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR);
	DUK_HOBJECT_CLEAR_EXTENSIBLE(h);

#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
	DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
	(void) duk_hobject_delprop_raw(thr,
	                               thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE],
	                               DUK_HTHREAD_STRING___PROTO__(thr),
	                               DUK_DELPROP_FLAG_THROW);
#endif

#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
	DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
	(void) duk_hobject_delprop_raw(thr,
	                               thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR],
	                               DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr),
	                               DUK_DELPROP_FLAG_THROW);
#endif

	/* XXX: relocate */
	duk_push_string(thr,
	/* Endianness indicator */
#if defined(DUK_USE_INTEGER_LE)
	                "l"
#elif defined(DUK_USE_INTEGER_BE)
	                "b"
#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */
	                "m"
#else
	                "?"
#endif
#if defined(DUK_USE_DOUBLE_LE)
	                "l"
#elif defined(DUK_USE_DOUBLE_BE)
	                "b"
#elif defined(DUK_USE_DOUBLE_ME)
	                "m"
#else
	                "?"
#endif
	                " "
	/* Packed or unpacked tval */
#if defined(DUK_USE_PACKED_TVAL)
	                "p"
#else
	                "u"
#endif
#if defined(DUK_USE_FASTINT)
	                "f"
#endif
	                " "
	/* Low memory/performance options */
#if defined(DUK_USE_STRTAB_PTRCOMP)
	                "s"
#endif
#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
	                "n"
#endif
#if defined(DUK_USE_HEAPPTR16)
	                "h"
#endif
#if defined(DUK_USE_DATAPTR16)
	                "d"
#endif
#if defined(DUK_USE_FUNCPTR16)
	                "f"
#endif
#if defined(DUK_USE_REFCOUNT16)
	                "R"
#endif
#if defined(DUK_USE_STRHASH16)
	                "H"
#endif
#if defined(DUK_USE_STRLEN16)
	                "S"
#endif
#if defined(DUK_USE_BUFLEN16)
	                "B"
#endif
#if defined(DUK_USE_OBJSIZES16)
	                "O"
#endif
#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
	                "L"
#endif
#if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
	                /* XXX: This won't be shown in practice now
	                 * because this code is not run when builtins
	                 * are in ROM.
	                 */
	                "Z"
#endif
#if defined(DUK_USE_LITCACHE_SIZE)
	                "l"
#endif
	                " "
	/* Object property allocation layout */
#if defined(DUK_USE_HOBJECT_LAYOUT_1)
	                "p1"
#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
	                "p2"
#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
	                "p3"
#else
	                "p?"
#endif
	                " "
	/* Alignment guarantee */
#if (DUK_USE_ALIGN_BY == 4)
	                "a4"
#elif (DUK_USE_ALIGN_BY == 8)
	                "a8"
#elif (DUK_USE_ALIGN_BY == 1)
	                "a1"
#else
#error invalid DUK_USE_ALIGN_BY
#endif
	                " "
	                /* Architecture, OS, and compiler strings */
	                DUK_USE_ARCH_STRING " " DUK_USE_OS_STRING " " DUK_USE_COMPILER_STRING);
	duk_xdef_prop_stridx_short(thr, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);

	/*
	 *  Since built-ins are not often extended, compact them.
	 */

	DUK_DD(DUK_DDPRINT("compact built-ins"));
	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
		duk_hobject_compact_props(thr, duk_known_hobject(thr, (duk_idx_t) i));
	}

	DUK_D(DUK_DPRINT("INITBUILTINS END"));

#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
	for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
		DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
		                   (long) i,
		                   (duk_heaphdr *) duk_require_hobject(thr, (duk_idx_t) i)));
	}
#endif

	/*
	 *  Pop built-ins from stack: they are now INCREF'd and
	 *  reachable from the builtins[] array or indirectly
	 *  through builtins[].
	 */

	duk_set_top(thr, 0);
	DUK_ASSERT_TOP(thr, 0);
}
#endif /* DUK_USE_ROM_OBJECTS */

DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
	duk_small_uint_t i;

	for (i = 0; i < DUK_NUM_BUILTINS; i++) {
		thr_to->builtins[i] = thr_from->builtins[i];
		DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
	}
}