Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

java: Removed the need for ClassDecoder and the unsafe, reflect pkgs.

for #2
  • Loading branch information...
commit 0ec7460112fee645d58a921dcb175c4a358ad53f 1 parent 1e76642
@quarnster authored
Showing with 162 additions and 178 deletions.
  1. +156 −172 java/class.go
  2. +1 −1  java/class_all_test.go
  3. +5 −5 java/completion.go
View
328 java/class.go
@@ -6,8 +6,6 @@ import (
"fmt"
"github.com/quarnster/completion/util"
"io"
- "reflect"
- "unsafe"
)
/*
@@ -20,9 +18,10 @@ type (
u4 uint32
Constant struct {
- tag u1
- index [2]u2
- value string
+ cp *ConstantPool
+ Tag u1
+ Index [2]u2
+ Value string
}
AccessFlags u2
@@ -30,52 +29,163 @@ type (
Access_flags AccessFlags
Name_index u2
Descriptor_index u2
- Attributes []attribute_info
+ Attributes_count u2
+ Attributes []attribute_info `length:"Attributes_count"`
}
attribute_info struct {
Attribute_name_index u2
- Info []byte
+ Attribute_length u4
+ Info []byte `length:"Attribute_length"`
+ }
+
+ ConstantPool struct {
+ constants []Constant
}
Class struct {
- Magic u4
- Minor_version u2
- Major_version u2
- Constant_pool []Constant
- Access_flags AccessFlags
- This_class u2
- Super_class u2
- Interfaces []u2
- RawFields []member_info
- RawMethods []member_info
- Attributes []attribute_info
+ Magic u4
+ Minor_version u2
+ Major_version u2
+ Constant_pool ConstantPool
+ Access_flags AccessFlags
+ This_class u2
+ Super_class u2
+ Interfaces_count u2
+ Interfaces []u2 `length:"Interfaces_count"`
+ Field_count u2
+ RawFields []member_info `length:"Field_count"`
+ Method_count u2
+ RawMethods []member_info `length:"Method_count"`
+ Attribute_count u2
+ Attributes []attribute_info `length:"Attribute_count"`
}
- ClassDecoder struct {
- reader util.BinaryReader
- err error
+ // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.3
+ exception_table struct {
+ start_pc u2
+ end_pc u2
+ handler_pc u2
+ catch_type u2
+ }
+ Code_attribute struct {
+ Attribute_name_index u2
+ Attribute_length u4
+ Max_stack u2
+ Max_locals u2
+ Code_length u4
+ Code []u1 `length:"Code_length"`
+ Exception_table_length u2
+ Exception_table []exception_table `length:"Exception_table_length"`
+ Attributes_count u2
+ Attributes []attribute_info `length:"Attributes_count"`
}
)
-func String(lut []Constant, idx u2) string {
- if idx > 0 && int(idx) <= len(lut) {
- return lut[idx-1].String(lut)
+func (cp *ConstantPool) readConstant(c *Constant, br *util.BinaryReader) error {
+ if err := br.ReadInterface(&c.Tag); err != nil {
+ return err
+ } else {
+ switch c.Tag {
+ case CONSTANT_String:
+ fallthrough
+ case CONSTANT_MethodType:
+ fallthrough
+ case CONSTANT_Class:
+ return br.ReadInterface(&c.Index[0])
+ case CONSTANT_Fieldref:
+ fallthrough
+ case CONSTANT_Methodref:
+ fallthrough
+ case CONSTANT_NameAndType:
+ fallthrough
+ case CONSTANT_InvokeDynamic:
+ fallthrough
+ case CONSTANT_InterfaceMethodref:
+ if err := br.ReadInterface(&c.Index[0]); err != nil {
+ return err
+ } else {
+ return br.ReadInterface(&c.Index[1])
+ }
+ case CONSTANT_Integer:
+ var v int32
+ return br.ReadInterface(&v)
+ case CONSTANT_Float:
+ var v float32
+ return br.ReadInterface(&v)
+ case CONSTANT_Long:
+ var v int64
+ return br.ReadInterface(&v)
+ case CONSTANT_Double:
+ var v float64
+ return br.ReadInterface(&v)
+ case CONSTANT_Utf8:
+ var length u2
+ if err := br.ReadInterface(&length); err != nil {
+ return err
+ } else if d, err := br.Read(int(length)); err != nil {
+ return err
+ } else {
+ c.Value = string(d)
+ }
+ case CONSTANT_MethodHandle:
+ var ref_kind u1
+ if err := br.ReadInterface(&ref_kind); err != nil {
+ return err
+ } else {
+ c.Index[0] = u2(ref_kind)
+ return br.ReadInterface(&c.Index[1])
+ }
+ default:
+ return errors.New(fmt.Sprintf("Unimplemented tag: %d", c.Tag))
+ }
}
- return fmt.Sprintf("Invalid index: %d", idx)
+ return nil
}
-func (c Constant) String(lut []Constant) string {
- switch c.tag {
+func (c *ConstantPool) Read(br *util.BinaryReader) error {
+ var count uint16
+ if err := br.ReadInterface(&count); err != nil {
+ return err
+ } else {
+ ic := int(count)
+ ic--
+ c.constants = make([]Constant, ic, ic)
+
+ for i := 0; i < len(c.constants); i++ {
+ cc := &c.constants[i]
+ cc.cp = c
+ if err := c.readConstant(cc, br); err != nil {
+ return err
+ }
+
+ if cc.Tag == CONSTANT_Double || cc.Tag == CONSTANT_Long {
+ // All 8-byte constants take up two entries in the constant_pool table of the class file.
+ i++
+ }
+ }
+ }
+ return nil
+}
+
+func (c *ConstantPool) Lut(idx u2) *Constant {
+ if idx > 0 && int(idx) <= len(c.constants) {
+ return &c.constants[idx-1]
+ }
+ return nil
+}
+
+func (c *Constant) String() string {
+ switch c.Tag {
case CONSTANT_Utf8:
- return c.value
+ return c.Value
case CONSTANT_String:
fallthrough
case CONSTANT_MethodType:
fallthrough
case CONSTANT_Class:
- return String(lut, c.index[0])
+ return fmt.Sprintf("%s", c.cp.Lut(c.Index[0]))
}
- return fmt.Sprintf("Non-stringed tag: %d", c.tag)
+ return fmt.Sprintf("Non-stringed tag: %d", c.Tag)
}
func (a AccessFlags) String() (ret string) {
@@ -109,27 +219,26 @@ func (a AccessFlags) String() (ret string) {
return ret
}
-func (mi *member_info) String(c []Constant) string {
+func (mi *member_info) String(c *ConstantPool) string {
ret := mi.Access_flags.String()
- ret += String(c, mi.Name_index)
- ret += " " + String(c, mi.Descriptor_index)
+ ret += fmt.Sprintf("%s %s", c.Lut(mi.Name_index), c.Lut(mi.Descriptor_index))
return ret
}
func (c *Class) String() (ret string) {
- ret += fmt.Sprintf("%sclass %s\n", c.Access_flags, String(c.Constant_pool, c.This_class))
- ret += fmt.Sprintln("extends", String(c.Constant_pool, c.Super_class))
+ ret += fmt.Sprintf("%sclass %s\n", c.Access_flags, c.Constant_pool.Lut(c.This_class))
+ ret += fmt.Sprintln("extends", c.Constant_pool.Lut(c.Super_class))
ret += fmt.Sprintln("implements")
for _, i := range c.Interfaces {
- ret += fmt.Sprintf("\t%s\n", String(c.Constant_pool, i))
+ ret += fmt.Sprintf("\t%s\n", c.Constant_pool.Lut(i))
}
ret += fmt.Sprintln("Fields")
for _, f := range c.RawFields {
- ret += fmt.Sprintf("\t%s\n", f.String(c.Constant_pool))
+ ret += fmt.Sprintf("\t%s\n", f.String(&c.Constant_pool))
}
ret += fmt.Sprintln("Methods")
for _, m := range c.RawMethods {
- ret += fmt.Sprintf("\t%s\n", m.String(c.Constant_pool))
+ ret += fmt.Sprintf("\t%s\n", m.String(&c.Constant_pool))
}
return ret
}
@@ -153,155 +262,30 @@ const (
)
const (
- // Declared public; may be accessed from outside its package.
+ // public Declared may be accessed from outside its package.
ACC_PUBLIC = 0x0001
- // Declared private; usable only within the defining class.
+ // private Declared usable only within the defining class.
ACC_PRIVATE = 0x0002
- // Declared protected; may be accessed within subclasses.
+ // protected Declared may be accessed within subclasses.
ACC_PROTECTED = 0x0004
// Declared static.
ACC_STATIC = 0x0008
- // Declared final; never directly assigned to after object construction (JLS §17.5).
+ // final Declared never directly assigned to after object construction (JLS §17.5).
ACC_FINAL = 0x0010
- // Declared volatile; cannot be cached.
+ // volatile Declared cannot be cached.
ACC_VOLATILE = 0x0040
- // Declared transient; not written or read by a persistent object manager.
+ // transient Declared not written or read by a persistent object manager.
ACC_TRANSIENT = 0x0080
- // Declared synthetic; not present in the source code.
+ // synthetic Declared not present in the source code.
ACC_SYNTHETIC = 0x1000
// Declared as an element of an enum.
ACC_ENUM = 0x4000
)
-func (dec *ClassDecoder) Decode(v interface{}) error {
- t := reflect.ValueOf(v)
- if t.Kind() != reflect.Ptr {
- return errors.New(fmt.Sprintf("Expected a pointer not %s", t.Kind()))
- }
- v2 := t.Elem()
-
- switch v2.Type().Name() {
- case "Constant":
- c := (*Constant)(unsafe.Pointer(t.Pointer()))
- if err := dec.Decode(&c.tag); err != nil {
- return err
- } else {
- switch c.tag {
- case CONSTANT_String:
- fallthrough
- case CONSTANT_MethodType:
- fallthrough
- case CONSTANT_Class:
- return dec.Decode(&c.index[0])
- case CONSTANT_Fieldref:
- fallthrough
- case CONSTANT_Methodref:
- fallthrough
- case CONSTANT_NameAndType:
- fallthrough
- case CONSTANT_InvokeDynamic:
- fallthrough
- case CONSTANT_InterfaceMethodref:
- if err := dec.Decode(&c.index[0]); err != nil {
- return err
- } else {
- return dec.Decode(&c.index[1])
- }
- case CONSTANT_Integer:
- var v int32
- return dec.Decode(&v)
- case CONSTANT_Float:
- var v float32
- return dec.Decode(&v)
- case CONSTANT_Long:
- var v int64
- return dec.Decode(&v)
- case CONSTANT_Double:
- var v float64
- return dec.Decode(&v)
- case CONSTANT_Utf8:
- var length u2
- if err := dec.Decode(&length); err != nil {
- return err
- } else if d, err := dec.reader.Read(int(length)); err != nil {
- return err
- } else {
- c.value = string(d)
- }
- case CONSTANT_MethodHandle:
- var ref_kind u1
- if err := dec.Decode(&ref_kind); err != nil {
- return err
- } else {
- c.index[0] = u2(ref_kind)
- return dec.Decode(&c.index[1])
- }
- default:
- return errors.New(fmt.Sprintf("Unimplemented tag: %d", c.tag))
- }
- }
- default:
- switch v2.Kind() {
- case reflect.Struct:
- for i := 0; i < v2.NumField(); i++ {
- f := v2.Field(i)
- if v2.Type().Name() == "attribute_info" && f.Kind() == reflect.Slice {
- var length u4
- if err := dec.Decode(&length); err != nil {
- return err
- } else {
- if d, err := dec.reader.Read(int(length)); err != nil {
- return err
- } else {
- f.SetBytes(d)
- }
- }
- } else {
- a := f.Addr()
- if err := dec.Decode(a.Interface()); err != nil {
- return err
- }
- }
- }
- case reflect.Slice:
- var count uint16
- if err := dec.Decode(&count); err != nil {
- return err
- } else {
- ic := int(count)
- isConstantPool := v2.Type().String() == "[]java.Constant"
- if isConstantPool {
- ic--
- }
- v2.Set(reflect.MakeSlice(v2.Type(), ic, ic))
-
- for i := 0; i < v2.Len(); i++ {
- f := v2.Index(i)
- a := f.Addr()
-
- if err := dec.Decode(a.Interface()); err != nil {
- return err
- }
- if isConstantPool {
- c := (*Constant)(unsafe.Pointer(a.Pointer()))
- if c.tag == CONSTANT_Double || c.tag == CONSTANT_Long {
- // All 8-byte constants take up two entries in the constant_pool table of the class file.
- i++
- }
- }
- }
- }
- default:
- return dec.reader.ReadInterface(v)
- }
- }
- return nil
-}
-
func NewClass(reader io.ReadSeeker) (*Class, error) {
- r := ClassDecoder{util.BinaryReader{reader, binary.BigEndian}, nil}
+ r := util.BinaryReader{reader, binary.BigEndian}
var c Class
- if err := r.Decode(&c); err != nil {
+ if err := r.ReadInterface(&c); err != nil {
return nil, err
} else if c.Magic != magic {
return nil, errors.New(fmt.Sprintf("Magic isn't what's expected: %x", c.Magic))
View
2  java/class_all_test.go
@@ -31,7 +31,7 @@ func TestLoadAllClasses(t *testing.T) {
if c, err := NewClass(f); err != nil {
outChan <- err
} else {
- t.Log("class", String(c.Constant_pool, c.This_class))
+ t.Log("class", c.Constant_pool.Lut(c.This_class))
}
}
wg.Done()
View
10 java/completion.go
@@ -26,7 +26,7 @@ func (af AccessFlags) ToContentFlags() (ret content.Flags) {
}
func (c *Class) ToContentFQN(index u2) (ret content.FullyQualifiedName) {
- ret.Absolute = strings.Replace(String(c.Constant_pool, index), "/", ".", -1)
+ ret.Absolute = strings.Replace(c.Constant_pool.Lut(index).String(), "/", ".", -1)
ret.Relative = ret.Absolute
if i := strings.LastIndex(ret.Absolute, "."); i > 0 {
ret.Relative = ret.Relative[i+1:]
@@ -37,10 +37,10 @@ func (c *Class) ToContentFQN(index u2) (ret content.FullyQualifiedName) {
func (c *Class) Fields() (fields []content.Field, err error) {
for _, inf := range c.RawFields {
var p descriptors.DESCRIPTORS
- p.Parse(String(c.Constant_pool, inf.Descriptor_index))
+ p.Parse(c.Constant_pool.Lut(inf.Descriptor_index).String())
outf := descriptors.ToContentField(p.RootNode().Children[0])
outf.Flags = inf.Access_flags.ToContentFlags()
- outf.Name.Relative = String(c.Constant_pool, inf.Name_index)
+ outf.Name.Relative = c.Constant_pool.Lut(inf.Name_index).String()
fields = append(fields, outf)
}
return
@@ -49,10 +49,10 @@ func (c *Class) Fields() (fields []content.Field, err error) {
func (c *Class) Methods() (methods []content.Method, err error) {
for _, inf := range c.RawMethods {
var p descriptors.DESCRIPTORS
- p.Parse(String(c.Constant_pool, inf.Descriptor_index))
+ p.Parse(c.Constant_pool.Lut(inf.Descriptor_index).String())
outf := descriptors.ToContentMethod(p.RootNode().Children[0])
outf.Flags = inf.Access_flags.ToContentFlags()
- outf.Name.Relative = String(c.Constant_pool, inf.Name_index)
+ outf.Name.Relative = c.Constant_pool.Lut(inf.Name_index).String()
methods = append(methods, outf)
}
return
Please sign in to comment.
Something went wrong with that request. Please try again.