2024-02-24 21:00:04 +00:00
|
|
|
package otto
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
type cloner struct {
|
|
|
|
runtime *runtime
|
|
|
|
obj map[*object]*object
|
|
|
|
objectstash map[*objectStash]*objectStash
|
|
|
|
dclstash map[*dclStash]*dclStash
|
|
|
|
fnstash map[*fnStash]*fnStash
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (rt *runtime) clone() *runtime {
|
|
|
|
rt.lck.Lock()
|
|
|
|
defer rt.lck.Unlock()
|
2024-02-24 21:00:04 +00:00
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
out := &runtime{
|
|
|
|
debugger: rt.debugger,
|
|
|
|
random: rt.random,
|
|
|
|
stackLimit: rt.stackLimit,
|
|
|
|
traceLimit: rt.traceLimit,
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
c := cloner{
|
|
|
|
runtime: out,
|
|
|
|
obj: make(map[*object]*object),
|
|
|
|
objectstash: make(map[*objectStash]*objectStash),
|
|
|
|
dclstash: make(map[*dclStash]*dclStash),
|
|
|
|
fnstash: make(map[*fnStash]*fnStash),
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
globalObject := c.object(rt.globalObject)
|
2024-02-24 21:00:04 +00:00
|
|
|
out.globalStash = out.newObjectStash(globalObject, nil)
|
|
|
|
out.globalObject = globalObject
|
2024-04-04 14:46:14 +00:00
|
|
|
out.global = global{
|
|
|
|
c.object(rt.global.Object),
|
|
|
|
c.object(rt.global.Function),
|
|
|
|
c.object(rt.global.Array),
|
|
|
|
c.object(rt.global.String),
|
|
|
|
c.object(rt.global.Boolean),
|
|
|
|
c.object(rt.global.Number),
|
|
|
|
c.object(rt.global.Math),
|
|
|
|
c.object(rt.global.Date),
|
|
|
|
c.object(rt.global.RegExp),
|
|
|
|
c.object(rt.global.Error),
|
|
|
|
c.object(rt.global.EvalError),
|
|
|
|
c.object(rt.global.TypeError),
|
|
|
|
c.object(rt.global.RangeError),
|
|
|
|
c.object(rt.global.ReferenceError),
|
|
|
|
c.object(rt.global.SyntaxError),
|
|
|
|
c.object(rt.global.URIError),
|
|
|
|
c.object(rt.global.JSON),
|
|
|
|
|
|
|
|
c.object(rt.global.ObjectPrototype),
|
|
|
|
c.object(rt.global.FunctionPrototype),
|
|
|
|
c.object(rt.global.ArrayPrototype),
|
|
|
|
c.object(rt.global.StringPrototype),
|
|
|
|
c.object(rt.global.BooleanPrototype),
|
|
|
|
c.object(rt.global.NumberPrototype),
|
|
|
|
c.object(rt.global.DatePrototype),
|
|
|
|
c.object(rt.global.RegExpPrototype),
|
|
|
|
c.object(rt.global.ErrorPrototype),
|
|
|
|
c.object(rt.global.EvalErrorPrototype),
|
|
|
|
c.object(rt.global.TypeErrorPrototype),
|
|
|
|
c.object(rt.global.RangeErrorPrototype),
|
|
|
|
c.object(rt.global.ReferenceErrorPrototype),
|
|
|
|
c.object(rt.global.SyntaxErrorPrototype),
|
|
|
|
c.object(rt.global.URIErrorPrototype),
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
out.eval = out.globalObject.property["eval"].value.(Value).value.(*object)
|
2024-02-24 21:00:04 +00:00
|
|
|
out.globalObject.prototype = out.global.ObjectPrototype
|
|
|
|
|
|
|
|
// Not sure if this is necessary, but give some help to the GC
|
2024-04-04 14:46:14 +00:00
|
|
|
c.runtime = nil
|
|
|
|
c.obj = nil
|
|
|
|
c.objectstash = nil
|
|
|
|
c.dclstash = nil
|
|
|
|
c.fnstash = nil
|
2024-02-24 21:00:04 +00:00
|
|
|
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) object(in *object) *object {
|
|
|
|
if out, exists := c.obj[in]; exists {
|
2024-02-24 21:00:04 +00:00
|
|
|
return out
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
out := &object{}
|
|
|
|
c.obj[in] = out
|
|
|
|
return in.objectClass.clone(in, out, c)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) dclStash(in *dclStash) (*dclStash, bool) {
|
|
|
|
if out, exists := c.dclstash[in]; exists {
|
2024-02-24 21:00:04 +00:00
|
|
|
return out, true
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
out := &dclStash{}
|
|
|
|
c.dclstash[in] = out
|
2024-02-24 21:00:04 +00:00
|
|
|
return out, false
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) objectStash(in *objectStash) (*objectStash, bool) {
|
|
|
|
if out, exists := c.objectstash[in]; exists {
|
2024-02-24 21:00:04 +00:00
|
|
|
return out, true
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
out := &objectStash{}
|
|
|
|
c.objectstash[in] = out
|
2024-02-24 21:00:04 +00:00
|
|
|
return out, false
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) fnStash(in *fnStash) (*fnStash, bool) {
|
|
|
|
if out, exists := c.fnstash[in]; exists {
|
2024-02-24 21:00:04 +00:00
|
|
|
return out, true
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
out := &fnStash{}
|
|
|
|
c.fnstash[in] = out
|
2024-02-24 21:00:04 +00:00
|
|
|
return out, false
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) value(in Value) Value {
|
2024-02-24 21:00:04 +00:00
|
|
|
out := in
|
2024-04-04 14:46:14 +00:00
|
|
|
if value, ok := in.value.(*object); ok {
|
|
|
|
out.value = c.object(value)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) valueArray(in []Value) []Value {
|
2024-02-24 21:00:04 +00:00
|
|
|
out := make([]Value, len(in))
|
|
|
|
for index, value := range in {
|
2024-04-04 14:46:14 +00:00
|
|
|
out[index] = c.value(value)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) stash(in stasher) stasher {
|
2024-02-24 21:00:04 +00:00
|
|
|
if in == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
return in.clone(c)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) property(in property) property {
|
2024-02-24 21:00:04 +00:00
|
|
|
out := in
|
|
|
|
|
|
|
|
switch value := in.value.(type) {
|
|
|
|
case Value:
|
2024-04-04 14:46:14 +00:00
|
|
|
out.value = c.value(value)
|
|
|
|
case propertyGetSet:
|
|
|
|
p := propertyGetSet{}
|
2024-02-24 21:00:04 +00:00
|
|
|
if value[0] != nil {
|
2024-04-04 14:46:14 +00:00
|
|
|
p[0] = c.object(value[0])
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
if value[1] != nil {
|
2024-04-04 14:46:14 +00:00
|
|
|
p[1] = c.object(value[1])
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
out.value = p
|
|
|
|
default:
|
|
|
|
panic(fmt.Errorf("in.value.(Value) != true; in.value is %T", in.value))
|
|
|
|
}
|
|
|
|
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func (c *cloner) dclProperty(in dclProperty) dclProperty {
|
2024-02-24 21:00:04 +00:00
|
|
|
out := in
|
2024-04-04 14:46:14 +00:00
|
|
|
out.value = c.value(in.value)
|
2024-02-24 21:00:04 +00:00
|
|
|
return out
|
|
|
|
}
|