Skip to content

Commit

Permalink
Code refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
zxh0 committed Oct 24, 2019
1 parent 3d63d08 commit 6005a68
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 65 deletions.
4 changes: 2 additions & 2 deletions classpath/classpath.go
Expand Up @@ -11,10 +11,10 @@ type ClassPath struct {
entries []Entry
}

func Parse(opts vm.Options) *ClassPath {
func Parse(opts *vm.Options) *ClassPath {
cp := &ClassPath{}
cp.parseBootAndExtClassPath(opts.AbsJavaHome)
cp.parseUserClassPath(opts.Classpath)
cp.parseUserClassPath(opts.ClassPath)
return cp
}

Expand Down
85 changes: 65 additions & 20 deletions cmd/java/main.go
Expand Up @@ -13,50 +13,95 @@ import (
"github.com/zxh0/jvm.go/rtda"
"github.com/zxh0/jvm.go/rtda/heap"
"github.com/zxh0/jvm.go/vm"
"github.com/zxh0/jvm.go/vmutils"
)

const usage = `
Usage: {java} [options] class [args...]
or {java} [options] -m <module>[/<mainclass>] [args...]
{java} [options] --module <module>[/<mainclass>] [args...]
`

var (
versionFlag bool
helpFlag bool
listModulesFlag bool
showModuleResolutionFlag bool
)

func main() {
opts, args := parseOptions()
if opts.HelpFlag || len(args) == 0 {
if helpFlag || opts.MainClass == "" {
printUsage()
} else if opts.VersionFlag {
} else if versionFlag {
printVersion()
} else if listModulesFlag {
listModules(opts)
} else if opts.MainModule != "" {
startJVM13(opts, args)
} else {
startJVM(opts, args[0], args[1:])
startJVM8(opts, args)
}
}

func parseOptions() (vm.Options, []string) {
options := vm.Options{}
flag.StringVar(&options.Classpath, "classpath", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.StringVar(&options.Classpath, "cp", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.BoolVar(&options.HelpFlag, "help", false, "Displays usage information and exit.")
flag.BoolVar(&options.HelpFlag, "h", false, "Displays usage information and exit.")
flag.BoolVar(&options.HelpFlag, "?", false, "Displays usage information and exit.")
func parseOptions() (*vm.Options, []string) {
options := &vm.Options{}
flag.BoolVar(&versionFlag, "version", false, "Displays version information and exit.")
flag.BoolVar(&helpFlag, "help", false, "Displays usage information and exit.")
flag.BoolVar(&helpFlag, "h", false, "Displays usage information and exit.")
flag.BoolVar(&helpFlag, "?", false, "Displays usage information and exit.")
flag.BoolVar(&listModulesFlag, "list-modules", false, "Lists observable modules and exit.")
flag.BoolVar(&showModuleResolutionFlag, "show-module-resolution", false, "Shows module resolution output during startup.")
flag.StringVar(&options.Xss, "Xss", "", "Sets the thread stack size.")
flag.StringVar(&options.MainModule, "module", "", "Specifies main module & main class.")
flag.StringVar(&options.MainModule, "m", "", "Specifies main module & main class.")
flag.StringVar(&options.ClassPath, "classpath", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.StringVar(&options.ClassPath, "cp", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.StringVar(&options.ModulePath, "module-path", "", "Specifies module path.") // TODO
flag.StringVar(&options.ModulePath, "p", "", "Specifies module path.") // TODO
flag.BoolVar(&options.VerboseClass, "verbose:class", false, "Displays information about each class loaded.")
flag.BoolVar(&options.VerboseInstr, "verbose:instr", false, "Displays information about each instruction executed.")
flag.BoolVar(&options.VerboseModule, "verbose:module", false, "Displays information about the modules in use.")
flag.BoolVar(&options.VerboseJNI, "verbose:jni", false, "Displays information about the use of native methods and other Java Native Interface (JNI) activity.")
flag.BoolVar(&options.VersionFlag, "version", false, "Displays version information and exit.")
flag.StringVar(&options.Xss, "Xss", "", "Sets the thread stack size.")
flag.BoolVar(&options.XUseJavaHome, "XuseJavaHome", false, "Uses JAVA_HOME")
flag.BoolVar(&options.XDebugInstr, "Xdebug:instr", false, "Displays executed instructions")
flag.StringVar(&options.Xjre, "Xjre", "", "Specifies JRE path.")
flag.BoolVar(&options.XUseJavaHome, "XuseJavaHome", false, "Uses JAVA_HOME to find JRE path.")
flag.BoolVar(&options.XDebugInstr, "Xdebug:instr", false, "Displays executed instructions.")
flag.StringVar(&options.XCPUProfile, "Xprofile:cpu", "", "")
flag.Parse()

args := flag.Args()
options.Init()
return options, flag.Args()

if mm := options.MainModule; mm != "" {
if idx := strings.IndexByte(mm, '/'); idx >= 0 {
options.MainModule = mm[:idx]
options.MainClass = mm[idx+1:]
}
} else if len(args) > 0 {
options.MainClass = args[0]
args = args[1:]
}

return options, args
}

func printUsage() {
fmt.Printf("usage: %s [-options] class [args...]\n", os.Args[0])
fmt.Println(strings.ReplaceAll(strings.TrimSpace(usage), "{java}", os.Args[0]))
flag.PrintDefaults()
}

func printVersion() {
fmt.Println("jvm.go 0.1.8.0")
}

func startJVM(opts vm.Options, mainClass string, args []string) {
func listModules(opts *vm.Options) {
// TODO
}

func startJVM13(opts *vm.Options, args []string) {
// TODO
}

func startJVM8(opts *vm.Options, args []string) {
if opts.XCPUProfile != "" {
f, err := os.Create(opts.XCPUProfile)
if err != nil {
Expand All @@ -69,13 +114,13 @@ func startJVM(opts vm.Options, mainClass string, args []string) {
cp := classpath.Parse(opts)
heap.InitBootLoader(cp, opts.VerboseClass)

mainClass = strings.ReplaceAll(mainClass, ".", "/")
mainClass := vmutils.DotToSlash(opts.MainClass)
mainThread := createMainThread(opts, mainClass, args)
cpu.Loop(mainThread)
cpu.KeepAlive()
}

func createMainThread(opts vm.Options, className string, args []string) *rtda.Thread {
func createMainThread(opts *vm.Options, className string, args []string) *rtda.Thread {
mainThread := rtda.NewThread(nil, opts)
bootMethod := rtda.ShimBootstrapMethod
bootArgs := []heap.Slot{heap.NewHackSlot(className), heap.NewHackSlot(args)}
Expand Down
36 changes: 21 additions & 15 deletions cmd/javap/main.go
Expand Up @@ -8,6 +8,12 @@ import (
"github.com/zxh0/jvm.go/classfile"
"github.com/zxh0/jvm.go/classpath"
"github.com/zxh0/jvm.go/vm"
"github.com/zxh0/jvm.go/vmutils"
)

var (
versionFlag bool
helpFlag bool
)

var (
Expand All @@ -34,20 +40,20 @@ var (

func main() {
opts, args := parseOptions()
if opts.HelpFlag || len(args) == 0 {
if helpFlag || len(args) == 0 {
printUsage()
}
printClassInfo(opts, args[0])
}

func parseOptions() (vm.Options, []string) {
options := vm.Options{}
flag.StringVar(&options.Classpath, "classpath", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.StringVar(&options.Classpath, "cp", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.BoolVar(&options.HelpFlag, "help", false, "Displays usage information and exit.")
flag.BoolVar(&options.HelpFlag, "h", false, "Displays usage information and exit.")
flag.BoolVar(&options.HelpFlag, "?", false, "Displays usage information and exit.")
flag.BoolVar(&options.VersionFlag, "version", false, "Displays version information and exit.")
func parseOptions() (*vm.Options, []string) {
options := &vm.Options{}
flag.StringVar(&options.ClassPath, "classpath", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.StringVar(&options.ClassPath, "cp", "", "Specifies a list of directories, JAR files, and ZIP archives to search for class files.")
flag.BoolVar(&helpFlag, "help", false, "Displays usage information and exit.")
flag.BoolVar(&helpFlag, "h", false, "Displays usage information and exit.")
flag.BoolVar(&helpFlag, "?", false, "Displays usage information and exit.")
flag.BoolVar(&versionFlag, "version", false, "Displays version information and exit.")
flag.Parse()
return options, flag.Args()
}
Expand All @@ -56,7 +62,7 @@ func printUsage() {
fmt.Println("usage: javap [-options] class [args...]")
}

func printClassInfo(opts vm.Options, className string) {
func printClassInfo(opts *vm.Options, className string) {
cp := classpath.Parse(opts)
_, classData := cp.ReadClass(className)
if classData == nil {
Expand All @@ -70,19 +76,19 @@ func printClassInfo(opts vm.Options, className string) {

fmt.Printf("%s %s",
accessFlagsForClass(cf.AccessFlags),
strings.ReplaceAll(cf.GetThisClassName(), "/", "."))
vmutils.SlashToDot(cf.GetThisClassName()))

superClassName := cf.GetSuperClassName()
interfaceNames := cf.GetInterfaceNames()

if superClassName != "" {
fmt.Printf(" extends %s",
strings.ReplaceAll(superClassName, "/", "."))
vmutils.SlashToDot(superClassName))
}

if len(interfaceNames) > 0 {
fmt.Printf(" implements %s",
strings.ReplaceAll(strings.Join(interfaceNames, ","), "/", "."))
vmutils.SlashToDot(strings.Join(interfaceNames, ",")))
}

fmt.Println(" {")
Expand Down Expand Up @@ -194,9 +200,9 @@ func descriptorToRealName(descriptor string) string {
return primitiveMap[descriptor]
} else {
if strings.Contains(descriptor, "[L") {
return strings.ReplaceAll(strings.TrimSuffix(strings.TrimPrefix(descriptor, "[L"), ";"), "/", ".") + "[]"
return vmutils.SlashToDot(strings.TrimSuffix(strings.TrimPrefix(descriptor, "[L"), ";")) + "[]"
} else {
return strings.ReplaceAll(strings.TrimSuffix(strings.TrimPrefix(descriptor, "L"), ";"), "/", ".")
return vmutils.SlashToDot(strings.TrimSuffix(strings.TrimPrefix(descriptor, "L"), ";"))
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/jmod/main.go
Expand Up @@ -63,11 +63,11 @@ func describe(filename string) {
panic(err)
}

modInfo := module.NewModuleInfo(classData)
modInfo := module.ParseModuleInfo(classData)
describeModule(jmodFile, modInfo)
}

func describeModule(jmodFile *vmutils.JModFile, modInfo module.Info) {
func describeModule(jmodFile *vmutils.JModFile, modInfo *module.Info) {
fmt.Printf("%s@%s\n", modInfo.Name, modInfo.Version)
// unqualified exports (sorted by package)
for _, export := range modInfo.Exports {
Expand Down Expand Up @@ -127,7 +127,7 @@ func describeModule(jmodFile *vmutils.JModFile, modInfo module.Info) {
// TODO: platform & hashes
}

func getPrivatePackages(jmodFile *vmutils.JModFile, modInfo module.Info) []string {
func getPrivatePackages(jmodFile *vmutils.JModFile, modInfo *module.Info) []string {
nonPrivatePkgMap := map[string]bool{}
for _, export := range modInfo.Exports {
nonPrivatePkgMap[export.Package] = true
Expand Down
8 changes: 4 additions & 4 deletions cpu/loop.go
Expand Up @@ -15,7 +15,7 @@ func ExecMethod(thread *rtda.Thread, method *heap.Method, args []heap.Slot) heap
thread.PushFrame(shimFrame)
thread.InvokeMethod(method)

verbose := thread.VMOptions.VerboseInstr
debug := thread.VMOptions.XDebugInstr
defer _catchErr(thread) // todo

for {
Expand All @@ -38,7 +38,7 @@ func ExecMethod(thread *rtda.Thread, method *heap.Method, args []heap.Slot) heap

// execute instruction
instr.Execute(frame)
if verbose {
if debug {
_logInstruction(frame, instr)
}
}
Expand All @@ -62,7 +62,7 @@ func Loop(thread *rtda.Thread) {
}

func _loop(thread *rtda.Thread) {
verbose := thread.VMOptions.VerboseInstr
debug := thread.VMOptions.XDebugInstr
defer _catchErr(thread) // todo

for {
Expand All @@ -76,7 +76,7 @@ func _loop(thread *rtda.Thread) {

// execute instruction
instr.Execute(frame)
if verbose {
if debug {
_logInstruction(frame, instr)
}
if thread.IsStackEmpty() {
Expand Down
5 changes: 2 additions & 3 deletions native/java/lang/Class_static.go
@@ -1,10 +1,9 @@
package lang

import (
"strings"

"github.com/zxh0/jvm.go/rtda"
"github.com/zxh0/jvm.go/rtda/heap"
"github.com/zxh0/jvm.go/vmutils"
)

func init() {
Expand Down Expand Up @@ -32,7 +31,7 @@ func forName0(frame *rtda.Frame) {
//jLoader := frame.GetRefVar(2)

goName := heap.JSToGoStr(jName)
goName = strings.ReplaceAll(goName, ".", "/")
goName = vmutils.DotToSlash(goName)
goClass := frame.GetClassLoader().LoadClass(goName)
jClass := goClass.JClass

Expand Down
4 changes: 2 additions & 2 deletions native/java/lang/System.go
Expand Up @@ -116,14 +116,14 @@ func _getSysPropKeys(m map[string]string) []string {
return keys
}

func _getSysProps(opts vm.Options) map[string]string {
func _getSysProps(opts *vm.Options) map[string]string {
return map[string]string{
"java.version": "1.8.0",
"java.vendor": "jvm.go",
"java.vendor.url": "https://github.com/zxh0/jvm.go",
"java.home": opts.AbsJavaHome,
"java.class.version": "52.0",
"java.class.path": opts.Classpath, // TODO
"java.class.path": opts.ClassPath, // TODO
"java.awt.graphicsenv": "sun.awt.CGraphicsEnvironment",
"os.name": runtime.GOOS, // todo
"os.arch": runtime.GOARCH, // todo
Expand Down
4 changes: 2 additions & 2 deletions rtda/thread.go
Expand Up @@ -29,12 +29,12 @@ type Thread struct {
interruptedFlag bool
parkingFlag bool // used by Unsafe
unparkedFlag bool // used by Unsafe
VMOptions vm.Options
VMOptions *vm.Options
JNIEnv interface{}
// todo
}

func NewThread(jThread *heap.Object, opts vm.Options) *Thread {
func NewThread(jThread *heap.Object, opts *vm.Options) *Thread {
stack := newStack(uint(opts.ThreadStackSize))
thread := &Thread{
stack: stack,
Expand Down

0 comments on commit 6005a68

Please sign in to comment.