From 0b563d4428391f6170d65bd30704b48b03a3f80f Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Thu, 19 Jan 2023 15:24:04 +0200 Subject: [PATCH] Update goja with some more AsyncContextTracker functionality --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/dop251/goja/func.go | 58 ++++++++++++++++-------- vendor/github.com/dop251/goja/runtime.go | 57 ++++++++++++++++------- vendor/github.com/dop251/goja/vm.go | 8 +--- vendor/modules.txt | 2 +- 6 files changed, 84 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index aeace54548d..2da6bcfb6e7 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/PuerkitoBio/goquery v1.8.0 github.com/Soontao/goHttpDigestClient v0.0.0-20170320082612-6d28bb1415c5 github.com/andybalholm/brotli v1.0.4 - github.com/dop251/goja v0.0.0-20230113101057-bf9ef13dd7b1 + github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe github.com/fatih/color v1.13.0 github.com/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index 66e01de1f00..1e961b6dc9a 100644 --- a/go.sum +++ b/go.sum @@ -85,8 +85,8 @@ github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRP github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja v0.0.0-20221106173738-3b8a68ca89b4/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= -github.com/dop251/goja v0.0.0-20230113101057-bf9ef13dd7b1 h1:xWehtM7T4bJajHcIV93/K6XFtq9d8jN4VLCUJT2L+xs= -github.com/dop251/goja v0.0.0-20230113101057-bf9ef13dd7b1/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe h1:PsLX9tWRxptk4COd23DJ0bnbXRKPDvBP+A6740Ndxp0= +github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= diff --git a/vendor/github.com/dop251/goja/func.go b/vendor/github.com/dop251/goja/func.go index ce056def124..e56ab267cad 100644 --- a/vendor/github.com/dop251/goja/func.go +++ b/vendor/github.com/dop251/goja/func.go @@ -22,10 +22,12 @@ var ( // AsyncContextTracker is a handler that allows to track async function's execution context. Every time an async // function is suspended on 'await', Suspended() is called. The trackingObject it returns is remembered and // the next time just before the context is resumed, Resumed is called with the same trackingObject as argument. +// Completed is called when an async function returns or throws. // To register it call Runtime.SetAsyncContextTracker(). type AsyncContextTracker interface { Suspended() (trackingObject interface{}) Resumed(trackingObject interface{}) + Completed() } type funcObjectImpl interface { @@ -562,6 +564,10 @@ func (f *asyncFuncObject) assertCallable() (func(FunctionCall) Value, bool) { return f.Call, true } +func (f *asyncFuncObject) export(*objectExportCtx) interface{} { + return f.Call +} + func (f *asyncArrowFuncObject) Call(call FunctionCall) Value { return f.asyncCall(call, f.arrowFuncObject.vmCall) } @@ -570,6 +576,10 @@ func (f *asyncArrowFuncObject) assertCallable() (func(FunctionCall) Value, bool) return f.Call, true } +func (f *asyncArrowFuncObject) export(*objectExportCtx) interface{} { + return f.Call +} + func (f *asyncArrowFuncObject) vmCall(vm *vm, n int) { f.asyncVmCall(vm, n, f.arrowFuncObject.vmCall) } @@ -582,6 +592,10 @@ func (f *asyncMethodFuncObject) assertCallable() (func(FunctionCall) Value, bool return f.Call, true } +func (f *asyncMethodFuncObject) export(ctx *objectExportCtx) interface{} { + return f.Call +} + func (f *asyncMethodFuncObject) vmCall(vm *vm, n int) { f.asyncVmCall(vm, n, f.methodFuncObject.vmCall) } @@ -640,29 +654,33 @@ func (ar *asyncRunner) onRejected(call FunctionCall) Value { } func (ar *asyncRunner) step(res Value, done bool, ex *Exception) { - if ex != nil { - ar.promiseCap.reject(ex.val) - return - } - if done { - ar.promiseCap.resolve(res) - } else { - // await - r := ar.f.runtime + r := ar.f.runtime + if done || ex != nil { if tracker := r.asyncContextTracker; tracker != nil { - ar.trackingObj = tracker.Suspended() + tracker.Completed() } - promise := r.promiseResolve(r.global.Promise, res) - promise.self.(*Promise).addReactions(&promiseReaction{ - typ: promiseReactionFulfill, - handler: &jobCallback{callback: ar.onFulfilled}, - asyncRunner: ar, - }, &promiseReaction{ - typ: promiseReactionReject, - handler: &jobCallback{callback: ar.onRejected}, - asyncRunner: ar, - }) + if ex == nil { + ar.promiseCap.resolve(res) + } else { + ar.promiseCap.reject(ex.val) + } + return } + + // await + if tracker := r.asyncContextTracker; tracker != nil { + ar.trackingObj = tracker.Suspended() + } + promise := r.promiseResolve(r.global.Promise, res) + promise.self.(*Promise).addReactions(&promiseReaction{ + typ: promiseReactionFulfill, + handler: &jobCallback{callback: ar.onFulfilled}, + asyncRunner: ar, + }, &promiseReaction{ + typ: promiseReactionReject, + handler: &jobCallback{callback: ar.onRejected}, + asyncRunner: ar, + }) } func (ar *asyncRunner) start(nArgs int) { diff --git a/vendor/github.com/dop251/goja/runtime.go b/vendor/github.com/dop251/goja/runtime.go index fc394a379ae..468113498da 100644 --- a/vendor/github.com/dop251/goja/runtime.go +++ b/vendor/github.com/dop251/goja/runtime.go @@ -292,21 +292,26 @@ func (f *StackFrame) Write(b *bytes.Buffer) { } } +// An un-catchable exception is not catchable by try/catch statements (finally is not executed either), +// but it is returned as an error to a Go caller rather than causing a panic. +type uncatchableException interface { + error + _uncatchableException() +} + type Exception struct { val Value stack []StackFrame } -type uncatchableException struct { - err error +type baseUncatchableException struct { + Exception } -func (ue *uncatchableException) Unwrap() error { - return ue.err -} +func (e *baseUncatchableException) _uncatchableException() {} type InterruptedError struct { - Exception + baseUncatchableException iface interface{} } @@ -318,7 +323,7 @@ func (e *InterruptedError) Unwrap() error { } type StackOverflowError struct { - Exception + baseUncatchableException } func (e *InterruptedError) Value() interface{} { @@ -1412,6 +1417,27 @@ func (r *Runtime) RunScript(name, src string) (Value, error) { return r.RunProgram(p) } +func isUncatchableException(e error) bool { + for ; e != nil; e = errors.Unwrap(e) { + if _, ok := e.(uncatchableException); ok { + return true + } + } + return false +} + +func asUncatchableException(v interface{}) error { + switch v := v.(type) { + case uncatchableException: + return v + case error: + if isUncatchableException(v) { + return v + } + } + return nil +} + // RunProgram executes a pre-compiled (see Compile()) code in the global context. func (r *Runtime) RunProgram(p *Program) (result Value, err error) { vm := r.vm @@ -1423,8 +1449,8 @@ func (r *Runtime) RunProgram(p *Program) (result Value, err error) { vm.callStack = vm.callStack[:len(vm.callStack)-1] } if x := recover(); x != nil { - if ex, ok := x.(*uncatchableException); ok { - err = ex.err + if ex := asUncatchableException(x); ex != nil { + err = ex if len(vm.callStack) == 0 { r.leaveAbrupt() } @@ -1990,17 +2016,14 @@ func (r *Runtime) wrapReflectFunc(value reflect.Value) func(FunctionCall) Value return _undefined } - if last := out[len(out)-1]; last.Type().Name() == "error" { + if last := out[len(out)-1]; last.Type() == reflectTypeError { if !last.IsNil() { err := last.Interface().(error) if _, ok := err.(*Exception); ok { panic(err) } - var intErr *InterruptedError - if errors.As(err, &intErr) { - panic(&uncatchableException{ - err: err, - }) + if isUncatchableException(err) { + panic(err) } panic(r.NewGoError(err)) } @@ -2442,8 +2465,8 @@ func AssertConstructor(v Value) (Constructor, bool) { func (r *Runtime) runWrapped(f func()) (err error) { defer func() { if x := recover(); x != nil { - if ex, ok := x.(*uncatchableException); ok { - err = ex.err + if ex := asUncatchableException(x); ex != nil { + err = ex if len(r.vm.callStack) == 0 { r.leaveAbrupt() } diff --git a/vendor/github.com/dop251/goja/vm.go b/vendor/github.com/dop251/goja/vm.go index 01bb0af584e..06d28120164 100644 --- a/vendor/github.com/dop251/goja/vm.go +++ b/vendor/github.com/dop251/goja/vm.go @@ -577,9 +577,7 @@ func (vm *vm) run() { } v.stack = vm.captureStack(nil, 0) vm.interruptLock.Unlock() - panic(&uncatchableException{ - err: v, - }) + panic(v) } } @@ -806,9 +804,7 @@ func (vm *vm) pushCtx() { if len(vm.callStack) > vm.maxCallStackSize { ex := &StackOverflowError{} ex.stack = vm.captureStack(nil, 0) - panic(&uncatchableException{ - err: ex, - }) + panic(ex) } vm.callStack = append(vm.callStack, context{}) ctx := &vm.callStack[len(vm.callStack)-1] diff --git a/vendor/modules.txt b/vendor/modules.txt index f74309f7e9a..0088c5e888c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -32,7 +32,7 @@ github.com/dgryski/go-rendezvous ## explicit; go 1.13 github.com/dlclark/regexp2 github.com/dlclark/regexp2/syntax -# github.com/dop251/goja v0.0.0-20230113101057-bf9ef13dd7b1 +# github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe ## explicit; go 1.16 github.com/dop251/goja github.com/dop251/goja/ast