|
@@ -76,12 +76,35 @@ type reflectTypeInfo struct {
|
|
FieldNames, MethodNames []string
|
|
FieldNames, MethodNames []string
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+type reflectValueWrapper interface {
|
|
|
|
+ esValue() Value
|
|
|
|
+ reflectValue() reflect.Value
|
|
|
|
+ setReflectValue(reflect.Value)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func isContainer(k reflect.Kind) bool {
|
|
|
|
+ switch k {
|
|
|
|
+ case reflect.Struct, reflect.Slice, reflect.Array:
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ return false
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func copyReflectValueWrapper(w reflectValueWrapper) {
|
|
|
|
+ v := w.reflectValue()
|
|
|
|
+ c := reflect.New(v.Type()).Elem()
|
|
|
|
+ c.Set(v)
|
|
|
|
+ w.setReflectValue(c)
|
|
|
|
+}
|
|
|
|
+
|
|
type objectGoReflect struct {
|
|
type objectGoReflect struct {
|
|
baseObject
|
|
baseObject
|
|
origValue, value reflect.Value
|
|
origValue, value reflect.Value
|
|
|
|
|
|
valueTypeInfo, origValueTypeInfo *reflectTypeInfo
|
|
valueTypeInfo, origValueTypeInfo *reflectTypeInfo
|
|
|
|
|
|
|
|
+ valueCache map[string]reflectValueWrapper
|
|
|
|
+
|
|
toJson func() interface{}
|
|
toJson func() interface{}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -104,7 +127,7 @@ func (o *objectGoReflect) init() {
|
|
o.class = classObject
|
|
o.class = classObject
|
|
o.prototype = o.val.runtime.global.ObjectPrototype
|
|
o.prototype = o.val.runtime.global.ObjectPrototype
|
|
if !o.value.CanAddr() {
|
|
if !o.value.CanAddr() {
|
|
- value := reflect.Indirect(reflect.New(o.value.Type()))
|
|
|
|
|
|
+ value := reflect.New(o.value.Type()).Elem()
|
|
value.Set(o.value)
|
|
value.Set(o.value)
|
|
o.origValue = value
|
|
o.origValue = value
|
|
o.value = value
|
|
o.value = value
|
|
@@ -140,8 +163,7 @@ func (o *objectGoReflect) getStr(name unistring.String, receiver Value) Value {
|
|
|
|
|
|
func (o *objectGoReflect) _getField(jsName string) reflect.Value {
|
|
func (o *objectGoReflect) _getField(jsName string) reflect.Value {
|
|
if info, exists := o.valueTypeInfo.Fields[jsName]; exists {
|
|
if info, exists := o.valueTypeInfo.Fields[jsName]; exists {
|
|
- v := o.value.FieldByIndex(info.Index)
|
|
|
|
- return v
|
|
|
|
|
|
+ return o.value.FieldByIndex(info.Index)
|
|
}
|
|
}
|
|
|
|
|
|
return reflect.Value{}
|
|
return reflect.Value{}
|
|
@@ -155,15 +177,58 @@ func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
|
|
return reflect.Value{}
|
|
return reflect.Value{}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrapper) {
|
|
|
|
+ if isContainer(ev.Kind()) {
|
|
|
|
+ if ev.Type() == reflectTypeArray {
|
|
|
|
+ a := o.val.runtime.newObjectGoSlice(ev.Addr().Interface().(*[]interface{}))
|
|
|
|
+ return a.val, a
|
|
|
|
+ }
|
|
|
|
+ ret := o.val.runtime.reflectValueToValue(ev)
|
|
|
|
+ if obj, ok := ret.(*Object); ok {
|
|
|
|
+ if w, ok := obj.self.(reflectValueWrapper); ok {
|
|
|
|
+ return ret, w
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ panic("reflectValueToValue() returned a value which is not a reflectValueWrapper")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for ev.Kind() == reflect.Interface {
|
|
|
|
+ ev = ev.Elem()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ev.Kind() == reflect.Invalid {
|
|
|
|
+ return _null, nil
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return o.val.runtime.ToValue(ev.Interface()), nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (o *objectGoReflect) _getFieldValue(name string) Value {
|
|
|
|
+ if v := o.valueCache[name]; v != nil {
|
|
|
|
+ return v.esValue()
|
|
|
|
+ }
|
|
|
|
+ if v := o._getField(name); v.IsValid() {
|
|
|
|
+ res, w := o.elemToValue(v)
|
|
|
|
+ if w != nil {
|
|
|
|
+ if o.valueCache == nil {
|
|
|
|
+ o.valueCache = make(map[string]reflectValueWrapper)
|
|
|
|
+ }
|
|
|
|
+ o.valueCache[name] = w
|
|
|
|
+ }
|
|
|
|
+ return res
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
+
|
|
func (o *objectGoReflect) _get(name string) Value {
|
|
func (o *objectGoReflect) _get(name string) Value {
|
|
if o.value.Kind() == reflect.Struct {
|
|
if o.value.Kind() == reflect.Struct {
|
|
- if v := o._getField(name); v.IsValid() {
|
|
|
|
- return o.val.runtime.toValue(v.Interface(), v)
|
|
|
|
|
|
+ if ret := o._getFieldValue(name); ret != nil {
|
|
|
|
+ return ret
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if v := o._getMethod(name); v.IsValid() {
|
|
if v := o._getMethod(name); v.IsValid() {
|
|
- return o.val.runtime.toValue(v.Interface(), v)
|
|
|
|
|
|
+ return o.val.runtime.reflectValueToValue(v)
|
|
}
|
|
}
|
|
|
|
|
|
return nil
|
|
return nil
|
|
@@ -172,10 +237,10 @@ func (o *objectGoReflect) _get(name string) Value {
|
|
func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
|
|
func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
|
|
n := name.String()
|
|
n := name.String()
|
|
if o.value.Kind() == reflect.Struct {
|
|
if o.value.Kind() == reflect.Struct {
|
|
- if v := o._getField(n); v.IsValid() {
|
|
|
|
|
|
+ if v := o._getFieldValue(n); v != nil {
|
|
return &valueProperty{
|
|
return &valueProperty{
|
|
- value: o.val.runtime.toValue(v.Interface(), v),
|
|
|
|
- writable: v.CanSet(),
|
|
|
|
|
|
+ value: v,
|
|
|
|
+ writable: true,
|
|
enumerable: true,
|
|
enumerable: true,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -183,7 +248,7 @@ func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
|
|
|
|
|
|
if v := o._getMethod(n); v.IsValid() {
|
|
if v := o._getMethod(n); v.IsValid() {
|
|
return &valueProperty{
|
|
return &valueProperty{
|
|
- value: o.val.runtime.toValue(v.Interface(), v),
|
|
|
|
|
|
+ value: o.val.runtime.reflectValueToValue(v),
|
|
enumerable: true,
|
|
enumerable: true,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -215,15 +280,22 @@ func (o *objectGoReflect) setForeignIdx(idx valueInt, val, receiver Value, throw
|
|
func (o *objectGoReflect) _put(name string, val Value, throw bool) (has, ok bool) {
|
|
func (o *objectGoReflect) _put(name string, val Value, throw bool) (has, ok bool) {
|
|
if o.value.Kind() == reflect.Struct {
|
|
if o.value.Kind() == reflect.Struct {
|
|
if v := o._getField(name); v.IsValid() {
|
|
if v := o._getField(name); v.IsValid() {
|
|
- if !v.CanSet() {
|
|
|
|
- o.val.runtime.typeErrorResult(throw, "Cannot assign to a non-addressable or read-only property %s of a host object", name)
|
|
|
|
- return true, false
|
|
|
|
|
|
+ cached := o.valueCache[name]
|
|
|
|
+ if cached != nil {
|
|
|
|
+ copyReflectValueWrapper(cached)
|
|
}
|
|
}
|
|
|
|
+
|
|
err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
|
|
err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
|
|
if err != nil {
|
|
if err != nil {
|
|
|
|
+ if cached != nil {
|
|
|
|
+ cached.setReflectValue(v)
|
|
|
|
+ }
|
|
o.val.runtime.typeErrorResult(throw, "Go struct conversion error: %v", err)
|
|
o.val.runtime.typeErrorResult(throw, "Go struct conversion error: %v", err)
|
|
return true, false
|
|
return true, false
|
|
}
|
|
}
|
|
|
|
+ if cached != nil {
|
|
|
|
+ delete(o.valueCache, name)
|
|
|
|
+ }
|
|
return true, true
|
|
return true, true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -413,11 +485,24 @@ func (o *objectGoReflect) exportType() reflect.Type {
|
|
|
|
|
|
func (o *objectGoReflect) equal(other objectImpl) bool {
|
|
func (o *objectGoReflect) equal(other objectImpl) bool {
|
|
if other, ok := other.(*objectGoReflect); ok {
|
|
if other, ok := other.(*objectGoReflect); ok {
|
|
- return o.value.Interface() == other.value.Interface()
|
|
|
|
|
|
+ return o.value == other.value
|
|
}
|
|
}
|
|
return false
|
|
return false
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func (o *objectGoReflect) reflectValue() reflect.Value {
|
|
|
|
+ return o.value
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (o *objectGoReflect) setReflectValue(v reflect.Value) {
|
|
|
|
+ o.value = v
|
|
|
|
+ o.origValue = v
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (o *objectGoReflect) esValue() Value {
|
|
|
|
+ return o.val
|
|
|
|
+}
|
|
|
|
+
|
|
func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectTypeInfo) {
|
|
func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectTypeInfo) {
|
|
n := t.NumField()
|
|
n := t.NumField()
|
|
for i := 0; i < n; i++ {
|
|
for i := 0; i < n; i++ {
|