github.com/luchsh/agentlib.go@v0.0.0-20221115155834-ffd0caec4d72/jgo/callbacks.go (about) 1 // 2 // Copyright 2020 chuanshenglu@gmail.com 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 package jgo 17 18 //#include "wrapper.h" 19 import "C" 20 21 import ( 22 "fmt" 23 "unsafe" 24 ) 25 26 // JVMTI event ID definitions 27 // TODO: need shorter GO name 28 const ( 29 // Fake events 30 JVMTI_MIN_FAKE_EVENT_TYPE_VAL = 100 31 JVMTI_EVENT_AGENT_UNLOAD = 100 32 JVMTI_MAX_FAKE_EVENT_TYPE_VAL = 100 33 JVMTI_EVENT_TYPE_LIMIT = 100 34 ) 35 36 // JvmtiCallbacks holds the JVMTI event callbacks 37 type JvmtiCallbacks struct { 38 // to hold callbacks 39 cbs []func(jvmtiEnv, ...JvmtiArg) 40 } 41 42 func (callbacks *JvmtiCallbacks) init() { 43 callbacks.cbs = make([]func(jvmtiEnv, ...JvmtiArg), JVMTI_EVENT_TYPE_LIMIT-JVMTI_MIN_EVENT_TYPE_VAL+1) 44 } 45 46 type JvmtiArg uintptr 47 48 // SetCallback links a go method to process a specific JVMTI event 49 func (callbacks *JvmtiCallbacks) SetCallback(eventId int, fn func(jvmtiEnv, ...JvmtiArg)) { 50 if eventId <= JVMTI_MAX_EVENT_TYPE_VAL && eventId >= JVMTI_MIN_EVENT_TYPE_VAL { 51 callbacks.cbs[eventId-JVMTI_MIN_EVENT_TYPE_VAL] = fn 52 C.EnableJvmtiCallback(unsafe.Pointer(_lib.jvmti), C.int(eventId)) 53 } else if eventId <= JVMTI_MAX_FAKE_EVENT_TYPE_VAL && eventId >= JVMTI_MIN_FAKE_EVENT_TYPE_VAL { 54 C.EnableJvmtiCallback(unsafe.Pointer(_lib.jvmti), C.int(eventId)) 55 } else { 56 fmt.Println("GO: Bad event id ", eventId) 57 } 58 } 59 60 func (callbacks *JvmtiCallbacks) dispatch(eventId int, jvmti jvmtiEnv, args ...JvmtiArg) { 61 fn := callbacks.cbs[eventId-JVMTI_MIN_EVENT_TYPE_VAL] 62 if fn != nil { 63 fn(jvmti, args...) 64 } 65 } 66 67 type rawArray struct { 68 base uintptr 69 len int 70 eSize int 71 idx int 72 } 73 74 func newRawArray(b uintptr, l int) *rawArray { 75 ar := new(rawArray) 76 ar.base = b 77 ar.len = l 78 ar.eSize = int(unsafe.Sizeof(ar.base)) 79 return ar 80 } 81 82 func (arr *rawArray) ptrAt(idx int) uintptr { 83 p := arr.base + uintptr(arr.eSize*idx) 84 return *(*uintptr)(unsafe.Pointer(p)) 85 } 86 87 func (arr *rawArray) next() uintptr { 88 if arr.idx >= arr.len { 89 return uintptr(0) 90 } 91 p := arr.base + uintptr(arr.eSize*arr.idx) 92 return *(*uintptr)(unsafe.Pointer(p)) 93 } 94 95 // OnJvmtiEvent dispatches all the event to corresponding Go handlers 96 // runs on a JavaThread 97 //export OnJvmtiEvent 98 func OnJvmtiEvent(eventId int, jvmti, params uintptr, paramsLen int) { 99 if _lib == nil { 100 return 101 } 102 callbacks := _lib.GetCallbacks() 103 jvmtiEnv := jvmtiEnv(jvmti) 104 ra := newRawArray(params, paramsLen) 105 106 args := make([]JvmtiArg, paramsLen) 107 for i := 0; i < paramsLen; i++ { 108 args[i] = JvmtiArg(ra.ptrAt(i)) 109 } 110 111 callbacks.dispatch(eventId, jvmtiEnv, args...) 112 }