mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-10 05:53:39 +00:00
Merge branch 'dev' into feature/usb-common
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// +build arm,!baremetal,!wasm arm,arm7tdmi
|
||||
// +build arm,!baremetal,!tinygo.wasm arm,arm7tdmi
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
// +build tinygo.wasm
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const GOARCH = "wasm"
|
||||
|
||||
// The bitness of the CPU (e.g. 8, 32, 64).
|
||||
const TargetBits = 32
|
||||
|
||||
//go:extern __heap_base
|
||||
var heapStartSymbol [0]byte
|
||||
|
||||
//go:extern __global_base
|
||||
var globalsStartSymbol [0]byte
|
||||
|
||||
//export llvm.wasm.memory.size.i32
|
||||
func wasm_memory_size(index int32) int32
|
||||
|
||||
//export llvm.wasm.memory.grow.i32
|
||||
func wasm_memory_grow(index int32, delta int32) int32
|
||||
|
||||
var (
|
||||
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
|
||||
globalsStart = uintptr(unsafe.Pointer(&globalsStartSymbol))
|
||||
globalsEnd = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||
)
|
||||
|
||||
const wasmPageSize = 64 * 1024
|
||||
|
||||
func align(ptr uintptr) uintptr {
|
||||
// Align to 16, which is the alignment of max_align_t:
|
||||
// https://godbolt.org/z/dYqTsWrGq
|
||||
const heapAlign = 16
|
||||
return (ptr + heapAlign - 1) &^ (heapAlign - 1)
|
||||
}
|
||||
|
||||
func getCurrentStackPointer() uintptr
|
||||
|
||||
// growHeap tries to grow the heap size. It returns true if it succeeds, false
|
||||
// otherwise.
|
||||
func growHeap() bool {
|
||||
// Grow memory by the available size, which means the heap size is doubled.
|
||||
memorySize := wasm_memory_size(0)
|
||||
result := wasm_memory_grow(0, memorySize)
|
||||
if result == -1 {
|
||||
// Grow failed.
|
||||
return false
|
||||
}
|
||||
|
||||
setHeapEnd(uintptr(wasm_memory_size(0) * wasmPageSize))
|
||||
|
||||
// Heap has grown successfully.
|
||||
return true
|
||||
}
|
||||
|
||||
// The below functions override the default allocator of wasi-libc.
|
||||
// Most functions are defined but unimplemented to make sure that if there is
|
||||
// any code using them, they will get an error instead of (incorrectly) using
|
||||
// the wasi-libc dlmalloc heap implementation instead. If they are needed by any
|
||||
// program, they can certainly be implemented.
|
||||
|
||||
//export malloc
|
||||
func libc_malloc(size uintptr) unsafe.Pointer {
|
||||
return alloc(size)
|
||||
}
|
||||
|
||||
//export free
|
||||
func libc_free(ptr unsafe.Pointer) {
|
||||
free(ptr)
|
||||
}
|
||||
|
||||
//export calloc
|
||||
func libc_calloc(nmemb, size uintptr) unsafe.Pointer {
|
||||
// Note: we could be even more correct here and check that nmemb * size
|
||||
// doesn't overflow. However the current implementation should normally work
|
||||
// fine.
|
||||
return alloc(nmemb * size)
|
||||
}
|
||||
|
||||
//export realloc
|
||||
func libc_realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer {
|
||||
runtimePanic("unimplemented: realloc")
|
||||
return nil
|
||||
}
|
||||
|
||||
//export posix_memalign
|
||||
func libc_posix_memalign(memptr *unsafe.Pointer, alignment, size uintptr) int {
|
||||
runtimePanic("unimplemented: posix_memalign")
|
||||
return 0
|
||||
}
|
||||
|
||||
//export aligned_alloc
|
||||
func libc_aligned_alloc(alignment, bytes uintptr) unsafe.Pointer {
|
||||
runtimePanic("unimplemented: aligned_alloc")
|
||||
return nil
|
||||
}
|
||||
|
||||
//export malloc_usable_size
|
||||
func libc_malloc_usable_size(ptr unsafe.Pointer) uintptr {
|
||||
runtimePanic("unimplemented: malloc_usable_size")
|
||||
return 0
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// +build wasm
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const GOARCH = "wasm"
|
||||
|
||||
// The bitness of the CPU (e.g. 8, 32, 64).
|
||||
const TargetBits = 32
|
||||
|
||||
//go:extern __heap_base
|
||||
var heapStartSymbol [0]byte
|
||||
|
||||
//go:extern __global_base
|
||||
var globalsStartSymbol [0]byte
|
||||
|
||||
//export llvm.wasm.memory.size.i32
|
||||
func wasm_memory_size(index int32) int32
|
||||
|
||||
//export llvm.wasm.memory.grow.i32
|
||||
func wasm_memory_grow(index int32, delta int32) int32
|
||||
|
||||
var (
|
||||
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
|
||||
globalsStart = uintptr(unsafe.Pointer(&globalsStartSymbol))
|
||||
globalsEnd = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||
)
|
||||
|
||||
const wasmPageSize = 64 * 1024
|
||||
|
||||
// Align on word boundary.
|
||||
func align(ptr uintptr) uintptr {
|
||||
return (ptr + 3) &^ 3
|
||||
}
|
||||
|
||||
func getCurrentStackPointer() uintptr
|
||||
|
||||
// growHeap tries to grow the heap size. It returns true if it succeeds, false
|
||||
// otherwise.
|
||||
func growHeap() bool {
|
||||
// Grow memory by the available size, which means the heap size is doubled.
|
||||
memorySize := wasm_memory_size(0)
|
||||
result := wasm_memory_grow(0, memorySize)
|
||||
if result == -1 {
|
||||
// Grow failed.
|
||||
return false
|
||||
}
|
||||
|
||||
setHeapEnd(uintptr(wasm_memory_size(0) * wasmPageSize))
|
||||
|
||||
// Heap has grown successfully.
|
||||
return true
|
||||
}
|
||||
@@ -52,3 +52,24 @@ func syscall_Exit(code int) {
|
||||
}
|
||||
|
||||
const baremetal = true
|
||||
|
||||
// timeOffset is how long the monotonic clock started after the Unix epoch. It
|
||||
// should be a positive integer under normal operation or zero when it has not
|
||||
// been set.
|
||||
var timeOffset int64
|
||||
|
||||
//go:linkname now time.now
|
||||
func now() (sec int64, nsec int32, mono int64) {
|
||||
mono = nanotime()
|
||||
sec = (mono + timeOffset) / (1000 * 1000 * 1000)
|
||||
nsec = int32((mono + timeOffset) - sec*(1000*1000*1000))
|
||||
return
|
||||
}
|
||||
|
||||
// AdjustTimeOffset adds the given offset to the built-in time offset. A
|
||||
// positive value adds to the time (skipping some time), a negative value moves
|
||||
// the clock into the past.
|
||||
func AdjustTimeOffset(offset int64) {
|
||||
// TODO: do this atomically?
|
||||
timeOffset += offset
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package runtime
|
||||
|
||||
func Callers(skip int, pc []uintptr) int {
|
||||
return 0
|
||||
}
|
||||
@@ -51,7 +51,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
metadataStart unsafe.Pointer // pointer to the start of the heap
|
||||
metadataStart unsafe.Pointer // pointer to the start of the heap metadata
|
||||
nextAlloc gcBlock // the next block that should be tried by the allocator
|
||||
endBlock gcBlock // the block just past the end of the available space
|
||||
)
|
||||
@@ -228,6 +228,14 @@ func setHeapEnd(newHeapEnd uintptr) {
|
||||
// This function can be called again when the heap size increases. The caller is
|
||||
// responsible for copying the metadata to the new location.
|
||||
func calculateHeapAddresses() {
|
||||
if GOARCH == "wasm" {
|
||||
// This is a workaround for a bug in wasm-ld: wasm-ld doesn't always
|
||||
// align __heap_base and when this memory is shared through an API, it
|
||||
// might result in unaligned memory. For details, see:
|
||||
// https://reviews.llvm.org/D106499
|
||||
// It should be removed once we switch to LLVM 13, where this is fixed.
|
||||
heapStart = align(heapStart)
|
||||
}
|
||||
totalSize := heapEnd - heapStart
|
||||
|
||||
// Allocate some memory to keep 2 bits of information about every block.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// +build gc.conservative gc.extalloc
|
||||
// +build baremetal wasm
|
||||
// +build baremetal tinygo.wasm
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// +build gc.conservative gc.extalloc
|
||||
// +build !baremetal,!wasm
|
||||
// +build !baremetal,!tinygo.wasm
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// +build gc.conservative gc.extalloc
|
||||
// +build wasm
|
||||
// +build tinygo.wasm
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// +build gc.conservative gc.extalloc
|
||||
// +build !wasm
|
||||
// +build !tinygo.wasm
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// +build gc.conservative
|
||||
|
||||
package runtime
|
||||
|
||||
// Memory statistics
|
||||
|
||||
// Subset of memory statistics from upstream Go.
|
||||
// Works with conservative gc only.
|
||||
|
||||
// A MemStats records statistics about the memory allocator.
|
||||
type MemStats struct {
|
||||
// General statistics.
|
||||
|
||||
// Sys is the total bytes of memory obtained from the OS.
|
||||
//
|
||||
// Sys is the sum of the XSys fields below. Sys measures the
|
||||
// address space reserved by the runtime for the
|
||||
// heap, stacks, and other internal data structures.
|
||||
Sys uint64
|
||||
|
||||
// Heap memory statistics.
|
||||
|
||||
// HeapSys is bytes of heap memory, total.
|
||||
//
|
||||
// In TinyGo unlike upstream Go, we make no distinction between
|
||||
// regular heap blocks used by escaped-to-the-heap variables and
|
||||
// blocks occupied by goroutine stacks,
|
||||
// all such blocks are marked as in-use, see HeapInuse below.
|
||||
HeapSys uint64
|
||||
|
||||
// HeapIdle is bytes in idle (unused) blocks.
|
||||
HeapIdle uint64
|
||||
|
||||
// HeapInuse is bytes in in-use blocks.
|
||||
HeapInuse uint64
|
||||
|
||||
// HeapReleased is bytes of physical memory returned to the OS.
|
||||
HeapReleased uint64
|
||||
|
||||
// Off-heap memory statistics.
|
||||
//
|
||||
// The following statistics measure runtime-internal
|
||||
// structures that are not allocated from heap memory (usually
|
||||
// because they are part of implementing the heap).
|
||||
|
||||
// GCSys is bytes of memory in garbage collection metadata.
|
||||
GCSys uint64
|
||||
}
|
||||
|
||||
// ReadMemStats populates m with memory statistics.
|
||||
//
|
||||
// The returned memory statistics are up to date as of the
|
||||
// call to ReadMemStats. This would not do GC implicitly for you.
|
||||
func ReadMemStats(m *MemStats) {
|
||||
m.HeapIdle = 0
|
||||
m.HeapInuse = 0
|
||||
for block := gcBlock(0); block < endBlock; block++ {
|
||||
bstate := block.state()
|
||||
if bstate == blockStateFree {
|
||||
m.HeapIdle += uint64(bytesPerBlock)
|
||||
} else {
|
||||
m.HeapInuse += uint64(bytesPerBlock)
|
||||
}
|
||||
}
|
||||
m.HeapReleased = 0 // always 0, we don't currently release memory back to the OS.
|
||||
m.HeapSys = m.HeapInuse + m.HeapIdle
|
||||
m.GCSys = uint64(heapEnd - uintptr(metadataStart))
|
||||
m.Sys = uint64(heapEnd - heapStart)
|
||||
}
|
||||
@@ -11,3 +11,9 @@ const (
|
||||
flag_MAP_PRIVATE = 0x2
|
||||
flag_MAP_ANONYMOUS = 0x1000 // MAP_ANON
|
||||
)
|
||||
|
||||
// Source: https://opensource.apple.com/source/Libc/Libc-1439.100.3/include/time.h.auto.html
|
||||
const (
|
||||
clock_REALTIME = 0
|
||||
clock_MONOTONIC_RAW = 4
|
||||
)
|
||||
|
||||
@@ -11,3 +11,9 @@ const (
|
||||
flag_MAP_PRIVATE = 0x2
|
||||
flag_MAP_ANONYMOUS = 0x20
|
||||
)
|
||||
|
||||
// Source: https://github.com/torvalds/linux/blob/master/include/uapi/linux/time.h
|
||||
const (
|
||||
clock_REALTIME = 0
|
||||
clock_MONOTONIC_RAW = 4
|
||||
)
|
||||
|
||||
@@ -68,27 +68,6 @@ func nanotime() int64 {
|
||||
return ticksToNanoseconds(ticks())
|
||||
}
|
||||
|
||||
// timeOffset is how long the monotonic clock started after the Unix epoch. It
|
||||
// should be a positive integer under normal operation or zero when it has not
|
||||
// been set.
|
||||
var timeOffset int64
|
||||
|
||||
//go:linkname now time.now
|
||||
func now() (sec int64, nsec int32, mono int64) {
|
||||
mono = nanotime()
|
||||
sec = (mono + timeOffset) / (1000 * 1000 * 1000)
|
||||
nsec = int32((mono + timeOffset) - sec*(1000*1000*1000))
|
||||
return
|
||||
}
|
||||
|
||||
// AdjustTimeOffset adds the given offset to the built-in time offset. A
|
||||
// positive value adds to the time (skipping some time), a negative value moves
|
||||
// the clock into the past.
|
||||
func AdjustTimeOffset(offset int64) {
|
||||
// TODO: do this atomically?
|
||||
timeOffset += offset
|
||||
}
|
||||
|
||||
// Copied from the Go runtime source code.
|
||||
//go:linkname os_sigpipe os.sigpipe
|
||||
func os_sigpipe() {
|
||||
|
||||
@@ -10,6 +10,9 @@ import (
|
||||
//export sd_app_evt_wait
|
||||
func sd_app_evt_wait()
|
||||
|
||||
// This is a global variable to avoid a heap allocation in waitForEvents.
|
||||
var softdeviceEnabled uint8
|
||||
|
||||
func waitForEvents() {
|
||||
// Call into the SoftDevice to sleep. This is necessary here because a
|
||||
// normal wfe will not put the chip in low power mode (it still consumes
|
||||
@@ -18,10 +21,9 @@ func waitForEvents() {
|
||||
|
||||
// First check whether the SoftDevice is enabled. Unfortunately,
|
||||
// sd_app_evt_wait cannot be called when the SoftDevice is not enabled.
|
||||
var enabled uint8
|
||||
arm.SVCall1(0x12, &enabled) // sd_softdevice_is_enabled
|
||||
arm.SVCall1(0x12, &softdeviceEnabled) // sd_softdevice_is_enabled
|
||||
|
||||
if enabled != 0 {
|
||||
if softdeviceEnabled != 0 {
|
||||
// Now pick the appropriate SVCall number. Hopefully they won't change
|
||||
// in the future with a different SoftDevice version.
|
||||
if nrf.Device == "nrf51" {
|
||||
|
||||
@@ -4,6 +4,8 @@ package runtime
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
|
||||
"machine"
|
||||
)
|
||||
|
||||
// machineTicks is provided by package machine.
|
||||
@@ -39,6 +41,7 @@ func waitForEvents() {
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
machine.Serial.WriteByte(c)
|
||||
}
|
||||
|
||||
// machineInit is provided by package machine.
|
||||
@@ -46,6 +49,8 @@ func machineInit()
|
||||
|
||||
func init() {
|
||||
machineInit()
|
||||
|
||||
machine.Serial.Configure(machine.UARTConfig{})
|
||||
}
|
||||
|
||||
func postinit() {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build wasm
|
||||
// +build tinygo.wasm
|
||||
|
||||
package runtime
|
||||
|
||||
@@ -50,6 +50,14 @@ func putchar(c byte) {
|
||||
}
|
||||
}
|
||||
|
||||
//go:linkname now time.now
|
||||
func now() (sec int64, nsec int32, mono int64) {
|
||||
mono = nanotime()
|
||||
sec = mono / (1000 * 1000 * 1000)
|
||||
nsec = int32(mono - sec*(1000*1000*1000))
|
||||
return
|
||||
}
|
||||
|
||||
// Abort executes the wasm 'unreachable' instruction.
|
||||
func abort() {
|
||||
trap()
|
||||
@@ -38,8 +38,6 @@ type timespec struct {
|
||||
tv_nsec int // long: on Linux and macOS, follows the platform bitness
|
||||
}
|
||||
|
||||
const CLOCK_MONOTONIC_RAW = 4
|
||||
|
||||
var stackTop uintptr
|
||||
|
||||
func postinit() {}
|
||||
@@ -138,19 +136,31 @@ func sleepTicks(d timeUnit) {
|
||||
usleep(uint(d) / 1000)
|
||||
}
|
||||
|
||||
// Return monotonic time in nanoseconds.
|
||||
//
|
||||
// TODO: noescape
|
||||
func monotime() uint64 {
|
||||
func getTime(clock int32) uint64 {
|
||||
ts := timespec{}
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts)
|
||||
clock_gettime(clock, &ts)
|
||||
return uint64(ts.tv_sec)*1000*1000*1000 + uint64(ts.tv_nsec)
|
||||
}
|
||||
|
||||
// Return monotonic time in nanoseconds.
|
||||
func monotime() uint64 {
|
||||
return getTime(clock_MONOTONIC_RAW)
|
||||
}
|
||||
|
||||
func ticks() timeUnit {
|
||||
return timeUnit(monotime())
|
||||
}
|
||||
|
||||
//go:linkname now time.now
|
||||
func now() (sec int64, nsec int32, mono int64) {
|
||||
ts := timespec{}
|
||||
clock_gettime(clock_REALTIME, &ts)
|
||||
sec = int64(ts.tv_sec)
|
||||
nsec = int32(ts.tv_nsec)
|
||||
mono = nanotime()
|
||||
return
|
||||
}
|
||||
|
||||
//go:linkname syscall_Exit syscall.Exit
|
||||
func syscall_Exit(code int) {
|
||||
exit(code)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build wasm,wasi
|
||||
// +build tinygo.wasm,wasi
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ func addSleepTask(t *task.Task, duration timeUnit) {
|
||||
panic("runtime: addSleepTask: expected next task to be nil")
|
||||
}
|
||||
}
|
||||
t.Data = uint(duration) // TODO: longer durations
|
||||
t.Data = uint64(duration)
|
||||
now := ticks()
|
||||
if sleepQueue == nil {
|
||||
scheduleLog(" -> sleep new queue")
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package runtime
|
||||
|
||||
type Frames struct {
|
||||
//
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
Function string
|
||||
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
func CallersFrames(callers []uintptr) *Frames {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ci *Frames) Next() (frame Frame, more bool) {
|
||||
return Frame{}, false
|
||||
}
|
||||
Reference in New Issue
Block a user