AST Tweaks (#551)

* Use pointers instead of copying around ast.Node

Node is a 56B struct that is constantly in the hot path. Passing nodes
around by copy had a cost that started to add up. This change replaces
them by pointers. Using unsafe pointer arithmetic and converting
sibling/child indexes to relative offsets, it removes the need to carry
around a pointer to the root of the tree. This saves 8B per Node. This
space will be used to store an extra []byte slice to provide contextual
error handling on all nodes, including the ones whose data is different
than the raw input (for example: strings with escaped characters), while
staying under the size of a cache line.

* Remove conditional

* Add Raw to track range in data for parsed values

* Simplify reference tracking
This commit is contained in:
Thomas Pelletier
2021-06-03 21:48:51 -04:00
committed by GitHub
parent f3bb20ea79
commit 618f0181ac
13 changed files with 239 additions and 165 deletions
+19 -22
View File
@@ -106,7 +106,6 @@ func (d *Decoder) Decode(v interface{}) error {
type decoder struct {
// Which parser instance in use for this decoding session.
// TODO: Think about removing later.
p *parser
// Flag indicating that the current expression is stashed.
@@ -132,7 +131,7 @@ type decoder struct {
strict strict
}
func (d *decoder) expr() ast.Node {
func (d *decoder) expr() *ast.Node {
return d.p.Expression()
}
@@ -208,7 +207,7 @@ Rules for the unmarshal code:
- An "object" is either a struct or a map.
*/
func (d *decoder) handleRootExpression(expr ast.Node, v reflect.Value) error {
func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
var x reflect.Value
var err error
@@ -533,7 +532,7 @@ func (d *decoder) handleTablePart(key ast.Iterator, v reflect.Value) (reflect.Va
return d.handleKeyPart(key, v, d.handleTable, makeMapStringInterface)
}
func tryTextUnmarshaler(node ast.Node, v reflect.Value) (bool, error) {
func (d *decoder) tryTextUnmarshaler(node *ast.Node, v reflect.Value) (bool, error) {
if v.Kind() != reflect.Struct {
return false, nil
}
@@ -547,9 +546,7 @@ func tryTextUnmarshaler(node ast.Node, v reflect.Value) (bool, error) {
if v.CanAddr() && v.Addr().Type().Implements(textUnmarshalerType) {
err := v.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
if err != nil {
return false, fmt.Errorf("toml: error calling UnmarshalText: %w", err)
// TODO: same as above
// return false, newDecodeError(node.Data, "error calling UnmarshalText: %w", err)
return false, newDecodeError(d.p.Raw(node.Raw), "error calling UnmarshalText: %w", err)
}
return true, nil
@@ -558,12 +555,12 @@ func tryTextUnmarshaler(node ast.Node, v reflect.Value) (bool, error) {
return false, nil
}
func (d *decoder) handleValue(value ast.Node, v reflect.Value) error {
func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
for v.Kind() == reflect.Ptr {
v = initAndDereferencePointer(v)
}
ok, err := tryTextUnmarshaler(value, v)
ok, err := d.tryTextUnmarshaler(value, v)
if ok || err != nil {
return err
}
@@ -592,7 +589,7 @@ func (d *decoder) handleValue(value ast.Node, v reflect.Value) error {
}
}
func (d *decoder) unmarshalArray(array ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
switch v.Kind() {
case reflect.Slice:
if v.IsNil() {
@@ -663,7 +660,7 @@ func (d *decoder) unmarshalArray(array ast.Node, v reflect.Value) error {
return nil
}
func (d *decoder) unmarshalInlineTable(itable ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalInlineTable(itable *ast.Node, v reflect.Value) error {
// Make sure v is an initialized object.
switch v.Kind() {
case reflect.Map:
@@ -699,7 +696,7 @@ func (d *decoder) unmarshalInlineTable(itable ast.Node, v reflect.Value) error {
return nil
}
func (d *decoder) unmarshalDateTime(value ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalDateTime(value *ast.Node, v reflect.Value) error {
dt, err := parseDateTime(value.Data)
if err != nil {
return err
@@ -709,7 +706,7 @@ func (d *decoder) unmarshalDateTime(value ast.Node, v reflect.Value) error {
return nil
}
func (d *decoder) unmarshalLocalDate(value ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalLocalDate(value *ast.Node, v reflect.Value) error {
ld, err := parseLocalDate(value.Data)
if err != nil {
return err
@@ -727,7 +724,7 @@ func (d *decoder) unmarshalLocalDate(value ast.Node, v reflect.Value) error {
return nil
}
func (d *decoder) unmarshalLocalDateTime(value ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalLocalDateTime(value *ast.Node, v reflect.Value) error {
ldt, rest, err := parseLocalDateTime(value.Data)
if err != nil {
return err
@@ -749,7 +746,7 @@ func (d *decoder) unmarshalLocalDateTime(value ast.Node, v reflect.Value) error
return nil
}
func (d *decoder) unmarshalBool(value ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalBool(value *ast.Node, v reflect.Value) error {
b := value.Data[0] == 't'
switch v.Kind() {
@@ -764,7 +761,7 @@ func (d *decoder) unmarshalBool(value ast.Node, v reflect.Value) error {
return nil
}
func (d *decoder) unmarshalFloat(value ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalFloat(value *ast.Node, v reflect.Value) error {
f, err := parseFloat(value.Data)
if err != nil {
return err
@@ -787,7 +784,7 @@ func (d *decoder) unmarshalFloat(value ast.Node, v reflect.Value) error {
return nil
}
func (d *decoder) unmarshalInteger(value ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalInteger(value *ast.Node, v reflect.Value) error {
const (
maxInt = int64(^uint(0) >> 1)
minInt = -maxInt - 1
@@ -865,7 +862,7 @@ func (d *decoder) unmarshalInteger(value ast.Node, v reflect.Value) error {
return err
}
func (d *decoder) unmarshalString(value ast.Node, v reflect.Value) error {
func (d *decoder) unmarshalString(value *ast.Node, v reflect.Value) error {
var err error
switch v.Kind() {
@@ -874,13 +871,13 @@ func (d *decoder) unmarshalString(value ast.Node, v reflect.Value) error {
case reflect.Interface:
v.Set(reflect.ValueOf(string(value.Data)))
default:
err = fmt.Errorf("toml: cannot store TOML string into a Go %s", v.Kind())
err = newDecodeError(d.p.Raw(value.Raw), "cannot store TOML string into a Go %s", v.Kind())
}
return err
}
func (d *decoder) handleKeyValue(expr ast.Node, v reflect.Value) (reflect.Value, error) {
func (d *decoder) handleKeyValue(expr *ast.Node, v reflect.Value) (reflect.Value, error) {
d.strict.EnterKeyValue(expr)
v, err := d.handleKeyValueInner(expr.Key(), expr.Value(), v)
@@ -894,7 +891,7 @@ func (d *decoder) handleKeyValue(expr ast.Node, v reflect.Value) (reflect.Value,
return v, err
}
func (d *decoder) handleKeyValueInner(key ast.Iterator, value ast.Node, v reflect.Value) (reflect.Value, error) {
func (d *decoder) handleKeyValueInner(key ast.Iterator, value *ast.Node, v reflect.Value) (reflect.Value, error) {
if key.Next() {
// Still scoping the key
return d.handleKeyValuePart(key, value, v)
@@ -904,7 +901,7 @@ func (d *decoder) handleKeyValueInner(key ast.Iterator, value ast.Node, v reflec
return reflect.Value{}, d.handleValue(value, v)
}
func (d *decoder) handleKeyValuePart(key ast.Iterator, value ast.Node, v reflect.Value) (reflect.Value, error) {
func (d *decoder) handleKeyValuePart(key ast.Iterator, value *ast.Node, v reflect.Value) (reflect.Value, error) {
// contains the replacement for v
var rv reflect.Value