1package goja
2
3import (
4	"fmt"
5	"math"
6	"reflect"
7	"sort"
8
9	"github.com/dop251/goja/unistring"
10)
11
12const (
13	classObject   = "Object"
14	classArray    = "Array"
15	classWeakSet  = "WeakSet"
16	classWeakMap  = "WeakMap"
17	classMap      = "Map"
18	classMath     = "Math"
19	classSet      = "Set"
20	classFunction = "Function"
21	classNumber   = "Number"
22	classString   = "String"
23	classBoolean  = "Boolean"
24	classError    = "Error"
25	classRegExp   = "RegExp"
26	classDate     = "Date"
27	classJSON     = "JSON"
28	classGlobal   = "global"
29
30	classArrayIterator        = "Array Iterator"
31	classMapIterator          = "Map Iterator"
32	classSetIterator          = "Set Iterator"
33	classStringIterator       = "String Iterator"
34	classRegExpStringIterator = "RegExp String Iterator"
35)
36
37var (
38	hintDefault Value = asciiString("default")
39	hintNumber  Value = asciiString("number")
40	hintString  Value = asciiString("string")
41)
42
43type Object struct {
44	id      uint64
45	runtime *Runtime
46	self    objectImpl
47
48	weakRefs map[weakMap]Value
49}
50
51type iterNextFunc func() (propIterItem, iterNextFunc)
52
53type PropertyDescriptor struct {
54	jsDescriptor *Object
55
56	Value Value
57
58	Writable, Configurable, Enumerable Flag
59
60	Getter, Setter Value
61}
62
63func (p *PropertyDescriptor) Empty() bool {
64	var empty PropertyDescriptor
65	return *p == empty
66}
67
68func (p *PropertyDescriptor) IsAccessor() bool {
69	return p.Setter != nil || p.Getter != nil
70}
71
72func (p *PropertyDescriptor) IsData() bool {
73	return p.Value != nil || p.Writable != FLAG_NOT_SET
74}
75
76func (p *PropertyDescriptor) IsGeneric() bool {
77	return !p.IsAccessor() && !p.IsData()
78}
79
80func (p *PropertyDescriptor) toValue(r *Runtime) Value {
81	if p.jsDescriptor != nil {
82		return p.jsDescriptor
83	}
84	if p.Empty() {
85		return _undefined
86	}
87	o := r.NewObject()
88	s := o.self
89
90	if p.Value != nil {
91		s._putProp("value", p.Value, true, true, true)
92	}
93
94	if p.Writable != FLAG_NOT_SET {
95		s._putProp("writable", valueBool(p.Writable.Bool()), true, true, true)
96	}
97
98	if p.Enumerable != FLAG_NOT_SET {
99		s._putProp("enumerable", valueBool(p.Enumerable.Bool()), true, true, true)
100	}
101
102	if p.Configurable != FLAG_NOT_SET {
103		s._putProp("configurable", valueBool(p.Configurable.Bool()), true, true, true)
104	}
105
106	if p.Getter != nil {
107		s._putProp("get", p.Getter, true, true, true)
108	}
109	if p.Setter != nil {
110		s._putProp("set", p.Setter, true, true, true)
111	}
112
113	return o
114}
115
116func (p *PropertyDescriptor) complete() {
117	if p.Getter == nil && p.Setter == nil {
118		if p.Value == nil {
119			p.Value = _undefined
120		}
121		if p.Writable == FLAG_NOT_SET {
122			p.Writable = FLAG_FALSE
123		}
124	} else {
125		if p.Getter == nil {
126			p.Getter = _undefined
127		}
128		if p.Setter == nil {
129			p.Setter = _undefined
130		}
131	}
132	if p.Enumerable == FLAG_NOT_SET {
133		p.Enumerable = FLAG_FALSE
134	}
135	if p.Configurable == FLAG_NOT_SET {
136		p.Configurable = FLAG_FALSE
137	}
138}
139
140type objectExportCacheItem map[reflect.Type]interface{}
141
142type objectExportCtx struct {
143	cache map[objectImpl]interface{}
144}
145
146type objectImpl interface {
147	sortable
148	className() string
149	getStr(p unistring.String, receiver Value) Value
150	getIdx(p valueInt, receiver Value) Value
151	getSym(p *Symbol, receiver Value) Value
152
153	getOwnPropStr(unistring.String) Value
154	getOwnPropIdx(valueInt) Value
155	getOwnPropSym(*Symbol) Value
156
157	setOwnStr(p unistring.String, v Value, throw bool) bool
158	setOwnIdx(p valueInt, v Value, throw bool) bool
159	setOwnSym(p *Symbol, v Value, throw bool) bool
160
161	setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool)
162	setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool)
163	setForeignSym(p *Symbol, v, receiver Value, throw bool) (res bool, handled bool)
164
165	hasPropertyStr(unistring.String) bool
166	hasPropertyIdx(idx valueInt) bool
167	hasPropertySym(s *Symbol) bool
168
169	hasOwnPropertyStr(unistring.String) bool
170	hasOwnPropertyIdx(valueInt) bool
171	hasOwnPropertySym(s *Symbol) bool
172
173	defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool
174	defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool
175	defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool
176
177	deleteStr(name unistring.String, throw bool) bool
178	deleteIdx(idx valueInt, throw bool) bool
179	deleteSym(s *Symbol, throw bool) bool
180
181	toPrimitiveNumber() Value
182	toPrimitiveString() Value
183	toPrimitive() Value
184	assertCallable() (call func(FunctionCall) Value, ok bool)
185	assertConstructor() func(args []Value, newTarget *Object) *Object
186	proto() *Object
187	setProto(proto *Object, throw bool) bool
188	hasInstance(v Value) bool
189	isExtensible() bool
190	preventExtensions(throw bool) bool
191	enumerateOwnKeys() iterNextFunc
192	export(ctx *objectExportCtx) interface{}
193	exportType() reflect.Type
194	equal(objectImpl) bool
195	ownKeys(all bool, accum []Value) []Value
196	ownSymbols(all bool, accum []Value) []Value
197	ownPropertyKeys(all bool, accum []Value) []Value
198
199	_putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value
200	_putSym(s *Symbol, prop Value)
201}
202
203type baseObject struct {
204	class      string
205	val        *Object
206	prototype  *Object
207	extensible bool
208
209	values    map[unistring.String]Value
210	propNames []unistring.String
211
212	lastSortedPropLen, idxPropCount int
213
214	symValues *orderedMap
215}
216
217type guardedObject struct {
218	baseObject
219	guardedProps map[unistring.String]struct{}
220}
221
222type primitiveValueObject struct {
223	baseObject
224	pValue Value
225}
226
227func (o *primitiveValueObject) export(*objectExportCtx) interface{} {
228	return o.pValue.Export()
229}
230
231func (o *primitiveValueObject) exportType() reflect.Type {
232	return o.pValue.ExportType()
233}
234
235type FunctionCall struct {
236	This      Value
237	Arguments []Value
238}
239
240type ConstructorCall struct {
241	This      *Object
242	Arguments []Value
243	NewTarget *Object
244}
245
246func (f FunctionCall) Argument(idx int) Value {
247	if idx < len(f.Arguments) {
248		return f.Arguments[idx]
249	}
250	return _undefined
251}
252
253func (f ConstructorCall) Argument(idx int) Value {
254	if idx < len(f.Arguments) {
255		return f.Arguments[idx]
256	}
257	return _undefined
258}
259
260func (o *baseObject) init() {
261	o.values = make(map[unistring.String]Value)
262}
263
264func (o *baseObject) className() string {
265	return o.class
266}
267
268func (o *baseObject) hasPropertyStr(name unistring.String) bool {
269	if o.val.self.hasOwnPropertyStr(name) {
270		return true
271	}
272	if o.prototype != nil {
273		return o.prototype.self.hasPropertyStr(name)
274	}
275	return false
276}
277
278func (o *baseObject) hasPropertyIdx(idx valueInt) bool {
279	return o.val.self.hasPropertyStr(idx.string())
280}
281
282func (o *baseObject) hasPropertySym(s *Symbol) bool {
283	if o.hasOwnPropertySym(s) {
284		return true
285	}
286	if o.prototype != nil {
287		return o.prototype.self.hasPropertySym(s)
288	}
289	return false
290}
291
292func (o *baseObject) getWithOwnProp(prop, p, receiver Value) Value {
293	if prop == nil && o.prototype != nil {
294		if receiver == nil {
295			return o.prototype.get(p, o.val)
296		}
297		return o.prototype.get(p, receiver)
298	}
299	if prop, ok := prop.(*valueProperty); ok {
300		if receiver == nil {
301			return prop.get(o.val)
302		}
303		return prop.get(receiver)
304	}
305	return prop
306}
307
308func (o *baseObject) getStrWithOwnProp(prop Value, name unistring.String, receiver Value) Value {
309	if prop == nil && o.prototype != nil {
310		if receiver == nil {
311			return o.prototype.self.getStr(name, o.val)
312		}
313		return o.prototype.self.getStr(name, receiver)
314	}
315	if prop, ok := prop.(*valueProperty); ok {
316		if receiver == nil {
317			return prop.get(o.val)
318		}
319		return prop.get(receiver)
320	}
321	return prop
322}
323
324func (o *baseObject) getIdx(idx valueInt, receiver Value) Value {
325	return o.val.self.getStr(idx.string(), receiver)
326}
327
328func (o *baseObject) getSym(s *Symbol, receiver Value) Value {
329	return o.getWithOwnProp(o.getOwnPropSym(s), s, receiver)
330}
331
332func (o *baseObject) getStr(name unistring.String, receiver Value) Value {
333	prop := o.values[name]
334	if prop == nil {
335		if o.prototype != nil {
336			if receiver == nil {
337				return o.prototype.self.getStr(name, o.val)
338			}
339			return o.prototype.self.getStr(name, receiver)
340		}
341	}
342	if prop, ok := prop.(*valueProperty); ok {
343		if receiver == nil {
344			return prop.get(o.val)
345		}
346		return prop.get(receiver)
347	}
348	return prop
349}
350
351func (o *baseObject) getOwnPropIdx(idx valueInt) Value {
352	return o.val.self.getOwnPropStr(idx.string())
353}
354
355func (o *baseObject) getOwnPropSym(s *Symbol) Value {
356	if o.symValues != nil {
357		return o.symValues.get(s)
358	}
359	return nil
360}
361
362func (o *baseObject) getOwnPropStr(name unistring.String) Value {
363	return o.values[name]
364}
365
366func (o *baseObject) checkDeleteProp(name unistring.String, prop *valueProperty, throw bool) bool {
367	if !prop.configurable {
368		o.val.runtime.typeErrorResult(throw, "Cannot delete property '%s' of %s", name, o.val.toString())
369		return false
370	}
371	return true
372}
373
374func (o *baseObject) checkDelete(name unistring.String, val Value, throw bool) bool {
375	if val, ok := val.(*valueProperty); ok {
376		return o.checkDeleteProp(name, val, throw)
377	}
378	return true
379}
380
381func (o *baseObject) _delete(name unistring.String) {
382	delete(o.values, name)
383	for i, n := range o.propNames {
384		if n == name {
385			names := o.propNames
386			if namesMarkedForCopy(names) {
387				newNames := make([]unistring.String, len(names)-1, shrinkCap(len(names), cap(names)))
388				copy(newNames, names[:i])
389				copy(newNames[i:], names[i+1:])
390				o.propNames = newNames
391			} else {
392				copy(names[i:], names[i+1:])
393				names[len(names)-1] = ""
394				o.propNames = names[:len(names)-1]
395			}
396			if i < o.lastSortedPropLen {
397				o.lastSortedPropLen--
398				if i < o.idxPropCount {
399					o.idxPropCount--
400				}
401			}
402			break
403		}
404	}
405}
406
407func (o *baseObject) deleteIdx(idx valueInt, throw bool) bool {
408	return o.val.self.deleteStr(idx.string(), throw)
409}
410
411func (o *baseObject) deleteSym(s *Symbol, throw bool) bool {
412	if o.symValues != nil {
413		if val := o.symValues.get(s); val != nil {
414			if !o.checkDelete(s.descriptiveString().string(), val, throw) {
415				return false
416			}
417			o.symValues.remove(s)
418		}
419	}
420	return true
421}
422
423func (o *baseObject) deleteStr(name unistring.String, throw bool) bool {
424	if val, exists := o.values[name]; exists {
425		if !o.checkDelete(name, val, throw) {
426			return false
427		}
428		o._delete(name)
429	}
430	return true
431}
432
433func (o *baseObject) setProto(proto *Object, throw bool) bool {
434	current := o.prototype
435	if current.SameAs(proto) {
436		return true
437	}
438	if !o.extensible {
439		o.val.runtime.typeErrorResult(throw, "%s is not extensible", o.val)
440		return false
441	}
442	for p := proto; p != nil; p = p.self.proto() {
443		if p.SameAs(o.val) {
444			o.val.runtime.typeErrorResult(throw, "Cyclic __proto__ value")
445			return false
446		}
447		if _, ok := p.self.(*proxyObject); ok {
448			break
449		}
450	}
451	o.prototype = proto
452	return true
453}
454
455func (o *baseObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
456	ownDesc := o.values[name]
457	if ownDesc == nil {
458		if proto := o.prototype; proto != nil {
459			// we know it's foreign because prototype loops are not allowed
460			if res, handled := proto.self.setForeignStr(name, val, o.val, throw); handled {
461				return res
462			}
463		}
464		// new property
465		if !o.extensible {
466			o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", name)
467			return false
468		} else {
469			o.values[name] = val
470			names := copyNamesIfNeeded(o.propNames, 1)
471			o.propNames = append(names, name)
472		}
473		return true
474	}
475	if prop, ok := ownDesc.(*valueProperty); ok {
476		if !prop.isWritable() {
477			o.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%s'", name)
478			return false
479		} else {
480			prop.set(o.val, val)
481		}
482	} else {
483		o.values[name] = val
484	}
485	return true
486}
487
488func (o *baseObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
489	return o.val.self.setOwnStr(idx.string(), val, throw)
490}
491
492func (o *baseObject) setOwnSym(name *Symbol, val Value, throw bool) bool {
493	var ownDesc Value
494	if o.symValues != nil {
495		ownDesc = o.symValues.get(name)
496	}
497	if ownDesc == nil {
498		if proto := o.prototype; proto != nil {
499			// we know it's foreign because prototype loops are not allowed
500			if res, handled := proto.self.setForeignSym(name, val, o.val, throw); handled {
501				return res
502			}
503		}
504		// new property
505		if !o.extensible {
506			o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", name)
507			return false
508		} else {
509			if o.symValues == nil {
510				o.symValues = newOrderedMap(nil)
511			}
512			o.symValues.set(name, val)
513		}
514		return true
515	}
516	if prop, ok := ownDesc.(*valueProperty); ok {
517		if !prop.isWritable() {
518			o.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%s'", name)
519			return false
520		} else {
521			prop.set(o.val, val)
522		}
523	} else {
524		o.symValues.set(name, val)
525	}
526	return true
527}
528
529func (o *baseObject) _setForeignStr(name unistring.String, prop, val, receiver Value, throw bool) (bool, bool) {
530	if prop != nil {
531		if prop, ok := prop.(*valueProperty); ok {
532			if !prop.isWritable() {
533				o.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%s'", name)
534				return false, true
535			}
536			if prop.setterFunc != nil {
537				prop.set(receiver, val)
538				return true, true
539			}
540		}
541	} else {
542		if proto := o.prototype; proto != nil {
543			if receiver != proto {
544				return proto.self.setForeignStr(name, val, receiver, throw)
545			}
546			return proto.self.setOwnStr(name, val, throw), true
547		}
548	}
549	return false, false
550}
551
552func (o *baseObject) _setForeignIdx(idx valueInt, prop, val, receiver Value, throw bool) (bool, bool) {
553	if prop != nil {
554		if prop, ok := prop.(*valueProperty); ok {
555			if !prop.isWritable() {
556				o.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d'", idx)
557				return false, true
558			}
559			if prop.setterFunc != nil {
560				prop.set(receiver, val)
561				return true, true
562			}
563		}
564	} else {
565		if proto := o.prototype; proto != nil {
566			if receiver != proto {
567				return proto.self.setForeignIdx(idx, val, receiver, throw)
568			}
569			return proto.self.setOwnIdx(idx, val, throw), true
570		}
571	}
572	return false, false
573}
574
575func (o *baseObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
576	return o._setForeignStr(name, o.values[name], val, receiver, throw)
577}
578
579func (o *baseObject) setForeignIdx(name valueInt, val, receiver Value, throw bool) (bool, bool) {
580	if idx := toIdx(name); idx != math.MaxUint32 {
581		if o.lastSortedPropLen != len(o.propNames) {
582			o.fixPropOrder()
583		}
584		if o.idxPropCount == 0 {
585			return o._setForeignIdx(name, name, nil, receiver, throw)
586		}
587	}
588	return o.setForeignStr(name.string(), val, receiver, throw)
589}
590
591func (o *baseObject) setForeignSym(name *Symbol, val, receiver Value, throw bool) (bool, bool) {
592	var prop Value
593	if o.symValues != nil {
594		prop = o.symValues.get(name)
595	}
596	if prop != nil {
597		if prop, ok := prop.(*valueProperty); ok {
598			if !prop.isWritable() {
599				o.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%s'", name)
600				return false, true
601			}
602			if prop.setterFunc != nil {
603				prop.set(receiver, val)
604				return true, true
605			}
606		}
607	} else {
608		if proto := o.prototype; proto != nil {
609			if receiver != o.val {
610				return proto.self.setForeignSym(name, val, receiver, throw)
611			}
612			return proto.self.setOwnSym(name, val, throw), true
613		}
614	}
615	return false, false
616}
617
618func (o *baseObject) hasOwnPropertySym(s *Symbol) bool {
619	if o.symValues != nil {
620		return o.symValues.has(s)
621	}
622	return false
623}
624
625func (o *baseObject) hasOwnPropertyStr(name unistring.String) bool {
626	_, exists := o.values[name]
627	return exists
628}
629
630func (o *baseObject) hasOwnPropertyIdx(idx valueInt) bool {
631	return o.val.self.hasOwnPropertyStr(idx.string())
632}
633
634func (o *baseObject) _defineOwnProperty(name unistring.String, existingValue Value, descr PropertyDescriptor, throw bool) (val Value, ok bool) {
635
636	getterObj, _ := descr.Getter.(*Object)
637	setterObj, _ := descr.Setter.(*Object)
638
639	var existing *valueProperty
640
641	if existingValue == nil {
642		if !o.extensible {
643			o.val.runtime.typeErrorResult(throw, "Cannot define property %s, object is not extensible", name)
644			return nil, false
645		}
646		existing = &valueProperty{}
647	} else {
648		if existing, ok = existingValue.(*valueProperty); !ok {
649			existing = &valueProperty{
650				writable:     true,
651				enumerable:   true,
652				configurable: true,
653				value:        existingValue,
654			}
655		}
656
657		if !existing.configurable {
658			if descr.Configurable == FLAG_TRUE {
659				goto Reject
660			}
661			if descr.Enumerable != FLAG_NOT_SET && descr.Enumerable.Bool() != existing.enumerable {
662				goto Reject
663			}
664		}
665		if existing.accessor && descr.Value != nil || !existing.accessor && (getterObj != nil || setterObj != nil) {
666			if !existing.configurable {
667				goto Reject
668			}
669		} else if !existing.accessor {
670			if !existing.configurable {
671				if !existing.writable {
672					if descr.Writable == FLAG_TRUE {
673						goto Reject
674					}
675					if descr.Value != nil && !descr.Value.SameAs(existing.value) {
676						goto Reject
677					}
678				}
679			}
680		} else {
681			if !existing.configurable {
682				if descr.Getter != nil && existing.getterFunc != getterObj || descr.Setter != nil && existing.setterFunc != setterObj {
683					goto Reject
684				}
685			}
686		}
687	}
688
689	if descr.Writable == FLAG_TRUE && descr.Enumerable == FLAG_TRUE && descr.Configurable == FLAG_TRUE && descr.Value != nil {
690		return descr.Value, true
691	}
692
693	if descr.Writable != FLAG_NOT_SET {
694		existing.writable = descr.Writable.Bool()
695	}
696	if descr.Enumerable != FLAG_NOT_SET {
697		existing.enumerable = descr.Enumerable.Bool()
698	}
699	if descr.Configurable != FLAG_NOT_SET {
700		existing.configurable = descr.Configurable.Bool()
701	}
702
703	if descr.Value != nil {
704		existing.value = descr.Value
705		existing.getterFunc = nil
706		existing.setterFunc = nil
707	}
708
709	if descr.Value != nil || descr.Writable != FLAG_NOT_SET {
710		existing.accessor = false
711	}
712
713	if descr.Getter != nil {
714		existing.getterFunc = propGetter(o.val, descr.Getter, o.val.runtime)
715		existing.value = nil
716		existing.accessor = true
717	}
718
719	if descr.Setter != nil {
720		existing.setterFunc = propSetter(o.val, descr.Setter, o.val.runtime)
721		existing.value = nil
722		existing.accessor = true
723	}
724
725	if !existing.accessor && existing.value == nil {
726		existing.value = _undefined
727	}
728
729	return existing, true
730
731Reject:
732	o.val.runtime.typeErrorResult(throw, "Cannot redefine property: %s", name)
733	return nil, false
734
735}
736
737func (o *baseObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
738	existingVal := o.values[name]
739	if v, ok := o._defineOwnProperty(name, existingVal, descr, throw); ok {
740		o.values[name] = v
741		if existingVal == nil {
742			names := copyNamesIfNeeded(o.propNames, 1)
743			o.propNames = append(names, name)
744		}
745		return true
746	}
747	return false
748}
749
750func (o *baseObject) defineOwnPropertyIdx(idx valueInt, desc PropertyDescriptor, throw bool) bool {
751	return o.val.self.defineOwnPropertyStr(idx.string(), desc, throw)
752}
753
754func (o *baseObject) defineOwnPropertySym(s *Symbol, descr PropertyDescriptor, throw bool) bool {
755	var existingVal Value
756	if o.symValues != nil {
757		existingVal = o.symValues.get(s)
758	}
759	if v, ok := o._defineOwnProperty(s.descriptiveString().string(), existingVal, descr, throw); ok {
760		if o.symValues == nil {
761			o.symValues = newOrderedMap(nil)
762		}
763		o.symValues.set(s, v)
764		return true
765	}
766	return false
767}
768
769func (o *baseObject) _put(name unistring.String, v Value) {
770	if _, exists := o.values[name]; !exists {
771		names := copyNamesIfNeeded(o.propNames, 1)
772		o.propNames = append(names, name)
773	}
774
775	o.values[name] = v
776}
777
778func valueProp(value Value, writable, enumerable, configurable bool) Value {
779	if writable && enumerable && configurable {
780		return value
781	}
782	return &valueProperty{
783		value:        value,
784		writable:     writable,
785		enumerable:   enumerable,
786		configurable: configurable,
787	}
788}
789
790func (o *baseObject) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
791	prop := valueProp(value, writable, enumerable, configurable)
792	o._put(name, prop)
793	return prop
794}
795
796func (o *baseObject) _putSym(s *Symbol, prop Value) {
797	if o.symValues == nil {
798		o.symValues = newOrderedMap(nil)
799	}
800	o.symValues.set(s, prop)
801}
802
803func (o *Object) tryPrimitive(methodName unistring.String) Value {
804	if method, ok := o.self.getStr(methodName, nil).(*Object); ok {
805		if call, ok := method.self.assertCallable(); ok {
806			v := call(FunctionCall{
807				This: o,
808			})
809			if _, fail := v.(*Object); !fail {
810				return v
811			}
812		}
813	}
814	return nil
815}
816
817func (o *Object) genericToPrimitiveNumber() Value {
818	if v := o.tryPrimitive("valueOf"); v != nil {
819		return v
820	}
821
822	if v := o.tryPrimitive("toString"); v != nil {
823		return v
824	}
825
826	panic(o.runtime.NewTypeError("Could not convert %v to primitive", o.self))
827}
828
829func (o *baseObject) toPrimitiveNumber() Value {
830	return o.val.genericToPrimitiveNumber()
831}
832
833func (o *Object) genericToPrimitiveString() Value {
834	if v := o.tryPrimitive("toString"); v != nil {
835		return v
836	}
837
838	if v := o.tryPrimitive("valueOf"); v != nil {
839		return v
840	}
841
842	panic(o.runtime.NewTypeError("Could not convert %v to primitive", o.self))
843}
844
845func (o *Object) genericToPrimitive() Value {
846	return o.genericToPrimitiveNumber()
847}
848
849func (o *baseObject) toPrimitiveString() Value {
850	return o.val.genericToPrimitiveString()
851}
852
853func (o *baseObject) toPrimitive() Value {
854	return o.val.genericToPrimitiveNumber()
855}
856
857func (o *Object) tryExoticToPrimitive(hint Value) Value {
858	exoticToPrimitive := toMethod(o.self.getSym(SymToPrimitive, nil))
859	if exoticToPrimitive != nil {
860		ret := exoticToPrimitive(FunctionCall{
861			This:      o,
862			Arguments: []Value{hint},
863		})
864		if _, fail := ret.(*Object); !fail {
865			return ret
866		}
867		panic(o.runtime.NewTypeError("Cannot convert object to primitive value"))
868	}
869	return nil
870}
871
872func (o *Object) toPrimitiveNumber() Value {
873	if v := o.tryExoticToPrimitive(hintNumber); v != nil {
874		return v
875	}
876
877	return o.self.toPrimitiveNumber()
878}
879
880func (o *Object) toPrimitiveString() Value {
881	if v := o.tryExoticToPrimitive(hintString); v != nil {
882		return v
883	}
884
885	return o.self.toPrimitiveString()
886}
887
888func (o *Object) toPrimitive() Value {
889	if v := o.tryExoticToPrimitive(hintDefault); v != nil {
890		return v
891	}
892	return o.self.toPrimitive()
893}
894
895func (o *baseObject) assertCallable() (func(FunctionCall) Value, bool) {
896	return nil, false
897}
898
899func (o *baseObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
900	return nil
901}
902
903func (o *baseObject) proto() *Object {
904	return o.prototype
905}
906
907func (o *baseObject) isExtensible() bool {
908	return o.extensible
909}
910
911func (o *baseObject) preventExtensions(bool) bool {
912	o.extensible = false
913	return true
914}
915
916func (o *baseObject) sortLen() int64 {
917	return toLength(o.val.self.getStr("length", nil))
918}
919
920func (o *baseObject) sortGet(i int64) Value {
921	return o.val.self.getIdx(valueInt(i), nil)
922}
923
924func (o *baseObject) swap(i, j int64) {
925	ii := valueInt(i)
926	jj := valueInt(j)
927
928	x := o.val.self.getIdx(ii, nil)
929	y := o.val.self.getIdx(jj, nil)
930
931	o.val.self.setOwnIdx(ii, y, false)
932	o.val.self.setOwnIdx(jj, x, false)
933}
934
935func (o *baseObject) export(ctx *objectExportCtx) interface{} {
936	if v, exists := ctx.get(o); exists {
937		return v
938	}
939	keys := o.ownKeys(false, nil)
940	m := make(map[string]interface{}, len(keys))
941	ctx.put(o, m)
942	for _, itemName := range keys {
943		itemNameStr := itemName.String()
944		v := o.val.self.getStr(itemName.string(), nil)
945		if v != nil {
946			m[itemNameStr] = exportValue(v, ctx)
947		} else {
948			m[itemNameStr] = nil
949		}
950	}
951
952	return m
953}
954
955func (o *baseObject) exportType() reflect.Type {
956	return reflectTypeMap
957}
958
959type enumerableFlag int
960
961const (
962	_ENUM_UNKNOWN enumerableFlag = iota
963	_ENUM_FALSE
964	_ENUM_TRUE
965)
966
967type propIterItem struct {
968	name       unistring.String
969	value      Value // set only when enumerable == _ENUM_UNKNOWN
970	enumerable enumerableFlag
971}
972
973type objectPropIter struct {
974	o         *baseObject
975	propNames []unistring.String
976	idx       int
977}
978
979type recursivePropIter struct {
980	o    objectImpl
981	cur  iterNextFunc
982	seen map[unistring.String]struct{}
983}
984
985type enumerableIter struct {
986	wrapped iterNextFunc
987}
988
989func (i *enumerableIter) next() (propIterItem, iterNextFunc) {
990	for {
991		var item propIterItem
992		item, i.wrapped = i.wrapped()
993		if i.wrapped == nil {
994			return item, nil
995		}
996		if item.enumerable == _ENUM_FALSE {
997			continue
998		}
999		if item.enumerable == _ENUM_UNKNOWN {
1000			if prop, ok := item.value.(*valueProperty); ok {
1001				if !prop.enumerable {
1002					continue
1003				}
1004			}
1005		}
1006		return item, i.next
1007	}
1008}
1009
1010func (i *recursivePropIter) next() (propIterItem, iterNextFunc) {
1011	for {
1012		var item propIterItem
1013		item, i.cur = i.cur()
1014		if i.cur == nil {
1015			if proto := i.o.proto(); proto != nil {
1016				i.cur = proto.self.enumerateOwnKeys()
1017				i.o = proto.self
1018				continue
1019			}
1020			return propIterItem{}, nil
1021		}
1022		if _, exists := i.seen[item.name]; !exists {
1023			i.seen[item.name] = struct{}{}
1024			return item, i.next
1025		}
1026	}
1027}
1028
1029func enumerateRecursive(o *Object) iterNextFunc {
1030	return (&enumerableIter{
1031		wrapped: (&recursivePropIter{
1032			o:    o.self,
1033			cur:  o.self.enumerateOwnKeys(),
1034			seen: make(map[unistring.String]struct{}),
1035		}).next,
1036	}).next
1037}
1038
1039func (i *objectPropIter) next() (propIterItem, iterNextFunc) {
1040	for i.idx < len(i.propNames) {
1041		name := i.propNames[i.idx]
1042		i.idx++
1043		prop := i.o.values[name]
1044		if prop != nil {
1045			return propIterItem{name: name, value: prop}, i.next
1046		}
1047	}
1048	clearNamesCopyMarker(i.propNames)
1049	return propIterItem{}, nil
1050}
1051
1052var copyMarker = unistring.String(" ")
1053
1054// Set a copy-on-write flag so that any subsequent modifications of anything below the current length
1055// trigger a copy.
1056// The marker is a special value put at the index position of cap-1. Capacity is set so that the marker is
1057// beyond the current length (therefore invisible to normal slice operations).
1058// This function is called before an iteration begins to avoid copying of the names array if
1059// there are no modifications within the iteration.
1060// Note that the copying also occurs in two cases: nested iterations (on the same object) and
1061// iterations after a previously abandoned iteration (because there is currently no mechanism to close an
1062// iterator). It is still better than copying every time.
1063func prepareNamesForCopy(names []unistring.String) []unistring.String {
1064	if len(names) == 0 {
1065		return names
1066	}
1067	if namesMarkedForCopy(names) || cap(names) == len(names) {
1068		var newcap int
1069		if cap(names) == len(names) {
1070			newcap = growCap(len(names)+1, len(names), cap(names))
1071		} else {
1072			newcap = cap(names)
1073		}
1074		newNames := make([]unistring.String, len(names), newcap)
1075		copy(newNames, names)
1076		names = newNames
1077	}
1078	names[cap(names)-1 : cap(names)][0] = copyMarker
1079	return names
1080}
1081
1082func namesMarkedForCopy(names []unistring.String) bool {
1083	return cap(names) > len(names) && names[cap(names)-1 : cap(names)][0] == copyMarker
1084}
1085
1086func clearNamesCopyMarker(names []unistring.String) {
1087	if cap(names) > len(names) {
1088		names[cap(names)-1 : cap(names)][0] = ""
1089	}
1090}
1091
1092func copyNamesIfNeeded(names []unistring.String, extraCap int) []unistring.String {
1093	if namesMarkedForCopy(names) && len(names)+extraCap >= cap(names) {
1094		var newcap int
1095		newsize := len(names) + extraCap + 1
1096		if newsize > cap(names) {
1097			newcap = growCap(newsize, len(names), cap(names))
1098		} else {
1099			newcap = cap(names)
1100		}
1101		newNames := make([]unistring.String, len(names), newcap)
1102		copy(newNames, names)
1103		return newNames
1104	}
1105	return names
1106}
1107
1108func (o *baseObject) enumerateOwnKeys() iterNextFunc {
1109	if len(o.propNames) > o.lastSortedPropLen {
1110		o.fixPropOrder()
1111	}
1112	propNames := prepareNamesForCopy(o.propNames)
1113	o.propNames = propNames
1114	return (&objectPropIter{
1115		o:         o,
1116		propNames: propNames,
1117	}).next
1118}
1119
1120func (o *baseObject) equal(objectImpl) bool {
1121	// Rely on parent reference comparison
1122	return false
1123}
1124
1125// Reorder property names so that any integer properties are shifted to the beginning of the list
1126// in ascending order. This is to conform to https://262.ecma-international.org/#sec-ordinaryownpropertykeys.
1127// Personally I think this requirement is strange. I can sort of understand where they are coming from,
1128// this way arrays can be specified just as objects with a 'magic' length property. However, I think
1129// it's safe to assume most devs don't use Objects to store integer properties. Therefore, performing
1130// property type checks when adding (and potentially looking up) properties would be unreasonable.
1131// Instead, we keep insertion order and only change it when (if) the properties get enumerated.
1132func (o *baseObject) fixPropOrder() {
1133	names := o.propNames
1134	for i := o.lastSortedPropLen; i < len(names); i++ {
1135		name := names[i]
1136		if idx := strToArrayIdx(name); idx != math.MaxUint32 {
1137			k := sort.Search(o.idxPropCount, func(j int) bool {
1138				return strToArrayIdx(names[j]) >= idx
1139			})
1140			if k < i {
1141				if namesMarkedForCopy(names) {
1142					newNames := make([]unistring.String, len(names), cap(names))
1143					copy(newNames[:k], names)
1144					copy(newNames[k+1:i+1], names[k:i])
1145					copy(newNames[i+1:], names[i+1:])
1146					names = newNames
1147					o.propNames = names
1148				} else {
1149					copy(names[k+1:i+1], names[k:i])
1150				}
1151				names[k] = name
1152			}
1153			o.idxPropCount++
1154		}
1155	}
1156	o.lastSortedPropLen = len(names)
1157}
1158
1159func (o *baseObject) ownKeys(all bool, keys []Value) []Value {
1160	if len(o.propNames) > o.lastSortedPropLen {
1161		o.fixPropOrder()
1162	}
1163	if all {
1164		for _, k := range o.propNames {
1165			keys = append(keys, stringValueFromRaw(k))
1166		}
1167	} else {
1168		for _, k := range o.propNames {
1169			prop := o.values[k]
1170			if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
1171				continue
1172			}
1173			keys = append(keys, stringValueFromRaw(k))
1174		}
1175	}
1176	return keys
1177}
1178
1179func (o *baseObject) ownSymbols(all bool, accum []Value) []Value {
1180	if o.symValues != nil {
1181		iter := o.symValues.newIter()
1182		if all {
1183			for {
1184				entry := iter.next()
1185				if entry == nil {
1186					break
1187				}
1188				accum = append(accum, entry.key)
1189			}
1190		} else {
1191			for {
1192				entry := iter.next()
1193				if entry == nil {
1194					break
1195				}
1196				if prop, ok := entry.value.(*valueProperty); ok {
1197					if !prop.enumerable {
1198						continue
1199					}
1200				}
1201				accum = append(accum, entry.key)
1202			}
1203		}
1204	}
1205
1206	return accum
1207}
1208
1209func (o *baseObject) ownPropertyKeys(all bool, accum []Value) []Value {
1210	return o.ownSymbols(all, o.val.self.ownKeys(all, accum))
1211}
1212
1213func (o *baseObject) hasInstance(Value) bool {
1214	panic(o.val.runtime.NewTypeError("Expecting a function in instanceof check, but got %s", o.val.toString()))
1215}
1216
1217func toMethod(v Value) func(FunctionCall) Value {
1218	if v == nil || IsUndefined(v) || IsNull(v) {
1219		return nil
1220	}
1221	if obj, ok := v.(*Object); ok {
1222		if call, ok := obj.self.assertCallable(); ok {
1223			return call
1224		}
1225	}
1226	panic(typeError(fmt.Sprintf("%s is not a method", v.String())))
1227}
1228
1229func instanceOfOperator(o Value, c *Object) bool {
1230	if instOfHandler := toMethod(c.self.getSym(SymHasInstance, c)); instOfHandler != nil {
1231		return instOfHandler(FunctionCall{
1232			This:      c,
1233			Arguments: []Value{o},
1234		}).ToBoolean()
1235	}
1236
1237	return c.self.hasInstance(o)
1238}
1239
1240func (o *Object) get(p Value, receiver Value) Value {
1241	switch p := p.(type) {
1242	case valueInt:
1243		return o.self.getIdx(p, receiver)
1244	case *Symbol:
1245		return o.self.getSym(p, receiver)
1246	default:
1247		return o.self.getStr(p.string(), receiver)
1248	}
1249}
1250
1251func (o *Object) getOwnProp(p Value) Value {
1252	switch p := p.(type) {
1253	case valueInt:
1254		return o.self.getOwnPropIdx(p)
1255	case *Symbol:
1256		return o.self.getOwnPropSym(p)
1257	default:
1258		return o.self.getOwnPropStr(p.string())
1259	}
1260}
1261
1262func (o *Object) hasOwnProperty(p Value) bool {
1263	switch p := p.(type) {
1264	case valueInt:
1265		return o.self.hasOwnPropertyIdx(p)
1266	case *Symbol:
1267		return o.self.hasOwnPropertySym(p)
1268	default:
1269		return o.self.hasOwnPropertyStr(p.string())
1270	}
1271}
1272
1273func (o *Object) hasProperty(p Value) bool {
1274	switch p := p.(type) {
1275	case valueInt:
1276		return o.self.hasPropertyIdx(p)
1277	case *Symbol:
1278		return o.self.hasPropertySym(p)
1279	default:
1280		return o.self.hasPropertyStr(p.string())
1281	}
1282}
1283
1284func (o *Object) setStr(name unistring.String, val, receiver Value, throw bool) bool {
1285	if receiver == o {
1286		return o.self.setOwnStr(name, val, throw)
1287	} else {
1288		if res, ok := o.self.setForeignStr(name, val, receiver, throw); !ok {
1289			if robj, ok := receiver.(*Object); ok {
1290				if prop := robj.self.getOwnPropStr(name); prop != nil {
1291					if desc, ok := prop.(*valueProperty); ok {
1292						if desc.accessor {
1293							o.runtime.typeErrorResult(throw, "Receiver property %s is an accessor", name)
1294							return false
1295						}
1296						if !desc.writable {
1297							o.runtime.typeErrorResult(throw, "Cannot assign to read only property '%s'", name)
1298							return false
1299						}
1300					}
1301					robj.self.defineOwnPropertyStr(name, PropertyDescriptor{Value: val}, throw)
1302				} else {
1303					robj.self.defineOwnPropertyStr(name, PropertyDescriptor{
1304						Value:        val,
1305						Writable:     FLAG_TRUE,
1306						Configurable: FLAG_TRUE,
1307						Enumerable:   FLAG_TRUE,
1308					}, throw)
1309				}
1310			} else {
1311				o.runtime.typeErrorResult(throw, "Receiver is not an object: %v", receiver)
1312				return false
1313			}
1314		} else {
1315			return res
1316		}
1317	}
1318	return true
1319}
1320
1321func (o *Object) set(name Value, val, receiver Value, throw bool) bool {
1322	switch name := name.(type) {
1323	case valueInt:
1324		return o.setIdx(name, val, receiver, throw)
1325	case *Symbol:
1326		return o.setSym(name, val, receiver, throw)
1327	default:
1328		return o.setStr(name.string(), val, receiver, throw)
1329	}
1330}
1331
1332func (o *Object) setOwn(name Value, val Value, throw bool) bool {
1333	switch name := name.(type) {
1334	case valueInt:
1335		return o.self.setOwnIdx(name, val, throw)
1336	case *Symbol:
1337		return o.self.setOwnSym(name, val, throw)
1338	default:
1339		return o.self.setOwnStr(name.string(), val, throw)
1340	}
1341}
1342
1343func (o *Object) setIdx(name valueInt, val, receiver Value, throw bool) bool {
1344	if receiver == o {
1345		return o.self.setOwnIdx(name, val, throw)
1346	} else {
1347		if res, ok := o.self.setForeignIdx(name, val, receiver, throw); !ok {
1348			if robj, ok := receiver.(*Object); ok {
1349				if prop := robj.self.getOwnPropIdx(name); prop != nil {
1350					if desc, ok := prop.(*valueProperty); ok {
1351						if desc.accessor {
1352							o.runtime.typeErrorResult(throw, "Receiver property %s is an accessor", name)
1353							return false
1354						}
1355						if !desc.writable {
1356							o.runtime.typeErrorResult(throw, "Cannot assign to read only property '%s'", name)
1357							return false
1358						}
1359					}
1360					robj.self.defineOwnPropertyIdx(name, PropertyDescriptor{Value: val}, throw)
1361				} else {
1362					robj.self.defineOwnPropertyIdx(name, PropertyDescriptor{
1363						Value:        val,
1364						Writable:     FLAG_TRUE,
1365						Configurable: FLAG_TRUE,
1366						Enumerable:   FLAG_TRUE,
1367					}, throw)
1368				}
1369			} else {
1370				o.runtime.typeErrorResult(throw, "Receiver is not an object: %v", receiver)
1371				return false
1372			}
1373		} else {
1374			return res
1375		}
1376	}
1377	return true
1378}
1379
1380func (o *Object) setSym(name *Symbol, val, receiver Value, throw bool) bool {
1381	if receiver == o {
1382		return o.self.setOwnSym(name, val, throw)
1383	} else {
1384		if res, ok := o.self.setForeignSym(name, val, receiver, throw); !ok {
1385			if robj, ok := receiver.(*Object); ok {
1386				if prop := robj.self.getOwnPropSym(name); prop != nil {
1387					if desc, ok := prop.(*valueProperty); ok {
1388						if desc.accessor {
1389							o.runtime.typeErrorResult(throw, "Receiver property %s is an accessor", name)
1390							return false
1391						}
1392						if !desc.writable {
1393							o.runtime.typeErrorResult(throw, "Cannot assign to read only property '%s'", name)
1394							return false
1395						}
1396					}
1397					robj.self.defineOwnPropertySym(name, PropertyDescriptor{Value: val}, throw)
1398				} else {
1399					robj.self.defineOwnPropertySym(name, PropertyDescriptor{
1400						Value:        val,
1401						Writable:     FLAG_TRUE,
1402						Configurable: FLAG_TRUE,
1403						Enumerable:   FLAG_TRUE,
1404					}, throw)
1405				}
1406			} else {
1407				o.runtime.typeErrorResult(throw, "Receiver is not an object: %v", receiver)
1408				return false
1409			}
1410		} else {
1411			return res
1412		}
1413	}
1414	return true
1415}
1416
1417func (o *Object) delete(n Value, throw bool) bool {
1418	switch n := n.(type) {
1419	case valueInt:
1420		return o.self.deleteIdx(n, throw)
1421	case *Symbol:
1422		return o.self.deleteSym(n, throw)
1423	default:
1424		return o.self.deleteStr(n.string(), throw)
1425	}
1426}
1427
1428func (o *Object) defineOwnProperty(n Value, desc PropertyDescriptor, throw bool) bool {
1429	switch n := n.(type) {
1430	case valueInt:
1431		return o.self.defineOwnPropertyIdx(n, desc, throw)
1432	case *Symbol:
1433		return o.self.defineOwnPropertySym(n, desc, throw)
1434	default:
1435		return o.self.defineOwnPropertyStr(n.string(), desc, throw)
1436	}
1437}
1438
1439func (o *Object) getWeakRefs() map[weakMap]Value {
1440	refs := o.weakRefs
1441	if refs == nil {
1442		refs = make(map[weakMap]Value)
1443		o.weakRefs = refs
1444	}
1445	return refs
1446}
1447
1448func (o *Object) getId() uint64 {
1449	id := o.id
1450	if id == 0 {
1451		id = o.runtime.genId()
1452		o.id = id
1453	}
1454	return id
1455}
1456
1457func (o *guardedObject) guard(props ...unistring.String) {
1458	if o.guardedProps == nil {
1459		o.guardedProps = make(map[unistring.String]struct{})
1460	}
1461	for _, p := range props {
1462		o.guardedProps[p] = struct{}{}
1463	}
1464}
1465
1466func (o *guardedObject) check(p unistring.String) {
1467	if _, exists := o.guardedProps[p]; exists {
1468		o.val.self = &o.baseObject
1469	}
1470}
1471
1472func (o *guardedObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
1473	res := o.baseObject.setOwnStr(p, v, throw)
1474	if res {
1475		o.check(p)
1476	}
1477	return res
1478}
1479
1480func (o *guardedObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
1481	res := o.baseObject.defineOwnPropertyStr(name, desc, throw)
1482	if res {
1483		o.check(name)
1484	}
1485	return res
1486}
1487
1488func (o *guardedObject) deleteStr(name unistring.String, throw bool) bool {
1489	res := o.baseObject.deleteStr(name, throw)
1490	if res {
1491		o.check(name)
1492	}
1493	return res
1494}
1495
1496func (ctx *objectExportCtx) get(key objectImpl) (interface{}, bool) {
1497	if v, exists := ctx.cache[key]; exists {
1498		if item, ok := v.(objectExportCacheItem); ok {
1499			r, exists := item[key.exportType()]
1500			return r, exists
1501		} else {
1502			return v, true
1503		}
1504	}
1505	return nil, false
1506}
1507
1508func (ctx *objectExportCtx) getTyped(key objectImpl, typ reflect.Type) (interface{}, bool) {
1509	if v, exists := ctx.cache[key]; exists {
1510		if item, ok := v.(objectExportCacheItem); ok {
1511			r, exists := item[typ]
1512			return r, exists
1513		} else {
1514			if reflect.TypeOf(v) == typ {
1515				return v, true
1516			}
1517		}
1518	}
1519	return nil, false
1520}
1521
1522func (ctx *objectExportCtx) put(key objectImpl, value interface{}) {
1523	if ctx.cache == nil {
1524		ctx.cache = make(map[objectImpl]interface{})
1525	}
1526	if item, ok := ctx.cache[key].(objectExportCacheItem); ok {
1527		item[key.exportType()] = value
1528	} else {
1529		ctx.cache[key] = value
1530	}
1531}
1532
1533func (ctx *objectExportCtx) putTyped(key objectImpl, typ reflect.Type, value interface{}) {
1534	if ctx.cache == nil {
1535		ctx.cache = make(map[objectImpl]interface{})
1536	}
1537	v, exists := ctx.cache[key]
1538	if exists {
1539		if item, ok := ctx.cache[key].(objectExportCacheItem); ok {
1540			item[typ] = value
1541		} else {
1542			m := make(objectExportCacheItem, 2)
1543			m[key.exportType()] = v
1544			m[typ] = value
1545			ctx.cache[key] = m
1546		}
1547	} else {
1548		m := make(objectExportCacheItem)
1549		m[typ] = value
1550		ctx.cache[key] = m
1551	}
1552}
1553