aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/debuglog.go115
-rw-r--r--src/runtime/debuglog_off.go6
-rw-r--r--src/runtime/debuglog_on.go11
-rw-r--r--src/runtime/export_debuglog_test.go6
4 files changed, 102 insertions, 36 deletions
diff --git a/src/runtime/debuglog.go b/src/runtime/debuglog.go
index ee649fb007..a278dfabe7 100644
--- a/src/runtime/debuglog.go
+++ b/src/runtime/debuglog.go
@@ -12,6 +12,16 @@
//
// This facility can be enabled by passing -tags debuglog when
// building. Without this tag, dlog calls compile to nothing.
+//
+// Implementation notes
+//
+// There are two implementations of the dlog interface: dloggerImpl and
+// dloggerFake. dloggerFake is a no-op implementation. dlogger is type-aliased
+// to one or the other depending on the debuglog build tag. However, both types
+// always exist and are always built. This helps ensure we compile as much of
+// the implementation as possible in the default build configuration, while also
+// enabling us to achieve good test coverage of the real debuglog implementation
+// even when the debuglog build tag is not set.
package runtime
@@ -31,8 +41,6 @@ const debugLogBytes = 16 << 10
// Above this, the string will be truncated with "..(n more bytes).."
const debugLogStringLimit = debugLogBytes / 8
-type dlogger = dloggerImpl
-
// dlog returns a debug logger. The caller can use methods on the
// returned logger to add values, which will be space-separated in the
// final output, much like println. The caller must call end() to
@@ -50,11 +58,20 @@ type dlogger = dloggerImpl
//
//go:nosplit
//go:nowritebarrierrec
-func dlog() *dloggerImpl {
- if !dlogEnabled {
- return nil
- }
+func dlog() dlogger {
+ // dlog1 is defined to either dlogImpl or dlogFake.
+ return dlog1()
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func dlogFake() dloggerFake {
+ return dloggerFake{}
+}
+//go:nosplit
+//go:nowritebarrierrec
+func dlogImpl() *dloggerImpl {
// Get the time.
tick, nano := uint64(cputicks()), uint64(nanotime())
@@ -142,12 +159,14 @@ type dloggerImpl struct {
// so it doesn't need to protect against ABA races.
var allDloggers *dloggerImpl
+// A dloggerFake is a no-op implementation of dlogger.
+type dloggerFake struct{}
+
//go:nosplit
-func (l *dloggerImpl) end() {
- if !dlogEnabled {
- return
- }
+func (l dloggerFake) end() {}
+//go:nosplit
+func (l *dloggerImpl) end() {
// Fill in framing header.
size := l.w.write - l.w.r.end
if !l.w.writeFrameAt(l.w.r.end, size) {
@@ -183,10 +202,10 @@ const (
)
//go:nosplit
+func (l dloggerFake) b(x bool) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) b(x bool) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
if x {
l.w.byte(debugLogBoolTrue)
} else {
@@ -196,85 +215,112 @@ func (l *dloggerImpl) b(x bool) *dloggerImpl {
}
//go:nosplit
+func (l dloggerFake) i(x int) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) i(x int) *dloggerImpl {
return l.i64(int64(x))
}
//go:nosplit
+func (l dloggerFake) i8(x int8) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) i8(x int8) *dloggerImpl {
return l.i64(int64(x))
}
//go:nosplit
+func (l dloggerFake) i16(x int16) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) i16(x int16) *dloggerImpl {
return l.i64(int64(x))
}
//go:nosplit
+func (l dloggerFake) i32(x int32) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) i32(x int32) *dloggerImpl {
return l.i64(int64(x))
}
//go:nosplit
+func (l dloggerFake) i64(x int64) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) i64(x int64) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
l.w.byte(debugLogInt)
l.w.varint(x)
return l
}
//go:nosplit
+func (l dloggerFake) u(x uint) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) u(x uint) *dloggerImpl {
return l.u64(uint64(x))
}
//go:nosplit
+func (l dloggerFake) uptr(x uintptr) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) uptr(x uintptr) *dloggerImpl {
return l.u64(uint64(x))
}
//go:nosplit
+func (l dloggerFake) u8(x uint8) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) u8(x uint8) *dloggerImpl {
return l.u64(uint64(x))
}
//go:nosplit
+func (l dloggerFake) u16(x uint16) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) u16(x uint16) *dloggerImpl {
return l.u64(uint64(x))
}
//go:nosplit
+func (l dloggerFake) u32(x uint32) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) u32(x uint32) *dloggerImpl {
return l.u64(uint64(x))
}
//go:nosplit
+func (l dloggerFake) u64(x uint64) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) u64(x uint64) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
l.w.byte(debugLogUint)
l.w.uvarint(x)
return l
}
//go:nosplit
+func (l dloggerFake) hex(x uint64) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) hex(x uint64) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
l.w.byte(debugLogHex)
l.w.uvarint(x)
return l
}
//go:nosplit
+func (l dloggerFake) p(x any) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) p(x any) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
l.w.byte(debugLogPtr)
if x == nil {
l.w.uvarint(0)
@@ -291,11 +337,10 @@ func (l *dloggerImpl) p(x any) *dloggerImpl {
}
//go:nosplit
-func (l *dloggerImpl) s(x string) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
+func (l dloggerFake) s(x string) dloggerFake { return l }
+//go:nosplit
+func (l *dloggerImpl) s(x string) *dloggerImpl {
strData := unsafe.StringData(x)
datap := &firstmoduledata
if len(x) > 4 && datap.etext <= uintptr(unsafe.Pointer(strData)) && uintptr(unsafe.Pointer(strData)) < datap.end {
@@ -327,20 +372,20 @@ func (l *dloggerImpl) s(x string) *dloggerImpl {
}
//go:nosplit
+func (l dloggerFake) pc(x uintptr) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) pc(x uintptr) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
l.w.byte(debugLogPC)
l.w.uvarint(uint64(x))
return l
}
//go:nosplit
+func (l dloggerFake) traceback(x []uintptr) dloggerFake { return l }
+
+//go:nosplit
func (l *dloggerImpl) traceback(x []uintptr) *dloggerImpl {
- if !dlogEnabled {
- return l
- }
l.w.byte(debugLogTraceback)
l.w.uvarint(uint64(len(x)))
for _, pc := range x {
diff --git a/src/runtime/debuglog_off.go b/src/runtime/debuglog_off.go
index 7ebec31bf6..4eb59fa683 100644
--- a/src/runtime/debuglog_off.go
+++ b/src/runtime/debuglog_off.go
@@ -8,6 +8,12 @@ package runtime
const dlogEnabled = false
+type dlogger = dloggerFake
+
+func dlog1() dloggerFake {
+ return dlogFake()
+}
+
type dlogPerM struct{}
func getCachedDlogger() *dloggerImpl {
diff --git a/src/runtime/debuglog_on.go b/src/runtime/debuglog_on.go
index b81d66498c..99773129ab 100644
--- a/src/runtime/debuglog_on.go
+++ b/src/runtime/debuglog_on.go
@@ -8,6 +8,17 @@ package runtime
const dlogEnabled = true
+// dlogger is the underlying implementation of the dlogger interface, selected
+// at build time.
+//
+// We use a type alias instead of struct embedding so that the dlogger type is
+// identical to the type returned by method chaining on the methods of this type.
+type dlogger = *dloggerImpl
+
+func dlog1() *dloggerImpl {
+ return dlogImpl()
+}
+
// dlogPerM is the per-M debug log data. This is embedded in the m
// struct.
type dlogPerM struct {
diff --git a/src/runtime/export_debuglog_test.go b/src/runtime/export_debuglog_test.go
index e4b4ab9914..a361c02299 100644
--- a/src/runtime/export_debuglog_test.go
+++ b/src/runtime/export_debuglog_test.go
@@ -12,7 +12,11 @@ const DebugLogBytes = debugLogBytes
const DebugLogStringLimit = debugLogStringLimit
-var Dlog = dlog
+type Dlogger = dloggerImpl
+
+func Dlog() *Dlogger {
+ return dlogImpl()
+}
func (l *dloggerImpl) End() { l.end() }
func (l *dloggerImpl) B(x bool) *dloggerImpl { return l.b(x) }