wip
This commit is contained in:
parent
0eee2a4ff3
commit
4ee315a4de
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type" FORCE)
|
||||
endif()
|
||||
# Set C++ standard
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
project(bb)
|
||||
|
||||
add_executable(bb src/main.cpp)
|
||||
target_compile_definitions(bb PUBLIC
|
||||
$<$<CONFIG:Debug>:BB_DEBUG=1>
|
||||
$<$<NOT:$<CONFIG:Debug>>:BB_DEBUG=0>
|
||||
)
|
63
build.sh
63
build.sh
@ -1,61 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
MY_CWD=$PWD
|
||||
|
||||
if [[ -z "${BB_CI-}" ]]; then
|
||||
BB_CI=0
|
||||
fi
|
||||
|
||||
if [[ -z "${BB_BUILD_TYPE-}" ]]; then
|
||||
BB_BUILD_TYPE=debug
|
||||
fi
|
||||
|
||||
if [[ -z "${BB_ERROR_ON_WARNINGS-}" ]]; then
|
||||
BB_ERROR_ON_WARNINGS=$BB_CI
|
||||
fi
|
||||
|
||||
if [[ -z "${BB_ERROR_LIMIT-}" ]]; then
|
||||
BB_ERROR_LIMIT=$((1 - BB_CI))
|
||||
fi
|
||||
|
||||
BB_COMPILE_SHADERS=0
|
||||
|
||||
BUILD_DIR=cache
|
||||
LARGE_ASSET_BASE_URL=https://github.com/birth-software/bloat-buster/releases/download/large-assets
|
||||
mkdir -p $BUILD_DIR
|
||||
|
||||
if [[ ! -f "$BUILD_DIR/large_assembly.s" ]]; then
|
||||
cd $BUILD_DIR
|
||||
wget $LARGE_ASSET_BASE_URL/large_assembly.s -o large_assembly.s
|
||||
cd $MY_CWD
|
||||
fi
|
||||
|
||||
if [[ "${BB_COMPILE_SHADERS}" == "1" ]]; then
|
||||
glslangValidator -V bootstrap/std/shaders/rect.vert -o $BUILD_DIR/rect.vert.spv --quiet
|
||||
glslangValidator -V bootstrap/std/shaders/rect.frag -o $BUILD_DIR/rect.frag.spv --quiet
|
||||
fi
|
||||
|
||||
BUILD_OUT=$BUILD_DIR/build
|
||||
C_COMPILER=clang
|
||||
TIME_TRACE=1
|
||||
BB_TIMETRACE=0
|
||||
GCC_ARGS=
|
||||
CLANG_ARGS=
|
||||
TIME_TRACE_ARG=
|
||||
|
||||
if [[ $C_COMPILER == "clang"* ]]; then
|
||||
CLANG_ARGS=-ferror-limit=1
|
||||
if [[ "$TIME_TRACE" == "1" ]]; then
|
||||
CLANG_ARGS="$CLANG_ARGS -ftime-trace"
|
||||
BB_TIMETRACE=1
|
||||
else
|
||||
CLANG_ARGS="$CLANG_ARGS -ftime-trace"
|
||||
fi
|
||||
elif [[ $C_COMPILER == "gcc"* ]]; then
|
||||
GCC_ARGS=-fmax-errors=1
|
||||
fi
|
||||
|
||||
$C_COMPILER build.c -g -o $BUILD_OUT -Ibootstrap -std=gnu2x $CLANG_ARGS $GCC_ARGS -DBB_TIMETRACE=$BB_TIMETRACE -DBB_CI=$BB_CI -DBB_BUILD_TYPE=\"$BB_BUILD_TYPE\" -DBB_ERROR_ON_WARNINGS=$BB_ERROR_ON_WARNINGS -DBB_ERROR_LIMIT=$BB_ERROR_LIMIT
|
||||
$BUILD_OUT $@
|
||||
exit 0
|
||||
cd build
|
||||
ninja --quiet
|
||||
cd ..
|
||||
|
7
generate.sh
Executable file
7
generate.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=MOLD
|
||||
cd ..
|
61
old_build.sh
Executable file
61
old_build.sh
Executable file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
MY_CWD=$PWD
|
||||
|
||||
if [[ -z "${BB_CI-}" ]]; then
|
||||
BB_CI=0
|
||||
fi
|
||||
|
||||
if [[ -z "${BB_BUILD_TYPE-}" ]]; then
|
||||
BB_BUILD_TYPE=debug
|
||||
fi
|
||||
|
||||
if [[ -z "${BB_ERROR_ON_WARNINGS-}" ]]; then
|
||||
BB_ERROR_ON_WARNINGS=$BB_CI
|
||||
fi
|
||||
|
||||
if [[ -z "${BB_ERROR_LIMIT-}" ]]; then
|
||||
BB_ERROR_LIMIT=$((1 - BB_CI))
|
||||
fi
|
||||
|
||||
BB_COMPILE_SHADERS=0
|
||||
|
||||
BUILD_DIR=cache
|
||||
LARGE_ASSET_BASE_URL=https://github.com/birth-software/bloat-buster/releases/download/large-assets
|
||||
mkdir -p $BUILD_DIR
|
||||
|
||||
if [[ ! -f "$BUILD_DIR/large_assembly.s" ]]; then
|
||||
cd $BUILD_DIR
|
||||
wget $LARGE_ASSET_BASE_URL/large_assembly.s -o large_assembly.s
|
||||
cd $MY_CWD
|
||||
fi
|
||||
|
||||
if [[ "${BB_COMPILE_SHADERS}" == "1" ]]; then
|
||||
glslangValidator -V bootstrap/std/shaders/rect.vert -o $BUILD_DIR/rect.vert.spv --quiet
|
||||
glslangValidator -V bootstrap/std/shaders/rect.frag -o $BUILD_DIR/rect.frag.spv --quiet
|
||||
fi
|
||||
|
||||
BUILD_OUT=$BUILD_DIR/build
|
||||
C_COMPILER=clang
|
||||
TIME_TRACE=1
|
||||
BB_TIMETRACE=0
|
||||
GCC_ARGS=
|
||||
CLANG_ARGS=
|
||||
TIME_TRACE_ARG=
|
||||
|
||||
if [[ $C_COMPILER == "clang"* ]]; then
|
||||
CLANG_ARGS=-ferror-limit=1
|
||||
if [[ "$TIME_TRACE" == "1" ]]; then
|
||||
CLANG_ARGS="$CLANG_ARGS -ftime-trace"
|
||||
BB_TIMETRACE=1
|
||||
else
|
||||
CLANG_ARGS="$CLANG_ARGS -ftime-trace"
|
||||
fi
|
||||
elif [[ $C_COMPILER == "gcc"* ]]; then
|
||||
GCC_ARGS=-fmax-errors=1
|
||||
fi
|
||||
|
||||
$C_COMPILER build.c -g -o $BUILD_OUT -Ibootstrap -std=gnu2x $CLANG_ARGS $GCC_ARGS -DBB_TIMETRACE=$BB_TIMETRACE -DBB_CI=$BB_CI -DBB_BUILD_TYPE=\"$BB_BUILD_TYPE\" -DBB_ERROR_ON_WARNINGS=$BB_ERROR_ON_WARNINGS -DBB_ERROR_LIMIT=$BB_ERROR_LIMIT
|
||||
$BUILD_OUT $@
|
||||
exit 0
|
298
src/main.cpp
Normal file
298
src/main.cpp
Normal file
@ -0,0 +1,298 @@
|
||||
#define fn static
|
||||
#define internal static
|
||||
#define unused(x) (void)(x)
|
||||
#define breakpoint() __builtin_debugtrap()
|
||||
|
||||
#define unreachable_raw() __builtin_unreachable()
|
||||
#define trap_raw() __builtin_trap()
|
||||
#if BB_DEBUG
|
||||
#define unreachable() trap_raw()
|
||||
#else
|
||||
#define unreachable() unreachable_raw()
|
||||
#endif
|
||||
|
||||
#define expect(x, b) __builtin_expect(!!(x), b)
|
||||
#define likely(x) expect(x, 1)
|
||||
#define unlikely(x) expect(x, 0)
|
||||
|
||||
#define assert(x) (unlikely(!(x)) ? unreachable() : unused(0))
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long u64;
|
||||
|
||||
typedef signed char s8;
|
||||
typedef signed short s16;
|
||||
typedef signed int s32;
|
||||
typedef signed long s64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
internal u64 align_forward(u64 value, u64 alignment)
|
||||
{
|
||||
assert(alignment != 0);
|
||||
auto mask = alignment - 1;
|
||||
auto result = (value + mask) & ~mask;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr u64 kb = 1024;
|
||||
constexpr u64 mb = 1024 * 1024;
|
||||
constexpr u64 gb = 1024 * 1024 * 1024;
|
||||
|
||||
template <typename T>
|
||||
struct Slice
|
||||
{
|
||||
T* pointer;
|
||||
u64 length;
|
||||
|
||||
T* begin() { return pointer; }
|
||||
T* end() { return pointer + length; }
|
||||
};
|
||||
|
||||
using String = Slice<u8>;
|
||||
|
||||
struct ProtectionFlags
|
||||
{
|
||||
u8 read:1;
|
||||
u8 write:1;
|
||||
u8 execute:1;
|
||||
};
|
||||
|
||||
struct MapFlags
|
||||
{
|
||||
u8 priv:1;
|
||||
u8 anonymous:1;
|
||||
u8 no_reserve:1;
|
||||
u8 populate:1;
|
||||
};
|
||||
|
||||
struct PROT
|
||||
{
|
||||
u32 read:1;
|
||||
u32 write:1;
|
||||
u32 execute:1;
|
||||
u32 sem:1;
|
||||
u32 _:28;
|
||||
};
|
||||
static_assert(sizeof(PROT) == sizeof(u32));
|
||||
|
||||
struct MAP
|
||||
{
|
||||
enum class Type : u32
|
||||
{
|
||||
shared = 0,
|
||||
priv = 1,
|
||||
shared_validate = 2,
|
||||
};
|
||||
|
||||
Type type:4;
|
||||
u32 fixed:1;
|
||||
u32 anonymous:1;
|
||||
u32 bit32:1;
|
||||
u32 _0: 1;
|
||||
u32 grows_down:1;
|
||||
u32 _1: 2;
|
||||
u32 deny_write:1;
|
||||
u32 executable:1;
|
||||
u32 locked:1;
|
||||
u32 no_reserve:1;
|
||||
u32 populate:1;
|
||||
u32 non_block:1;
|
||||
u32 stack:1;
|
||||
u32 huge_tlb:1;
|
||||
u32 sync:1;
|
||||
u32 fixed_no_replace:1;
|
||||
u32 _2:5;
|
||||
u32 uninitialized:1;
|
||||
u32 _3:5;
|
||||
};
|
||||
static_assert(sizeof(MAP) == sizeof(u32));
|
||||
|
||||
#include <string.h>
|
||||
extern "C" void *memcpy (void *__restrict __dest, const void *__restrict __src, size_t __n) __THROW __nonnull ((1, 2));
|
||||
|
||||
extern "C" void* mmap(void*, u64, PROT, MAP, s32, s64);
|
||||
extern "C" s32 mprotect(void*, u64, PROT);
|
||||
|
||||
fn void* os_reserve(void* base, u64 size, ProtectionFlags protection, MapFlags map)
|
||||
{
|
||||
auto protection_flags = PROT
|
||||
{
|
||||
.read = protection.read,
|
||||
.write = protection.write,
|
||||
.execute = protection.execute,
|
||||
};
|
||||
|
||||
auto map_flags = MAP
|
||||
{
|
||||
.type = map.priv ? MAP::Type::priv : MAP::Type::shared,
|
||||
.anonymous = map.anonymous,
|
||||
.no_reserve = map.no_reserve,
|
||||
.populate = map.populate,
|
||||
};
|
||||
|
||||
auto* address = mmap(base, size, protection_flags, map_flags, -1, 0);
|
||||
assert((u64)address != ~(u64)0);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
fn void os_commit(void* address, u64 size, ProtectionFlags protection)
|
||||
{
|
||||
auto protection_flags = PROT
|
||||
{
|
||||
.read = protection.read,
|
||||
.write = protection.write,
|
||||
.execute = protection.execute,
|
||||
};
|
||||
auto result = mprotect(address, size, protection_flags);
|
||||
assert(!result);
|
||||
}
|
||||
|
||||
struct ArenaInitialization
|
||||
{
|
||||
u64 reserved_size;
|
||||
u64 granularity;
|
||||
u64 initial_size;
|
||||
};
|
||||
|
||||
struct Arena
|
||||
{
|
||||
u64 reserved_size;
|
||||
u64 position;
|
||||
u64 os_position;
|
||||
u64 granularity;
|
||||
u8 reserved[32];
|
||||
};
|
||||
|
||||
constexpr u64 arena_minimum_position = sizeof(Arena);
|
||||
|
||||
fn Arena& arena_initialize(ArenaInitialization i)
|
||||
{
|
||||
ProtectionFlags protection_flags = {
|
||||
.read = 1,
|
||||
.write = 1,
|
||||
};
|
||||
MapFlags map_flags = {
|
||||
.priv = 1,
|
||||
.anonymous = 1,
|
||||
.no_reserve = 1,
|
||||
};
|
||||
|
||||
auto* arena = (Arena*)os_reserve(0, i.reserved_size, protection_flags, map_flags);
|
||||
os_commit(arena, i.initial_size, { .read = 1, .write = 1 });
|
||||
|
||||
*arena = {
|
||||
.reserved_size = i.reserved_size,
|
||||
.position = arena_minimum_position,
|
||||
.os_position = i.initial_size,
|
||||
.granularity = i.granularity,
|
||||
};
|
||||
|
||||
return *arena;
|
||||
}
|
||||
|
||||
fn inline Arena& arena_initialize_default(u64 initial_size)
|
||||
{
|
||||
ArenaInitialization i = {
|
||||
.reserved_size = 4 * gb,
|
||||
.granularity = 4 * kb,
|
||||
.initial_size = initial_size,
|
||||
};
|
||||
return arena_initialize(i);
|
||||
}
|
||||
|
||||
fn void* arena_allocate_bytes(Arena& arena, u64 size, u64 alignment)
|
||||
{
|
||||
auto aligned_offset = align_forward(arena.position, alignment);
|
||||
auto aligned_size_after = aligned_offset + size;
|
||||
|
||||
if (aligned_size_after > arena.os_position)
|
||||
{
|
||||
unreachable();
|
||||
}
|
||||
|
||||
auto* result = (u8*)&arena + aligned_offset;
|
||||
arena.position = aligned_size_after;
|
||||
assert(arena.position <= arena.os_position);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
fn Slice<T> arena_allocate(Arena& arena, u64 count)
|
||||
{
|
||||
return { (T*)arena_allocate_bytes(arena, sizeof(T) * count, alignof(T)), count };
|
||||
}
|
||||
|
||||
fn String arena_join_string(Arena& arena, Slice<String> pieces)
|
||||
{
|
||||
u64 size = 0;
|
||||
for (auto piece : pieces)
|
||||
{
|
||||
size += piece.length;
|
||||
}
|
||||
|
||||
auto* pointer = (u8*)arena_allocate_bytes(arena, size + 1, 1);
|
||||
u64 i = 0;
|
||||
for (auto piece : pieces)
|
||||
{
|
||||
memcpy(pointer + i, piece.pointer, piece.length);
|
||||
i += piece.length;
|
||||
}
|
||||
|
||||
assert(i == size);
|
||||
pointer[i] = 0;
|
||||
|
||||
return { pointer, size };
|
||||
}
|
||||
|
||||
fn String arena_duplicate_string(Arena& arena, String string)
|
||||
{
|
||||
auto memory = (u8*)arena_allocate_bytes(arena, string.length + 1, 1);
|
||||
memcpy(memory, string.pointer, string.length);
|
||||
memory[string.length] = 0;
|
||||
return { memory, string.length};
|
||||
}
|
||||
|
||||
fn void arena_restore(Arena& arena, u64 position)
|
||||
{
|
||||
assert(position <= arena.position);
|
||||
arena.position = position;
|
||||
}
|
||||
|
||||
fn void arena_reset(Arena& arena)
|
||||
{
|
||||
arena.position = arena_minimum_position;
|
||||
}
|
||||
|
||||
struct GlobalState
|
||||
{
|
||||
Arena* arena;
|
||||
};
|
||||
|
||||
fn void entry_point(Slice<const char*> arguments, Slice<const char*> environment);
|
||||
|
||||
int main(int argc, const char* argv[], const char* envp[])
|
||||
{
|
||||
auto* envp_end = envp;
|
||||
while (*envp_end)
|
||||
{
|
||||
envp_end += 1;
|
||||
}
|
||||
|
||||
entry_point({argv, (u64)argc}, {envp, (u64)(envp_end - envp)});
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn void entry_point(Slice<const char*> arguments, Slice<const char*> environment)
|
||||
{
|
||||
auto arena = arena_initialize_default(8 * mb);
|
||||
|
||||
if (arguments.length < 2)
|
||||
{
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user