sw.Compiled.Append(ifNil)
// Load hash from type or itab.
- dotHash := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil)
- dotHash.SetType(types.Types[types.TUINT32])
- dotHash.SetTypecheck(1)
- if s.facename.Type().IsEmptyInterface() {
- dotHash.Offset = int64(2 * types.PtrSize) // offset of hash in runtime._type
- } else {
- dotHash.Offset = int64(2 * types.PtrSize) // offset of hash in runtime.itab
- }
- dotHash.SetBounded(true) // guaranteed not to fault
+ dotHash := typeHashFieldOf(base.Pos, itab)
s.hashname = copyExpr(dotHash, dotHash.Type(), &sw.Compiled)
br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)
walkStmtList(sw.Compiled)
}
+// typeHashFieldOf returns an expression to select the type hash field
+// from an interface's descriptor word (whether a *runtime._type or
+// *runtime.itab pointer).
+func typeHashFieldOf(pos src.XPos, itab *ir.UnaryExpr) *ir.SelectorExpr {
+ if itab.Op() != ir.OITAB {
+ base.Fatalf("expected OITAB, got %v", itab.Op())
+ }
+ var hashField *types.Field
+ if itab.X.Type().IsEmptyInterface() {
+ // runtime._type's hash field
+ if rtypeHashField == nil {
+ rtypeHashField = runtimeField("hash", int64(2*types.PtrSize), types.Types[types.TUINT32])
+ }
+ hashField = rtypeHashField
+ } else {
+ // runtime.itab's hash field
+ if itabHashField == nil {
+ itabHashField = runtimeField("hash", int64(2*types.PtrSize), types.Types[types.TUINT32])
+ }
+ hashField = itabHashField
+ }
+ return boundedDotPtr(pos, itab, hashField)
+}
+
+var rtypeHashField, itabHashField *types.Field
+
// A typeSwitch walks a type switch.
type typeSwitch struct {
// Temporary variables (i.e., ONAMEs) used by type switch dispatch logic:
// itabType loads the _type field from a runtime.itab struct.
func itabType(itab ir.Node) ir.Node {
- typ := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil)
- typ.SetType(types.NewPtr(types.Types[types.TUINT8]))
- typ.SetTypecheck(1)
- typ.Offset = int64(types.PtrSize) // offset of _type in runtime.itab
- typ.SetBounded(true) // guaranteed not to fault
- return typ
+ if itabTypeField == nil {
+ // runtime.itab's _type field
+ itabTypeField = runtimeField("_type", int64(types.PtrSize), types.NewPtr(types.Types[types.TUINT8]))
+ }
+ return boundedDotPtr(base.Pos, itab, itabTypeField)
+}
+
+var itabTypeField *types.Field
+
+// boundedDotPtr returns a selector expression representing ptr.field
+// and omits nil-pointer checks for ptr.
+func boundedDotPtr(pos src.XPos, ptr ir.Node, field *types.Field) *ir.SelectorExpr {
+ sel := ir.NewSelectorExpr(pos, ir.ODOTPTR, ptr, field.Sym)
+ sel.Selection = field
+ sel.Offset = field.Offset
+ sel.SetType(field.Type)
+ sel.SetTypecheck(1)
+ sel.SetBounded(true) // guaranteed not to fault
+ return sel
+}
+
+func runtimeField(name string, offset int64, typ *types.Type) *types.Field {
+ f := types.NewField(src.NoXPos, ir.Pkgs.Runtime.Lookup(name), typ)
+ f.Offset = offset
+ return f
}
// ifaceData loads the data field from an interface.