builtin_weakmap.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package goja
  2. type weakMap uint64
  3. type weakMapObject struct {
  4. baseObject
  5. m weakMap
  6. }
  7. func (wmo *weakMapObject) init() {
  8. wmo.baseObject.init()
  9. wmo.m = weakMap(wmo.val.runtime.genId())
  10. }
  11. func (wm weakMap) set(key *Object, value Value) {
  12. key.getWeakRefs()[wm] = value
  13. }
  14. func (wm weakMap) get(key *Object) Value {
  15. return key.weakRefs[wm]
  16. }
  17. func (wm weakMap) remove(key *Object) bool {
  18. if _, exists := key.weakRefs[wm]; exists {
  19. delete(key.weakRefs, wm)
  20. return true
  21. }
  22. return false
  23. }
  24. func (wm weakMap) has(key *Object) bool {
  25. _, exists := key.weakRefs[wm]
  26. return exists
  27. }
  28. func (r *Runtime) weakMapProto_delete(call FunctionCall) Value {
  29. thisObj := r.toObject(call.This)
  30. wmo, ok := thisObj.self.(*weakMapObject)
  31. if !ok {
  32. panic(r.NewTypeError("Method WeakMap.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
  33. }
  34. key, ok := call.Argument(0).(*Object)
  35. if ok && wmo.m.remove(key) {
  36. return valueTrue
  37. }
  38. return valueFalse
  39. }
  40. func (r *Runtime) weakMapProto_get(call FunctionCall) Value {
  41. thisObj := r.toObject(call.This)
  42. wmo, ok := thisObj.self.(*weakMapObject)
  43. if !ok {
  44. panic(r.NewTypeError("Method WeakMap.prototype.get called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
  45. }
  46. var res Value
  47. if key, ok := call.Argument(0).(*Object); ok {
  48. res = wmo.m.get(key)
  49. }
  50. if res == nil {
  51. return _undefined
  52. }
  53. return res
  54. }
  55. func (r *Runtime) weakMapProto_has(call FunctionCall) Value {
  56. thisObj := r.toObject(call.This)
  57. wmo, ok := thisObj.self.(*weakMapObject)
  58. if !ok {
  59. panic(r.NewTypeError("Method WeakMap.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
  60. }
  61. key, ok := call.Argument(0).(*Object)
  62. if ok && wmo.m.has(key) {
  63. return valueTrue
  64. }
  65. return valueFalse
  66. }
  67. func (r *Runtime) weakMapProto_set(call FunctionCall) Value {
  68. thisObj := r.toObject(call.This)
  69. wmo, ok := thisObj.self.(*weakMapObject)
  70. if !ok {
  71. panic(r.NewTypeError("Method WeakMap.prototype.set called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
  72. }
  73. key := r.toObject(call.Argument(0))
  74. wmo.m.set(key, call.Argument(1))
  75. return call.This
  76. }
  77. func (r *Runtime) needNew(name string) *Object {
  78. return r.NewTypeError("Constructor %s requires 'new'", name)
  79. }
  80. func (r *Runtime) builtin_newWeakMap(args []Value, newTarget *Object) *Object {
  81. if newTarget == nil {
  82. panic(r.needNew("WeakMap"))
  83. }
  84. proto := r.getPrototypeFromCtor(newTarget, r.global.WeakMap, r.global.WeakMapPrototype)
  85. o := &Object{runtime: r}
  86. wmo := &weakMapObject{}
  87. wmo.class = classObject
  88. wmo.val = o
  89. wmo.extensible = true
  90. o.self = wmo
  91. wmo.prototype = proto
  92. wmo.init()
  93. if len(args) > 0 {
  94. if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
  95. adder := wmo.getStr("set", nil)
  96. adderFn := toMethod(adder)
  97. if adderFn == nil {
  98. panic(r.NewTypeError("WeakMap.set in missing"))
  99. }
  100. iter := r.getIterator(arg, nil)
  101. i0 := valueInt(0)
  102. i1 := valueInt(1)
  103. if adder == r.global.weakMapAdder {
  104. iter.iterate(func(item Value) {
  105. itemObj := r.toObject(item)
  106. k := itemObj.self.getIdx(i0, nil)
  107. v := nilSafe(itemObj.self.getIdx(i1, nil))
  108. wmo.m.set(r.toObject(k), v)
  109. })
  110. } else {
  111. iter.iterate(func(item Value) {
  112. itemObj := r.toObject(item)
  113. k := itemObj.self.getIdx(i0, nil)
  114. v := itemObj.self.getIdx(i1, nil)
  115. adderFn(FunctionCall{This: o, Arguments: []Value{k, v}})
  116. })
  117. }
  118. }
  119. }
  120. return o
  121. }
  122. func (r *Runtime) createWeakMapProto(val *Object) objectImpl {
  123. o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
  124. o._putProp("constructor", r.getWeakMap(), true, false, true)
  125. r.global.weakMapAdder = r.newNativeFunc(r.weakMapProto_set, "set", 2)
  126. o._putProp("set", r.global.weakMapAdder, true, false, true)
  127. o._putProp("delete", r.newNativeFunc(r.weakMapProto_delete, "delete", 1), true, false, true)
  128. o._putProp("has", r.newNativeFunc(r.weakMapProto_has, "has", 1), true, false, true)
  129. o._putProp("get", r.newNativeFunc(r.weakMapProto_get, "get", 1), true, false, true)
  130. o._putSym(SymToStringTag, valueProp(asciiString(classWeakMap), false, false, true))
  131. return o
  132. }
  133. func (r *Runtime) createWeakMap(val *Object) objectImpl {
  134. o := r.newNativeConstructOnly(val, r.builtin_newWeakMap, r.getWeakMapPrototype(), "WeakMap", 0)
  135. return o
  136. }
  137. func (r *Runtime) getWeakMapPrototype() *Object {
  138. ret := r.global.WeakMapPrototype
  139. if ret == nil {
  140. ret = &Object{runtime: r}
  141. r.global.WeakMapPrototype = ret
  142. ret.self = r.createWeakMapProto(ret)
  143. }
  144. return ret
  145. }
  146. func (r *Runtime) getWeakMap() *Object {
  147. ret := r.global.WeakMap
  148. if ret == nil {
  149. ret = &Object{runtime: r}
  150. r.global.WeakMap = ret
  151. ret.self = r.createWeakMap(ret)
  152. }
  153. return ret
  154. }