runtime1.go 8.93 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

// Keep a cached value to make gotraceback fast,
// since we call it on every call to gentraceback.
// The cached value is a uint32 in which the low bit
// is the "crash" setting and the top 31 bits are the
// gotraceback value.
var traceback_cache uint32 = 2 << 1

// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
//	GOTRACEBACK=0   suppress all tracebacks
//	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
//	GOTRACEBACK=2   show tracebacks including runtime frames
//	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
//go:nosplit
func gotraceback(crash *bool) int32 {
	_g_ := getg()
	if crash != nil {
		*crash = false
	}
	if _g_.m.traceback != 0 {
		return int32(_g_.m.traceback)
	}
	if crash != nil {
		*crash = traceback_cache&1 != 0
	}
	return int32(traceback_cache >> 1)
}

var (
	argc int32
	argv **byte
)

// nosplit for use in linux/386 startup linux_setup_vdso
//go:nosplit
func argv_index(argv **byte, i int32) *byte {
	return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*ptrSize))
}

func args(c int32, v **byte) {
	argc = c
	argv = v
	sysargs(c, v)
}

var (
	// TODO: Retire in favor of GOOS== checks.
	isplan9   int32
	issolaris int32
	iswindows int32
)

func goargs() {
	if GOOS == "windows" {
		return
	}

	argslice = make([]string, argc)
	for i := int32(0); i < argc; i++ {
		argslice[i] = gostringnocopy(argv_index(argv, i))
	}
}

func goenvs_unix() {
73 74 75
	// TODO(austin): ppc64 in dynamic linking mode doesn't
	// guarantee env[] will immediately follow argv.  Might cause
	// problems.
76 77 78 79 80 81 82
	n := int32(0)
	for argv_index(argv, argc+1+n) != nil {
		n++
	}

	envs = make([]string, n)
	for i := int32(0); i < n; i++ {
83
		envs[i] = gostring(argv_index(argv, argc+1+i))
84 85 86 87 88 89 90
	}
}

func environ() []string {
	return envs
}

91 92 93 94
// TODO: These should be locals in testAtomic64, but we don't 8-byte
// align stack variables on 386.
var test_z64, test_x64 uint64

95
func testAtomic64() {
96 97 98 99 100 101 102
	test_z64 = 42
	test_x64 = 0
	prefetcht0(uintptr(unsafe.Pointer(&test_z64)))
	prefetcht1(uintptr(unsafe.Pointer(&test_z64)))
	prefetcht2(uintptr(unsafe.Pointer(&test_z64)))
	prefetchnta(uintptr(unsafe.Pointer(&test_z64)))
	if cas64(&test_z64, test_x64, 1) {
103
		throw("cas64 failed")
104
	}
105
	if test_x64 != 0 {
106
		throw("cas64 failed")
107
	}
108 109
	test_x64 = 42
	if !cas64(&test_z64, test_x64, 1) {
110
		throw("cas64 failed")
111
	}
112
	if test_x64 != 42 || test_z64 != 1 {
113
		throw("cas64 failed")
114
	}
115
	if atomicload64(&test_z64) != 1 {
116
		throw("load64 failed")
117
	}
118 119
	atomicstore64(&test_z64, (1<<40)+1)
	if atomicload64(&test_z64) != (1<<40)+1 {
120
		throw("store64 failed")
121
	}
122
	if xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 {
123
		throw("xadd64 failed")
124
	}
125
	if atomicload64(&test_z64) != (2<<40)+2 {
126
		throw("xadd64 failed")
127
	}
128
	if xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 {
129
		throw("xchg64 failed")
130
	}
131
	if atomicload64(&test_z64) != (3<<40)+3 {
132
		throw("xchg64 failed")
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
	}
}

func check() {
	var (
		a     int8
		b     uint8
		c     int16
		d     uint16
		e     int32
		f     uint32
		g     int64
		h     uint64
		i, i1 float32
		j, j1 float64
		k, k1 unsafe.Pointer
		l     *uint16
150
		m     [4]byte
151 152 153 154 155 156 157 158 159 160 161 162
	)
	type x1t struct {
		x uint8
	}
	type y1t struct {
		x1 x1t
		y  uint8
	}
	var x1 x1t
	var y1 y1t

	if unsafe.Sizeof(a) != 1 {
163
		throw("bad a")
164 165
	}
	if unsafe.Sizeof(b) != 1 {
166
		throw("bad b")
167 168
	}
	if unsafe.Sizeof(c) != 2 {
169
		throw("bad c")
170 171
	}
	if unsafe.Sizeof(d) != 2 {
172
		throw("bad d")
173 174
	}
	if unsafe.Sizeof(e) != 4 {
175
		throw("bad e")
176 177
	}
	if unsafe.Sizeof(f) != 4 {
178
		throw("bad f")
179 180
	}
	if unsafe.Sizeof(g) != 8 {
181
		throw("bad g")
182 183
	}
	if unsafe.Sizeof(h) != 8 {
184
		throw("bad h")
185 186
	}
	if unsafe.Sizeof(i) != 4 {
187
		throw("bad i")
188 189
	}
	if unsafe.Sizeof(j) != 8 {
190
		throw("bad j")
191 192
	}
	if unsafe.Sizeof(k) != ptrSize {
193
		throw("bad k")
194 195
	}
	if unsafe.Sizeof(l) != ptrSize {
196
		throw("bad l")
197 198
	}
	if unsafe.Sizeof(x1) != 1 {
199
		throw("bad unsafe.Sizeof x1")
200 201
	}
	if unsafe.Offsetof(y1.y) != 1 {
202
		throw("bad offsetof y1.y")
203 204
	}
	if unsafe.Sizeof(y1) != 2 {
205
		throw("bad unsafe.Sizeof y1")
206 207 208
	}

	if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
209
		throw("bad timediv")
210 211 212 213 214
	}

	var z uint32
	z = 1
	if !cas(&z, 1, 2) {
215
		throw("cas1")
216 217
	}
	if z != 2 {
218
		throw("cas2")
219 220 221 222
	}

	z = 4
	if cas(&z, 5, 6) {
223
		throw("cas3")
224 225
	}
	if z != 4 {
226
		throw("cas4")
227 228
	}

229 230
	z = 0xffffffff
	if !cas(&z, 0xffffffff, 0xfffffffe) {
231
		throw("cas5")
232 233
	}
	if z != 0xfffffffe {
234
		throw("cas6")
235 236
	}

237 238 239 240 241
	k = unsafe.Pointer(uintptr(0xfedcb123))
	if ptrSize == 8 {
		k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
	}
	if casp(&k, nil, nil) {
242
		throw("casp1")
243 244 245
	}
	k1 = add(k, 1)
	if !casp(&k, k, k1) {
246
		throw("casp2")
247 248
	}
	if k != k1 {
249
		throw("casp3")
250 251
	}

252 253 254
	m = [4]byte{1, 1, 1, 1}
	atomicor8(&m[1], 0xf0)
	if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
255
		throw("atomicor8")
256 257
	}

258 259
	*(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
	if j == j {
260
		throw("float64nan")
261 262
	}
	if !(j != j) {
263
		throw("float64nan1")
264 265 266 267
	}

	*(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
	if j == j1 {
268
		throw("float64nan2")
269 270
	}
	if !(j != j1) {
271
		throw("float64nan3")
272 273 274 275
	}

	*(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
	if i == i {
276
		throw("float32nan")
277 278
	}
	if i == i {
279
		throw("float32nan1")
280 281 282 283
	}

	*(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
	if i == i1 {
284
		throw("float32nan2")
285 286
	}
	if i == i1 {
287
		throw("float32nan3")
288 289 290 291 292
	}

	testAtomic64()

	if _FixedStack != round2(_FixedStack) {
293
		throw("FixedStack is not power-of-2")
294 295 296 297 298 299 300 301
	}
}

type dbgVar struct {
	name  string
	value *int32
}

302 303
// TODO(rsc): Make GC respect debug.invalidptr.

304
// Holds variables parsed from GODEBUG env var,
305
// except for "memprofilerate" since there is an
306 307
// existing int var for that value, which may
// already have an initial value.
308
var debug struct {
309 310 311 312 313 314 315 316 317 318 319 320 321 322
	allocfreetrace    int32
	efence            int32
	gccheckmark       int32
	gcpacertrace      int32
	gcshrinkstackoff  int32
	gcstackbarrieroff int32
	gcstoptheworld    int32
	gctrace           int32
	invalidptr        int32
	sbrk              int32
	scavenge          int32
	scheddetail       int32
	schedtrace        int32
	wbshadow          int32
323
}
324 325 326 327

var dbgvars = []dbgVar{
	{"allocfreetrace", &debug.allocfreetrace},
	{"efence", &debug.efence},
328 329 330 331 332
	{"gccheckmark", &debug.gccheckmark},
	{"gcpacertrace", &debug.gcpacertrace},
	{"gcshrinkstackoff", &debug.gcshrinkstackoff},
	{"gcstackbarrieroff", &debug.gcstackbarrieroff},
	{"gcstoptheworld", &debug.gcstoptheworld},
333 334
	{"gctrace", &debug.gctrace},
	{"invalidptr", &debug.invalidptr},
335
	{"sbrk", &debug.sbrk},
336
	{"scavenge", &debug.scavenge},
337 338
	{"scheddetail", &debug.scheddetail},
	{"schedtrace", &debug.schedtrace},
339
	{"wbshadow", &debug.wbshadow},
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
}

func parsedebugvars() {
	for p := gogetenv("GODEBUG"); p != ""; {
		field := ""
		i := index(p, ",")
		if i < 0 {
			field, p = p, ""
		} else {
			field, p = p[:i], p[i+1:]
		}
		i = index(field, "=")
		if i < 0 {
			continue
		}
		key, value := field[:i], field[i+1:]
356 357

		// Update MemProfileRate directly here since it
358
		// is int, not int32, and should only be updated
359
		// if specified in GODEBUG.
360
		if key == "memprofilerate" {
361 362 363 364 365 366
			MemProfileRate = atoi(value)
		} else {
			for _, v := range dbgvars {
				if v.name == key {
					*v.value = int32(atoi(value))
				}
367 368 369 370 371 372 373 374 375 376
			}
		}
	}

	switch p := gogetenv("GOTRACEBACK"); p {
	case "":
		traceback_cache = 1 << 1
	case "crash":
		traceback_cache = 2<<1 | 1
	default:
377
		traceback_cache = uint32(atoi(p)) << 1
378
	}
379 380 381 382 383
	// when C owns the process, simply exit'ing the process on fatal errors
	// and panics is surprising. Be louder and abort instead.
	if islibrary || isarchive {
		traceback_cache |= 1
	}
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
}

// Poor mans 64-bit division.
// This is a very special function, do not use it if you are not sure what you are doing.
// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
// Handles overflow in a time-specific manner.
//go:nosplit
func timediv(v int64, div int32, rem *int32) int32 {
	res := int32(0)
	for bit := 30; bit >= 0; bit-- {
		if v >= int64(div)<<uint(bit) {
			v = v - (int64(div) << uint(bit))
			res += 1 << uint(bit)
		}
	}
	if v >= int64(div) {
		if rem != nil {
			*rem = 0
		}
		return 0x7fffffff
	}
	if rem != nil {
		*rem = int32(v)
	}
	return res
}

// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.

//go:nosplit
func acquirem() *m {
	_g_ := getg()
	_g_.m.locks++
	return _g_.m
}

//go:nosplit
func releasem(mp *m) {
	_g_ := getg()
	mp.locks--
	if mp.locks == 0 && _g_.preempt {
		// restore the preemption request in case we've cleared it in newstack
426
		_g_.stackguard0 = stackPreempt
427 428 429 430 431 432 433 434
	}
}

//go:nosplit
func gomcache() *mcache {
	return getg().m.mcache
}

Russ Cox's avatar
Russ Cox committed
435
//go:linkname reflect_typelinks reflect.typelinks
436
//go:nosplit
437
func reflect_typelinks() [][]*_type {
438 439
	ret := [][]*_type{firstmoduledata.typelinks}
	for datap := firstmoduledata.next; datap != nil; datap = datap.next {
440 441 442
		ret = append(ret, datap.typelinks)
	}
	return ret
443
}