Update goja and fix console.[log|error]

This commit is contained in:
Guillaume Ballet 2019-11-20 22:12:07 +01:00
parent c003b9e321
commit f857b8076b
13 changed files with 82 additions and 86 deletions

View file

@ -71,6 +71,7 @@ type Console struct {
histPath string // Absolute path to the console scrollback history histPath string // Absolute path to the console scrollback history
history []string // Scroll history maintained by the console history []string // Scroll history maintained by the console
printer io.Writer // Output writer to serialize any display strings to printer io.Writer // Output writer to serialize any display strings to
runtime *goja.Runtime // The javascript runtime
} }
// New initializes a JavaScript interpreted runtime environment and sets defaults // New initializes a JavaScript interpreted runtime environment and sets defaults
@ -86,10 +87,15 @@ func New(config Config) (*Console, error) {
if config.Printer == nil { if config.Printer == nil {
config.Printer = colorable.NewColorableStdout() config.Printer = colorable.NewColorableStdout()
} }
// Create the JS runtime
runtime := goja.New()
// Initialize the console and return // Initialize the console and return
console := &Console{ console := &Console{
runtime: runtime,
client: config.Client, client: config.Client,
jsre: jsre.New(config.DocRoot, config.Printer), jsre: jsre.New(config.DocRoot, config.Printer, runtime),
prompt: config.Prompt, prompt: config.Prompt,
prompter: config.Prompter, prompter: config.Prompter,
printer: config.Printer, printer: config.Printer,
@ -108,18 +114,25 @@ func New(config Config) (*Console, error) {
// the console's JavaScript namespaces based on the exposed modules. // the console's JavaScript namespaces based on the exposed modules.
func (c *Console) init(preload []string) error { func (c *Console) init(preload []string) error {
// Initialize the JavaScript <-> Go RPC bridge // Initialize the JavaScript <-> Go RPC bridge
runtime := goja.New() bridge := newBridge(c.client, c.prompter, c.printer, c.runtime)
bridge := newBridge(c.client, c.prompter, c.printer, runtime) c.jsre.Run("jeth = {};")
c.jsre.Set("jeth", struct{}{}) c.jsre.Run("console = {};")
c.jsre.Set("console", struct{}{})
jethObj := c.jsre.Get("jeth").ToObject(runtime) jethObj := c.jsre.Get("jeth").ToObject(c.runtime)
jethObj.Set("send", bridge.Send) if err := jethObj.Set("send", bridge.Send); err != nil {
jethObj.Set("sendAsync", bridge.Send) panic(err)
}
if err := jethObj.Set("sendAsync", bridge.Send); err != nil {
panic(err)
}
consoleObj := c.jsre.Get("console").ToObject(runtime) consoleObj := c.runtime.Get("console").ToObject(c.runtime)
consoleObj.Set("log", c.consoleOutput) if err := consoleObj.Set("log", c.consoleOutput); err != nil {
consoleObj.Set("error", c.consoleOutput) panic(err)
}
if err := consoleObj.Set("error", c.consoleOutput); err != nil {
panic(err)
}
// Load all the internal utility JavaScript libraries // Load all the internal utility JavaScript libraries
if err := c.jsre.Compile("bignumber.js", string(jsre.BignumberJs)); err != nil { if err := c.jsre.Compile("bignumber.js", string(jsre.BignumberJs)); err != nil {
@ -150,7 +163,7 @@ func (c *Console) init(preload []string) error {
return fmt.Errorf("%s.js: %v", api, err) return fmt.Errorf("%s.js: %v", api, err)
} }
flatten += fmt.Sprintf("var %s = web3.%s; ", api, api) flatten += fmt.Sprintf("var %s = web3.%s; ", api, api)
} else if obj, err := c.jsre.Run("web3." + api); err == nil && obj.ToObject(runtime) != nil { } else if obj, err := c.jsre.Run("web3." + api); err == nil && obj.ToObject(c.runtime) != nil {
// Enable web3.js built-in extension if available. // Enable web3.js built-in extension if available.
flatten += fmt.Sprintf("var %s = web3.%s; ", api, api) flatten += fmt.Sprintf("var %s = web3.%s; ", api, api)
} }
@ -173,7 +186,7 @@ func (c *Console) init(preload []string) error {
// original web3 callbacks. These will be called by the jeth.* methods after // original web3 callbacks. These will be called by the jeth.* methods after
// they got the password from the user and send the original web3 request to // they got the password from the user and send the original web3 request to
// the backend. // the backend.
if obj := personal.ToObject(runtime); obj != nil { // make sure the personal api is enabled over the interface if obj := personal.ToObject(c.runtime); obj != nil { // make sure the personal api is enabled over the interface
if _, err = c.jsre.Run(`jeth.openWallet = personal.openWallet;`); err != nil { if _, err = c.jsre.Run(`jeth.openWallet = personal.openWallet;`); err != nil {
return fmt.Errorf("personal.openWallet: %v", err) return fmt.Errorf("personal.openWallet: %v", err)
} }
@ -197,7 +210,7 @@ func (c *Console) init(preload []string) error {
if admin == nil { if admin == nil {
return fmt.Errorf("Could not find admin") return fmt.Errorf("Could not find admin")
} }
if obj := admin.ToObject(runtime); obj != nil { // make sure the admin api is enabled over the interface if obj := admin.ToObject(c.runtime); obj != nil { // make sure the admin api is enabled over the interface
obj.Set("sleepBlocks", bridge.SleepBlocks) obj.Set("sleepBlocks", bridge.SleepBlocks)
obj.Set("sleep", bridge.Sleep) obj.Set("sleep", bridge.Sleep)
obj.Set("clearHistory", c.clearHistory) obj.Set("clearHistory", c.clearHistory)

View file

@ -68,13 +68,14 @@ type evalReq struct {
} }
// runtime must be stopped with Stop() after use and cannot be used after stopping // runtime must be stopped with Stop() after use and cannot be used after stopping
func New(assetPath string, output io.Writer) *JSRE { func New(assetPath string, output io.Writer, vm *goja.Runtime) *JSRE {
re := &JSRE{ re := &JSRE{
assetPath: assetPath, assetPath: assetPath,
output: output, output: output,
closed: make(chan struct{}), closed: make(chan struct{}),
evalQueue: make(chan *evalReq), evalQueue: make(chan *evalReq),
stopEventLoop: make(chan bool), stopEventLoop: make(chan bool),
vm: vm,
} }
go re.runEventLoop() go re.runEventLoop()
re.Set("loadScript", re.loadScript) re.Set("loadScript", re.loadScript)
@ -106,7 +107,6 @@ func randomSource() *rand.Rand {
func (re *JSRE) runEventLoop() { func (re *JSRE) runEventLoop() {
defer close(re.closed) defer close(re.closed)
re.vm = goja.New()
r := randomSource() r := randomSource()
re.vm.SetRandSource(r.Float64) re.vm.SetRandSource(r.Float64)

View file

@ -22,10 +22,6 @@ func (a *arrayObject) init() {
a._put("length", &a.lengthProp) a._put("length", &a.lengthProp)
} }
func (a *arrayObject) getLength() Value {
return intToValue(a.length)
}
func (a *arrayObject) _setLengthInt(l int64, throw bool) bool { func (a *arrayObject) _setLengthInt(l int64, throw bool) bool {
if l >= 0 && l <= math.MaxUint32 { if l >= 0 && l <= math.MaxUint32 {
ret := true ret := true
@ -57,7 +53,7 @@ func (a *arrayObject) _setLengthInt(l int64, throw bool) bool {
a.values = ar a.values = ar
} else { } else {
ar := a.values[l:len(a.values)] ar := a.values[l:len(a.values)]
for i, _ := range ar { for i := range ar {
ar[i] = nil ar[i] = nil
} }
a.values = a.values[:l] a.values = a.values[:l]

View file

@ -27,10 +27,6 @@ func (a *sparseArrayObject) init() {
a._put("length", &a.lengthProp) a._put("length", &a.lengthProp)
} }
func (a *sparseArrayObject) getLength() Value {
return intToValue(a.length)
}
func (a *sparseArrayObject) findIdx(idx int64) int { func (a *sparseArrayObject) findIdx(idx int64) int {
return sort.Search(len(a.items), func(i int) bool { return sort.Search(len(a.items), func(i int) bool {
return a.items[i].idx >= idx return a.items[i].idx >= idx
@ -64,7 +60,7 @@ func (a *sparseArrayObject) _setLengthInt(l int64, throw bool) bool {
idx := a.findIdx(l) idx := a.findIdx(l)
aa := a.items[idx:] aa := a.items[idx:]
for i, _ := range aa { for i := range aa {
aa[i].value = nil aa[i].value = nil
} }
a.items = a.items[:idx] a.items = a.items[:idx]

View file

@ -278,7 +278,7 @@ func (c *compiler) compile(in *ast.Program) {
} }
c.p.code = append(c.p.code, code...) c.p.code = append(c.p.code, code...)
for i, _ := range c.p.srcMap { for i := range c.p.srcMap {
c.p.srcMap[i].pc += len(c.scope.names) c.p.srcMap[i].pc += len(c.scope.names)
} }

View file

@ -770,11 +770,6 @@ func (e *compiledFunctionLiteral) emitGetter(putOnStack bool) {
needCallee = true needCallee = true
} }
} }
lenBefore := len(e.c.scope.names)
namesBefore := make([]string, 0, lenBefore)
for key, _ := range e.c.scope.names {
namesBefore = append(namesBefore, key)
}
maxPreambleLen := 2 maxPreambleLen := 2
e.c.p.code = make([]instruction, maxPreambleLen) e.c.p.code = make([]instruction, maxPreambleLen)
if needCallee { if needCallee {
@ -801,7 +796,7 @@ func (e *compiledFunctionLiteral) emitGetter(putOnStack bool) {
e.c.p.code = e.c.p.code[maxPreambleLen-1:] e.c.p.code = e.c.p.code[maxPreambleLen-1:]
} }
e.c.convertFunctionToStashless(e.c.p.code, paramsCount) e.c.convertFunctionToStashless(e.c.p.code, paramsCount)
for i, _ := range e.c.p.srcMap { for i := range e.c.p.srcMap {
e.c.p.srcMap[i].pc -= maxPreambleLen - l e.c.p.srcMap[i].pc -= maxPreambleLen - l
} }
} else { } else {
@ -842,7 +837,7 @@ func (e *compiledFunctionLiteral) emitGetter(putOnStack bool) {
copy(code[l:], e.c.p.code[maxPreambleLen:]) copy(code[l:], e.c.p.code[maxPreambleLen:])
e.c.p.code = code e.c.p.code = code
for i, _ := range e.c.p.srcMap { for i := range e.c.p.srcMap {
e.c.p.srcMap[i].pc += l - maxPreambleLen e.c.p.srcMap[i].pc += l - maxPreambleLen
} }
} }

View file

@ -22,8 +22,6 @@ type dateObject struct {
var ( var (
dateLayoutList = []string{ dateLayoutList = []string{
"2006-01-02T15:04:05.000Z0700",
"2006-01-02T15:04:05.000",
"2006-01-02T15:04:05Z0700", "2006-01-02T15:04:05Z0700",
"2006-01-02T15:04:05", "2006-01-02T15:04:05",
"2006-01-02", "2006-01-02",
@ -46,18 +44,12 @@ var (
"2006T15:04:05", "2006T15:04:05",
"2006-01T15:04:05", "2006-01T15:04:05",
"2006T15:04:05.000",
"2006-01T15:04:05.000",
"2006T15:04Z0700", "2006T15:04Z0700",
"2006-01T15:04Z0700", "2006-01T15:04Z0700",
"2006-01-02T15:04Z0700", "2006-01-02T15:04Z0700",
"2006T15:04:05Z0700", "2006T15:04:05Z0700",
"2006-01T15:04:05Z0700", "2006-01T15:04:05Z0700",
"2006T15:04:05.000Z0700",
"2006-01T15:04:05.000Z0700",
} }
) )

View file

@ -1,8 +1,6 @@
package goja package goja
import ( import "reflect"
"reflect"
)
type baseFuncObject struct { type baseFuncObject struct {
baseObject baseObject

View file

@ -18,7 +18,7 @@ type FieldNameMapper interface {
// If this method returns "" the field becomes hidden. // If this method returns "" the field becomes hidden.
FieldName(t reflect.Type, f reflect.StructField) string FieldName(t reflect.Type, f reflect.StructField) string
// FieldName returns a JavaScript name for the given method in the given type. // MethodName returns a JavaScript name for the given method in the given type.
// If this method returns "" the method becomes hidden. // If this method returns "" the method becomes hidden.
MethodName(t reflect.Type, m reflect.Method) string MethodName(t reflect.Type, m reflect.Method) string
} }
@ -216,9 +216,8 @@ func (r *Runtime) checkHostObjectPropertyDescr(name string, descr propertyDescr,
} }
func (o *objectGoReflect) defineOwnProperty(n Value, descr propertyDescr, throw bool) bool { func (o *objectGoReflect) defineOwnProperty(n Value, descr propertyDescr, throw bool) bool {
name := n.String()
if ast.IsExported(name) {
if o.value.Kind() == reflect.Struct { if o.value.Kind() == reflect.Struct {
name := n.String()
if v := o._getField(name); v.IsValid() { if v := o._getField(name); v.IsValid() {
if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) { if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
return false return false
@ -236,15 +235,11 @@ func (o *objectGoReflect) defineOwnProperty(n Value, descr propertyDescr, throw
return true return true
} }
} }
}
return o.baseObject.defineOwnProperty(n, descr, throw) return o.baseObject.defineOwnProperty(n, descr, throw)
} }
func (o *objectGoReflect) _has(name string) bool { func (o *objectGoReflect) _has(name string) bool {
if !ast.IsExported(name) {
return false
}
if o.value.Kind() == reflect.Struct { if o.value.Kind() == reflect.Struct {
if v := o._getField(name); v.IsValid() { if v := o._getField(name); v.IsValid() {
return true return true
@ -508,7 +503,7 @@ func (r *Runtime) typeInfo(t reflect.Type) (info *reflectTypeInfo) {
return return
} }
// Sets a custom field name mapper for Go types. It can be called at any time, however // SetFieldNameMapper sets a custom field name mapper for Go types. It can be called at any time, however
// the mapping for any given value is fixed at the point of creation. // the mapping for any given value is fixed at the point of creation.
// Setting this to nil restores the default behaviour which is all exported fields and methods are mapped to their // Setting this to nil restores the default behaviour which is all exported fields and methods are mapped to their
// original unchanged names. // original unchanged names.

View file

@ -974,7 +974,7 @@ func (r *Runtime) ToValue(i interface{}) Value {
case int64: case int64:
return intToValue(i) return intToValue(i)
case uint: case uint:
if int64(i) <= math.MaxInt64 { if uint64(i) <= math.MaxInt64 {
return intToValue(int64(i)) return intToValue(int64(i))
} else { } else {
return floatToValue(float64(i)) return floatToValue(float64(i))
@ -995,6 +995,9 @@ func (r *Runtime) ToValue(i interface{}) Value {
case float64: case float64:
return floatToValue(i) return floatToValue(i)
case map[string]interface{}: case map[string]interface{}:
if i == nil {
return _null
}
obj := &Object{runtime: r} obj := &Object{runtime: r}
m := &objectGoMapSimple{ m := &objectGoMapSimple{
baseObject: baseObject{ baseObject: baseObject{
@ -1007,6 +1010,9 @@ func (r *Runtime) ToValue(i interface{}) Value {
m.init() m.init()
return obj return obj
case []interface{}: case []interface{}:
if i == nil {
return _null
}
obj := &Object{runtime: r} obj := &Object{runtime: r}
a := &objectGoSlice{ a := &objectGoSlice{
baseObject: baseObject{ baseObject: baseObject{
@ -1018,6 +1024,9 @@ func (r *Runtime) ToValue(i interface{}) Value {
a.init() a.init()
return obj return obj
case *[]interface{}: case *[]interface{}:
if i == nil {
return _null
}
obj := &Object{runtime: r} obj := &Object{runtime: r}
a := &objectGoSlice{ a := &objectGoSlice{
baseObject: baseObject{ baseObject: baseObject{

View file

@ -436,7 +436,7 @@ func (p *valueProperty) get(this Value) Value {
} }
return _undefined return _undefined
} }
call, r := p.getterFunc.self.assertCallable() call, _ := p.getterFunc.self.assertCallable()
return call(FunctionCall{ return call(FunctionCall{
This: this, This: this,
}) })

View file

@ -2,7 +2,6 @@ package goja
import ( import (
"fmt" "fmt"
"log"
"math" "math"
"runtime" "runtime"
"strconv" "strconv"
@ -364,11 +363,14 @@ func (vm *vm) try(f func()) (ex *Exception) {
case *Exception: case *Exception:
ex = x1 ex = x1
default: default:
/*
if vm.prg != nil { if vm.prg != nil {
vm.prg.dumpCode(log.Printf) vm.prg.dumpCode(log.Printf)
} }
//log.Print("Stack: ", string(debug.Stack())) log.Print("Stack: ", string(debug.Stack()))
panic(fmt.Errorf("Panic at %d: %v", vm.pc, x)) panic(fmt.Errorf("Panic at %d: %v", vm.pc, x))
*/
panic(x)
} }
ex.stack = vm.captureStack(ex.stack, ctxOffset) ex.stack = vm.captureStack(ex.stack, ctxOffset)
} }

6
vendor/vendor.json vendored
View file

@ -75,10 +75,10 @@
"revisionTime": "2018-06-25T18:44:42Z" "revisionTime": "2018-06-25T18:44:42Z"
}, },
{ {
"checksumSHA1": "h5A0DLu0ZXvpW1F0Lh2oNOlKWf0=", "checksumSHA1": "2oeluLsV3EQS1b0kjmgLc/i2d7E=",
"path": "github.com/dop251/goja", "path": "github.com/dop251/goja",
"revision": "cc13d3ec34f7c6e4e73dddbfe0a7e868cd3b5c93", "revision": "aa89e6a4c7339be720f99bae0a56a8f6055b5b3e",
"revisionTime": "2019-06-21T10:59:25Z" "revisionTime": "2019-09-12T22:33:29Z"
}, },
{ {
"checksumSHA1": "zYnPsNAVm1/ViwCkN++dX2JQhBo=", "checksumSHA1": "zYnPsNAVm1/ViwCkN++dX2JQhBo=",