clone.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package otto
  2. import (
  3. "fmt"
  4. )
  5. type _clone struct {
  6. runtime *_runtime
  7. _object map[*_object]*_object
  8. _objectStash map[*_objectStash]*_objectStash
  9. _dclStash map[*_dclStash]*_dclStash
  10. _fnStash map[*_fnStash]*_fnStash
  11. }
  12. func (in *_runtime) clone() *_runtime {
  13. in.lck.Lock()
  14. defer in.lck.Unlock()
  15. out := &_runtime{
  16. debugger: in.debugger,
  17. random: in.random,
  18. stackLimit: in.stackLimit,
  19. traceLimit: in.traceLimit,
  20. }
  21. clone := _clone{
  22. runtime: out,
  23. _object: make(map[*_object]*_object),
  24. _objectStash: make(map[*_objectStash]*_objectStash),
  25. _dclStash: make(map[*_dclStash]*_dclStash),
  26. _fnStash: make(map[*_fnStash]*_fnStash),
  27. }
  28. globalObject := clone.object(in.globalObject)
  29. out.globalStash = out.newObjectStash(globalObject, nil)
  30. out.globalObject = globalObject
  31. out.global = _global{
  32. clone.object(in.global.Object),
  33. clone.object(in.global.Function),
  34. clone.object(in.global.Array),
  35. clone.object(in.global.String),
  36. clone.object(in.global.Boolean),
  37. clone.object(in.global.Number),
  38. clone.object(in.global.Math),
  39. clone.object(in.global.Date),
  40. clone.object(in.global.RegExp),
  41. clone.object(in.global.Error),
  42. clone.object(in.global.EvalError),
  43. clone.object(in.global.TypeError),
  44. clone.object(in.global.RangeError),
  45. clone.object(in.global.ReferenceError),
  46. clone.object(in.global.SyntaxError),
  47. clone.object(in.global.URIError),
  48. clone.object(in.global.JSON),
  49. clone.object(in.global.ObjectPrototype),
  50. clone.object(in.global.FunctionPrototype),
  51. clone.object(in.global.ArrayPrototype),
  52. clone.object(in.global.StringPrototype),
  53. clone.object(in.global.BooleanPrototype),
  54. clone.object(in.global.NumberPrototype),
  55. clone.object(in.global.DatePrototype),
  56. clone.object(in.global.RegExpPrototype),
  57. clone.object(in.global.ErrorPrototype),
  58. clone.object(in.global.EvalErrorPrototype),
  59. clone.object(in.global.TypeErrorPrototype),
  60. clone.object(in.global.RangeErrorPrototype),
  61. clone.object(in.global.ReferenceErrorPrototype),
  62. clone.object(in.global.SyntaxErrorPrototype),
  63. clone.object(in.global.URIErrorPrototype),
  64. }
  65. out.eval = out.globalObject.property["eval"].value.(Value).value.(*_object)
  66. out.globalObject.prototype = out.global.ObjectPrototype
  67. // Not sure if this is necessary, but give some help to the GC
  68. clone.runtime = nil
  69. clone._object = nil
  70. clone._objectStash = nil
  71. clone._dclStash = nil
  72. clone._fnStash = nil
  73. return out
  74. }
  75. func (clone *_clone) object(in *_object) *_object {
  76. if out, exists := clone._object[in]; exists {
  77. return out
  78. }
  79. out := &_object{}
  80. clone._object[in] = out
  81. return in.objectClass.clone(in, out, clone)
  82. }
  83. func (clone *_clone) dclStash(in *_dclStash) (*_dclStash, bool) {
  84. if out, exists := clone._dclStash[in]; exists {
  85. return out, true
  86. }
  87. out := &_dclStash{}
  88. clone._dclStash[in] = out
  89. return out, false
  90. }
  91. func (clone *_clone) objectStash(in *_objectStash) (*_objectStash, bool) {
  92. if out, exists := clone._objectStash[in]; exists {
  93. return out, true
  94. }
  95. out := &_objectStash{}
  96. clone._objectStash[in] = out
  97. return out, false
  98. }
  99. func (clone *_clone) fnStash(in *_fnStash) (*_fnStash, bool) {
  100. if out, exists := clone._fnStash[in]; exists {
  101. return out, true
  102. }
  103. out := &_fnStash{}
  104. clone._fnStash[in] = out
  105. return out, false
  106. }
  107. func (clone *_clone) value(in Value) Value {
  108. out := in
  109. switch value := in.value.(type) {
  110. case *_object:
  111. out.value = clone.object(value)
  112. }
  113. return out
  114. }
  115. func (clone *_clone) valueArray(in []Value) []Value {
  116. out := make([]Value, len(in))
  117. for index, value := range in {
  118. out[index] = clone.value(value)
  119. }
  120. return out
  121. }
  122. func (clone *_clone) stash(in _stash) _stash {
  123. if in == nil {
  124. return nil
  125. }
  126. return in.clone(clone)
  127. }
  128. func (clone *_clone) property(in _property) _property {
  129. out := in
  130. switch value := in.value.(type) {
  131. case Value:
  132. out.value = clone.value(value)
  133. case _propertyGetSet:
  134. p := _propertyGetSet{}
  135. if value[0] != nil {
  136. p[0] = clone.object(value[0])
  137. }
  138. if value[1] != nil {
  139. p[1] = clone.object(value[1])
  140. }
  141. out.value = p
  142. default:
  143. panic(fmt.Errorf("in.value.(Value) != true; in.value is %T", in.value))
  144. }
  145. return out
  146. }
  147. func (clone *_clone) dclProperty(in _dclProperty) _dclProperty {
  148. out := in
  149. out.value = clone.value(in.value)
  150. return out
  151. }