builtin_weakmap.go 5.1 KB

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