Просмотр исходного кода

Merge pull request #5558 from odin-lang/bill/init-fini-changes

`@(init)` & `@(finit)` Changes.
gingerBill 1 месяц назад
Родитель
Сommit
a0ff05e633
67 измененных файлов с 225 добавлено и 135 удалено
  1. 1 1
      base/runtime/default_allocators_nil.odin
  2. 5 2
      base/runtime/default_temp_allocator_arena.odin
  3. 3 3
      base/runtime/default_temporary_allocator.odin
  4. 2 2
      base/runtime/procs_js.odin
  5. 9 2
      base/runtime/thread_management.odin
  6. 6 4
      core/encoding/cbor/tags.odin
  7. 1 1
      core/flags/rtti.odin
  8. 1 1
      core/image/bmp/bmp.odin
  9. 5 5
      core/image/general.odin
  10. 1 1
      core/image/netpbm/netpbm.odin
  11. 1 1
      core/image/png/png.odin
  12. 1 1
      core/image/qoi/qoi.odin
  13. 1 1
      core/image/tga/tga.odin
  14. 3 1
      core/log/file_console_logger.odin
  15. 10 8
      core/math/big/helpers.odin
  16. 4 4
      core/math/big/internal.odin
  17. 1 1
      core/mem/virtual/virtual.odin
  18. 2 2
      core/mem/virtual/virtual_linux.odin
  19. 1 1
      core/mem/virtual/virtual_other.odin
  20. 2 2
      core/mem/virtual/virtual_posix.odin
  21. 2 2
      core/mem/virtual/virtual_windows.odin
  22. 1 1
      core/net/socket_windows.odin
  23. 2 2
      core/os/os2/allocators.odin
  24. 2 2
      core/os/os2/file_linux.odin
  25. 2 2
      core/os/os2/file_posix.odin
  26. 2 2
      core/os/os2/file_wasi.odin
  27. 4 4
      core/os/os2/file_windows.odin
  28. 1 1
      core/os/os2/path_windows.odin
  29. 8 1
      core/os/os2/process.odin
  30. 1 1
      core/os/os2/process_posix_darwin.odin
  31. 4 2
      core/os/os_darwin.odin
  32. 4 2
      core/os/os_freebsd.odin
  33. 4 2
      core/os/os_haiku.odin
  34. 4 2
      core/os/os_linux.odin
  35. 4 2
      core/os/os_netbsd.odin
  36. 4 2
      core/os/os_openbsd.odin
  37. 11 8
      core/os/os_wasi.odin
  38. 4 2
      core/os/os_windows.odin
  39. 2 2
      core/sys/info/cpu_intel.odin
  40. 3 1
      core/sys/info/cpu_linux_arm.odin
  41. 4 1
      core/sys/info/cpu_linux_intel.odin
  42. 5 5
      core/sys/info/cpu_linux_riscv64.odin
  43. 4 1
      core/sys/info/cpu_windows.odin
  44. 4 2
      core/sys/info/platform_bsd.odin
  45. 4 1
      core/sys/info/platform_darwin.odin
  46. 4 2
      core/sys/info/platform_freebsd.odin
  47. 6 3
      core/sys/info/platform_linux.odin
  48. 8 4
      core/sys/info/platform_windows.odin
  49. 1 1
      core/sys/posix/stdlib_libc.odin
  50. 1 1
      core/sys/unix/sysctl_freebsd.odin
  51. 1 1
      core/sys/unix/sysctl_netbsd.odin
  52. 1 1
      core/sys/unix/sysctl_openbsd.odin
  53. 2 2
      core/sys/windows/util.odin
  54. 5 2
      core/terminal/internal.odin
  55. 3 3
      core/terminal/terminal_js.odin
  56. 5 3
      core/terminal/terminal_posix.odin
  57. 6 3
      core/terminal/terminal_windows.odin
  58. 6 0
      src/check_decl.cpp
  59. 6 2
      src/check_expr.cpp
  60. 9 0
      src/checker.cpp
  61. 1 1
      tests/core/flags/test_core_flags.odin
  62. 2 2
      tests/core/normal.odin
  63. 1 1
      tests/internal/test_global_any.odin
  64. 3 2
      vendor/libc/libc.odin
  65. 1 1
      vendor/libc/stdlib.odin
  66. 2 2
      vendor/miniaudio/common.odin
  67. 1 1
      vendor/wgpu/wgpu_js.odin

+ 1 - 1
base/runtime/default_allocators_nil.odin

@@ -23,7 +23,7 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
 	return nil, .None
 }
 
-nil_allocator :: proc() -> Allocator {
+nil_allocator :: proc "contextless" () -> Allocator {
 	return Allocator{
 		procedure = nil_allocator_proc,
 		data = nil,

+ 5 - 2
base/runtime/default_temp_allocator_arena.odin

@@ -52,10 +52,13 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint
 	return
 }
 
-memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) {
+memory_block_dealloc :: proc "contextless" (block_to_free: ^Memory_Block, loc := #caller_location) {
 	if block_to_free != nil {
+
 		allocator := block_to_free.allocator
 		// sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity)
+		context = default_context()
+		context.allocator = allocator
 		mem_free(block_to_free, allocator, loc)
 	}
 }
@@ -172,7 +175,7 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
 	arena.total_used = 0
 }
 
-arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
+arena_destroy :: proc "contextless" (arena: ^Arena, loc := #caller_location) {
 	for arena.curr_block != nil {
 		free_block := arena.curr_block
 		arena.curr_block = free_block.prev

+ 3 - 3
base/runtime/default_temporary_allocator.odin

@@ -8,7 +8,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
 	
 	default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {}
 	
-	default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {}
+	default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {}
 	
 	default_temp_allocator_proc :: nil_allocator_proc
 
@@ -28,7 +28,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
 		_ = arena_init(&s.arena, uint(size), backing_allocator)
 	}
 
-	default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
+	default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {
 		if s != nil {
 			arena_destroy(&s.arena)
 			s^ = {}
@@ -56,7 +56,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
 	}
 
 	@(fini, private)
-	_destroy_temp_allocator_fini :: proc() {
+	_destroy_temp_allocator_fini :: proc "contextless" () {
 		default_temp_allocator_destroy(&global_default_temp_allocator_data)
 	}
 }

+ 2 - 2
base/runtime/procs_js.odin

@@ -3,8 +3,8 @@ package runtime
 
 init_default_context_for_js: Context
 @(init, private="file")
-init_default_context :: proc() {
-	init_default_context_for_js = context
+init_default_context :: proc "contextless" () {
+	__init_context(&init_default_context_for_js)
 }
 
 @(export)

+ 9 - 2
base/runtime/thread_management.odin

@@ -1,10 +1,14 @@
 package runtime
 
-Thread_Local_Cleaner :: #type proc "odin" ()
+Thread_Local_Cleaner_Odin :: #type proc "odin" ()
+Thread_Local_Cleaner_Contextless :: #type proc "contextless" ()
+
+Thread_Local_Cleaner :: union #shared_nil {Thread_Local_Cleaner_Odin, Thread_Local_Cleaner_Contextless}
 
 @(private="file")
 thread_local_cleaners: [8]Thread_Local_Cleaner
 
+
 // Add a procedure that will be run at the end of a thread for the purpose of
 // deallocating state marked as `thread_local`.
 //
@@ -29,6 +33,9 @@ run_thread_local_cleaners :: proc "odin" () {
 		if p == nil {
 			break
 		}
-		p()
+		switch v in p {
+		case Thread_Local_Cleaner_Odin:        v()
+		case Thread_Local_Cleaner_Contextless: v()
+		}
 	}
 }

+ 6 - 4
core/encoding/cbor/tags.odin

@@ -82,14 +82,16 @@ _tag_implementations_id: map[string]Tag_Implementation
 _tag_implementations_type: map[typeid]Tag_Implementation
 
 // Register a custom tag implementation to be used when marshalling that type and unmarshalling that tag number.
-tag_register_type :: proc(impl: Tag_Implementation, nr: Tag_Number, type: typeid) {
+tag_register_type :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, type: typeid) {
+	context = runtime.default_context()
 	_tag_implementations_nr[nr] = impl
 	_tag_implementations_type[type] = impl
 }
 
 // Register a custom tag implementation to be used when marshalling that tag number or marshalling
 // a field with the struct tag `cbor_tag:"nr"`.
-tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string) {
+tag_register_number :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, id: string) {
+	context = runtime.default_context()
 	_tag_implementations_nr[nr] = impl
 	_tag_implementations_id[id] = impl
 }
@@ -98,13 +100,13 @@ tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string
 INITIALIZE_DEFAULT_TAGS :: #config(CBOR_INITIALIZE_DEFAULT_TAGS, !ODIN_DEFAULT_TO_PANIC_ALLOCATOR && !ODIN_DEFAULT_TO_NIL_ALLOCATOR)
 
 @(private, init, disabled=!INITIALIZE_DEFAULT_TAGS)
-tags_initialize_defaults :: proc() {
+tags_initialize_defaults :: proc "contextless" () {
 	tags_register_defaults()
 }
 
 // Registers tags that have implementations provided by this package.
 // This is done by default and can be controlled with the `CBOR_INITIALIZE_DEFAULT_TAGS` define.
-tags_register_defaults :: proc() {
+tags_register_defaults :: proc "contextless" () {
 	tag_register_number({nil, tag_time_unmarshal,   tag_time_marshal},   TAG_EPOCH_TIME_NR, TAG_EPOCH_TIME_ID)
 	tag_register_number({nil, tag_base64_unmarshal, tag_base64_marshal}, TAG_BASE64_NR,     TAG_BASE64_ID)
 	tag_register_number({nil, tag_cbor_unmarshal,   tag_cbor_marshal},   TAG_CBOR_NR,       TAG_CBOR_ID)

+ 1 - 1
core/flags/rtti.odin

@@ -38,6 +38,6 @@ Note that only one can be active at a time.
 Inputs:
 - setter: The type setter. Pass `nil` to disable any previously set setter.
 */
-register_type_setter :: proc(setter: Custom_Type_Setter) {
+register_type_setter :: proc "contextless" (setter: Custom_Type_Setter) {
 	global_custom_type_setter = setter
 }

+ 1 - 1
core/image/bmp/bmp.odin

@@ -741,6 +741,6 @@ destroy :: proc(img: ^Image) {
 }
 
 @(init, private)
-_register :: proc() {
+_register :: proc "contextless" () {
 	image.register(.BMP, load_from_bytes, destroy)
 }

+ 5 - 5
core/image/general.odin

@@ -10,13 +10,13 @@ Destroy_Proc :: #type proc(img: ^Image)
 _internal_loaders: [Which_File_Type]Loader_Proc
 _internal_destroyers: [Which_File_Type]Destroy_Proc
 
-register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
-	assert(loader != nil)
-	assert(destroyer != nil)
-	assert(_internal_loaders[kind] == nil)
+register :: proc "contextless" (kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
+	assert_contextless(loader != nil)
+	assert_contextless(destroyer != nil)
+	assert_contextless(_internal_loaders[kind] == nil)
 	_internal_loaders[kind] = loader
 
-	assert(_internal_destroyers[kind] == nil)
+	assert_contextless(_internal_destroyers[kind] == nil)
 	_internal_destroyers[kind] = destroyer
 }
 

+ 1 - 1
core/image/netpbm/netpbm.odin

@@ -720,7 +720,7 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for
 }
 
 @(init, private)
-_register :: proc() {
+_register :: proc "contextless" () {
 	loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) {
 		return load_from_bytes(data, allocator)
 	}

+ 1 - 1
core/image/png/png.odin

@@ -1611,6 +1611,6 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
 }
 
 @(init, private)
-_register :: proc() {
+_register :: proc "contextless" () {
 	image.register(.PNG, load_from_bytes, destroy)
 }

+ 1 - 1
core/image/qoi/qoi.odin

@@ -371,6 +371,6 @@ qoi_hash :: #force_inline proc(pixel: RGBA_Pixel) -> (index: u8) {
 }
 
 @(init, private)
-_register :: proc() {
+_register :: proc "contextless" () {
 	image.register(.QOI, load_from_bytes, destroy)
 }

+ 1 - 1
core/image/tga/tga.odin

@@ -406,6 +406,6 @@ IMAGE_DESCRIPTOR_RIGHT_MASK :: 1<<4
 IMAGE_DESCRIPTOR_TOP_MASK   :: 1<<5
 
 @(init, private)
-_register :: proc() {
+_register :: proc "contextless" () {
 	image.register(.TGA, load_from_bytes, destroy)
 }

+ 3 - 1
core/log/file_console_logger.odin

@@ -43,12 +43,14 @@ File_Console_Logger_Data :: struct {
 @(private) global_subtract_stderr_options: Options
 
 @(init, private)
-init_standard_stream_status :: proc() {
+init_standard_stream_status :: proc "contextless" () {
 	// NOTE(Feoramund): While it is technically possible for these streams to
 	// be redirected during the runtime of the program, the cost of checking on
 	// every single log message is not worth it to support such an
 	// uncommonly-used feature.
 	if terminal.color_enabled {
+		context = runtime.default_context()
+
 		// This is done this way because it's possible that only one of these
 		// streams could be redirected to a file.
 		if !terminal.is_terminal(os.stdout) {

+ 10 - 8
core/math/big/helpers.odin

@@ -7,6 +7,7 @@
 package math_big
 
 import "base:intrinsics"
+import "base:runtime"
 import rnd "core:math/rand"
 
 /*
@@ -778,22 +779,23 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
 INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
 
 @(init, private)
-_init_constants :: proc() {
+_init_constants :: proc "contextless" () {
 	initialize_constants()
 }
 
-initialize_constants :: proc() -> (res: int) {
-	internal_set(     INT_ZERO,  0);      INT_ZERO.flags = {.Immutable}
-	internal_set(      INT_ONE,  1);       INT_ONE.flags = {.Immutable}
-	internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
+initialize_constants :: proc "contextless" () -> (res: int) {
+	context = runtime.default_context()
+	internal_int_set_from_integer(     INT_ZERO,  0);      INT_ZERO.flags = {.Immutable}
+	internal_int_set_from_integer(      INT_ONE,  1);       INT_ONE.flags = {.Immutable}
+	internal_int_set_from_integer(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
 
 	/*
 		We set these special values to -1 or 1 so they don't get mistake for zero accidentally.
 		This allows for shortcut tests of is_zero as .used == 0.
 	*/
-	internal_set(      INT_NAN,  1);       INT_NAN.flags = {.Immutable, .NaN}
-	internal_set(      INT_INF,  1);       INT_INF.flags = {.Immutable, .Inf}
-	internal_set(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
+	internal_int_set_from_integer(      INT_NAN,  1);       INT_NAN.flags = {.Immutable, .NaN}
+	internal_int_set_from_integer(      INT_INF,  1);       INT_INF.flags = {.Immutable, .Inf}
+	internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
 
 	return _DEFAULT_MUL_KARATSUBA_CUTOFF
 }

+ 4 - 4
core/math/big/internal.odin

@@ -27,10 +27,10 @@
 
 package math_big
 
-import "core:mem"
+import "base:builtin"
 import "base:intrinsics"
+import "core:mem"
 import rnd "core:math/rand"
-import "base:builtin"
 
 /*
 	Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7.
@@ -2885,12 +2885,12 @@ internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context
 }
 internal_clear_if_uninitialized :: proc {internal_clear_if_uninitialized_single, internal_clear_if_uninitialized_multi, }
 
-internal_error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) {
+internal_error_if_immutable_single :: proc "contextless" (arg: ^Int) -> (err: Error) {
 	if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable }
 	return nil
 }
 
-internal_error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) {
+internal_error_if_immutable_multi :: proc "contextless" (args: ..^Int) -> (err: Error) {
 	for i in args {
 		if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable }
 	}

+ 1 - 1
core/mem/virtual/virtual.odin

@@ -9,7 +9,7 @@ _ :: runtime
 DEFAULT_PAGE_SIZE := uint(4096)
 
 @(init, private)
-platform_memory_init :: proc() {
+platform_memory_init :: proc "contextless" () {
 	_platform_memory_init()
 }
 

+ 2 - 2
core/mem/virtual/virtual_linux.odin

@@ -43,10 +43,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
 	return errno == .NONE
 }
 
-_platform_memory_init :: proc() {
+_platform_memory_init :: proc "contextless" () {
 	DEFAULT_PAGE_SIZE = 4096
 	// is power of two
-	assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
+	assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
 }
 
 

+ 1 - 1
core/mem/virtual/virtual_other.odin

@@ -25,7 +25,7 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
 	return false
 }
 
-_platform_memory_init :: proc() {
+_platform_memory_init :: proc "contextless" () {
 }
 
 _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {

+ 2 - 2
core/mem/virtual/virtual_posix.odin

@@ -28,13 +28,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
 	return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK
 }
 
-_platform_memory_init :: proc() {
+_platform_memory_init :: proc "contextless" () {
 	// NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`.
 	size := posix.sysconf(._PAGESIZE)
 	DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE))
 
 	// is power of two
-	assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
+	assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
 }
 
 _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {

+ 2 - 2
core/mem/virtual/virtual_windows.odin

@@ -146,13 +146,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
 
 
 @(no_sanitize_address)
-_platform_memory_init :: proc() {
+_platform_memory_init :: proc "contextless" () {
 	sys_info: SYSTEM_INFO
 	GetSystemInfo(&sys_info)
 	DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize))
 	
 	// is power of two
-	assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
+	assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
 }
 
 

+ 1 - 1
core/net/socket_windows.odin

@@ -79,7 +79,7 @@ Shutdown_Manner :: enum c.int {
 }
 
 @(init, private)
-ensure_winsock_initialized :: proc() {
+ensure_winsock_initialized :: proc "contextless" () {
 	win.ensure_winsock_initialized()
 }
 

+ 2 - 2
core/os/os2/allocators.odin

@@ -16,7 +16,7 @@ MAX_TEMP_ARENA_COLLISIONS :: MAX_TEMP_ARENA_COUNT - 1
 global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena
 
 @(fini, private)
-temp_allocator_fini :: proc() {
+temp_allocator_fini :: proc "contextless" () {
 	for &arena in global_default_temp_allocator_arenas {
 		runtime.arena_destroy(&arena)
 	}
@@ -69,6 +69,6 @@ _temp_allocator_end :: proc(tmp: runtime.Arena_Temp) {
 }
 
 @(init, private)
-init_thread_local_cleaner :: proc() {
+init_thread_local_cleaner :: proc "contextless" () {
 	runtime.add_thread_local_cleaner(temp_allocator_fini)
 }

+ 2 - 2
core/os/os2/file_linux.odin

@@ -45,8 +45,8 @@ _stderr := File{
 }
 
 @init
-_standard_stream_init :: proc() {
-	new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
+_standard_stream_init :: proc "contextless" () {
+	new_std :: proc "contextless" (impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
 		impl.file.impl = impl
 		impl.fd = linux.Fd(fd)
 		impl.allocator = runtime.nil_allocator()

+ 2 - 2
core/os/os2/file_posix.odin

@@ -25,8 +25,8 @@ File_Impl :: struct {
 }
 
 @(init)
-init_std_files :: proc() {
-	new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
+init_std_files :: proc "contextless" () {
+	new_std :: proc "contextless" (impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
 		impl.file.impl = impl
 		impl.fd = fd
 		impl.allocator = runtime.nil_allocator()

+ 2 - 2
core/os/os2/file_wasi.odin

@@ -30,8 +30,8 @@ Preopen :: struct {
 preopens: []Preopen
 
 @(init)
-init_std_files :: proc() {
-	new_std :: proc(impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File {
+init_std_files :: proc "contextless" () {
+	new_std :: proc "contextless" (impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File {
 		impl.file.impl = impl
 		impl.allocator = runtime.nil_allocator()
 		impl.fd = fd

+ 4 - 4
core/os/os2/file_windows.odin

@@ -43,8 +43,8 @@ File_Impl :: struct {
 }
 
 @(init)
-init_std_files :: proc() {
-	new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File {
+init_std_files :: proc "contextless" () {
+	new_std :: proc "contextless" (impl: ^File_Impl, code: u32, name: string) -> ^File {
 		impl.file.impl = impl
 
 		impl.allocator = runtime.nil_allocator()
@@ -77,7 +77,7 @@ init_std_files :: proc() {
 	stderr = new_std(&files[2], win32.STD_ERROR_HANDLE,  "<stderr>")
 }
 
-_handle :: proc(f: ^File) -> win32.HANDLE {
+_handle :: proc "contextless" (f: ^File) -> win32.HANDLE {
 	return win32.HANDLE(_fd(f))
 }
 
@@ -234,7 +234,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) {
 	return _new_file(uintptr(clonefd), name(f), file_allocator())
 }
 
-_fd :: proc(f: ^File) -> uintptr {
+_fd :: proc "contextless" (f: ^File) -> uintptr {
 	if f == nil || f.impl == nil {
 		return INVALID_HANDLE
 	}

+ 1 - 1
core/os/os2/path_windows.odin

@@ -160,7 +160,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
 can_use_long_paths: bool
 
 @(init)
-init_long_path_support :: proc() {
+init_long_path_support :: proc "contextless" () {
 	can_use_long_paths = false
 
 	key: win32.HKEY

+ 8 - 1
core/os/os2/process.odin

@@ -16,7 +16,8 @@ Arguments to the current process.
 args := get_args()
 
 @(private="file")
-get_args :: proc() -> []string {
+get_args :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	result := make([]string, len(runtime.args__), heap_allocator())
 	for rt_arg, i in runtime.args__ {
 		result[i] = string(rt_arg)
@@ -24,6 +25,12 @@ get_args :: proc() -> []string {
 	return result
 }
 
+@(fini, private="file")
+delete_args :: proc "contextless" () {
+	context = runtime.default_context()
+	delete(args, heap_allocator())
+}
+
 /*
 Exit the current process.
 */

+ 1 - 1
core/os/os2/process_posix_darwin.odin

@@ -13,7 +13,7 @@ import "core:time"
 foreign import lib "system:System"
 
 foreign lib {
-	sysctl :: proc(
+	sysctl :: proc "c" (
 		name: [^]i32, namelen: u32,
 		oldp: rawptr, oldlenp: ^uint,
 		newp: rawptr, newlen: uint,

+ 4 - 2
core/os/os_darwin.odin

@@ -1226,7 +1226,8 @@ _processor_core_count :: proc() -> int {
 }
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> []string {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	res := make([]string, len(runtime.args__))
 	for _, i in res {
 		res[i] = string(runtime.args__[i])
@@ -1235,7 +1236,8 @@ _alloc_command_line_arguments :: proc() -> []string {
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	delete(args)
 }
 

+ 4 - 2
core/os/os_freebsd.odin

@@ -965,7 +965,8 @@ _processor_core_count :: proc() -> int {
 
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> []string {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	res := make([]string, len(runtime.args__))
 	for _, i in res {
 		res[i] = string(runtime.args__[i])
@@ -974,6 +975,7 @@ _alloc_command_line_arguments :: proc() -> []string {
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	delete(args)
 }

+ 4 - 2
core/os/os_haiku.odin

@@ -317,7 +317,8 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
 args := _alloc_command_line_arguments()
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> []string {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	res := make([]string, len(runtime.args__))
 	for arg, i in runtime.args__ {
 		res[i] = string(arg)
@@ -326,7 +327,8 @@ _alloc_command_line_arguments :: proc() -> []string {
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	delete(args)
 }
 

+ 4 - 2
core/os/os_linux.odin

@@ -1098,7 +1098,8 @@ _processor_core_count :: proc() -> int {
 }
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> []string {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	res := make([]string, len(runtime.args__))
 	for _, i in  res {
 		res[i] = string(runtime.args__[i])
@@ -1107,7 +1108,8 @@ _alloc_command_line_arguments :: proc() -> []string {
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	delete(args)
 }
 

+ 4 - 2
core/os/os_netbsd.odin

@@ -1015,7 +1015,8 @@ _processor_core_count :: proc() -> int {
 }
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> []string {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	res := make([]string, len(runtime.args__))
 	for _, i in res {
 		res[i] = string(runtime.args__[i])
@@ -1024,6 +1025,7 @@ _alloc_command_line_arguments :: proc() -> []string {
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	delete(args)
 }

+ 4 - 2
core/os/os_openbsd.odin

@@ -915,7 +915,8 @@ _processor_core_count :: proc() -> int {
 }
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> []string {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	res := make([]string, len(runtime.args__))
 	for _, i in res {
 		res[i] = string(runtime.args__[i])
@@ -924,6 +925,7 @@ _alloc_command_line_arguments :: proc() -> []string {
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	delete(args)
 }

+ 11 - 8
core/os/os_wasi.odin

@@ -28,16 +28,18 @@ stderr: Handle = 2
 args := _alloc_command_line_arguments()
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> (args: []string) {
-	args = make([]string, len(runtime.args__))
-	for &arg, i in args {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
+	cmd_args := make([]string, len(runtime.args__))
+	for &arg, i in cmd_args {
 		arg = string(runtime.args__[i])
 	}
-	return
+	return cmd_args
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	delete(args)
 }
 
@@ -57,9 +59,8 @@ Preopen :: struct {
 preopens: []Preopen
 
 @(init, private)
-init_preopens :: proc() {
-
-	strip_prefixes :: proc(path: string) -> string {
+init_preopens :: proc "contextless" () {
+	strip_prefixes :: proc "contextless"(path: string) -> string {
 		path := path
 		loop: for len(path) > 0 {
 			switch {
@@ -76,6 +77,8 @@ init_preopens :: proc() {
 		return path
 	}
 
+	context = runtime.default_context()
+
 	dyn_preopens: [dynamic]Preopen
 	loop: for fd := wasi.fd_t(3); ; fd += 1 {
 		desc, err := wasi.fd_prestat_get(fd)

+ 4 - 2
core/os/os_windows.odin

@@ -194,7 +194,8 @@ current_thread_id :: proc "contextless" () -> int {
 
 
 @(private, require_results)
-_alloc_command_line_arguments :: proc() -> []string {
+_alloc_command_line_arguments :: proc "contextless" () -> []string {
+	context = runtime.default_context()
 	arg_count: i32
 	arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count)
 	arg_list := make([]string, int(arg_count))
@@ -216,7 +217,8 @@ _alloc_command_line_arguments :: proc() -> []string {
 }
 
 @(private, fini)
-_delete_command_line_arguments :: proc() {
+_delete_command_line_arguments :: proc "contextless" () {
+	context = runtime.default_context()
 	for s in args {
 		delete(s)
 	}

+ 2 - 2
core/sys/info/cpu_intel.odin

@@ -52,7 +52,7 @@ CPU :: struct {
 cpu: CPU
 
 @(init, private)
-init_cpu_features :: proc "c" () {
+init_cpu_features :: proc "contextless" () {
 	is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool {
 		return (value>>bit) & 0x1 != 0
 	}
@@ -156,7 +156,7 @@ init_cpu_features :: proc "c" () {
 _cpu_name_buf: [72]u8
 
 @(init, private)
-init_cpu_name :: proc "c" () {
+init_cpu_name :: proc "contextless" () {
 	number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0)
 	if number_of_extended_ids < 0x8000_0004 {
 		return

+ 3 - 1
core/sys/info/cpu_linux_arm.odin

@@ -2,11 +2,13 @@
 #+build linux
 package sysinfo
 
+import "base:runtime"
 import "core:sys/linux"
 import "core:strings"
 
 @(init, private)
-init_cpu_features :: proc() {
+init_cpu_features :: proc "contextless" () {
+	context = runtime.default_context()
 	fd, err := linux.open("/proc/cpuinfo", {})
 	if err != .NONE { return }
 	defer linux.close(fd)

+ 4 - 1
core/sys/info/cpu_linux_intel.odin

@@ -2,12 +2,15 @@
 #+build linux
 package sysinfo
 
+import "base:runtime"
 import "core:sys/linux"
 import "core:strings"
 import "core:strconv"
 
 @(init, private)
-init_cpu_core_count :: proc() {
+init_cpu_core_count :: proc "contextless" () {
+	context = runtime.default_context()
+
 	fd, err := linux.open("/proc/cpuinfo", {})
 	if err != .NONE { return }
 	defer linux.close(fd)

+ 5 - 5
core/sys/info/cpu_linux_riscv64.odin

@@ -7,7 +7,7 @@ import "base:intrinsics"
 import "core:sys/linux"
 
 @(init, private)
-init_cpu_features :: proc() {
+init_cpu_features :: proc "contextless" () {
 	_features: CPU_Features
 	defer cpu.features = _features
 
@@ -81,11 +81,11 @@ init_cpu_features :: proc() {
 		}
 		err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {})
 		if err != nil {
-			assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
+			assert_contextless(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
 			return
 		}
 
-		assert(pairs[0].key == .IMA_EXT_0)
+		assert_contextless(pairs[0].key == .IMA_EXT_0)
 		exts := pairs[0].value.ima_ext_0
 		exts -= { .FD, .C, .V }
 		_features += transmute(CPU_Features)exts
@@ -97,7 +97,7 @@ init_cpu_features :: proc() {
 				_features += { .Misaligned_Supported }
 			}
 		} else {
-			assert(pairs[1].key == .CPUPERF_0)
+			assert_contextless(pairs[1].key == .CPUPERF_0)
 			if .FAST in pairs[1].value.cpu_perf_0 {
 				_features += { .Misaligned_Supported, .Misaligned_Fast }
 			} else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 {
@@ -108,6 +108,6 @@ init_cpu_features :: proc() {
 }
 
 @(init, private)
-init_cpu_name :: proc() {
+init_cpu_name :: proc "contextless" () {
 	cpu.name = "RISCV64"
 }

+ 4 - 1
core/sys/info/cpu_windows.odin

@@ -2,9 +2,12 @@ package sysinfo
 
 import sys "core:sys/windows"
 import "base:intrinsics"
+import "base:runtime"
 
 @(init, private)
-init_cpu_core_count :: proc() {
+init_cpu_core_count :: proc "contextless" () {
+	context = runtime.default_context()
+
 	infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION
 	defer delete(infos)
 

+ 4 - 2
core/sys/info/platform_bsd.odin

@@ -10,7 +10,9 @@ import "base:runtime"
 version_string_buf: [1024]u8
 
 @(init, private)
-init_os_version :: proc () {
+init_os_version :: proc "contextless" () {
+	context = runtime.default_context()
+
 	when ODIN_OS == .NetBSD {
 		os_version.platform = .NetBSD
 	} else {
@@ -66,7 +68,7 @@ init_os_version :: proc () {
 }
 
 @(init, private)
-init_ram :: proc() {
+init_ram :: proc "contextless" () {
 	// Retrieve RAM info using `sysctl`
 	mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64}
 	mem_size: u64

+ 4 - 1
core/sys/info/platform_darwin.odin

@@ -1,5 +1,7 @@
 package sysinfo
 
+import "base:runtime"
+
 import    "core:strconv"
 import    "core:strings"
 import    "core:sys/unix"
@@ -9,7 +11,8 @@ import NS "core:sys/darwin/Foundation"
 version_string_buf: [1024]u8
 
 @(init, private)
-init_platform :: proc() {
+init_platform :: proc "contextless" () {
+	context = runtime.default_context()
 	ws :: strings.write_string
 	wi :: strings.write_int
 

+ 4 - 2
core/sys/info/platform_freebsd.odin

@@ -9,7 +9,9 @@ import "base:runtime"
 version_string_buf: [1024]u8
 
 @(init, private)
-init_os_version :: proc () {
+init_os_version :: proc "contextless" () {
+	context = runtime.default_context()
+
 	os_version.platform = .FreeBSD
 
 	kernel_version_buf: [1024]u8
@@ -68,7 +70,7 @@ init_os_version :: proc () {
 }
 
 @(init, private)
-init_ram :: proc() {
+init_ram :: proc "contextless" () {
 	// Retrieve RAM info using `sysctl`
 	mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM}
 	mem_size: u64

+ 6 - 3
core/sys/info/platform_linux.odin

@@ -1,6 +1,7 @@
 package sysinfo
 
 import "base:intrinsics"
+import "base:runtime"
 
 import "core:strconv"
 import "core:strings"
@@ -10,7 +11,9 @@ import "core:sys/linux"
 version_string_buf: [1024]u8
 
 @(init, private)
-init_os_version :: proc () {
+init_os_version :: proc "contextless" () {
+	context = runtime.default_context()
+
 	os_version.platform = .Linux
 
 	b := strings.builder_from_bytes(version_string_buf[:])
@@ -91,11 +94,11 @@ init_os_version :: proc () {
 }
 
 @(init, private)
-init_ram :: proc() {
+init_ram :: proc "contextless" () {
 	// Retrieve RAM info using `sysinfo`
 	sys_info: linux.Sys_Info
 	errno := linux.sysinfo(&sys_info)
-	assert(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!")
+	assert_contextless(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!")
 	ram = RAM{
 		total_ram  = int(sys_info.totalram)  * int(sys_info.mem_unit),
 		free_ram   = int(sys_info.freeram)   * int(sys_info.mem_unit),

+ 8 - 4
core/sys/info/platform_windows.odin

@@ -12,7 +12,9 @@ import "base:runtime"
 version_string_buf: [1024]u8
 
 @(init, private)
-init_os_version :: proc () {
+init_os_version :: proc "contextless" () {
+	context = runtime.default_context()
+
 	/*
 		NOTE(Jeroen):
 			`GetVersionEx`  will return 6.2 for Windows 10 unless the program is manifested for Windows 10.
@@ -43,6 +45,7 @@ init_os_version :: proc () {
 	os_version.minor    = int(osvi.dwMinorVersion)
 	os_version.build[0] = int(osvi.dwBuildNumber)
 
+
 	b := strings.builder_from_bytes(version_string_buf[:])
 	strings.write_string(&b, "Windows ")
 
@@ -259,7 +262,7 @@ init_os_version :: proc () {
 }
 
 @(init, private)
-init_ram :: proc() {
+init_ram :: proc "contextless" () {
 	state: sys.MEMORYSTATUSEX
 
 	state.dwLength = size_of(state)
@@ -276,10 +279,11 @@ init_ram :: proc() {
 }
 
 @(init, private)
-init_gpu_info :: proc() {
-
+init_gpu_info :: proc "contextless" () {
 	GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\"
 
+	context = runtime.default_context()
+
 	gpu_list: [dynamic]GPU
 	gpu_index: int
 

+ 1 - 1
core/sys/posix/stdlib_libc.odin

@@ -60,7 +60,7 @@ wctomb        :: libc.wctomb
 mbstowcs      :: libc.mbstowcs
 wcstombs      :: libc.wcstombs
 
-free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring {
+free :: #force_inline proc "c" (ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring {
 	libc.free(rawptr(ptr))
 }
 

+ 1 - 1
core/sys/unix/sysctl_freebsd.odin

@@ -3,7 +3,7 @@ package unix
 
 import "base:intrinsics"
 
-sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
+sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
 	mib := mib
 	result_size := u64(size_of(T))
 

+ 1 - 1
core/sys/unix/sysctl_netbsd.odin

@@ -8,7 +8,7 @@ foreign libc {
 	@(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
 }
 
-sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
+sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
 	mib := mib
 	result_size := c.size_t(size_of(T))
 	res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)

+ 1 - 1
core/sys/unix/sysctl_openbsd.odin

@@ -9,7 +9,7 @@ foreign libc {
 	@(link_name="sysctl")	_unix_sysctl    :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
 }
 
-sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
+sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
 	mib := mib
 	result_size := c.size_t(size_of(T))
 	res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)

+ 2 - 2
core/sys/windows/util.odin

@@ -628,7 +628,7 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P
 	}
 }
 
-ensure_winsock_initialized :: proc() {
+ensure_winsock_initialized :: proc "contextless" () {
 	@static gate := false
 	@static initted := false
 
@@ -644,7 +644,7 @@ ensure_winsock_initialized :: proc() {
 	unused_info: WSADATA
 	version_requested := WORD(2) << 8 | 2
 	res := WSAStartup(version_requested, &unused_info)
-	assert(res == 0, "unable to initialized Winsock2")
+	assert_contextless(res == 0, "unable to initialized Winsock2")
 
 	initted = true
 }

+ 5 - 2
core/terminal/internal.odin

@@ -1,6 +1,7 @@
 #+private
 package terminal
 
+import "base:runtime"
 import "core:os"
 import "core:strings"
 
@@ -68,9 +69,11 @@ get_environment_color :: proc() -> Color_Depth {
 }
 
 @(init)
-init_terminal :: proc() {
+init_terminal :: proc "contextless" () {
 	_init_terminal()
 
+	context = runtime.default_context()
+
 	// We respect `NO_COLOR` specifically as a color-disabler but not as a
 	// blanket ban on any terminal manipulation codes, hence why this comes
 	// after `_init_terminal` which will allow Windows to enable Virtual
@@ -81,6 +84,6 @@ init_terminal :: proc() {
 }
 
 @(fini)
-fini_terminal :: proc() {
+fini_terminal :: proc "contextless" () {
 	_fini_terminal()
 }

+ 3 - 3
core/terminal/terminal_js.odin

@@ -4,12 +4,12 @@ package terminal
 
 import "core:os"
 
-_is_terminal :: proc(handle: os.Handle) -> bool {
+_is_terminal :: proc "contextless" (handle: os.Handle) -> bool {
 	return true
 }
 
-_init_terminal :: proc() {
+_init_terminal :: proc "contextless" () {
 	color_depth = .None
 }
 
-_fini_terminal :: proc() { }
+_fini_terminal :: proc "contextless" () { }

+ 5 - 3
core/terminal/terminal_posix.odin

@@ -2,15 +2,17 @@
 #+build linux, darwin, netbsd, openbsd, freebsd, haiku
 package terminal
 
+import "base:runtime"
 import "core:os"
 import "core:sys/posix"
 
-_is_terminal :: proc(handle: os.Handle) -> bool {
+_is_terminal :: proc "contextless" (handle: os.Handle) -> bool {
 	return bool(posix.isatty(posix.FD(handle)))
 }
 
-_init_terminal :: proc() {
+_init_terminal :: proc "contextless" () {
+	context = runtime.default_context()
 	color_depth = get_environment_color()
 }
 
-_fini_terminal :: proc() { }
+_fini_terminal :: proc "contextless" () { }

+ 6 - 3
core/terminal/terminal_windows.odin

@@ -1,10 +1,11 @@
 #+private
 package terminal
 
+import "base:runtime"
 import "core:os"
 import "core:sys/windows"
 
-_is_terminal :: proc(handle: os.Handle) -> bool {
+_is_terminal :: proc "contextless" (handle: os.Handle) -> bool {
 	is_tty := windows.GetFileType(windows.HANDLE(handle)) == windows.FILE_TYPE_CHAR
 	return is_tty
 }
@@ -18,7 +19,7 @@ old_modes: [2]struct{
 }
 
 @(init)
-_init_terminal :: proc() {
+_init_terminal :: proc "contextless" () {
 	vtp_enabled: bool
 
 	for &v in old_modes {
@@ -42,13 +43,15 @@ _init_terminal :: proc() {
 		// This color depth is available on Windows 10 since build 10586.
 		color_depth = .Four_Bit
 	} else {
+		context = runtime.default_context()
+
 		// The user may be on a non-default terminal emulator.
 		color_depth = get_environment_color()
 	}
 }
 
 @(fini)
-_fini_terminal :: proc() {
+_fini_terminal :: proc "contextless" () {
 	for v in old_modes {
 		handle := windows.GetStdHandle(v.handle)
 		if handle == windows.INVALID_HANDLE || handle == nil {

+ 6 - 0
src/check_decl.cpp

@@ -1851,6 +1851,12 @@ gb_internal void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d,
 		c.scope = d->scope;
 		c.decl  = d;
 		c.type_level = 0;
+		c.curr_proc_calling_convention = ProcCC_Contextless;
+
+		auto prev_flags = c.scope->flags;
+		defer (c.scope->flags = prev_flags);
+		c.scope->flags &= ~ScopeFlag_ContextDefined;
+
 
 		e->parent_proc_decl = c.curr_proc_decl;
 		e->state = EntityState_InProgress;

+ 6 - 2
src/check_expr.cpp

@@ -8169,8 +8169,12 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
 	if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) {
 		if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) {
 			ERROR_BLOCK();
-			error(call, "'context' has not been defined within this scope, but is required for this procedure call");
-			error_line("\tSuggestion: 'context = runtime.default_context()'");
+			if (c->scope->flags & ScopeFlag_File) {
+				error(call, "Procedures requiring a 'context' cannot be called at the global scope");
+			} else {
+				error(call, "'context' has not been defined within this scope, but is required for this procedure call");
+				error_line("\tSuggestion: 'context = runtime.default_context()'");
+			}
 		}
 	}
 

+ 9 - 0
src/checker.cpp

@@ -2675,6 +2675,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
 					is_init = false;
 				}
 
+				if (t->Proc.calling_convention != ProcCC_Contextless) {
+					error(e->token, "@(init) procedures must be declared as \"contextless\"");
+				}
+
 				if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
 					error(e->token, "@(init) procedures must be declared at the file scope");
 					is_init = false;
@@ -2689,6 +2693,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
 					error(e->token, "An @(init) procedure must not use a blank identifier as its name");
 				}
 
+
 				if (is_init) {
 					add_dependency_to_set(c, e);
 					array_add(&c->info.init_procedures, e);
@@ -2706,6 +2711,10 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st
 					is_fini = false;
 				}
 
+				if (t->Proc.calling_convention != ProcCC_Contextless) {
+					error(e->token, "@(fini) procedures must be declared as \"contextless\"");
+				}
+
 				if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
 					error(e->token, "@(fini) procedures must be declared at the file scope");
 					is_fini = false;

+ 1 - 1
tests/core/flags/test_core_flags.odin

@@ -17,7 +17,7 @@ Custom_Data :: struct {
 }
 
 @(init)
-init_custom_type_setter :: proc() {
+init_custom_type_setter :: proc "contextless" () {
 	// NOTE: This is done here so it can be out of the flow of the
 	// multi-threaded test runner, to prevent any data races that could be
 	// reported by using `-sanitize:thread`.

+ 2 - 2
tests/core/normal.odin

@@ -3,9 +3,9 @@ package tests_core
 import rlibc "core:c/libc"
 
 @(init)
-download_assets :: proc() {
+download_assets :: proc "contextless" () {
 	if rlibc.system("python3 " + ODIN_ROOT + "tests/core/download_assets.py " + ODIN_ROOT + "tests/core/assets") != 0 {
-		panic("downloading test assets failed!")
+		panic_contextless("downloading test assets failed!")
 	}
 }
 

+ 1 - 1
tests/internal/test_global_any.odin

@@ -3,7 +3,7 @@ package test_internal
 @(private="file")
 global_any_from_proc: any = from_proc()
 
-from_proc :: proc() -> f32 {
+from_proc :: proc "contextless" () -> f32 {
 	return 1.1
 }
 

+ 3 - 2
vendor/libc/libc.odin

@@ -10,8 +10,9 @@ g_ctx: runtime.Context
 g_allocator: mem.Compat_Allocator
 
 @(init)
-init_context :: proc() {
-	g_ctx = context
+init_context :: proc "contextless" () {
+	g_ctx = runtime.default_context()
+	context = g_ctx
 
 	// Wrapping the allocator with the mem.Compat_Allocator so we can
 	// mimic the realloc semantics.

+ 1 - 1
vendor/libc/stdlib.odin

@@ -169,7 +169,7 @@ exit :: proc "c" (exit_code: c.int) -> ! {
 }
 
 @(private, fini)
-finish_atexit :: proc "c" () {
+finish_atexit :: proc "contextless" () {
 	n := intrinsics.atomic_exchange(&atexit_functions_count, 0)
 	for function in atexit_functions[:n] {
 		function()

+ 2 - 2
vendor/miniaudio/common.odin

@@ -25,7 +25,7 @@ BINDINGS_VERSION          :: [3]u32{BINDINGS_VERSION_MAJOR, BINDINGS_VERSION_MIN
 BINDINGS_VERSION_STRING   :: "0.11.22"
 
 @(init)
-version_check :: proc() {
+version_check :: proc "contextless" () {
 	v: [3]u32
 	version(&v.x, &v.y, &v.z)
 	if v != BINDINGS_VERSION {
@@ -43,7 +43,7 @@ version_check :: proc() {
 			n += copy(buf[n:], "and executing `make`")
 		}
 
-		panic(string(buf[:n]))
+		panic_contextless(string(buf[:n]))
 	}
 }
 

+ 1 - 1
vendor/wgpu/wgpu_js.odin

@@ -5,7 +5,7 @@ import "base:runtime"
 g_context: runtime.Context
 
 @(private="file", init)
-wgpu_init_allocator :: proc() {
+wgpu_init_allocator :: proc "contextless" () {
 	if g_context.allocator.procedure == nil {
 		g_context = runtime.default_context()
 	}