github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/proxy.go (about)

     1  package goja
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/nuvolaris/goja/unistring"
     8  )
     9  
    10  // Proxy is a Go wrapper around ECMAScript Proxy. Calling Runtime.ToValue() on it
    11  // returns the underlying Proxy. Calling Export() on an ECMAScript Proxy returns a wrapper.
    12  // Use Runtime.NewProxy() to create one.
    13  type Proxy struct {
    14  	proxy *proxyObject
    15  }
    16  
    17  var (
    18  	proxyType = reflect.TypeOf(Proxy{})
    19  )
    20  
    21  type proxyPropIter struct {
    22  	p     *proxyObject
    23  	names []Value
    24  	idx   int
    25  }
    26  
    27  func (i *proxyPropIter) next() (propIterItem, iterNextFunc) {
    28  	for i.idx < len(i.names) {
    29  		name := i.names[i.idx]
    30  		i.idx++
    31  		return propIterItem{name: name}, i.next
    32  	}
    33  	return propIterItem{}, nil
    34  }
    35  
    36  func (r *Runtime) newProxyObject(target, handler, proto *Object) *proxyObject {
    37  	return r._newProxyObject(target, &jsProxyHandler{handler: handler}, proto)
    38  }
    39  
    40  func (r *Runtime) _newProxyObject(target *Object, handler proxyHandler, proto *Object) *proxyObject {
    41  	v := &Object{runtime: r}
    42  	p := &proxyObject{}
    43  	v.self = p
    44  	p.val = v
    45  	p.class = classObject
    46  	if proto == nil {
    47  		p.prototype = r.global.ObjectPrototype
    48  	} else {
    49  		p.prototype = proto
    50  	}
    51  	p.extensible = false
    52  	p.init()
    53  	p.target = target
    54  	p.handler = handler
    55  	if call, ok := target.self.assertCallable(); ok {
    56  		p.call = call
    57  	}
    58  	if ctor := target.self.assertConstructor(); ctor != nil {
    59  		p.ctor = ctor
    60  	}
    61  	return p
    62  }
    63  
    64  func (p Proxy) Revoke() {
    65  	p.proxy.revoke()
    66  }
    67  
    68  func (p Proxy) Handler() *Object {
    69  	if handler := p.proxy.handler; handler != nil {
    70  		return handler.toObject(p.proxy.val.runtime)
    71  	}
    72  	return nil
    73  }
    74  
    75  func (p Proxy) Target() *Object {
    76  	return p.proxy.target
    77  }
    78  
    79  func (p Proxy) toValue(r *Runtime) Value {
    80  	if p.proxy == nil {
    81  		return _null
    82  	}
    83  	proxy := p.proxy.val
    84  	if proxy.runtime != r {
    85  		panic(r.NewTypeError("Illegal runtime transition of a Proxy"))
    86  	}
    87  	return proxy
    88  }
    89  
    90  type proxyTrap string
    91  
    92  const (
    93  	proxy_trap_getPrototypeOf           = "getPrototypeOf"
    94  	proxy_trap_setPrototypeOf           = "setPrototypeOf"
    95  	proxy_trap_isExtensible             = "isExtensible"
    96  	proxy_trap_preventExtensions        = "preventExtensions"
    97  	proxy_trap_getOwnPropertyDescriptor = "getOwnPropertyDescriptor"
    98  	proxy_trap_defineProperty           = "defineProperty"
    99  	proxy_trap_has                      = "has"
   100  	proxy_trap_get                      = "get"
   101  	proxy_trap_set                      = "set"
   102  	proxy_trap_deleteProperty           = "deleteProperty"
   103  	proxy_trap_ownKeys                  = "ownKeys"
   104  	proxy_trap_apply                    = "apply"
   105  	proxy_trap_construct                = "construct"
   106  )
   107  
   108  func (p proxyTrap) String() (name string) {
   109  	return string(p)
   110  }
   111  
   112  type proxyHandler interface {
   113  	getPrototypeOf(target *Object) (Value, bool)
   114  	setPrototypeOf(target *Object, proto *Object) (bool, bool)
   115  	isExtensible(target *Object) (bool, bool)
   116  	preventExtensions(target *Object) (bool, bool)
   117  
   118  	getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool)
   119  	getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool)
   120  	getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool)
   121  
   122  	definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool)
   123  	definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool)
   124  	definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool)
   125  
   126  	hasStr(target *Object, prop unistring.String) (bool, bool)
   127  	hasIdx(target *Object, prop valueInt) (bool, bool)
   128  	hasSym(target *Object, prop *Symbol) (bool, bool)
   129  
   130  	getStr(target *Object, prop unistring.String, receiver Value) (Value, bool)
   131  	getIdx(target *Object, prop valueInt, receiver Value) (Value, bool)
   132  	getSym(target *Object, prop *Symbol, receiver Value) (Value, bool)
   133  
   134  	setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool)
   135  	setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool)
   136  	setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool)
   137  
   138  	deleteStr(target *Object, prop unistring.String) (bool, bool)
   139  	deleteIdx(target *Object, prop valueInt) (bool, bool)
   140  	deleteSym(target *Object, prop *Symbol) (bool, bool)
   141  
   142  	ownKeys(target *Object) (*Object, bool)
   143  	apply(target *Object, this Value, args []Value) (Value, bool)
   144  	construct(target *Object, args []Value, newTarget *Object) (Value, bool)
   145  
   146  	toObject(*Runtime) *Object
   147  }
   148  
   149  type jsProxyHandler struct {
   150  	handler *Object
   151  }
   152  
   153  func (h *jsProxyHandler) toObject(*Runtime) *Object {
   154  	return h.handler
   155  }
   156  
   157  func (h *jsProxyHandler) proxyCall(trap proxyTrap, args ...Value) (Value, bool) {
   158  	r := h.handler.runtime
   159  
   160  	if m := toMethod(r.getVStr(h.handler, unistring.String(trap.String()))); m != nil {
   161  		return m(FunctionCall{
   162  			This:      h.handler,
   163  			Arguments: args,
   164  		}), true
   165  	}
   166  
   167  	return nil, false
   168  }
   169  
   170  func (h *jsProxyHandler) boolProxyCall(trap proxyTrap, args ...Value) (bool, bool) {
   171  	if v, ok := h.proxyCall(trap, args...); ok {
   172  		return v.ToBoolean(), true
   173  	}
   174  	return false, false
   175  }
   176  
   177  func (h *jsProxyHandler) getPrototypeOf(target *Object) (Value, bool) {
   178  	return h.proxyCall(proxy_trap_getPrototypeOf, target)
   179  }
   180  
   181  func (h *jsProxyHandler) setPrototypeOf(target *Object, proto *Object) (bool, bool) {
   182  	var protoVal Value
   183  	if proto != nil {
   184  		protoVal = proto
   185  	} else {
   186  		protoVal = _null
   187  	}
   188  	return h.boolProxyCall(proxy_trap_setPrototypeOf, target, protoVal)
   189  }
   190  
   191  func (h *jsProxyHandler) isExtensible(target *Object) (bool, bool) {
   192  	return h.boolProxyCall(proxy_trap_isExtensible, target)
   193  }
   194  
   195  func (h *jsProxyHandler) preventExtensions(target *Object) (bool, bool) {
   196  	return h.boolProxyCall(proxy_trap_preventExtensions, target)
   197  }
   198  
   199  func (h *jsProxyHandler) getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool) {
   200  	return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, stringValueFromRaw(prop))
   201  }
   202  
   203  func (h *jsProxyHandler) getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool) {
   204  	return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, prop.toString())
   205  }
   206  
   207  func (h *jsProxyHandler) getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool) {
   208  	return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, prop)
   209  }
   210  
   211  func (h *jsProxyHandler) definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool) {
   212  	return h.boolProxyCall(proxy_trap_defineProperty, target, stringValueFromRaw(prop), desc.toValue(h.handler.runtime))
   213  }
   214  
   215  func (h *jsProxyHandler) definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool) {
   216  	return h.boolProxyCall(proxy_trap_defineProperty, target, prop.toString(), desc.toValue(h.handler.runtime))
   217  }
   218  
   219  func (h *jsProxyHandler) definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool) {
   220  	return h.boolProxyCall(proxy_trap_defineProperty, target, prop, desc.toValue(h.handler.runtime))
   221  }
   222  
   223  func (h *jsProxyHandler) hasStr(target *Object, prop unistring.String) (bool, bool) {
   224  	return h.boolProxyCall(proxy_trap_has, target, stringValueFromRaw(prop))
   225  }
   226  
   227  func (h *jsProxyHandler) hasIdx(target *Object, prop valueInt) (bool, bool) {
   228  	return h.boolProxyCall(proxy_trap_has, target, prop.toString())
   229  }
   230  
   231  func (h *jsProxyHandler) hasSym(target *Object, prop *Symbol) (bool, bool) {
   232  	return h.boolProxyCall(proxy_trap_has, target, prop)
   233  }
   234  
   235  func (h *jsProxyHandler) getStr(target *Object, prop unistring.String, receiver Value) (Value, bool) {
   236  	return h.proxyCall(proxy_trap_get, target, stringValueFromRaw(prop), receiver)
   237  }
   238  
   239  func (h *jsProxyHandler) getIdx(target *Object, prop valueInt, receiver Value) (Value, bool) {
   240  	return h.proxyCall(proxy_trap_get, target, prop.toString(), receiver)
   241  }
   242  
   243  func (h *jsProxyHandler) getSym(target *Object, prop *Symbol, receiver Value) (Value, bool) {
   244  	return h.proxyCall(proxy_trap_get, target, prop, receiver)
   245  }
   246  
   247  func (h *jsProxyHandler) setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool) {
   248  	return h.boolProxyCall(proxy_trap_set, target, stringValueFromRaw(prop), value, receiver)
   249  }
   250  
   251  func (h *jsProxyHandler) setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool) {
   252  	return h.boolProxyCall(proxy_trap_set, target, prop.toString(), value, receiver)
   253  }
   254  
   255  func (h *jsProxyHandler) setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool) {
   256  	return h.boolProxyCall(proxy_trap_set, target, prop, value, receiver)
   257  }
   258  
   259  func (h *jsProxyHandler) deleteStr(target *Object, prop unistring.String) (bool, bool) {
   260  	return h.boolProxyCall(proxy_trap_deleteProperty, target, stringValueFromRaw(prop))
   261  }
   262  
   263  func (h *jsProxyHandler) deleteIdx(target *Object, prop valueInt) (bool, bool) {
   264  	return h.boolProxyCall(proxy_trap_deleteProperty, target, prop.toString())
   265  }
   266  
   267  func (h *jsProxyHandler) deleteSym(target *Object, prop *Symbol) (bool, bool) {
   268  	return h.boolProxyCall(proxy_trap_deleteProperty, target, prop)
   269  }
   270  
   271  func (h *jsProxyHandler) ownKeys(target *Object) (*Object, bool) {
   272  	if v, ok := h.proxyCall(proxy_trap_ownKeys, target); ok {
   273  		return h.handler.runtime.toObject(v), true
   274  	}
   275  	return nil, false
   276  }
   277  
   278  func (h *jsProxyHandler) apply(target *Object, this Value, args []Value) (Value, bool) {
   279  	return h.proxyCall(proxy_trap_apply, target, this, h.handler.runtime.newArrayValues(args))
   280  }
   281  
   282  func (h *jsProxyHandler) construct(target *Object, args []Value, newTarget *Object) (Value, bool) {
   283  	return h.proxyCall(proxy_trap_construct, target, h.handler.runtime.newArrayValues(args), newTarget)
   284  }
   285  
   286  type proxyObject struct {
   287  	baseObject
   288  	target  *Object
   289  	handler proxyHandler
   290  	call    func(FunctionCall) Value
   291  	ctor    func(args []Value, newTarget *Object) *Object
   292  }
   293  
   294  func (p *proxyObject) checkHandler() proxyHandler {
   295  	r := p.val.runtime
   296  	if handler := p.handler; handler != nil {
   297  		return handler
   298  	}
   299  	panic(r.NewTypeError("Proxy already revoked"))
   300  }
   301  
   302  func (p *proxyObject) proto() *Object {
   303  	target := p.target
   304  	if v, ok := p.checkHandler().getPrototypeOf(target); ok {
   305  		var handlerProto *Object
   306  		if v != _null {
   307  			handlerProto = p.val.runtime.toObject(v)
   308  		}
   309  		if !target.self.isExtensible() && !p.__sameValue(handlerProto, target.self.proto()) {
   310  			panic(p.val.runtime.NewTypeError("'getPrototypeOf' on proxy: proxy target is non-extensible but the trap did not return its actual prototype"))
   311  		}
   312  		return handlerProto
   313  	}
   314  
   315  	return target.self.proto()
   316  }
   317  
   318  func (p *proxyObject) setProto(proto *Object, throw bool) bool {
   319  	target := p.target
   320  	if v, ok := p.checkHandler().setPrototypeOf(target, proto); ok {
   321  		if v {
   322  			if !target.self.isExtensible() && !p.__sameValue(proto, target.self.proto()) {
   323  				panic(p.val.runtime.NewTypeError("'setPrototypeOf' on proxy: trap returned truish for setting a new prototype on the non-extensible proxy target"))
   324  			}
   325  			return true
   326  		} else {
   327  			p.val.runtime.typeErrorResult(throw, "'setPrototypeOf' on proxy: trap returned falsish")
   328  			return false
   329  		}
   330  	}
   331  
   332  	return target.self.setProto(proto, throw)
   333  }
   334  
   335  func (p *proxyObject) isExtensible() bool {
   336  	target := p.target
   337  	if booleanTrapResult, ok := p.checkHandler().isExtensible(p.target); ok {
   338  		if te := target.self.isExtensible(); booleanTrapResult != te {
   339  			panic(p.val.runtime.NewTypeError("'isExtensible' on proxy: trap result does not reflect extensibility of proxy target (which is '%v')", te))
   340  		}
   341  		return booleanTrapResult
   342  	}
   343  
   344  	return target.self.isExtensible()
   345  }
   346  
   347  func (p *proxyObject) preventExtensions(throw bool) bool {
   348  	target := p.target
   349  	if booleanTrapResult, ok := p.checkHandler().preventExtensions(target); ok {
   350  		if !booleanTrapResult {
   351  			p.val.runtime.typeErrorResult(throw, "'preventExtensions' on proxy: trap returned falsish")
   352  			return false
   353  		}
   354  		if te := target.self.isExtensible(); booleanTrapResult && te {
   355  			panic(p.val.runtime.NewTypeError("'preventExtensions' on proxy: trap returned truish but the proxy target is extensible"))
   356  		}
   357  	}
   358  
   359  	return target.self.preventExtensions(throw)
   360  }
   361  
   362  func propToValueProp(v Value) *valueProperty {
   363  	if v == nil {
   364  		return nil
   365  	}
   366  	if v, ok := v.(*valueProperty); ok {
   367  		return v
   368  	}
   369  	return &valueProperty{
   370  		value:        v,
   371  		writable:     true,
   372  		configurable: true,
   373  		enumerable:   true,
   374  	}
   375  }
   376  
   377  func (p *proxyObject) proxyDefineOwnPropertyPreCheck(trapResult, throw bool) bool {
   378  	if !trapResult {
   379  		p.val.runtime.typeErrorResult(throw, "'defineProperty' on proxy: trap returned falsish")
   380  		return false
   381  	}
   382  	return true
   383  }
   384  
   385  func (p *proxyObject) proxyDefineOwnPropertyPostCheck(prop Value, target *Object, descr PropertyDescriptor) {
   386  	targetDesc := propToValueProp(prop)
   387  	extensibleTarget := target.self.isExtensible()
   388  	settingConfigFalse := descr.Configurable == FLAG_FALSE
   389  	if targetDesc == nil {
   390  		if !extensibleTarget {
   391  			panic(p.val.runtime.NewTypeError())
   392  		}
   393  		if settingConfigFalse {
   394  			panic(p.val.runtime.NewTypeError())
   395  		}
   396  	} else {
   397  		if !p.__isCompatibleDescriptor(extensibleTarget, &descr, targetDesc) {
   398  			panic(p.val.runtime.NewTypeError())
   399  		}
   400  		if settingConfigFalse && targetDesc.configurable {
   401  			panic(p.val.runtime.NewTypeError())
   402  		}
   403  		if targetDesc.value != nil && !targetDesc.configurable && targetDesc.writable {
   404  			if descr.Writable == FLAG_FALSE {
   405  				panic(p.val.runtime.NewTypeError())
   406  			}
   407  		}
   408  	}
   409  }
   410  
   411  func (p *proxyObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
   412  	target := p.target
   413  	if booleanTrapResult, ok := p.checkHandler().definePropertyStr(target, name, descr); ok {
   414  		if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
   415  			return false
   416  		}
   417  		p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropStr(name), target, descr)
   418  		return true
   419  	}
   420  	return target.self.defineOwnPropertyStr(name, descr, throw)
   421  }
   422  
   423  func (p *proxyObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
   424  	target := p.target
   425  	if booleanTrapResult, ok := p.checkHandler().definePropertyIdx(target, idx, descr); ok {
   426  		if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
   427  			return false
   428  		}
   429  		p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropIdx(idx), target, descr)
   430  		return true
   431  	}
   432  
   433  	return target.self.defineOwnPropertyIdx(idx, descr, throw)
   434  }
   435  
   436  func (p *proxyObject) defineOwnPropertySym(s *Symbol, descr PropertyDescriptor, throw bool) bool {
   437  	target := p.target
   438  	if booleanTrapResult, ok := p.checkHandler().definePropertySym(target, s, descr); ok {
   439  		if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
   440  			return false
   441  		}
   442  		p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropSym(s), target, descr)
   443  		return true
   444  	}
   445  
   446  	return target.self.defineOwnPropertySym(s, descr, throw)
   447  }
   448  
   449  func (p *proxyObject) proxyHasChecks(targetProp Value, target *Object, name fmt.Stringer) {
   450  	targetDesc := propToValueProp(targetProp)
   451  	if targetDesc != nil {
   452  		if !targetDesc.configurable {
   453  			panic(p.val.runtime.NewTypeError("'has' on proxy: trap returned falsish for property '%s' which exists in the proxy target as non-configurable", name.String()))
   454  		}
   455  		if !target.self.isExtensible() {
   456  			panic(p.val.runtime.NewTypeError("'has' on proxy: trap returned falsish for property '%s' but the proxy target is not extensible", name.String()))
   457  		}
   458  	}
   459  }
   460  
   461  func (p *proxyObject) hasPropertyStr(name unistring.String) bool {
   462  	target := p.target
   463  	if b, ok := p.checkHandler().hasStr(target, name); ok {
   464  		if !b {
   465  			p.proxyHasChecks(target.self.getOwnPropStr(name), target, name)
   466  		}
   467  		return b
   468  	}
   469  
   470  	return target.self.hasPropertyStr(name)
   471  }
   472  
   473  func (p *proxyObject) hasPropertyIdx(idx valueInt) bool {
   474  	target := p.target
   475  	if b, ok := p.checkHandler().hasIdx(target, idx); ok {
   476  		if !b {
   477  			p.proxyHasChecks(target.self.getOwnPropIdx(idx), target, idx)
   478  		}
   479  		return b
   480  	}
   481  
   482  	return target.self.hasPropertyIdx(idx)
   483  }
   484  
   485  func (p *proxyObject) hasPropertySym(s *Symbol) bool {
   486  	target := p.target
   487  	if b, ok := p.checkHandler().hasSym(target, s); ok {
   488  		if !b {
   489  			p.proxyHasChecks(target.self.getOwnPropSym(s), target, s)
   490  		}
   491  		return b
   492  	}
   493  
   494  	return target.self.hasPropertySym(s)
   495  }
   496  
   497  func (p *proxyObject) hasOwnPropertyStr(name unistring.String) bool {
   498  	return p.getOwnPropStr(name) != nil
   499  }
   500  
   501  func (p *proxyObject) hasOwnPropertyIdx(idx valueInt) bool {
   502  	return p.getOwnPropIdx(idx) != nil
   503  }
   504  
   505  func (p *proxyObject) hasOwnPropertySym(s *Symbol) bool {
   506  	return p.getOwnPropSym(s) != nil
   507  }
   508  
   509  func (p *proxyObject) proxyGetOwnPropertyDescriptor(targetProp Value, target *Object, trapResult Value, name fmt.Stringer) Value {
   510  	r := p.val.runtime
   511  	targetDesc := propToValueProp(targetProp)
   512  	var trapResultObj *Object
   513  	if trapResult != nil && trapResult != _undefined {
   514  		if obj, ok := trapResult.(*Object); ok {
   515  			trapResultObj = obj
   516  		} else {
   517  			panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap returned neither object nor undefined for property '%s'", name.String()))
   518  		}
   519  	}
   520  	if trapResultObj == nil {
   521  		if targetDesc == nil {
   522  			return nil
   523  		}
   524  		if !targetDesc.configurable {
   525  			panic(r.NewTypeError())
   526  		}
   527  		if !target.self.isExtensible() {
   528  			panic(r.NewTypeError())
   529  		}
   530  		return nil
   531  	}
   532  	extensibleTarget := target.self.isExtensible()
   533  	resultDesc := r.toPropertyDescriptor(trapResultObj)
   534  	resultDesc.complete()
   535  	if !p.__isCompatibleDescriptor(extensibleTarget, &resultDesc, targetDesc) {
   536  		panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property '%s' that is incompatible with the existing property in the proxy target", name.String()))
   537  	}
   538  
   539  	if resultDesc.Configurable == FLAG_FALSE {
   540  		if targetDesc == nil {
   541  			panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '%s' which is non-existent in the proxy target", name.String()))
   542  		}
   543  
   544  		if targetDesc.configurable {
   545  			panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '%s' which is configurable in the proxy target", name.String()))
   546  		}
   547  
   548  		if resultDesc.Writable == FLAG_FALSE && targetDesc.writable {
   549  			panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurable and writable for property '%s' which is non-configurable, non-writable in the proxy target", name.String()))
   550  		}
   551  	}
   552  
   553  	if resultDesc.Writable == FLAG_TRUE && resultDesc.Configurable == FLAG_TRUE &&
   554  		resultDesc.Enumerable == FLAG_TRUE {
   555  		return resultDesc.Value
   556  	}
   557  	return r.toValueProp(trapResultObj)
   558  }
   559  
   560  func (p *proxyObject) getOwnPropStr(name unistring.String) Value {
   561  	target := p.target
   562  	if v, ok := p.checkHandler().getOwnPropertyDescriptorStr(target, name); ok {
   563  		return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropStr(name), target, v, name)
   564  	}
   565  
   566  	return target.self.getOwnPropStr(name)
   567  }
   568  
   569  func (p *proxyObject) getOwnPropIdx(idx valueInt) Value {
   570  	target := p.target
   571  	if v, ok := p.checkHandler().getOwnPropertyDescriptorIdx(target, idx); ok {
   572  		return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropIdx(idx), target, v, idx)
   573  	}
   574  
   575  	return target.self.getOwnPropIdx(idx)
   576  }
   577  
   578  func (p *proxyObject) getOwnPropSym(s *Symbol) Value {
   579  	target := p.target
   580  	if v, ok := p.checkHandler().getOwnPropertyDescriptorSym(target, s); ok {
   581  		return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropSym(s), target, v, s)
   582  	}
   583  
   584  	return target.self.getOwnPropSym(s)
   585  }
   586  
   587  func (p *proxyObject) proxyGetChecks(targetProp, trapResult Value, name fmt.Stringer) {
   588  	if targetDesc, ok := targetProp.(*valueProperty); ok {
   589  		if !targetDesc.accessor {
   590  			if !targetDesc.writable && !targetDesc.configurable && !trapResult.SameAs(targetDesc.value) {
   591  				panic(p.val.runtime.NewTypeError("'get' on proxy: property '%s' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '%s' but got '%s')", name.String(), nilSafe(targetDesc.value), ret))
   592  			}
   593  		} else {
   594  			if !targetDesc.configurable && targetDesc.getterFunc == nil && trapResult != _undefined {
   595  				panic(p.val.runtime.NewTypeError("'get' on proxy: property '%s' is a non-configurable accessor property on the proxy target and does not have a getter function, but the trap did not return 'undefined' (got '%s')", name.String(), ret))
   596  			}
   597  		}
   598  	}
   599  }
   600  
   601  func (p *proxyObject) getStr(name unistring.String, receiver Value) Value {
   602  	target := p.target
   603  	if receiver == nil {
   604  		receiver = p.val
   605  	}
   606  	if v, ok := p.checkHandler().getStr(target, name, receiver); ok {
   607  		p.proxyGetChecks(target.self.getOwnPropStr(name), v, name)
   608  		return v
   609  	}
   610  	return target.self.getStr(name, receiver)
   611  }
   612  
   613  func (p *proxyObject) getIdx(idx valueInt, receiver Value) Value {
   614  	target := p.target
   615  	if receiver == nil {
   616  		receiver = p.val
   617  	}
   618  	if v, ok := p.checkHandler().getIdx(target, idx, receiver); ok {
   619  		p.proxyGetChecks(target.self.getOwnPropIdx(idx), v, idx)
   620  		return v
   621  	}
   622  	return target.self.getIdx(idx, receiver)
   623  }
   624  
   625  func (p *proxyObject) getSym(s *Symbol, receiver Value) Value {
   626  	target := p.target
   627  	if receiver == nil {
   628  		receiver = p.val
   629  	}
   630  	if v, ok := p.checkHandler().getSym(target, s, receiver); ok {
   631  		p.proxyGetChecks(target.self.getOwnPropSym(s), v, s)
   632  		return v
   633  	}
   634  
   635  	return target.self.getSym(s, receiver)
   636  }
   637  
   638  func (p *proxyObject) proxySetPreCheck(trapResult, throw bool, name fmt.Stringer) bool {
   639  	if !trapResult {
   640  		p.val.runtime.typeErrorResult(throw, "'set' on proxy: trap returned falsish for property '%s'", name.String())
   641  	}
   642  	return trapResult
   643  }
   644  
   645  func (p *proxyObject) proxySetPostCheck(targetProp, value Value, name fmt.Stringer) {
   646  	if prop, ok := targetProp.(*valueProperty); ok {
   647  		if prop.accessor {
   648  			if !prop.configurable && prop.setterFunc == nil {
   649  				panic(p.val.runtime.NewTypeError("'set' on proxy: trap returned truish for property '%s' which exists in the proxy target as a non-configurable and non-writable accessor property without a setter", name.String()))
   650  			}
   651  		} else if !prop.configurable && !prop.writable && !p.__sameValue(prop.value, value) {
   652  			panic(p.val.runtime.NewTypeError("'set' on proxy: trap returned truish for property '%s' which exists in the proxy target as a non-configurable and non-writable data property with a different value", name.String()))
   653  		}
   654  	}
   655  }
   656  
   657  func (p *proxyObject) proxySetStr(name unistring.String, value, receiver Value, throw bool) bool {
   658  	target := p.target
   659  	if v, ok := p.checkHandler().setStr(target, name, value, receiver); ok {
   660  		if p.proxySetPreCheck(v, throw, name) {
   661  			p.proxySetPostCheck(target.self.getOwnPropStr(name), value, name)
   662  			return true
   663  		}
   664  		return false
   665  	}
   666  	return target.setStr(name, value, receiver, throw)
   667  }
   668  
   669  func (p *proxyObject) proxySetIdx(idx valueInt, value, receiver Value, throw bool) bool {
   670  	target := p.target
   671  	if v, ok := p.checkHandler().setIdx(target, idx, value, receiver); ok {
   672  		if p.proxySetPreCheck(v, throw, idx) {
   673  			p.proxySetPostCheck(target.self.getOwnPropIdx(idx), value, idx)
   674  			return true
   675  		}
   676  		return false
   677  	}
   678  	return target.setIdx(idx, value, receiver, throw)
   679  }
   680  
   681  func (p *proxyObject) proxySetSym(s *Symbol, value, receiver Value, throw bool) bool {
   682  	target := p.target
   683  	if v, ok := p.checkHandler().setSym(target, s, value, receiver); ok {
   684  		if p.proxySetPreCheck(v, throw, s) {
   685  			p.proxySetPostCheck(target.self.getOwnPropSym(s), value, s)
   686  			return true
   687  		}
   688  		return false
   689  	}
   690  	return target.setSym(s, value, receiver, throw)
   691  }
   692  
   693  func (p *proxyObject) setOwnStr(name unistring.String, v Value, throw bool) bool {
   694  	return p.proxySetStr(name, v, p.val, throw)
   695  }
   696  
   697  func (p *proxyObject) setOwnIdx(idx valueInt, v Value, throw bool) bool {
   698  	return p.proxySetIdx(idx, v, p.val, throw)
   699  }
   700  
   701  func (p *proxyObject) setOwnSym(s *Symbol, v Value, throw bool) bool {
   702  	return p.proxySetSym(s, v, p.val, throw)
   703  }
   704  
   705  func (p *proxyObject) setForeignStr(name unistring.String, v, receiver Value, throw bool) (bool, bool) {
   706  	return p.proxySetStr(name, v, receiver, throw), true
   707  }
   708  
   709  func (p *proxyObject) setForeignIdx(idx valueInt, v, receiver Value, throw bool) (bool, bool) {
   710  	return p.proxySetIdx(idx, v, receiver, throw), true
   711  }
   712  
   713  func (p *proxyObject) setForeignSym(s *Symbol, v, receiver Value, throw bool) (bool, bool) {
   714  	return p.proxySetSym(s, v, receiver, throw), true
   715  }
   716  
   717  func (p *proxyObject) proxyDeleteCheck(trapResult bool, targetProp Value, name fmt.Stringer, target *Object, throw bool) {
   718  	if trapResult {
   719  		if targetProp == nil {
   720  			return
   721  		}
   722  		if targetDesc, ok := targetProp.(*valueProperty); ok {
   723  			if !targetDesc.configurable {
   724  				panic(p.val.runtime.NewTypeError("'deleteProperty' on proxy: property '%s' is a non-configurable property but the trap returned truish", name.String()))
   725  			}
   726  		}
   727  		if !target.self.isExtensible() {
   728  			panic(p.val.runtime.NewTypeError("'deleteProperty' on proxy: trap returned truish for property '%s' but the proxy target is non-extensible", name.String()))
   729  		}
   730  	} else {
   731  		p.val.runtime.typeErrorResult(throw, "'deleteProperty' on proxy: trap returned falsish for property '%s'", name.String())
   732  	}
   733  }
   734  
   735  func (p *proxyObject) deleteStr(name unistring.String, throw bool) bool {
   736  	target := p.target
   737  	if v, ok := p.checkHandler().deleteStr(target, name); ok {
   738  		p.proxyDeleteCheck(v, target.self.getOwnPropStr(name), name, target, throw)
   739  		return v
   740  	}
   741  
   742  	return target.self.deleteStr(name, throw)
   743  }
   744  
   745  func (p *proxyObject) deleteIdx(idx valueInt, throw bool) bool {
   746  	target := p.target
   747  	if v, ok := p.checkHandler().deleteIdx(target, idx); ok {
   748  		p.proxyDeleteCheck(v, target.self.getOwnPropIdx(idx), idx, target, throw)
   749  		return v
   750  	}
   751  
   752  	return target.self.deleteIdx(idx, throw)
   753  }
   754  
   755  func (p *proxyObject) deleteSym(s *Symbol, throw bool) bool {
   756  	target := p.target
   757  	if v, ok := p.checkHandler().deleteSym(target, s); ok {
   758  		p.proxyDeleteCheck(v, target.self.getOwnPropSym(s), s, target, throw)
   759  		return v
   760  	}
   761  
   762  	return target.self.deleteSym(s, throw)
   763  }
   764  
   765  func (p *proxyObject) keys(all bool, _ []Value) []Value {
   766  	if v, ok := p.proxyOwnKeys(); ok {
   767  		if !all {
   768  			k := 0
   769  			for i, key := range v {
   770  				prop := p.val.getOwnProp(key)
   771  				if prop == nil || prop == _undefined {
   772  					continue
   773  				}
   774  				if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
   775  					continue
   776  				}
   777  				if k != i {
   778  					v[k] = v[i]
   779  				}
   780  				k++
   781  			}
   782  			v = v[:k]
   783  		}
   784  		return v
   785  	}
   786  	return p.target.self.keys(all, nil)
   787  }
   788  
   789  func (p *proxyObject) proxyOwnKeys() ([]Value, bool) {
   790  	target := p.target
   791  	if v, ok := p.checkHandler().ownKeys(target); ok {
   792  		keys := p.val.runtime.toObject(v)
   793  		var keyList []Value
   794  		keySet := make(map[Value]struct{})
   795  		l := toLength(keys.self.getStr("length", nil))
   796  		for k := int64(0); k < l; k++ {
   797  			item := keys.self.getIdx(valueInt(k), nil)
   798  			if _, ok := item.(String); !ok {
   799  				if _, ok := item.(*Symbol); !ok {
   800  					panic(p.val.runtime.NewTypeError("%s is not a valid property name", item.String()))
   801  				}
   802  			}
   803  			if _, exists := keySet[item]; exists {
   804  				panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned duplicate entries"))
   805  			}
   806  			keyList = append(keyList, item)
   807  			keySet[item] = struct{}{}
   808  		}
   809  		ext := target.self.isExtensible()
   810  		for item, next := target.self.iterateKeys()(); next != nil; item, next = next() {
   811  			if _, exists := keySet[item.name]; exists {
   812  				delete(keySet, item.name)
   813  			} else {
   814  				if !ext {
   815  					panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include '%s'", item.name.String()))
   816  				}
   817  				var prop Value
   818  				if item.value == nil {
   819  					prop = target.getOwnProp(item.name)
   820  				} else {
   821  					prop = item.value
   822  				}
   823  				if prop, ok := prop.(*valueProperty); ok && !prop.configurable {
   824  					panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include non-configurable '%s'", item.name.String()))
   825  				}
   826  			}
   827  		}
   828  		if !ext && len(keyList) > 0 && len(keySet) > 0 {
   829  			panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned extra keys but proxy target is non-extensible"))
   830  		}
   831  
   832  		return keyList, true
   833  	}
   834  
   835  	return nil, false
   836  }
   837  
   838  func (p *proxyObject) iterateStringKeys() iterNextFunc {
   839  	return (&proxyPropIter{
   840  		p:     p,
   841  		names: p.stringKeys(true, nil),
   842  	}).next
   843  }
   844  
   845  func (p *proxyObject) iterateSymbols() iterNextFunc {
   846  	return (&proxyPropIter{
   847  		p:     p,
   848  		names: p.symbols(true, nil),
   849  	}).next
   850  }
   851  
   852  func (p *proxyObject) iterateKeys() iterNextFunc {
   853  	return (&proxyPropIter{
   854  		p:     p,
   855  		names: p.keys(true, nil),
   856  	}).next
   857  }
   858  
   859  func (p *proxyObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
   860  	if p.call != nil {
   861  		return func(call FunctionCall) Value {
   862  			return p.apply(call)
   863  		}, true
   864  	}
   865  	return nil, false
   866  }
   867  
   868  func (p *proxyObject) vmCall(vm *vm, n int) {
   869  	vm.pushCtx()
   870  	vm.prg = nil
   871  	vm.sb = vm.sp - n // so that [sb-1] points to the callee
   872  	ret := p.apply(FunctionCall{This: vm.stack[vm.sp-n-2], Arguments: vm.stack[vm.sp-n : vm.sp]})
   873  	if ret == nil {
   874  		ret = _undefined
   875  	}
   876  	vm.stack[vm.sp-n-2] = ret
   877  	vm.popCtx()
   878  	vm.sp -= n + 1
   879  	vm.pc++
   880  }
   881  
   882  func (p *proxyObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
   883  	if p.ctor != nil {
   884  		return p.construct
   885  	}
   886  	return nil
   887  }
   888  
   889  func (p *proxyObject) apply(call FunctionCall) Value {
   890  	if p.call == nil {
   891  		panic(p.val.runtime.NewTypeError("proxy target is not a function"))
   892  	}
   893  	if v, ok := p.checkHandler().apply(p.target, nilSafe(call.This), call.Arguments); ok {
   894  		return v
   895  	}
   896  	return p.call(call)
   897  }
   898  
   899  func (p *proxyObject) construct(args []Value, newTarget *Object) *Object {
   900  	if p.ctor == nil {
   901  		panic(p.val.runtime.NewTypeError("proxy target is not a constructor"))
   902  	}
   903  	if newTarget == nil {
   904  		newTarget = p.val
   905  	}
   906  	if v, ok := p.checkHandler().construct(p.target, args, newTarget); ok {
   907  		return p.val.runtime.toObject(v)
   908  	}
   909  	return p.ctor(args, newTarget)
   910  }
   911  
   912  func (p *proxyObject) __isCompatibleDescriptor(extensible bool, desc *PropertyDescriptor, current *valueProperty) bool {
   913  	if current == nil {
   914  		return extensible
   915  	}
   916  
   917  	if !current.configurable {
   918  		if desc.Configurable == FLAG_TRUE {
   919  			return false
   920  		}
   921  
   922  		if desc.Enumerable != FLAG_NOT_SET && desc.Enumerable.Bool() != current.enumerable {
   923  			return false
   924  		}
   925  
   926  		if desc.IsGeneric() {
   927  			return true
   928  		}
   929  
   930  		if desc.IsData() != !current.accessor {
   931  			return desc.Configurable != FLAG_FALSE
   932  		}
   933  
   934  		if desc.IsData() && !current.accessor {
   935  			if !current.configurable {
   936  				if desc.Writable == FLAG_TRUE && !current.writable {
   937  					return false
   938  				}
   939  				if !current.writable {
   940  					if desc.Value != nil && !desc.Value.SameAs(current.value) {
   941  						return false
   942  					}
   943  				}
   944  			}
   945  			return true
   946  		}
   947  		if desc.IsAccessor() && current.accessor {
   948  			if !current.configurable {
   949  				if desc.Setter != nil && desc.Setter.SameAs(current.setterFunc) {
   950  					return false
   951  				}
   952  				if desc.Getter != nil && desc.Getter.SameAs(current.getterFunc) {
   953  					return false
   954  				}
   955  			}
   956  		}
   957  	}
   958  	return true
   959  }
   960  
   961  func (p *proxyObject) __sameValue(val1, val2 Value) bool {
   962  	if val1 == nil && val2 == nil {
   963  		return true
   964  	}
   965  	if val1 != nil {
   966  		return val1.SameAs(val2)
   967  	}
   968  	return false
   969  }
   970  
   971  func (p *proxyObject) filterKeys(vals []Value, all, symbols bool) []Value {
   972  	if !all {
   973  		k := 0
   974  		for i, val := range vals {
   975  			var prop Value
   976  			if symbols {
   977  				if s, ok := val.(*Symbol); ok {
   978  					prop = p.getOwnPropSym(s)
   979  				} else {
   980  					continue
   981  				}
   982  			} else {
   983  				if _, ok := val.(*Symbol); !ok {
   984  					prop = p.getOwnPropStr(val.string())
   985  				} else {
   986  					continue
   987  				}
   988  			}
   989  			if prop == nil {
   990  				continue
   991  			}
   992  			if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
   993  				continue
   994  			}
   995  			if k != i {
   996  				vals[k] = vals[i]
   997  			}
   998  			k++
   999  		}
  1000  		vals = vals[:k]
  1001  	} else {
  1002  		k := 0
  1003  		for i, val := range vals {
  1004  			if _, ok := val.(*Symbol); ok != symbols {
  1005  				continue
  1006  			}
  1007  			if k != i {
  1008  				vals[k] = vals[i]
  1009  			}
  1010  			k++
  1011  		}
  1012  		vals = vals[:k]
  1013  	}
  1014  	return vals
  1015  }
  1016  
  1017  func (p *proxyObject) stringKeys(all bool, _ []Value) []Value { // we can assume accum is empty
  1018  	var keys []Value
  1019  	if vals, ok := p.proxyOwnKeys(); ok {
  1020  		keys = vals
  1021  	} else {
  1022  		keys = p.target.self.stringKeys(true, nil)
  1023  	}
  1024  
  1025  	return p.filterKeys(keys, all, false)
  1026  }
  1027  
  1028  func (p *proxyObject) symbols(all bool, accum []Value) []Value {
  1029  	var symbols []Value
  1030  	if vals, ok := p.proxyOwnKeys(); ok {
  1031  		symbols = vals
  1032  	} else {
  1033  		symbols = p.target.self.symbols(true, nil)
  1034  	}
  1035  	symbols = p.filterKeys(symbols, all, true)
  1036  	if accum == nil {
  1037  		return symbols
  1038  	}
  1039  	accum = append(accum, symbols...)
  1040  	return accum
  1041  }
  1042  
  1043  func (p *proxyObject) className() string {
  1044  	if p.target == nil {
  1045  		panic(p.val.runtime.NewTypeError("proxy has been revoked"))
  1046  	}
  1047  	if p.call != nil || p.ctor != nil {
  1048  		return classFunction
  1049  	}
  1050  	return classObject
  1051  }
  1052  
  1053  func (p *proxyObject) typeOf() String {
  1054  	if p.call == nil {
  1055  		return stringObjectC
  1056  	}
  1057  
  1058  	return stringFunction
  1059  }
  1060  
  1061  func (p *proxyObject) exportType() reflect.Type {
  1062  	return proxyType
  1063  }
  1064  
  1065  func (p *proxyObject) export(*objectExportCtx) interface{} {
  1066  	return Proxy{
  1067  		proxy: p,
  1068  	}
  1069  }
  1070  
  1071  func (p *proxyObject) revoke() {
  1072  	p.handler = nil
  1073  	p.target = nil
  1074  }