diff options
author | Péter Szilágyi <peterke@gmail.com> | 2017-12-21 19:56:11 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-21 19:56:11 +0800 |
commit | 5258785c81959109138ebeca613f12c277188abc (patch) | |
tree | b3d21fc2f38927841f44541a3717b69f5a3c5ec1 /vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go | |
parent | 1a5425779b026587e36f5d21a6e50efe17cc6a9d (diff) | |
download | dexon-5258785c81959109138ebeca613f12c277188abc.tar.gz dexon-5258785c81959109138ebeca613f12c277188abc.tar.zst dexon-5258785c81959109138ebeca613f12c277188abc.zip |
cmd, core, eth/tracers: support fancier js tracing (#15516)
* cmd, core, eth/tracers: support fancier js tracing
* eth, internal/web3ext: rework trace API, concurrency, chain tracing
* eth/tracers: add three more JavaScript tracers
* eth/tracers, vendor: swap ottovm to duktape for tracing
* core, eth, internal: finalize call tracer and needed extras
* eth, tests: prestate tracer, call test suite, rewinding
* vendor: fix windows builds for tracer js engine
* vendor: temporary duktape fix
* eth/tracers: fix up 4byte and evmdis tracer
* vendor: pull in latest duktape with my upstream fixes
* eth: fix some review comments
* eth: rename rewind to reexec to make it more obvious
* core/vm: terminate tracing using defers
Diffstat (limited to 'vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go')
-rw-r--r-- | vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go new file mode 100644 index 000000000..f0806fcae --- /dev/null +++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go @@ -0,0 +1,356 @@ +package duktape + +/* +#cgo !windows CFLAGS: -std=c99 -O3 -Wall -fomit-frame-pointer -fstrict-aliasing +#cgo windows CFLAGS: -O3 -Wall -fomit-frame-pointer -fstrict-aliasing +#cgo linux LDFLAGS: -lm +#cgo freebsd LDFLAGS: -lm + +#include "duktape.h" +#include "duk_logging.h" +#include "duk_print_alert.h" +#include "duk_module_duktape.h" +#include "duk_console.h" +extern duk_ret_t goFunctionCall(duk_context *ctx); +extern void goFinalizeCall(duk_context *ctx); +*/ +import "C" +import ( + "errors" + "fmt" + "regexp" + "sync" + "unsafe" +) + +var reFuncName = regexp.MustCompile("^[a-z_][a-z0-9_]*([A-Z_][a-z0-9_]*)*$") + +const ( + goFunctionPtrProp = "\xff" + "goFunctionPtrProp" + goContextPtrProp = "\xff" + "goContextPtrProp" +) + +type Context struct { + *context +} + +// transmute replaces the value from Context with the value of pointer +func (c *Context) transmute(p unsafe.Pointer) { + *c = *(*Context)(p) +} + +// this is a pojo containing only the values of the Context +type context struct { + sync.Mutex + duk_context *C.duk_context + fnIndex *functionIndex + timerIndex *timerIndex +} + +// New returns plain initialized duktape context object +// See: http://duktape.org/api.html#duk_create_heap_default +func New() *Context { + d := &Context{ + &context{ + duk_context: C.duk_create_heap(nil, nil, nil, nil, nil), + fnIndex: newFunctionIndex(), + timerIndex: &timerIndex{}, + }, + } + + ctx := d.duk_context + C.duk_logging_init(ctx, 0) + C.duk_print_alert_init(ctx, 0) + C.duk_module_duktape_init(ctx) + C.duk_console_init(ctx, 0) + + return d +} + +// Flags is a set of flags for controlling the behaviour of duktape. +type Flags struct { + Logging uint + PrintAlert uint + Console uint +} + +// FlagConsoleProxyWrapper is a Console flag. +// Use a proxy wrapper to make undefined methods (console.foo()) no-ops. +const FlagConsoleProxyWrapper = 1 << 0 + +// FlagConsoleFlush is a Console flag. +// Flush output after every call. +const FlagConsoleFlush = 1 << 1 + +// NewWithFlags returns plain initialized duktape context object +// You can control the behaviour of duktape by setting flags. +// See: http://duktape.org/api.html#duk_create_heap_default +func NewWithFlags(flags *Flags) *Context { + d := &Context{ + &context{ + duk_context: C.duk_create_heap(nil, nil, nil, nil, nil), + fnIndex: newFunctionIndex(), + timerIndex: &timerIndex{}, + }, + } + + ctx := d.duk_context + C.duk_logging_init(ctx, C.duk_uint_t(flags.Logging)) + C.duk_print_alert_init(ctx, C.duk_uint_t(flags.PrintAlert)) + C.duk_module_duktape_init(ctx) + C.duk_console_init(ctx, C.duk_uint_t(flags.Console)) + + return d +} + +func contextFromPointer(ctx *C.duk_context) *Context { + return &Context{&context{duk_context: ctx}} +} + +// PushGlobalGoFunction push the given function into duktape global object +// Returns non-negative index (relative to stack bottom) of the pushed function +// also returns error if the function name is invalid +func (d *Context) PushGlobalGoFunction(name string, fn func(*Context) int) (int, error) { + if !reFuncName.MatchString(name) { + return -1, errors.New("Malformed function name '" + name + "'") + } + + d.PushGlobalObject() + idx := d.PushGoFunction(fn) + d.PutPropString(-2, name) + d.Pop() + + return idx, nil +} + +// PushGoFunction push the given function into duktape stack, returns non-negative +// index (relative to stack bottom) of the pushed function +func (d *Context) PushGoFunction(fn func(*Context) int) int { + funPtr := d.fnIndex.add(fn) + ctxPtr := contexts.add(d) + + idx := d.PushCFunction((*[0]byte)(C.goFunctionCall), C.DUK_VARARGS) + d.PushCFunction((*[0]byte)(C.goFinalizeCall), 1) + d.PushPointer(funPtr) + d.PutPropString(-2, goFunctionPtrProp) + d.PushPointer(ctxPtr) + d.PutPropString(-2, goContextPtrProp) + d.SetFinalizer(-2) + + d.PushPointer(funPtr) + d.PutPropString(-2, goFunctionPtrProp) + d.PushPointer(ctxPtr) + d.PutPropString(-2, goContextPtrProp) + + return idx +} + +//export goFunctionCall +func goFunctionCall(cCtx *C.duk_context) C.duk_ret_t { + d := contextFromPointer(cCtx) + + funPtr, ctx := d.getFunctionPtrs() + d.transmute(unsafe.Pointer(ctx)) + + result := d.fnIndex.get(funPtr)(d) + + return C.duk_ret_t(result) +} + +//export goFinalizeCall +func goFinalizeCall(cCtx *C.duk_context) { + d := contextFromPointer(cCtx) + + funPtr, ctx := d.getFunctionPtrs() + d.transmute(unsafe.Pointer(ctx)) + + d.fnIndex.delete(funPtr) +} + +func (d *Context) getFunctionPtrs() (unsafe.Pointer, *Context) { + d.PushCurrentFunction() + d.GetPropString(-1, goFunctionPtrProp) + funPtr := d.GetPointer(-1) + + d.Pop() + + d.GetPropString(-1, goContextPtrProp) + ctx := contexts.get(d.GetPointer(-1)) + d.Pop2() + return funPtr, ctx +} + +// Destroy destroy all the references to the functions and freed the pointers +func (d *Context) Destroy() { + d.fnIndex.destroy() + contexts.delete(d) +} + +type Error struct { + Type string + Message string + FileName string + LineNumber int + Stack string +} + +func (e *Error) Error() string { + return fmt.Sprintf("%s: %s", e.Type, e.Message) +} + +type Type int + +func (t Type) IsNone() bool { return t == TypeNone } +func (t Type) IsUndefined() bool { return t == TypeUndefined } +func (t Type) IsNull() bool { return t == TypeNull } +func (t Type) IsBool() bool { return t == TypeBoolean } +func (t Type) IsNumber() bool { return t == TypeNumber } +func (t Type) IsString() bool { return t == TypeString } +func (t Type) IsObject() bool { return t == TypeObject } +func (t Type) IsBuffer() bool { return t == TypeBuffer } +func (t Type) IsPointer() bool { return t == TypePointer } +func (t Type) IsLightFunc() bool { return t == TypeLightFunc } + +func (t Type) String() string { + switch t { + case TypeNone: + return "None" + case TypeUndefined: + return "Undefined" + case TypeNull: + return "Null" + case TypeBoolean: + return "Boolean" + case TypeNumber: + return "Number" + case TypeString: + return "String" + case TypeObject: + return "Object" + case TypeBuffer: + return "Buffer" + case TypePointer: + return "Pointer" + case TypeLightFunc: + return "LightFunc" + default: + return "Unknown" + } +} + +type functionIndex struct { + functions map[unsafe.Pointer]func(*Context) int + sync.RWMutex +} + +type timerIndex struct { + c float64 + sync.Mutex +} + +func (t *timerIndex) get() float64 { + t.Lock() + defer t.Unlock() + t.c++ + return t.c +} + +func newFunctionIndex() *functionIndex { + return &functionIndex{ + functions: make(map[unsafe.Pointer]func(*Context) int, 0), + } +} + +func (i *functionIndex) add(fn func(*Context) int) unsafe.Pointer { + ptr := C.malloc(1) + + i.Lock() + i.functions[ptr] = fn + i.Unlock() + + return ptr +} + +func (i *functionIndex) get(ptr unsafe.Pointer) func(*Context) int { + i.RLock() + fn := i.functions[ptr] + i.RUnlock() + + return fn +} + +func (i *functionIndex) delete(ptr unsafe.Pointer) { + i.Lock() + delete(i.functions, ptr) + i.Unlock() + + C.free(ptr) +} + +func (i *functionIndex) destroy() { + i.Lock() + + for ptr, _ := range i.functions { + delete(i.functions, ptr) + C.free(ptr) + } + i.Unlock() +} + +type ctxIndex struct { + sync.RWMutex + ctxs map[unsafe.Pointer]*Context +} + +func (ci *ctxIndex) add(ctx *Context) unsafe.Pointer { + + ci.RLock() + for ptr, ctxPtr := range ci.ctxs { + if ctxPtr == ctx { + ci.RUnlock() + return ptr + } + } + ci.RUnlock() + + ci.Lock() + for ptr, ctxPtr := range ci.ctxs { + if ctxPtr == ctx { + ci.Unlock() + return ptr + } + } + ptr := C.malloc(1) + ci.ctxs[ptr] = ctx + ci.Unlock() + + return ptr +} + +func (ci *ctxIndex) get(ptr unsafe.Pointer) *Context { + ci.RLock() + ctx := ci.ctxs[ptr] + ci.RUnlock() + return ctx +} + +func (ci *ctxIndex) delete(ctx *Context) { + ci.Lock() + for ptr, ctxPtr := range ci.ctxs { + if ctxPtr == ctx { + delete(ci.ctxs, ptr) + C.free(ptr) + ci.Unlock() + return + } + } + panic(fmt.Sprintf("context (%p) doesn't exist", ctx)) +} + +var contexts *ctxIndex + +func init() { + contexts = &ctxIndex{ + ctxs: make(map[unsafe.Pointer]*Context), + } +} |