blob: c632aba784bc1574c884c923f501c175f56ffa7a [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package jdwp
import (
"fmt"
"reflect"
"android.googlesource.com/platform/tools/gpu/framework/binary"
)
// debug adds panic handlers to encode() and decode() so that incorrectly
// handled types can be more easily identified.
const debug = false
func unbox(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface {
return v.Elem()
}
return v
}
// encode writes the value v to w, using the JDWP encoding scheme.
func (c *Connection) encode(w binary.Writer, v reflect.Value) error {
if debug {
defer func() {
if r := recover(); r != nil {
panic(fmt.Errorf("Type %T %v %v", v.Interface(), v.Type().Name(), v.Kind()))
}
}()
}
t := v.Type()
o := v.Interface()
switch v.Type() {
case reflect.TypeOf((*EventModifier)(nil)).Elem():
// EventModifier's are prefixed with their 1-byte modKind.
w.Uint8(o.(EventModifier).modKind())
case reflect.TypeOf((*Value)(nil)).Elem():
// values are prefixed with their 1-tag type.
switch o.(type) {
case ArrayID:
w.Uint8(uint8(TagArray))
case byte:
w.Uint8(uint8(TagByte))
case Char:
w.Uint8(uint8(TagChar))
case ObjectID:
w.Uint8(uint8(TagObject))
case float32:
w.Uint8(uint8(TagFloat))
case float64:
w.Uint8(uint8(TagDouble))
case int, int32:
w.Uint8(uint8(TagInt))
case int16:
w.Uint8(uint8(TagShort))
case int64:
w.Uint8(uint8(TagLong))
case nil:
w.Uint8(uint8(TagVoid))
case bool:
w.Uint8(uint8(TagBoolean))
case StringID:
w.Uint8(uint8(TagString))
case ThreadID:
w.Uint8(uint8(TagThread))
case ThreadGroupID:
w.Uint8(uint8(TagThreadGroup))
case ClassLoaderID:
w.Uint8(uint8(TagClassLoader))
case ClassObjectID:
w.Uint8(uint8(TagClassObject))
default:
panic(fmt.Errorf("Got Value of type %T", o))
}
}
switch o := o.(type) {
case ReferenceTypeID, ClassID, InterfaceID, ArrayTypeID:
binary.WriteUint(w, c.idSizes.ReferenceTypeIDSize*8, unbox(v).Uint())
case MethodID:
binary.WriteUint(w, c.idSizes.MethodIDSize*8, unbox(v).Uint())
case ObjectID, ThreadID, ThreadGroupID, StringID, ClassLoaderID, ClassObjectID, ArrayID:
binary.WriteUint(w, c.idSizes.ObjectIDSize*8, unbox(v).Uint())
case []byte: // Optimisation
w.Uint32(uint32(len(o)))
w.Data(o)
default:
switch t.Kind() {
case reflect.Ptr, reflect.Interface:
return c.encode(w, v.Elem())
case reflect.String:
w.Uint32(uint32(v.Len()))
w.Data([]byte(v.String()))
case reflect.Uint8:
w.Uint8(uint8(v.Uint()))
case reflect.Uint64:
w.Uint64(uint64(v.Uint()))
case reflect.Int8:
w.Int8(int8(v.Int()))
case reflect.Int16:
w.Int16(int16(v.Int()))
case reflect.Int32, reflect.Int:
w.Int32(int32(v.Int()))
case reflect.Int64:
w.Int64(v.Int())
case reflect.Float32:
w.Float32(float32(v.Float()))
case reflect.Float64:
w.Float64(v.Float())
case reflect.Struct:
for i, count := 0, v.NumField(); i < count; i++ {
c.encode(w, v.Field(i))
}
case reflect.Slice:
count := v.Len()
w.Uint32(uint32(count))
for i := 0; i < count; i++ {
c.encode(w, v.Index(i))
}
default:
panic(fmt.Errorf("Unhandled type %T %v %v", o, t.Name(), t.Kind()))
}
}
return w.Error()
}
// decode reads the value v from r, using the JDWP encoding scheme.
func (c *Connection) decode(r binary.Reader, v reflect.Value) error {
if debug {
defer func() {
if r := recover(); r != nil {
panic(fmt.Errorf("Type %T %v %v", v.Interface(), v.Type().Name(), v.Kind()))
}
}()
}
switch v.Type() {
case reflect.TypeOf((*Event)(nil)).Elem():
var kind EventKind
if err := c.decode(r, reflect.ValueOf(&kind)); err != nil {
return err
}
event := kind.event()
v.Set(reflect.ValueOf(event))
v = v.Elem()
// Continue to decode event body below.
case reflect.TypeOf((*Value)(nil)).Elem():
tag := Tag(r.Uint8())
var ty reflect.Type
switch tag {
case TagArray:
ty = reflect.TypeOf(ArrayID(0))
case TagByte:
ty = reflect.TypeOf(byte(0))
case TagChar:
ty = reflect.TypeOf(Char(0))
case TagObject:
ty = reflect.TypeOf(ObjectID(0))
case TagFloat:
ty = reflect.TypeOf(float32(0))
case TagDouble:
ty = reflect.TypeOf(float64(0))
case TagInt:
ty = reflect.TypeOf(int(0))
case TagShort:
ty = reflect.TypeOf(int16(0))
case TagLong:
ty = reflect.TypeOf(int64(0))
case TagBoolean:
ty = reflect.TypeOf(false)
case TagString:
ty = reflect.TypeOf(StringID(0))
case TagThread:
ty = reflect.TypeOf(ThreadID(0))
case TagThreadGroup:
ty = reflect.TypeOf(ThreadGroupID(0))
case TagClassLoader:
ty = reflect.TypeOf(ClassLoaderID(0))
case TagClassObject:
ty = reflect.TypeOf(ClassObjectID(0))
case TagVoid:
v.Set(reflect.New(v.Type()).Elem())
return r.Error()
default:
panic(fmt.Errorf("Unhandled value type %v", tag))
}
data := reflect.New(ty).Elem()
c.decode(r, data)
v.Set(data)
return r.Error()
}
t := v.Type()
o := v.Interface()
switch o := o.(type) {
case ReferenceTypeID, ClassID, InterfaceID, ArrayTypeID:
v.Set(reflect.ValueOf(binary.ReadUint(r, c.idSizes.ReferenceTypeIDSize*8)).Convert(t))
case MethodID:
v.Set(reflect.ValueOf(binary.ReadUint(r, c.idSizes.MethodIDSize*8)).Convert(t))
case ObjectID, ThreadID, ThreadGroupID, StringID, ClassLoaderID, ClassObjectID, ArrayID:
v.Set(reflect.ValueOf(binary.ReadUint(r, c.idSizes.ObjectIDSize*8)).Convert(t))
case EventModifier:
panic("Cannot decode EventModifiers")
default:
switch t.Kind() {
case reflect.Ptr, reflect.Interface:
return c.decode(r, v.Elem())
case reflect.String:
data := make([]byte, r.Uint32())
r.Data(data)
v.Set(reflect.ValueOf(string(data)).Convert(t))
case reflect.Bool:
v.Set(reflect.ValueOf(r.Bool()).Convert(t))
case reflect.Uint8:
v.Set(reflect.ValueOf(r.Uint8()).Convert(t))
case reflect.Uint64:
v.Set(reflect.ValueOf(r.Uint64()).Convert(t))
case reflect.Int8:
v.Set(reflect.ValueOf(r.Int8()).Convert(t))
case reflect.Int16:
v.Set(reflect.ValueOf(r.Int16()).Convert(t))
case reflect.Int32, reflect.Int:
v.Set(reflect.ValueOf(r.Int32()).Convert(t))
case reflect.Int64:
v.Set(reflect.ValueOf(r.Int64()).Convert(t))
case reflect.Struct:
for i, count := 0, v.NumField(); i < count; i++ {
c.decode(r, v.Field(i))
}
case reflect.Slice:
count := int(r.Uint32())
slice := reflect.MakeSlice(t, count, count)
for i := 0; i < count; i++ {
c.decode(r, slice.Index(i))
}
v.Set(slice)
default:
panic(fmt.Errorf("Unhandled type %T %v %v", o, t.Name(), t.Kind()))
}
}
return r.Error()
}