diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8a44724 --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar +14 rue de Plaisance, 75014 Paris, France + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. You just DO WHAT THE FUCK YOU WANT TO. + diff --git a/README b/README index e69de29..33a6d46 100644 --- a/README +++ b/README @@ -0,0 +1,129 @@ +This is the XOmB-barebones distribution. It comes with the bare minimum needed to get a booting OS in D. + +Except we added kprintfln. You're welcome. + +The updated version of this file is kept on our wiki, located here: +http://wiki.xomb.org/index.php?title=XOmB_Bare_Bones + +Don't expect this to be kept as up to date. We'll try, but the newest version will always be on the wiki, so check there. + +The XOmB Bare Bones distribution is a minimal 64 bit OS written in D, distilled from the main project by [[User:Wilkie|wilkie]] and [[User:Steveklabnik|Steve Klabnik]]. + + +== About == +The [http://wiki.osdev.org osdev wiki] has a page called [http://wiki.osdev.org/Bare_Bones Bare Bones]. On it, they show how to make a minimal OS written in the C programming language. When we started [http://forum.osdev.org/viewtopic.php?f=15&t=18914 discussing programming an OS in D], some people indicated an interest in having a similar example, but in the D language. + +We decided to oblige. We've distilled a minimal OS out of XOmB, and are releasing it as the "XOmB Bare Bones" distribution. + +== Get XBB == +The git repository is located [http://github.com/xomboverlord/xomb-bare-bones/tree/master here]. If you haven't used git before, check out our [[Using Git]] tutorial. + +The short lowdown: + +git clone git://github.com/xomboverlord/xomb-bare-bones.git + + +== Using XBB == + +First, a small word about compilers: GDC is dead. Unfortunatly, LDC isn't quite up to snuff yet, and while it's being worked on, unfortunatly, we have to stick with GDC. Expect things to get better in this area soon. + +The first thing that you need to do in order to use XBB is create a cross compiler. Unfortunatly, our wiki is sparse on this subject at the moment, and so is the [http://wiki.osdev.org/GDC_Cross-Compiler osdev wiki]... we're sorry. That's coming soon. + +After you have that up and running, you need to add a profile. We use dsss/rebuild to build stuff, and when we did it, it installed to /opt/etc/. So copy the gdc-xomb file from build/ (in the xomb-bare-bones directory) to /opt/etc/rebuild/ and you should be golden. Hopefully. + +To build, just run +
dsss build
from within the build/ directory. This will make 'xomb.iso'. Then feel free to run it with bochs, xen, or whatever. + +And that's it! Pretty easy, right? + +== XBB Features == +Considering that XBB is, well, bare-bones, it doesn't do much. kmain consists of one kprintfln! statement, which just prints a line to the screen. We've included a kprintfln! implementation to show off the power of D's templating system, but feel free to replace it, of course. + +== XBB Organization == + +The XBB directory looks like this: +$ tree -L 1 +. +|-- LICENSE +|-- README +|-- build +|-- kernel + +2 directories, 2 files + +We've moved all of the source into kernel, because you (at some point) will want to write userspace code. You'd probably want to make another directory in the main tree with all of that code in it. The main XOmB project has libos/ and tools/ and such. + +=== LICENSE === +XBB is distributed under the [http://sam.zoy.org/wtfpl/ WTFPL]. This is the most free license we could possibly imagine that still contains a swear word, so have at it. + +=== README === +The readme contains a copy of this page, though it's not updated quite as often as this page is. + +=== build/ === +$ tree -L 1 build/ +build/ +|-- bochsrc +|-- dsss.conf +|-- dsss.last +|-- dsss_objs +|-- iso +|-- linker.ld +|-- xomb.dump +`-- xomb.iso + +2 directories, 6 files +==== bochsrc ==== +Assuming you're running bochs, we've given you a bochsrc. + +==== dsss.conf ==== +This file tells dsss how to build XBB. + +==== dsss.last ==== +This is another file that dsss generates. + +==== dsss_objs ==== +This directory contains all of the intermediate stuff that dsss needs to do its job. + +==== iso ==== +This directory contains a copy of the actual FS contained in xomb.iso. + +==== linker.ld ==== +This script lets ld know how it should link everything together. + +==== xomb.dump ==== +A dump of the iso. Very useful for seeing exactly what asm gets generated after compiling things. + +==== xomb.iso ==== +This is the actual .iso file that needs to be burnt to a CD (or run in some other manner) to run the OS! + +=== kernel/ === +$ tree -L 1 kernel/ +kernel/ +|-- arch +|-- config.d +|-- core +|-- dev +`-- runtime + +4 directories, 1 file + +==== arch ==== +This directory contains everything pertaining to architecture. If you wanted to port XBB to arm or something, the code would go in here. + +==== config.d ==== +This sets a bunch of configuration options, mostly relating to debugging information. + +==== core ==== +This is where it all goes down. The core kernel code is located inside. + +==== dev ==== +Everything in this directory pertains to devices. + +==== runtime ==== +The kernel D runtime. This runtime is nowhere near robust as a full userspace runtime would be, as the kernel donesn't need such niceties as garbage collection. Just the bare minimum, thanks. + +== For More Info == +Check out the individual source files for information on how specific things work. We've made an attempt to heavily comment everything, so that you can see in the code itself how things work. + +If you find that you need more help, please [[Contact |contact]] us, and we'll do our best. Please let us know if there's anything that we can do to make this project better! + diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..5cdc0e0 --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,4 @@ +dsss_objs/* +dsss.last +xomb.dump +xomb.iso diff --git a/build/bochsrc b/build/bochsrc new file mode 100644 index 0000000..bca0759 --- /dev/null +++ b/build/bochsrc @@ -0,0 +1,5 @@ +romimage: file=/usr/src/bochs-2.3.7/bios/BIOS-bochs-latest +megs: 128 +ata1-slave: type=cdrom, path="./xomb.iso", status=inserted +boot: cdrom +cpu: count=2, reset_on_triple_fault=0 diff --git a/build/dsss.conf b/build/dsss.conf new file mode 100644 index 0000000..dcb888c --- /dev/null +++ b/build/dsss.conf @@ -0,0 +1,64 @@ +name = xomb + +CC = x86_64-pc-elf-gcc +CFLAGS = -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel + +[*] +buildflags=-dc=gdc-xomb + +[../kernel/core/kmain.d] + +buildflags=-dc=gdc-xomb -I.. + +# compile the assembly for the target + +prebuild= \ +\ +\ +echo ; \ +echo Compiling Assembly for target: x86_64 ;\ +echo '--> boot.S';\ +x86_64-pc-elf-gcc -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel -c ../kernel/arch/x86_64/boot/boot.S -o dsss_objs/G/kernel.arch.x86_64.boot.boot.o ; \ +echo '--> load.S';\ +x86_64-pc-elf-gcc -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel -c ../kernel/arch/x86_64/boot/load.S -o dsss_objs/G/kernel.arch.x86_64.boot.load.o ; \ +#echo '--> trampoline.S';\ +#x86_64-pc-elf-gcc -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel -c ../kernel/arch/x86_64/boot/trampoline.S -o dsss_objs/G/kernel.arch.x86_64.boot.trampoline.o ;\ +\ +\ +echo ; \ +echo Compiling Kernel Runtime ; \ +echo '--> kernel/runtime/object.d';\ +x86_64-pc-elf-gdc -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel -I .. -I ../kernel/runtime/. -c ../kernel/runtime/object.d -o dsss_objs/G/kernel.runtime.object.o ;\ +echo '--> kernel/runtime/invariant.d';\ +x86_64-pc-elf-gdc -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel -I .. -I ../kernel/runtime/. -c ../kernel/runtime/invariant.d -o dsss_objs/G/kernel.runtime.invariant.o ;\ +echo '--> kernel/runtime/std/typeinfo/*';\ +x86_64-pc-elf-gdmd -q,-nostdlib,-nodefaultlibs,-g,-DUSE_ASSERT,-mcmodel=kernel -I.. -I../kernel/runtime/. -c `ls ../kernel/runtime/std/typeinfo/*.d` -oddsss_objs/G/. ;\ +echo '--> kernel/runtime/dstubs.d';\ +x86_64-pc-elf-gdc -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel -I .. -I ../kernel/runtime/. -c ../kernel/runtime/dstubs.d -o dsss_objs/G/kernel.runtime.dstubs.o ;\ +echo '--> kernel/runtime/util.d';\ +x86_64-pc-elf-gdc -nostdlib -nodefaultlibs -g -DUSE_ASSERT -mcmodel=kernel -I .. -I ../kernel/runtime/. -c ../kernel/runtime/util.d -o dsss_objs/G/kernel.runtime.util.o ;\ +\ +echo ; \ +echo Compiling Kernel Proper ; + +# what the target is + +target = xomb.iso + +# we will need some post build foo to link and create the iso + +postbuild = \ +\ +echo ; \ +echo Creating Kernel Executable; \ +echo '--> xomb';\ +x86_64-pc-elf-ld -nostdlib -nodefaultlibs -b elf64-x86-64 -T linker.ld -o iso/boot/xomb `ls dsss_objs/G/*.o`;\ +\ +echo ;\ +echo Creating Kernel Dump; \ +echo '--> xomb.dump';\ +rm -f xomb.dump && x86_64-pc-elf-objdump -d -S -r iso/boot/xomb > xomb.dump;\ +\ +echo ;\ +echo Compiling ISO; \ +mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 16 -boot-info-table -o xomb.iso ./iso diff --git a/build/gdc-xomb b/build/gdc-xomb new file mode 100644 index 0000000..9dabbc9 --- /dev/null +++ b/build/gdc-xomb @@ -0,0 +1,35 @@ +profile=phobos + +compiler=x86_64-pc-elf-gdc + +exeext= +objext=o + + +noversion=DigitalMars +version=GNU +testversion=linux +testversion=darwin +version=Unix +version=Posix +noversion=Windows +noversion=Win32 +noversion=Win64 +testversion=X86 +testversion=PPC +testversion=X86_64 +testversion=D_InlineAsm +testversion=D_InlineAsm_X86 +testversion=D_InlineAsm_PPC +testversion=D_InlineAsm_X86_64 +testversion=LittleEndian +testversion=BigEndian + +[compile] +cmd=x86_64-pc-elf-gdmd -q,-nostdlib,-nodefaultlibs,-g,-DUSE_ASSERT,-mcmodel=kernel -I../kernel/runtime/ -c $i + +[link] +cmd=# + +[postlink] +cmd=echo "lol fuckers" diff --git a/build/iso/boot/grub/menu.lst b/build/iso/boot/grub/menu.lst new file mode 100644 index 0000000..89a0671 --- /dev/null +++ b/build/iso/boot/grub/menu.lst @@ -0,0 +1,129 @@ +# menu.lst - See: grub(8), info grub, update-grub(8) +# grub-install(8), grub-floppy(8), +# grub-md5-crypt, /usr/share/doc/grub +# and /usr/share/doc/grub-doc/. + +## default num +# Set the default entry to the entry number NUM. Numbering starts from 0, and +# the entry number 0 is the default if the command is not used. +# +# You can specify 'saved' instead of a number. In this case, the default entry +# is the entry saved with the command 'savedefault'. +# WARNING: If you are using dmraid do not change this entry to 'saved' or your +# array will desync and will not let you boot your system. +default 0 + +## timeout sec +# Set a timeout, in SEC seconds, before automatically booting the default entry +# (normally the first entry defined). +timeout 0 + +## hiddenmenu +# Hides the menu by default (press ESC to see the menu) +hiddenmenu + +# Pretty colours +#color cyan/blue white/blue + +## password ['--md5'] passwd +# If used in the first section of a menu file, disable all interactive editing +# control (menu entry editor and command-line) and entries protected by the +# command 'lock' +# e.g. password topsecret +# password --md5 $1$gLhU0/$aW78kHK1QfV3P2b2znUoe/ +# password topsecret + +# +# examples +# +# title Windows 95/98/NT/2000 +# root (hd0,0) +# makeactive +# chainloader +1 +# +# title Linux +# root (hd0,1) +# kernel /vmlinuz root=/dev/hda2 ro +# + +# +# Put static boot stanzas before and/or after AUTOMAGIC KERNEL LIST + +### BEGIN AUTOMAGIC KERNELS LIST +## lines between the AUTOMAGIC KERNELS LIST markers will be modified +## by the debian update-grub script except for the default options below + +## DO NOT UNCOMMENT THEM, Just edit them to your needs + +## ## Start Default Options ## +## default kernel options +## default kernel options for automagic boot options +## If you want special options for specific kernels use kopt_x_y_z +## where x.y.z is kernel version. Minor versions can be omitted. +## e.g. kopt=root=/dev/hda1 ro +## kopt_2_6_8=root=/dev/hdc1 ro +## kopt_2_6_8_2_686=root=/dev/hdc2 ro +# kopt=root=UUID=766f85b2-0ecb-45b7-8ad9-b108f2eba4a2 ro + +## Setup crashdump menu entries +## e.g. crashdump=1 +# crashdump=0 + +## default grub root device +## e.g. groot=(hd0,0) +# groot=(hd0,0) + +## should update-grub create alternative automagic boot options +## e.g. alternative=true +## alternative=false +# alternative=true + +## should update-grub lock alternative automagic boot options +## e.g. lockalternative=true +## lockalternative=false +# lockalternative=false + +## additional options to use with the default boot option, but not with the +## alternatives +## e.g. defoptions=vga=791 resume=/dev/hda5 +# defoptions=quiet splash + +## should update-grub lock old automagic boot options +## e.g. lockold=false +## lockold=true +# lockold=false + +## Xen hypervisor options to use with the default Xen boot option +# xenhopt= + +## Xen Linux kernel options to use with the default Xen boot option +# xenkopt=console=tty0 + +## altoption boot targets option +## multiple altoptions lines are allowed +## e.g. altoptions=(extra menu suffix) extra boot options +## altoptions=(recovery) single +# altoptions=(recovery mode) single + +## controls how many kernels should be put into the menu.lst +## only counts the first occurence of a kernel, not the +## alternative kernel options +## e.g. howmany=all +## howmany=7 +# howmany=all + +## should update-grub create memtest86 boot option +## e.g. memtest86=true +## memtest86=false +# memtest86=true + +## should update-grub adjust the value of the default booted system +## can be true or false +# updatedefaultentry=false + +## ## End Default Options ## + +title XOmB +kernel /boot/xomb +#module /your/module +### END PITTGEEKS AUTOMAGIC KERNELS LIST diff --git a/build/iso/boot/grub/stage2_eltorito b/build/iso/boot/grub/stage2_eltorito new file mode 100644 index 0000000..0fbaee7 Binary files /dev/null and b/build/iso/boot/grub/stage2_eltorito differ diff --git a/build/linker.ld b/build/linker.ld new file mode 100644 index 0000000..52c15fc --- /dev/null +++ b/build/linker.ld @@ -0,0 +1,125 @@ +/* +linker.ld + +* This script is given as the only script to the linker +* Will map boot.S to LMA, and then everything else + will be linked to the VMA and mapped at the LMA +* _etext, _edata, _end are defined here + +*/ + + +/* KERNEL LINK LOCATIONS + + these are the locations to map to + they need to be set within boot.h + as well + + */ + +kernel_VMA = 0xffffffff80000000; +kernel_LMA = 0x100000; + +/* start from the entry point */ +ENTRY(_start) +SECTIONS +{ + /* link from LMA */ + . = kernel_LMA; + + _boot = .; + + /* boot.S is ran in linear addresses */ + .text_boot : + { + dsss_objs/G/kernel.arch.x86_64.boot.boot.o (.text) + } + + _eboot = .; + + /* The following is for the trampoline code, if and when + * multiprocessor support will be necessary. + */ + + /* PROVIDE(_trampoline = .); + + .text_trampoline ALIGN(0x1000) : + { + dsss_objs/G/kernel.arch.x86_64.boot.trampoline.o (.text) + } + + PROVIDE(_etrampoline = .); */ + + /* link from VMA */ + . = . + kernel_VMA; + + _text = .; + + PROVIDE(_kernel = .); + PROVIDE(_kernelBase = kernel_VMA); + + /* the rest of the code links to higher memory */ + .text : AT(ADDR(.text) - kernel_VMA + kernel_LMA) + { + code = .; + *(.text) + *(.text*) + + /* read only data */ + *(.rodata*) + *(.rdata*) + + . = ALIGN(4096); + } + + PROVIDE(_ekernel = .); + + /* _etext defined */ + PROVIDE (_etext = .); + + _data = .; + + /* data section */ + .data : AT(ADDR(.data) - kernel_VMA + kernel_LMA) + { + data = .; + *(.data) + + /* constructors and deconstructors + (if needed, doesn't hurt) */ + + start_ctors = .; + *(.ctor*) + end_ctors = .; + + start_dtors = .; + *(.dtor*) + end_dtors = .; + + . = ALIGN(4096); + } + + /* _edata defined */ + _edata = .; PROVIDE (edata = .); + + /* static code */ + .bss : AT(ADDR(.bss) - kernel_VMA + kernel_LMA) + { + *(.bss) + . = ALIGN(4096); + } + + /* */ + .ehframe : AT(ADDR(.ehframe) - kernel_VMA + kernel_LMA) + { + ehframe = .; + *(.ehframe) + . = ALIGN(4096); + } + + /* _end defined */ + _end = .; PROVIDE (end = .); + +} + + diff --git a/kernel/arch/select.d b/kernel/arch/select.d new file mode 100644 index 0000000..e5d0304 --- /dev/null +++ b/kernel/arch/select.d @@ -0,0 +1,16 @@ +module kernel.arch.select; + +// This module shows D's mixin capabilities to load modules for different architecture targets. + +const char[] architecture = "x86_64"; + +template PublicArchImport(char[] mod) +{ + const char[] PublicArchImport = ` + + public import kernel.arch.` ~ architecture ~ `.` ~ mod ~ `; + + `; +} + + diff --git a/kernel/arch/x86_64/boot/boot.S b/kernel/arch/x86_64/boot/boot.S new file mode 100644 index 0000000..6bc361d --- /dev/null +++ b/kernel/arch/x86_64/boot/boot.S @@ -0,0 +1,275 @@ +/* + +boot.S - bootstrap the kernel + +The 32 bit bootstrap code that serves these functions: + +- contains multiboot header +- contains 32 bit GDT +- contains 32 bit IDT (for debugging, can be removed later) +- contains page tables + - lower 40MB are mapped 1-1 + - higher 40MB (from 0xffffffff80000000) are mapped from 0x0 on + - after code in load.S runs, the lower half map should not be needed + +- transitions into long mode: + - enables PAE (physical-address-extensions) + - setting PML4 (page-map-level-4) + - setting EFER flags for LMA (long-mode-active) and SYSCALL-SYSRET + - enables paging by setting the PG bit in CR0 (Control Register 0) + - long jumps to code within load.S + +- note: some addresses located within the higher half need to be converted + to linear addresses: the stack, _edata, _end +- this is because: the multiboot header expects linear addresses, + the CPU expects stack at linear address, as it would for GDT, IDT, etc + +*/ + +#define EXE_COMPAT_HACK + +#define ASM 1 +#include "multiboot.h" + +#include "boot.h" + +.globl start, _start + +.text + +start: +_start: + .code32 + + /* Stash values for multiboot we won't touch until 64 bit mode */ + movl %ebx, %esi + movl %eax, %edi + + /* jump to the 32 bit common start */ + jmp (start32) + + /* Align 32 bits boundary. */ + .align 4 + + /* Multiboot header. */ + +multiboot_header: + /* magic */ + .long MULTIBOOT_HEADER_MAGIC + /* flags */ + .long MULTIBOOT_HEADER_FLAGS + /* checksum */ + .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) + +#ifdef EXE_COMPAT_HACK + + /* header_addr */ + .long (multiboot_header) + /* load_addr */ + .long (_start) + /* load_end_addr */ + .long (_edata-KERNEL_VMA_BASE) + /* bss_end_addr */ + .long (_end-KERNEL_VMA_BASE) + /* entry_addr */ + .long (start) +#endif + +.global start32, _start32 + +_start32: +start32: + + /* disable interrupts (CLear Interrupt flag) */ + cli + + /* enable 64-bit page-translation-table entries by + setting CR4.PAE=1. Paging not enabled until after + long mode enabled */ + movl %cr4, %eax + bts $5, %eax + movl %eax, %cr4 + + /* Create long mode page table and init CR3 to point to + the base of the PML4 page table. */ + movl $(pml4_base), %eax + movl %eax, %cr3 + + /* Enable Long mode and SYSCALL/SYSRET instructions */ + movl $0xc0000080, %ecx + rdmsr + bts $8, %eax + bts $0, %eax + wrmsr + + /* Load the 32 bit GDT */ + lgdt (pGDT32) + + /* Load the 32 bit IDT */ + lidt (pIDT32) + + /* establish a stack for 32 bit code */ + mov $((stack-KERNEL_VMA_BASE) + STACK_SIZE), %esp + + /* enable paging to activate long mode */ + movl %cr0, %eax + bts $31, %eax + movl %eax, %cr0 + + // make the jump to long mode! + ljmp $CS_KERNEL, $(start64-KERNEL_VMA_BASE) + + + + + +// The following are a series of kernel structures used by the cpu +// These are temporary and will be replaced by permanent ones when the +// kernel is executed proper. + + + + + + +// 32 BIT GDT + + .align 4096 + .globl pGDT32 +pGDT32: + .word GDT_END - GDT_TABLE - 1 + .quad GDT_TABLE - KERNEL_VMA_BASE + +.align 4096 +GDT_TABLE: + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x00cf9a000000ffff /* __KERNEL32_CS */ + .quad 0x00af9a000000ffff /* __KERNEL_CS */ + .quad 0x0000000000000000 /* upper half of CS */ + .quad 0x00af93000000ffff /* __KERNEL_DS */ + .quad 0x0000000000000000 /* upper half of DS */ + .quad 0x00affa000000ffff /* __USER_CS */ + .quad 0x0000000000000000 /* upper half of CS */ + .quad 0x00aff3000000ffff /* __USER_DS */ + .quad 0x0000000000000000 /* upper half of DS */ + .quad 0,0 /* TSS */ + .quad 0,0 /* TSS */ + .quad 0,0 /* LDT */ + .quad 0,0 /* LDT */ + + // wtf? + .quad 0,0,0 /* three TLS descriptors */ + .quad 0x0000f40000000000 /* node/CPU stored in limit */ +GDT_END: + + +// 32 BIT IDT + + .align 4096 + + + .globl pIDT32 +pIDT32: + + + .word IDT_END - IDT_TABLE - 1 + .quad IDT_TABLE - KERNEL_VMA_BASE + +#define IDT_LOCATION 0x106000 + +.align 4096 +IDT_TABLE: + i = 0 + .rept 32 + .long 0x100000 | ((IDT_LOCATION + i) & 0xFFFF) + .long ((IDT_LOCATION + i) & 0xFFFF0000) | 0x8E00 + i = i + 8 + .endr +IDT_END: + +.align 4096 + +int_handler_32: + + i = 0 + .rept 32 + mov i, %eax + iret + i = i + 1 + .endr + +int_handler_32_end: + +.align 4096 // the others may not be needed, but this one MUST BE THERE +.globl pml4_base + +// PML4 +pml4_base: + .quad (level3_ident_pgt + 0x0000000000000007) + .fill 510,8,0 + .quad (level3_ident_pgt + 0x0000000000000007) + + +// --- THIS SHOULD BE ALIGNED AT 4K --- // + +.align 4096 +.globl level3_ident_pgt +// PDP +// PML3 +level3_ident_pgt: + .quad (level2_ident_pgt + 0x07) + .quad 0 //(level2_ident_pgt + 0x07) + .quad (level2_ident_pgt + 0x07) + + .rept (507) + .quad 0 + .endr + + .quad (level2_ident_pgt + 0x07) + .quad 0 // (level2_ident_pgt + 0x07) + + + +// --- THIS SHOULD BE ALIGNED AT 4K --- // + + +.align 4096 +.globl level2_ident_pgt + // flags 0x00087 +// PDE +// PML2 +level2_ident_pgt: + i = 0 + +// 15 TABLE ENTRIES + .rept 15 + .quad (level1_ident_pgt + i + 0x0000000000000007) + i = i + 4096 + .endr + + .fill 497,8,0 + + +// --- THIS SHOULD BE ALIGNED AT 4K --- // + + +// PTE +// PML1 +.align 4096 +.globl level1_ident_pgt +level1_ident_pgt: + // UM + // 40MB for bootup. + i = 0 + +// 15 TABLES + .rept (512 * 15) + .quad i << 12 | 0x087 + i = i + 1 + .endr + + + + + + diff --git a/kernel/arch/x86_64/boot/boot.h b/kernel/arch/x86_64/boot/boot.h new file mode 100644 index 0000000..a5792fe --- /dev/null +++ b/kernel/arch/x86_64/boot/boot.h @@ -0,0 +1,21 @@ +/* + +boot.h + +- Contains information pertinant to the bootstrap about where + the kernel is located + +*/ + +/* the code section for the kernel + 0x10 = code section 2 ( right shift it by 3 ) */ +#define CS_KERNEL 0x10 +#define CS_KERNEL32 0x8 + +/* the location, in physical address (LMA) and virtual (VMA) */ +/* these should correspond to linker.ld */ + +#define KERNEL_LMA_BASE 0x100000 +#define KERNEL_VMA_BASE (0xffffffff80000000) +#define KERNEL_LOCATION (KERNEL_VMA_BASE + KERNEL_LMA_BASE) + diff --git a/kernel/arch/x86_64/boot/load.S b/kernel/arch/x86_64/boot/load.S new file mode 100644 index 0000000..618804c --- /dev/null +++ b/kernel/arch/x86_64/boot/load.S @@ -0,0 +1,94 @@ +/* + +load.S + +The 64 bit code that serves these functions: + +- sets up stack +- transfers %rip to higher half +- clears cpu flags +- calls kmain with multiboot information + +*/ + +#define ASM 1 + +#include "multiboot.h" +#include "boot.h" + + + .text + .code64 + +.globl start64, _start64 + + start64: + _start64: + + + /* Initialize the 64 bit stack pointer. */ + movq $((stack - KERNEL_VMA_BASE) + STACK_SIZE), %rsp + + /* set up the stack for the return */ + pushq $CS_KERNEL + pushq $long_entry + + /* Go into canonical higher half */ + /* This trick is borrowed from the linux kernel, + /arch/x86_64/kernel/head.S */ + + lretq + +long_entry: + + /* From here on out, we are running instructions + Within the higher half (0xffffffff80000000 ... ) + + We can safely unmap the lower half, we do not + need an identity mapping of the lower half. */ + + movq $(stack + STACK_SIZE), %rsp + + /* Set cpu flags */ + pushq $0 + lss (%rsp), %eax + popf + + /* Sets the Input/Output Permission Level to 3, so + that it will not check the IO permissions bitmap when access is requested. */ + + pushf + popq %rax + or $0x3000, %rax + pushq %rax + popf + + addq $(KERNEL_VMA_BASE), %rsi + + /* Push the pointer to the Multiboot information structure. */ + pushq %rsi + /* Push the magic value. */ + pushq %rdi + + /* Now enter the kmain function... */ + call EXT_C(kmain) + + + + /* We should not get here */ + +loop: + + hlt + jmp loop + +// --- STACK --- // +.globl stack +.align 4096 + + // Our stack area. +stack: + .rept STACK_SIZE + .long 0 + .endr + diff --git a/kernel/arch/x86_64/boot/multiboot.h b/kernel/arch/x86_64/boot/multiboot.h new file mode 100644 index 0000000..8202938 --- /dev/null +++ b/kernel/arch/x86_64/boot/multiboot.h @@ -0,0 +1,104 @@ +/* multiboot.h - the header for Multiboot */ + +/* Macros. */ + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +//#ifdef __ELF__ +//# define MULTIBOOT_HEADER_FLAGS 0x00000003 +//#else +# define MULTIBOOT_HEADER_FLAGS 0x00010003 +//#endif + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (16KB). */ +#define STACK_SIZE 0x4000 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* Do not include here in boot.S. */ + +/* Types. */ + +/* The Multiboot header. */ +typedef struct multiboot_header +{ +unsigned long magic; +unsigned long flags; +unsigned long checksum; +unsigned long header_addr; +unsigned long load_addr; +unsigned long load_end_addr; +unsigned long bss_end_addr; +unsigned long entry_addr; +} multiboot_header_t; + +/* The symbol table for a.out. */ +typedef struct aout_symbol_table +{ +unsigned long tabsize; +unsigned long strsize; +unsigned long addr; +unsigned long reserved; +} aout_symbol_table_t; + +/* The section header table for ELF. */ +typedef struct elf_section_header_table +{ +unsigned long num; +unsigned long size; +unsigned long addr; +unsigned long shndx; +} elf_section_header_table_t; + +/* The Multiboot information. */ +typedef struct multiboot_info +{ +unsigned long flags; +unsigned long mem_lower; +unsigned long mem_upper; +unsigned long boot_device; +unsigned long cmdline; +unsigned long mods_count; +unsigned long mods_addr; +union +{ + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; +} u; +unsigned long mmap_length; +unsigned long mmap_addr; +} multiboot_info_t; + +/* The module structure. */ +typedef struct module +{ +unsigned long mod_start; +unsigned long mod_end; +unsigned long string; +unsigned long reserved; +} module_t; + +/* The memory map. Be careful that the offset 0 is base_addr_low +but no size. */ +typedef struct memory_map +{ +unsigned long size; +unsigned long base_addr_low; +unsigned long base_addr_high; +unsigned long length_low; +unsigned long length_high; +unsigned long type; +} memory_map_t; + +#endif /* ! ASM */ diff --git a/kernel/config.d b/kernel/config.d new file mode 100644 index 0000000..6f2e026 --- /dev/null +++ b/kernel/config.d @@ -0,0 +1,27 @@ +//Config options + +bool enable_kgdb = false; +bool remote_debug = true; // Its like debugging for the debugger + +// Kernel options +// Make sure this is the same as the value in boot.h +const ulong KERNEL_VM_BASE = 0xFFFFFFFF80000000; + +// Debugging options +// Setting DEBUG_ALL to true will cause *ALL* debug +// flags to turn on. If you only want to see some +// debug messages, turn DEBUG_ALL off, and only +// turn on the debug messages you wish to see. +const auto DEBUG_ALL = false; + +// Individual debug options +const auto DEBUG_PAGING = false; +const auto DEBUG_PAGEFAULTS = false; +const auto DEBUG_PMEM = false; +const auto DEBUG_INTERRUPTS = false; +const auto DEBUG_MPTABLE = false; +const auto DEBUG_LAPIC = false; +const auto DEBUG_IOAPIC = false; +const auto DEBUG_APENTRY = false; +const auto DEBUG_KBD = false; +const auto DEBUG_SCHEDULER = false; diff --git a/kernel/core/kmain.d b/kernel/core/kmain.d new file mode 100644 index 0000000..48487a4 --- /dev/null +++ b/kernel/core/kmain.d @@ -0,0 +1,41 @@ +/* XOmB Bare Bones + * + * This is the bare minimum needed for an OS written in the D language. + * + * Note: The kmain will be called in the higher memory region. + * The next step is setting up permanent kernel structures. + * + */ + +module kernel.core.kmain; + +// This module contains our powerful kprintf function +import kernel.core.kprintf; + + + + + +// The main function for the kernel. +// This will receive data from the boot loader. + +// bootLoaderID is the unique identifier for a boot loader. +// data is a structure given by the boot loader. + +// For GRUB: the identifier is the magic number. +// data is the pointer to the multiboot structure. +extern(C) void kmain(int bootLoaderID, void *data) +{ + + kprintfln!("{!cls}Welcome to {}! (version {}.{}.{})")("XOmB Bare Bones", 1,0,0); + + + kprintfln!("{x} {x}")(bootLoaderID, data); + + + // Ok, so we don't want to just infinite loop (if you want it to do something) + // Replace this with your kernel logic! + + for(;;) {} + +} diff --git a/kernel/core/kprintf.d b/kernel/core/kprintf.d new file mode 100644 index 0000000..d7bedcc --- /dev/null +++ b/kernel/core/kprintf.d @@ -0,0 +1,428 @@ +// This module implements the print logic for the kernel + + +module kernel.core.kprintf; + +// Contains the interface to the VGA textmode driver. +import kernel.dev.console; + +// Contains some nice logic and cool templates. +import kernel.core.util; + + + + +/* This template will generate code for printing and will do + * all parsing of the format string at compile time + * + * USAGE: + * kprintf!("format string {specifier} ... ")(args...); + * + * EXAMPLES: + * kprintf!("Integer: {}")(10); + * kprintf!("{!cls}Cleared the screen.")(); + * kprintf!("{!pos:2,3}At position (2,3)")(); + * kprintf!("{!fg:LightBlue!bg:Gray}{}")(25); + * kprintf!("{!fg:Red}redness")(); + * kprintf!("{x} Hex!")(145); + * kprintf!("Curly Brace: {{")(); + * + * COMMANDS: + * !cls - Clears the screen. + * !fg - Sets the foreground color, see the Color enum + * in kernel/dev/console.d. + * !bg - Sets the background color, same as above. + * !pos - Moves the cursor to the x and y given, see example above. + * + * SPECIFIERS: + * {x} - Prints the hex value. + * {u} - Treats as unsigned. + * {} - Prints common form. + * + * WHY IS IT COOL? + * - Compile time parsing of format strings + * - Type checking at compile time as well + * - That means it can tell you that you are dumb before you execute. + * - No need to specify type information. + * + * - So we can do this and not care about the + * output of the function: + * + * auto blah = someFunction(); + * kprintf!("Some Arbitrary Info: {}")(blah); + * + * WOWWY WOW WOW! + * + */ + +template kprintf(char[] Format) +{ + void kprintf(Args...)(Args args) + { + mixin(ConvertFormat!(Format, Args)); + } +} + +/* This template will generate code like kprintf but will also + * print a newline afterward. + * + * USAGE: See kprintf above. + * + */ +template kprintfln(char[] Format) +{ + void kprintfln(Args...)(Args args) + { + mixin(ConvertFormat!(Format, Args)); + Console.putChar('\n'); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// The crazy D templating logic that implements the kprintf + +private +{ + + // The following are functions that implement logic for printing different primatives. + + void printInt(long i, char[] fmt) + { + char[20] buf; + + if(fmt.length is 0) + Console.putString(itoa(buf, 'd', i)); + else if(fmt[0] is 'd' || fmt[0] is 'D') + Console.putString(itoa(buf, 'd', i)); + else if(fmt[0] is 'u' || fmt[0] is 'U') + Console.putString(itoa(buf, 'u', i)); + else if(fmt[0] is 'x' || fmt[0] is 'X') + Console.putString(itoa(buf, 'x', i)); + } + + // Floats are not supported by the kernel, but the interface to this exists anyway. + void printFloat(real f, char[] fmt) + { + Console.putString("?float?"); + } + + void printChar(dchar c, char[] fmt) + { + Console.putChar(c); + } + + void printString(T)(T s, char[] fmt) + { + static assert(isStringType!(T)); + Console.putString(s); + } + + void printPointer(void* p, char[] fmt) + { + Console.putString("0x"); + char[20] buf; + Console.putString(itoa(buf, 'x', cast(ulong)p)); + } + + // The core template that will parse the format to find the string until a format specifier and return the length. + template ExtractString(char[] format) + { + static if(format.length == 0) + { + const size_t ExtractString = 0; + } + else static if(format[0] is '{') + { + static if(format.length > 1 && format[1] is '{') + const size_t ExtractString = 2 + ExtractString!(format[2 .. $]); + else + const size_t ExtractString = 0; + } + else + const size_t ExtractString = 1 + ExtractString!(format[1 .. $]); + } + + // Extracts the format string and returns the length of that string. + template ExtractFormatStringImpl(char[] format) + { + static assert(format.length !is 0, "Unterminated format specifier"); + + static if(format[0] is '}') + const ExtractFormatStringImpl = 0; + else + const ExtractFormatStringImpl = 1 + ExtractFormatStringImpl!(format[1 .. $]); + } + + // This template compares the format given (eg {x} would be "x") against the type of the argument passed. + template CheckFormatAgainstType(char[] rawFormat, size_t idx, T) + { + const char[] format = rawFormat[1 .. idx]; + + static if(isIntType!(T)) + { + static assert(format == "" || format == "x" || format == "X" || format == "u" || format == "U", + "Invalid integer format specifier '" ~ format ~ "'"); + } + + // This is an inherited attribute to describe the length of the format string + const size_t res = idx; + } + + // This template will compare a format with a type. + template ExtractFormatString(char[] format, T) + { + const ExtractFormatString = CheckFormatAgainstType!(format, ExtractFormatStringImpl!(format), T).res; + } + + // This will get the length of a single command + template ExtractCommandStringImpl(char[] format) + { + static if (format.length == 0 || format[0] is '}') + { + const int ExtractCommandStringImpl = 0; + } + else + { + const int ExtractCommandStringImpl = 1 + ExtractCommandStringImpl!(format[1..$]); + } + } + + // This template will extract a command string, or set of command strings + template ExtractCommandString(char[] format) + { + const ExtractCommandString = ExtractCommandStringImpl!(format); + } + + // This template will take a string 's' and convert any '{{' to a single '{'. + // This is done after parsing the format string. + template StripDoubleLeftBrace(char[] s) + { + static if(s.length is 0) + const char[] StripDoubleLeftBrace = ""; + else static if(s.length is 1) + const char[] StripDoubleLeftBrace = s; + else + { + static if(s[0 .. 2] == "{{") + const char[] StripDoubleLeftBrace = "{" ~ StripDoubleLeftBrace!(s[2 .. $]); + else + const char[] StripDoubleLeftBrace = s[0] ~ StripDoubleLeftBrace!(s[1 .. $]); + } + } + + // Generates the code to print the string. + template MakePrintString(char[] s) + { + const char[] MakePrintString = "printString(\"" ~ StripDoubleLeftBrace!(s) ~ "\", \"\");\n"; + } + + // This template will generate the code to print out the string. + template MakePrintOther(T, char[] fmt, size_t idx) + { + static if(isIntType!(T)) + const char[] MakePrintOther = "printInt(args[" ~ idx.stringof ~ "], \"" ~ fmt ~ "\");\n"; + else static if(isCharType!(T)) + const char[] MakePrintOther = "printChar(args[" ~ idx.stringof ~ "], \"" ~ fmt ~ "\");\n"; + else static if(isStringType!(T)) + const char[] MakePrintOther = "printString(args[" ~ idx.stringof ~ "], \"" ~ fmt ~ "\");\n"; + else static if(isFloatType!(T)) + const char[] MakePrintOther = "printFloat(args[" ~ idx.stringof ~ "], \"" ~ fmt ~ "\");\n"; + else static if(isPointerType!(T)) + const char[] MakePrintOther = "printPointer(args[" ~ idx.stringof ~ "], \"" ~ fmt ~ "\");\n"; + else static if(isArrayType!(T)) + const char[] MakePrintOther = "printArray(args[" ~ idx.stringof ~ "], true, false);\n"; + else + static assert(false, "I don't know how to handle argument " ~ idx.stringof ~ " of type '" ~ T.stringof ~ "'."); + } + + // For the !fg command + template MakePrintCommand_fg(char[] format) + { + static if (format.length <= 1) + { + static assert(false, "Not enough parameters to the !fg command."); + } + else + { + const char[] MakePrintCommand_fg = "Console.setForeColor(Color." ~ format[1..$] ~ ");\n"; + } + } + + // For the !bg command + template MakePrintCommand_bg(char[] format) + { + static if (format.length <= 1) + { + static assert(false, "Not enough parameters to the !bg command."); + } + else + { + const char[] MakePrintCommand_bg = "Console.setBackColor(Color." ~ format[1..$] ~ ");\n"; + } + } + + template MakePrintCommand_pos(char[] format) + { + static if (format.length <= 3) + { + static assert(false, "Not enough parameters to the !pos command. USAGE: {!pos:x,y} where x and y are integers."); + } + else + { + const char[] MakePrintCommand_pos = "Console.setPosition(" ~ format[1..$] ~ ");\n"; + } + } + + // Output code to do the command. + template MakePrintCommandGenerate(char[] format) + { + static if (format.length >= 3 && format[0..3] == "cls") + { + const char[] MakePrintCommandGenerate = "Console.clearScreen();\n"; + } + else static if (format.length >= 2 && format[0..2] == "fg") + { + const char[] MakePrintCommandGenerate = MakePrintCommand_fg!(format[2..$]); + } + else static if (format.length >= 2 && format[0..2] == "bg") + { + const char[] MakePrintCommandGenerate = MakePrintCommand_bg!(format[2..$]); + } + else static if (format.length >= 3 && format[0..3] == "pos") + { + const char[] MakePrintCommandGenerate = MakePrintCommand_pos!(format[3..$]); + } + else + { + static assert(false, "Unknown Command, !" ~ format ~ ", for kprintf."); + } + } + + // Finds the length of the command string + template ExtractCommand(char[] format) + { + static if (format.length == 0 || format[0] is '}' || format[0] is '!') + { + const ExtractCommand = 0; + } + else + { + const ExtractCommand = 1 + ExtractCommand!(format[1..$]); + } + } + + // This template will take everything up to a ! or a } and generate the code for that command + template MakePrintCommandImpl(char[] format) + { + static if (format.length == 0) + { + const char[] res = ""; + } + else + { + static if (format[0] is '!') + { + const char[] res = MakePrintCommandImpl!(format[1..$]).res; + } + else + { + const lengthOfString = ExtractCommand!(format); + + const char[] res = MakePrintCommandGenerate!(format[0..lengthOfString]) ~ + MakePrintCommandImpl!(format[lengthOfString..$]).res; + } + } + } + + // commands: !cls, !fg:color, !bg:color + + // This template parses the command string (excluding the initial !) and generates the commands necessary. + template MakePrintCommand(char[] format) + { + const char[] MakePrintCommand = MakePrintCommandImpl!(format).res; + } + + // This template implements the logic behind format extraction. + template ConvertFormatImpl(char[] format, size_t argIdx, Types...) + { + static if(format.length == 0) + { + static assert(argIdx == Types.length, "More parameters than format specifiers"); + const char[] res = ""; + } + else + { + // Look for a token that starts with a left curly brace that would signify a format specifier. + static if (format[0] is '{' && (!(format.length > 1 && (format[1] is '{' || format[1] is '!')))) + { + // We have a format specifier, but no arguments to convert? + static assert(argIdx < Types.length, "More format specifiers than parameters"); + + // We will convert the string and generate code for the print. + + // Get the format string + const lengthOfString = ExtractFormatString!(format, Types[argIdx]); + + // Generate the code and recall this template. + const char[] res = MakePrintOther!(Types[argIdx], format[1 .. lengthOfString] , argIdx) ~ + ConvertFormatImpl!(format[lengthOfString + 1 .. $], argIdx + 1, Types).res; + } + else static if (format[0] is '{' && format.length > 1 && format[1] is '!') + { + // Command Token found, acts very similarly to a normal format specifier, expect it doesn't compare the types from the arguments. + const lengthOfString = ExtractCommandString!(format); + + // Generate the code and recall this template. + const char[] res = MakePrintCommand!(format[2..lengthOfString]) + ~ ConvertFormatImpl!(format[lengthOfString + 1 .. $], argIdx, Types).res; + } + else + { + // We want to know how long of a string we can print out without intervention + const lengthOfString = ExtractString!(format); + + // Then we can generate the code to print it out with the console and recall this template. + const char[] res = MakePrintString!(format[0..lengthOfString]) ~ + ConvertFormatImpl!(format[lengthOfString..$], argIdx, Types).res; + } + } + } + + // This template is the core routine. It will take the format and the arguments and generate the code to logically print out the string. + template ConvertFormat(char[] format, Types...) + { + const char[] ConvertFormat = ConvertFormatImpl!(format, 0, Types).res; + } +} + + + diff --git a/kernel/core/util.d b/kernel/core/util.d new file mode 100644 index 0000000..27b1faa --- /dev/null +++ b/kernel/core/util.d @@ -0,0 +1,383 @@ +module kernel.core.util; + +/** +This method checks to see if the value stored in the bit number declared +by the input variable "bit" in the flag declared by the input +variable "flags" is set. Returns a 1 if it is set, returns a 0 if it is not set. + Params: + flags = The flags from the multiboot header the kernel wishes to check. + bit = The number of the bit the kernel would like to check for data. + Returns: Whether the bit "bit" in "flags" has a value (1 if it is set, 0 if it is not) +*/ +uint CHECK_FLAG(uint flags, uint bit) +{ + return ((flags) & (1 << (bit))); +} + +/** +Given a struct type, gives a tuple of strings of the names of fields in the struct. +*/ +public template FieldNames(S, int idx = 0) +{ + static if(idx >= S.tupleof.length) + alias Tuple!() FieldNames; + else + alias Tuple!(GetLastName!(S.tupleof[idx].stringof), FieldNames!(S, idx + 1)) FieldNames; +} + +private template GetLastName(char[] fullName, int idx = fullName.length - 1) +{ + static if(idx < 0) + const char[] GetLastName = fullName; + else static if(fullName[idx] == '.') + const char[] GetLastName = fullName[idx + 1 .. $]; + else + const char[] GetLastName = GetLastName!(fullName, idx - 1); +} + +template Tuple(T...) +{ + alias T Tuple; +} + +template Bitfield(alias data, Args...) +{ + static assert(!(Args.length & 1), "Bitfield arguments must be an even number"); + const char[] Bitfield = BitfieldShim!((typeof(data)).stringof, data, Args).Ret; +} + +// Odd bug in D templates -- putting "data.stringof" as a template argument gives it the +// string of the type, rather than the string of the symbol. This shim works around that. +template BitfieldShim(char[] typeStr, alias data, Args...) +{ + const char[] Name = data.stringof; + const char[] Ret = BitfieldImpl!(typeStr, Name, 0, Args).Ret; +} + +template BitfieldImpl(char[] typeStr, char[] nameStr, int offset, Args...) +{ + static if(Args.length == 0) + const char[] Ret = ""; + else + { + const Name = Args[0]; + const Size = Args[1]; + const Mask = Bitmask!(Size); + + const char[] Getter = "public " ~ typeStr ~ " " ~ Name ~ "() { return ( " ~ + nameStr ~ " >> " ~ Itoh!(offset) ~ " ) & " ~ Itoh!(Mask) ~ "; }"; + + const char[] Setter = "public void " ~ Name ~ "(" ~ typeStr ~ " val) { " ~ + nameStr ~ " = (" ~ nameStr ~ " & " ~ Itoh!(~(Mask << offset)) ~ ") | ((val & " ~ + Itoh!(Mask) ~ ") << " ~ Itoh!(offset) ~ "); }"; + + const char[] Ret = Getter ~ Setter ~ BitfieldImpl!(typeStr, nameStr, offset + Size, Args[2 .. $]).Ret; + } +} + +template Itoa(long i) +{ + static if(i < 0) + const char[] Itoa = "-" ~ IntToStr!(-i, 10); + else + const char[] Itoa = IntToStr!(i, 10); +} + +template Itoh(long i) +{ + const char[] Itoh = "0x" ~ IntToStr!(i, 16); +} + +template Digits(long i) +{ + const char[] Digits = "0123456789abcdefghijklmnopqrstuvwxyz"[0 .. i]; +} + +template IntToStr(ulong i, int base) +{ + static if(i >= base) + const char[] IntToStr = IntToStr!(i / base, base) ~ Digits!(base)[i % base]; + else + const char[] IntToStr = "" ~ Digits!(base)[i % base]; +} + +template Bitmask(long size) +{ + const long Bitmask = (1L << size) - 1; +} + +template isStringType(T) +{ + const bool isStringType = is(T : char[]) || is(T : wchar[]) || is(T : dchar[]); +} + +/** +Sees if a type is char, wchar, or dchar. +*/ +template isCharType(T) +{ + const bool isCharType = is(T == char) || is(T == wchar) || is(T == dchar); +} + +/** +Sees if a type is a signed or unsigned byte, short, int, or long. +*/ +template isIntType(T) +{ + const bool isIntType = is(T == int) || is(T == uint) || is(T == long) || is(T == ulong) || + is(T == short) || is(T == ushort) || is(T == byte) || is(T == ubyte) /* || is(T == cent) || is(T == ucent) */; +} + +/** +Sees if a type is a signed or unsigned byte, short, int, or long. +*/ +template isUnsignedIntType(T) +{ + const bool isUnsignedIntType = is(T == uint) || is(T == ulong) || + is(T == ushort) || is(T == ubyte) /* || is(T == ucent) */; +} + +/** +Sees if a type is a signed or unsigned byte, short, int, or long. +*/ +template isSignedIntType(T) +{ + const bool isSignedIntType = is(T == int) || is(T == long) || + is(T == short) || is(T == byte) /* || is(T == cent) */; +} + + + + + +/** +Sees if a type is float, double, or real. +*/ +template isFloatType(T) +{ + const bool isFloatType = is(T == float) || is(T == double) || is(T == real); +} + +/** +Sees if a type is an array. +*/ +template isArrayType(T) +{ + const bool isArrayType = false; +} + +template isArrayType(T : T[]) +{ + const bool isArrayType = true; +} + +/** +Sees if a type is an associative array. +*/ +template isAAType(T) +{ + const bool isAAType = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T); +} + +/** +Sees if a type is a pointer. +*/ +template isPointerType(T) +{ + const bool isPointerType = false; +} + +template isPointerType(T : T*) +{ + const bool isPointerType = true; +} + +/** +Get to the bottom of any chain of typedefs! Returns the first non-typedef'ed type. +*/ +template realType(T) +{ + static if(is(T Base == typedef) || is(T Base == enum)) + alias realType!(Base) realType; + else + alias T realType; +} + +/** +See if a character is a lowercase character. +*/ +template IsLower(char c) +{ + const bool IsLower = c >= 'a' && c <= 'z'; +} + +/** +See if a character is an uppercase character. +*/ +template IsUpper(char c) +{ + const bool IsUpper = c >= 'A' && c <= 'Z'; +} + +/** +Convert a character or string to lowercase. +*/ +template ToLower(char c) +{ + const char ToLower = IsUpper!(c) ? c + ('a' - 'A') : c; +} + +/// ditto +template ToLower(char[] s) +{ + static if(s.length == 0) + const ToLower = ""c; + else + const ToLower = ToLower!(s[0]) ~ s[1 .. $]; +} + +/** +Convert a character or string to uppercase. +*/ +template ToUpper(char c) +{ + const char ToUpper = IsLower!(c) ? c - ('a' - 'A') : c; +} + +/// ditto +template ToUpper(char[] s) +{ + static if(s.length == 0) + const ToUpper = ""c; + else + const ToUpper = ToUpper!(s[0]) ~ s[1 .. $]; +} + +/** +Capitalize a word so that the first letter is capital. +*/ +template Capitalize(char[] s) +{ + static if(s.length == 0) + const char[] Capitalize = ""c; + else + const char[] Capitalize = ToUpper!(s[0]) ~ ToLower!(s[1 .. $]); +} + +/** +Compile-time map. Takes a template "function" which should take a single argument +of the type of the elements of the list of values that follows. Resolves to a tuple. +*/ +template Map(alias Templ, List...) +{ + static if(List.length == 0) + alias Tuple!() Map; + else + alias Tuple!(Templ!(List[0]), Map!(Templ, List[1 .. $])) Map; +} + +/** +Compile-time reduce. Takes a template "function" that should take two arguments of the type +of the elements of the list of values that follows. The list must be at least one element +long. Resolves to a single value of the type that the template function returns. +*/ +template Reduce(alias Templ, List...) +{ + static assert(List.length > 0, "Reduce must be called on a list of at least one element"); + + static if(is(List[0])) + { + static if(List.length == 1) + alias List[0] Reduce; + else + alias Reduce!(Templ, Tuple!(Templ!(List[0], List[1]), List[2 .. $])) Reduce; + } + else + { + static if(List.length == 1) + const Reduce = List[0]; + else + const Reduce = Reduce!(Templ, Tuple!(Templ!(List[0], List[1]), List[2 .. $])); + } +} + +/** +Compile-time range. Given lower and upper bound, yields a tuple of integers in the +range [min, max). +*/ +template Range(uint min, uint max) +{ + static if(min >= max) + alias Tuple!() Range; + else + alias Tuple!(min, Range!(min + 1, max)) Range; +} + +/// ditto +template Range(uint max) +{ + alias Range!(0, max) Range; +} + +/** +Compile time metafunction meant to be used with Reduce. Concatenates its first two +arguments and resolves to the result of that concatentation. +*/ +template Cat(T...) +{ + const Cat = T[0] ~ T[1]; +} + + + + + + + + + + + +// standard functions + + +/** +This function converts an integer to a string, depending on the base passed in. + Params: + buf = The function will save the translated string into this character array. + base = The base of the integer value. If "d," it will be assumed to be decimal. If "x," the integer + will be hexadecimal. + d = The integer to translate. + Returns: The translated string in a character array. +*/ +char[] itoa(char[] buf, char base, long d) +{ + size_t p = buf.length - 1; + size_t startIdx = 0; + ulong ud = d; + bool negative = false; + + int divisor = 10; + + // If %d is specified and D is minus, put `-' in the head. + if(base == 'd' && d < 0) + { + negative = true; + ud = -d; + } + else if(base == 'x') + divisor = 16; + + // Divide UD by DIVISOR until UD == 0. + do + { + int remainder = ud % divisor; + buf[p--] = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; + } + while (ud /= divisor) + + if(negative) + buf[p--] = '-'; + + return buf[p + 1 .. $]; +} diff --git a/kernel/dev/console.d b/kernel/dev/console.d new file mode 100644 index 0000000..f954a4f --- /dev/null +++ b/kernel/dev/console.d @@ -0,0 +1,191 @@ +// This implements a console (text-mode) VGA driver. + +module kernel.dev.console; + +// This contains the hexidecimal values for various colors for printing to the screen. +enum Color : ubyte +{ + Black = 0x00, + Blue = 0x01, + Green = 0x02, + Cyan = 0x03, + Red = 0x04, + Magenta = 0x05, + Yellow = 0x06, + LightGray = 0x07, + Gray = 0x08, + LightBlue = 0x09, + LightGreen = 0x0A, + LightCyan = 0x0B, + LightRed = 0x0C, + LightMagenta = 0x0D, + LightYellow = 0x0E, + White = 0x0F +} + +// This is the true interface to the console +struct Console +{ +static: +public: + + // The number of columns and lines on the screen. + const uint COLUMNS = 80; + const uint LINES = 24; + + // The default color. + const ubyte DEFAULTCOLORS = Color.LightGray; + + ubyte* videoMemoryLocation = cast(ubyte*)0xFFFFFFFF800B8000; + + // The cursor position + private int xpos = 0; + private int ypos = 0; + + // The current color + private ubyte colorAttribute = DEFAULTCOLORS; + + // The width of a tab + const auto TABSTOP = 4; + + // This method will clear the screen and return the cursor to (0,0). + void clearScreen() + { + int i; + + for (i=0; i < COLUMNS * LINES * 2; i++) + { + volatile *(videoMemoryLocation + i) = 0; + } + + xpos = 0; + ypos = 0; + } + + // This method will return the current location of the cursor + void getPosition(out int x, out int y) + { + x = xpos; + y = ypos; + } + + // This method will set the current location of the cursor to the x and y given. + void setPosition(int x, int y) + { + if (x < 0) { x = 0; } + if (y < 0) { y = 0; } + if (x >= COLUMNS) { x = COLUMNS - 1; } + if (y >= LINES) { y = LINES - 1; } + + xpos = x; + ypos = y; + } + + // This method will post the character to the screen at the current location. + void putChar(char c) + { + if (c == '\t') + { + // Insert a tab. + xpos += TABSTOP; + } + else if (c != '\n' && c != '\r') + { + // Set the current piece of video memory to the character to print. + volatile *(videoMemoryLocation + (xpos + ypos * COLUMNS) * 2) = c & 0xFF; + volatile *(videoMemoryLocation + (xpos + ypos * COLUMNS) * 2 + 1) = colorAttribute; + + // increase the cursor position + xpos++; + } + + // if you have reached the end of the line, or printing a newline, increase the y position + if (c == '\n' || c == '\r' || xpos >= COLUMNS) + { + xpos = 0; + ypos++; + + if (ypos >= LINES) + { + scrollDisplay(1); + } + } + } + + // This mehtod will post a string to the screen at the current location. + void putString(char[] s) + { + foreach(c; s) + { + putChar(c); + } + } + + // This function sets the console colors back to their defaults. + void resetColors() + { + colorAttribute = DEFAULTCOLORS; + } + + // This function will set the text foreground to a new color. + void setForeColor(Color newColor) + { + colorAttribute = (colorAttribute & 0xf0) | newColor; + } + + // This function will set the text background to a new color. + void setBackColor(Color newColor) + { + colorAttribute = (colorAttribute & 0x0f) | (newColor << 4); + } + + // This function will set both the foreground and background colors. + void setColors(Color foreColor, Color backColor) + { + colorAttribute = (foreColor & 0x0f) | (backColor << 4); + } + + // This function will scroll the entire screen. + void scrollDisplay(uint numLines) + { + // obviously, scrolling all lines results in a cleared display. Use the faster function. + if (numLines >= LINES) + { + clearScreen(); + return; + } + + int cury = 0; + int offset1 = 0; + int offset2 = numLines * COLUMNS; + + // Go through and shift the correct amount. + for ( ; cury <= LINES - numLines; cury++) + { + for (int curx = 0; curx < COLUMNS; curx++) + { + *(videoMemoryLocation + (curx + offset1) * 2) = *(videoMemoryLocation + (curx + offset1 + offset2) * 2); + *(videoMemoryLocation + (curx + offset1) * 2 + 1) = *(videoMemoryLocation + (curx + offset1 + offset2) * 2 + 1); + } + + offset1 += COLUMNS; + } + + // clear the remaining lines + for (; cury <= LINES; cury++) + { + for (int curx = 0; curx < COLUMNS; curx++) + { + *(videoMemoryLocation + (curx + offset1) * 2) = 0x00; + *(videoMemoryLocation + (curx + offset1) * 2 + 1) = 0x00; + } + } + + ypos -= numLines; + + if (ypos < 0) + { + ypos = 0; + } + } +} diff --git a/kernel/runtime/dstubs.d b/kernel/runtime/dstubs.d new file mode 100644 index 0000000..a83a4e1 --- /dev/null +++ b/kernel/runtime/dstubs.d @@ -0,0 +1,1014 @@ +// This is the stubbed out runtime for D. + +// It is magical and full of nondescriptive mystical creatures. + +module kernel.core.dstubs; + +// some utility functions and routines for the runtime +import kernel.runtime.util; + +// for printing out runtime errors +import kernel.core.kprintf; + +// magical gcc business (BEWARE THE MAGICAL EMPTY FILE!!!) +static import gcc.builtins; + +extern(C) +{ + +alias gcc.builtins.__builtin_alloca alloca; + +private +{ + struct Array + { + size_t length; + byte *data; + } + + struct aaA + { + aaA *left; + aaA *right; + hash_t hash; + /* key */ + /* value */ + } + + struct BB + { + aaA*[] b; + size_t nodes; + } + + struct AA + { + BB* a; + } + + alias long ArrayRet_t; + extern(D) typedef int delegate(void *) aa_dg_t; + extern(D) typedef int delegate(void *, void *) aa_dg2_t; + extern(D) typedef int delegate(void *) array_dg_t; + extern(D) typedef int delegate(void *, void *) array_dg2_t; + + enum BlkAttr : uint + { + FINALIZE = 0b0000_0001, + NO_SCAN = 0b0000_0010, + NO_MOVE = 0b0000_0100, + ALL_BITS = 0b1111_1111 + } + + template Stub(char[] signature) + { + const char[] Stub = signature ~ " { assert(false, \"Undefined runtime stub executed: " ~ signature ~ "\"); }"; + } +} + +/************************************************** + Random stubs (they'll go somewhere eventually) +**************************************************/ + +mixin(Stub!("void abort()")); +mixin(Stub!("bool rt_isHalting()")); +mixin(Stub!("bool runModuleUnitTests()")); +mixin(Stub!("void _d_monitordelete(Object h, bool det = true)")); + +/****************************************** + * Given a pointer: + * If it is an Object, return that Object. + * If it is an interface, return the Object implementing the interface. + * If it is null, return null. + * Else, undefined crash + */ + +Object _d_toObject(void* p) +{ Object o; + + if (p) + { + o = cast(Object)p; + ClassInfo oc = o.classinfo; + Interface *pi = **cast(Interface ***)p; + + /* Interface.offset lines up with ClassInfo.name.ptr, + * so we rely on pointers never being less than 64K, + * and Objects never being greater. + */ + if (pi.offset < 0x10000) + { + //printf("\tpi.offset = %d\n", pi.offset); + o = cast(Object)(p - pi.offset); + } + } + return o; +} + + +/************************************* + * Attempts to cast Object o to class c. + * Returns o if successful, null if not. + */ + +Object _d_interface_cast(void* p, ClassInfo c) +{ Object o; + + //printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name); + if (p) + { + Interface *pi = **cast(Interface ***)p; + + //printf("\tpi.offset = %d\n", pi.offset); + o = cast(Object)(p - pi.offset); + return _d_dynamic_cast(o, c); + } + return o; +} + +Object _d_dynamic_cast(Object o, ClassInfo c) +{ ClassInfo oc; + size_t offset = 0; + + //printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name); + + if (o) + { + oc = o.classinfo; + if (_d_isbaseof2(oc, c, offset)) + { + //printf("\toffset = %d\n", offset); + o = cast(Object)(cast(void*)o + offset); + } + else + o = null; + } + //printf("\tresult = %p\n", o); + return o; +} + +int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout size_t offset) +{ int i; + + if (oc is c) + return 1; + do + { + if (oc.base is c) + return 1; + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo ic; + + ic = oc.interfaces[i].classinfo; + if (ic is c) + { offset = oc.interfaces[i].offset; + return 1; + } + } + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo ic; + + ic = oc.interfaces[i].classinfo; + if (_d_isbaseof2(ic, c, offset)) + { offset = oc.interfaces[i].offset; + return 1; + } + } + oc = oc.base; + } while (oc); + return 0; +} + +int _d_isbaseof(ClassInfo oc, ClassInfo c) +{ int i; + + if (oc is c) + return 1; + do + { + if (oc.base is c) + return 1; + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo ic; + + ic = oc.interfaces[i].classinfo; + if (ic is c || _d_isbaseof(ic, c)) + return 1; + } + oc = oc.base; + } while (oc); + return 0; +} + +/********************************* + * Find the vtbl[] associated with Interface ic. + */ + +void *_d_interface_vtbl(ClassInfo ic, Object o) +{ int i; + ClassInfo oc; + + //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic); + + assert(o); + + oc = o.classinfo; + for (i = 0; i < oc.interfaces.length; i++) + { + ClassInfo oic; + + oic = oc.interfaces[i].classinfo; + if (oic is ic) + { + return cast(void *)oc.interfaces[i].vtbl; + } + } + assert(0); +} + +int _d_obj_eq(Object o1, Object o2) +{ + return o1 is o2 || (o1 && o1.opEquals(o2)); +} + +int _d_obj_cmp(Object o1, Object o2) +{ + return o1.opCmp(o2); +} + +int _d_switch_string(char[][] table, char[] ca) +{ + int low; + int high; + int mid; + int c; + char[] pca; + + low = 0; + high = table.length; + + if (high && + ca.length >= table[0].length && + ca.length <= table[high - 1].length) + { + // Looking for 0 length string, which would only be at the beginning + if (ca.length == 0) + return 0; + + char c1 = ca[0]; + + // Do binary search + while (low < high) + { + mid = (low + high) >> 1; + pca = table[mid]; + c = ca.length - pca.length; + if (c == 0) + { + c = cast(ubyte)c1 - cast(ubyte)pca[0]; + if (c == 0) + { + c = memcmp(ca.ptr, pca.ptr, ca.length); + if (c == 0) + { + return mid; + } + } + } + if (c < 0) + { + high = mid; + } + else + { + low = mid + 1; + } + } + } + + return -1; // not found +} + +int _d_switch_ustring(wchar[][] table, wchar[] ca) +{ + int low; + int high; + int mid; + int c; + wchar[] pca; + + low = 0; + high = table.length; + + // Do binary search + while (low < high) + { + mid = (low + high) >> 1; + pca = table[mid]; + c = ca.length - pca.length; + if (c == 0) + { + c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof); + if (c == 0) + { + return mid; + } + } + if (c < 0) + { + high = mid; + } + else + { + low = mid + 1; + } + } + + return -1; // not found +} + +int _d_switch_dstring(dchar[][] table, dchar[] ca) +{ + int low; + int high; + int mid; + int c; + dchar[] pca; + + low = 0; + high = table.length; + + // Do binary search + while (low < high) + { + mid = (low + high) >> 1; + pca = table[mid]; + c = ca.length - pca.length; + if (c == 0) + { + c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof); + if (c == 0) + { + return mid; + } + } + if (c < 0) + { + high = mid; + } + else + { + low = mid + 1; + } + } + + return -1; // not found +} + +/************************************************** + Lifetime stubs +**************************************************/ + +mixin(Stub!("Object _d_newclass(ClassInfo ci)")); +mixin(Stub!("void _d_delinterface(void** p)")); +mixin(Stub!("void _d_delclass(Object* p)")); +mixin(Stub!("Array _d_newarrayT(TypeInfo ti, size_t length)")); +mixin(Stub!("Array _d_newarrayiT(TypeInfo ti, size_t length)")); +mixin(Stub!("void[] _d_newarraymTp(TypeInfo ti, int ndims, size_t* pdim)")); +mixin(Stub!("void[] _d_newarraymiTp(TypeInfo ti, int ndims, size_t* pdim)")); +mixin(Stub!("void _d_delarray(Array *p)")); +mixin(Stub!("void _d_delmemory(void* *p)")); +mixin(Stub!("void _d_callfinalizer(void* p)")); +mixin(Stub!("void rt_finalize(void* p, bool det = true)")); +mixin(Stub!("byte[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, Array *p)")); +mixin(Stub!("byte[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, Array *p)")); +mixin(Stub!("Array _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)")); +mixin(Stub!("byte[] _d_arrayappendcTp(TypeInfo ti, inout byte[] x, void *argp)")); +mixin(Stub!("byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)")); +mixin(Stub!("byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)")); +mixin(Stub!("Array _adDupT(TypeInfo ti, Array a)")); + +/************************************************** + GC stubs +**************************************************/ + +mixin(Stub!("void gc_init()")); +mixin(Stub!("void gc_term()")); +mixin(Stub!("void gc_enable()")); +mixin(Stub!("void gc_disable()")); +mixin(Stub!("void gc_collect()")); +mixin(Stub!("uint gc_getAttr( void* p )")); +mixin(Stub!("uint gc_setAttr( void* p, uint a )")); +mixin(Stub!("uint gc_clrAttr( void* p, uint a )")); +mixin(Stub!("void* gc_malloc( size_t sz, uint ba = 0 )")); +mixin(Stub!("void* gc_calloc( size_t sz, uint ba = 0 )")); +mixin(Stub!("void* gc_realloc( void* p, size_t sz, uint ba = 0 )")); +mixin(Stub!("size_t gc_extend( void* p, size_t mx, size_t sz )")); +mixin(Stub!("void gc_free( void* p )")); +mixin(Stub!("size_t gc_sizeOf( void* p )")); +mixin(Stub!("void gc_addRoot( void* p )")); +mixin(Stub!("void gc_addRange( void* p, size_t sz )")); +mixin(Stub!("void gc_removeRoot( void *p )")); +mixin(Stub!("void gc_removeRange( void *p )")); +mixin(Stub!("bool onCollectResource( Object obj )")); + +/************************************************** + Exception stubs +**************************************************/ + +void _d_assert( char[] file, uint line ) +{ + onAssertError( file, line ); +} + +void _d_assert_msg( char[] msg, char[] file, uint line ) +{ + onAssertErrorMsg( file, line, msg ); +} + +void _d_array_bounds( char[] file, uint line ) +{ + onArrayBoundsError( file, line ); +} + +void _d_switch_error( char[] file, uint line ) +{ + onSwitchError( file, line ); +} + +private void onAssertError(char[] file, size_t line) +{ + kprintfln!("Error in {}, line {}: assertion failed.")(file, line); + asm { l: hlt; jmp l; } +} + +private void onAssertErrorMsg(char[] file, size_t line, char[] msg) +{ + kprintfln!("Error in {}, line {}: assertion failed: \"{}\"")(file, line, msg); + asm { l: hlt; jmp l; } +} + +private void onArrayBoundsError(char[] file, size_t line) +{ + kprintfln!("Error in {}, line {}: array index out of bounds.")(file, line); + asm { l: hlt; jmp l; } +} + +private void onSwitchError(char[] file, size_t line) +{ + kprintfln!("Error in {}, line {}: switch has no case or default to handle the switched-upon value.")(file, line); + asm { l: hlt; jmp l; } +} + +mixin(Stub!("void onFinalizeError( ClassInfo info, Exception ex )")); +mixin(Stub!("void onOutOfMemoryError()")); +mixin(Stub!("void onUnicodeError( char[] msg, size_t idx )")); + +/************************************************** + DEH and Unwind stubs +**************************************************/ + +mixin(Stub!("void _gdc_cleanupException()")); +mixin(Stub!("void _d_throw(Object obj)")); +mixin(Stub!("int __gdc_personality_v0()")); +mixin(Stub!("void _Unwind_RaiseException ()")); +mixin(Stub!("void _Unwind_ForcedUnwind ()")); +mixin(Stub!("void _Unwind_DeleteException ()")); +mixin(Stub!("void _Unwind_Resume()")); +mixin(Stub!("void _Unwind_Resume_or_Rethrow ()")); +mixin(Stub!("void _Unwind_Backtrace ()")); +mixin(Stub!("void _Unwind_GetGR ()")); +mixin(Stub!("void _Unwind_SetGR ()")); +mixin(Stub!("void _Unwind_GetIP ()")); +mixin(Stub!("void _Unwind_SetIP ()")); +mixin(Stub!("void _Unwind_GetCFA ()")); +mixin(Stub!("void *_Unwind_GetLanguageSpecificData ()")); +mixin(Stub!("void _Unwind_GetRegionStart ()")); +mixin(Stub!("void _Unwind_SjLj_RaiseException()")); +mixin(Stub!("void _Unwind_SjLj_ForcedUnwind()")); +mixin(Stub!("void _Unwind_SjLj_Resume ()")); +mixin(Stub!("void _Unwind_GetDataRelBase ()")); +mixin(Stub!("void _Unwind_GetTextRelBase ()")); +mixin(Stub!("uint size_of_encoded_value (ubyte encoding)")); +mixin(Stub!("void base_of_encoded_value ()")); +mixin(Stub!("void read_uleb128()")); +mixin(Stub!("void read_sleb128()")); +mixin(Stub!("void read_encoded_value_with_base()")); +mixin(Stub!("void read_encoded_value()")); + +/************************************************** + AA stubs +**************************************************/ + +mixin(Stub!("size_t _aaLen(AA aa)")); +mixin(Stub!("void *_aaGetp(AA* aa, TypeInfo keyti, size_t valuesize, void *pkey)")); +mixin(Stub!("void *_aaGetRvaluep(AA aa, TypeInfo keyti, size_t valuesize, void *pkey)")); +mixin(Stub!("void* _aaInp(AA aa, TypeInfo keyti, void *pkey)")); +mixin(Stub!("void _aaDelp(AA aa, TypeInfo keyti, void *pkey)")); +mixin(Stub!("Array _aaValues(AA aa, size_t keysize, size_t valuesize)")); +mixin(Stub!("AA _aaRehash(AA* paa, TypeInfo keyti)")); +mixin(Stub!("Array _aaKeys(AA aa, size_t keysize)")); +mixin(Stub!("int _aaApply(AA aa, size_t keysize, aa_dg_t dg)")); +mixin(Stub!("int _aaApply2(AA aa, size_t keysize, aa_dg2_t dg)")); +mixin(Stub!("BB* _d_assocarrayliteralTp(TypeInfo_AssociativeArray ti, size_t length, void *keys, void *values)")); + +/************************************************** + Array stubs +**************************************************/ + +mixin(Stub!("int _aApplycw1(char[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplycd1(char[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplywc1(wchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplywd1(wchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplydc1(dchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplydw1(dchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplycw2(char[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplycd2(char[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplywc2(wchar[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplywd2(wchar[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplydc2(dchar[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplydw2(dchar[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplyRcw1(char[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplyRcd1(char[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplyRwc1(wchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplyRwd1(wchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplyRdc1(dchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplyRdw1(dchar[] aa, array_dg_t dg)")); +mixin(Stub!("int _aApplyRcw2(char[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplyRcd2(char[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplyRwc2(wchar[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplyRwd2(wchar[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplyRdc2(dchar[] aa, array_dg2_t dg)")); +mixin(Stub!("int _aApplyRdw2(dchar[] aa, array_dg2_t dg)")); +mixin(Stub!("char[] _adSortChar(char[] a)")); +mixin(Stub!("wchar[] _adSortWchar(wchar[] a)")); + + +const ubyte[256] UTF8stride = +[ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, +]; + +Array _adReverseChar(char[] a) +{ + if(a.length > 1) + { + char[6] tmp; + char[6] tmplo; + char* lo = a.ptr; + char* hi = &a[length - 1]; + + while (lo < hi) + { auto clo = *lo; + auto chi = *hi; + + if (clo <= 0x7F && chi <= 0x7F) + { + *lo = chi; + *hi = clo; + lo++; + hi--; + continue; + } + + uint stridelo = UTF8stride[clo]; + + uint stridehi = 1; + while ((chi & 0xC0) == 0x80) + { + chi = *--hi; + stridehi++; + assert(hi >= lo); + } + if (lo == hi) + break; + + if (stridelo == stridehi) + { + + memcpy(tmp.ptr, lo, stridelo); + memcpy(lo, hi, stridelo); + memcpy(hi, tmp.ptr, stridelo); + lo += stridelo; + hi--; + continue; + } + + /* Shift the whole array. This is woefully inefficient + */ + memcpy(tmp.ptr, hi, stridehi); + memcpy(tmplo.ptr, lo, stridelo); + memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo); + memcpy(lo, tmp.ptr, stridehi); + memcpy(hi + cast(int) stridehi - cast(int) stridelo, tmplo.ptr, stridelo); + + lo += stridehi; + hi = hi - 1 + (cast(int) stridehi - cast(int) stridelo); + } + } + + Array aaa = *cast(Array*)(&a); + return aaa; +} + +Array _adReverseWchar(wchar[] a) +{ + if (a.length > 1) + { + wchar[2] tmp; + wchar* lo = a.ptr; + wchar* hi = &a[length - 1]; + + while (lo < hi) + { auto clo = *lo; + auto chi = *hi; + + if ((clo < 0xD800 || clo > 0xDFFF) && + (chi < 0xD800 || chi > 0xDFFF)) + { + *lo = chi; + *hi = clo; + lo++; + hi--; + continue; + } + + int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF); + + int stridehi = 1; + if (chi >= 0xDC00 && chi <= 0xDFFF) + { + chi = *--hi; + stridehi++; + assert(hi >= lo); + } + if (lo == hi) + break; + + if (stridelo == stridehi) + { int stmp; + + assert(stridelo == 2); + assert(stmp.sizeof == 2 * (*lo).sizeof); + stmp = *cast(int*)lo; + *cast(int*)lo = *cast(int*)hi; + *cast(int*)hi = stmp; + lo += stridelo; + hi--; + continue; + } + + /* Shift the whole array. This is woefully inefficient + */ + memcpy(tmp.ptr, hi, stridehi * wchar.sizeof); + memcpy(hi + cast(int) stridehi - cast(int) stridelo, lo, stridelo * wchar.sizeof); + memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof); + memcpy(lo, tmp.ptr, stridehi * wchar.sizeof); + + lo += stridehi; + hi = hi - 1 + (cast(int) stridehi - cast(int) stridelo); + } + } + + Array aaa = *cast(Array*)(&a); + return aaa; +} + +int _adCmpChar(Array a1, Array a2) +{ + version (Asm86) + { + asm + { naked ; + + push EDI ; + push ESI ; + + mov ESI,a1+4[4+ESP] ; + mov EDI,a2+4[4+ESP] ; + + mov ECX,a1[4+ESP] ; + mov EDX,a2[4+ESP] ; + + cmp ECX,EDX ; + jb GotLength ; + + mov ECX,EDX ; + + GotLength: + cmp ECX,4 ; + jb DoBytes ; + + // Do alignment if neither is dword aligned + test ESI,3 ; + jz Aligned ; + + test EDI,3 ; + jz Aligned ; + DoAlign: + mov AL,[ESI] ; //align ESI to dword bounds + mov DL,[EDI] ; + + cmp AL,DL ; + jnz Unequal ; + + inc ESI ; + inc EDI ; + + test ESI,3 ; + + lea ECX,[ECX-1] ; + jnz DoAlign ; + Aligned: + mov EAX,ECX ; + + // do multiple of 4 bytes at a time + + shr ECX,2 ; + jz TryOdd ; + + repe ; + cmpsd ; + + jnz UnequalQuad ; + + TryOdd: + mov ECX,EAX ; + DoBytes: + // if still equal and not end of string, do up to 3 bytes slightly + // slower. + + and ECX,3 ; + jz Equal ; + + repe ; + cmpsb ; + + jnz Unequal ; + Equal: + mov EAX,a1[4+ESP] ; + mov EDX,a2[4+ESP] ; + + sub EAX,EDX ; + pop ESI ; + + pop EDI ; + ret ; + + UnequalQuad: + mov EDX,[EDI-4] ; + mov EAX,[ESI-4] ; + + cmp AL,DL ; + jnz Unequal ; + + cmp AH,DH ; + jnz Unequal ; + + shr EAX,16 ; + + shr EDX,16 ; + + cmp AL,DL ; + jnz Unequal ; + + cmp AH,DH ; + Unequal: + sbb EAX,EAX ; + pop ESI ; + + or EAX,1 ; + pop EDI ; + + ret ; + } + } + else + { + int len; + int c; + + len = a1.length; + if (a2.length < len) + len = a2.length; + c = memcmp(cast(char *)a1.data, cast(char *)a2.data, len); + if (!c) + c = cast(int)a1.length - cast(int)a2.length; + return c; + } +} + +Array _adReverse(Array a, size_t szelem) +{ + if (a.length >= 2) + { + byte* tmp; + byte[16] buffer; + + void* lo = a.data; + void* hi = a.data + (a.length - 1) * szelem; + + tmp = buffer.ptr; + if (szelem > 16) + tmp = cast(byte*)alloca(szelem); + + for (; lo < hi; lo += szelem, hi -= szelem) + { + memcpy(tmp, lo, szelem); + memcpy(lo, hi, szelem); + memcpy(hi, tmp, szelem); + } + } + return a; +} + +int _adEq(Array a1, Array a2, TypeInfo ti) +{ + if(a1.length != a2.length) + return 0; // not equal + + auto sz = ti.tsize(); + auto p1 = a1.data; + auto p2 = a2.data; + + if(sz == 1) + // We should really have a ti.isPOD() check for this + return (memcmp(p1, p2, a1.length) == 0); + + for(size_t i = 0; i < a1.length; i++) + { + if(!ti.equals(p1 + i * sz, p2 + i * sz)) + return 0; // not equal + } + + return 1; // equal +} + +int _adCmp(Array a1, Array a2, TypeInfo ti) +{ + //printf("adCmp()\n"); + auto len = a1.length; + if (a2.length < len) + len = a2.length; + auto sz = ti.tsize(); + void *p1 = a1.data; + void *p2 = a2.data; + + if (sz == 1) + { // We should really have a ti.isPOD() check for this + auto c = memcmp(p1, p2, len); + if (c) + return c; + } + else + { + for (size_t i = 0; i < len; i++) + { + auto c = ti.compare(p1 + i * sz, p2 + i * sz); + if (c) + return c; + } + } + if (a1.length == a2.length) + return 0; + return (a1.length > a2.length) ? 1 : -1; +} + +Array _adSort(Array a, TypeInfo ti) +{ + static const uint Qsort_Threshold = 7; + + struct StackEntry { + byte *l; + byte *r; + } + + size_t elem_size = ti.tsize(); + size_t qsort_limit = elem_size * Qsort_Threshold; + + static assert(ubyte.sizeof == 1); + static assert(ubyte.max == 255); + + StackEntry[size_t.sizeof * 8] stack; // log2( size_t.max ) + StackEntry * sp = stack.ptr; + byte* lbound = cast(byte *) a.data; + byte* rbound = cast(byte *) a.data + a.length * elem_size; + byte* li = void; + byte* ri = void; + + while (1) + { + if (rbound - lbound > qsort_limit) + { + ti.swap(lbound, + lbound + ( + ((rbound - lbound) >>> 1) - + (((rbound - lbound) >>> 1) % elem_size) + )); + + li = lbound + elem_size; + ri = rbound - elem_size; + + if (ti.compare(li, ri) > 0) + ti.swap(li, ri); + if (ti.compare(lbound, ri) > 0) + ti.swap(lbound, ri); + if (ti.compare(li, lbound) > 0) + ti.swap(li, lbound); + + while (1) + { + do + li += elem_size; + while (ti.compare(li, lbound) < 0); + do + ri -= elem_size; + while (ti.compare(ri, lbound) > 0); + if (li > ri) + break; + ti.swap(li, ri); + } + ti.swap(lbound, ri); + if (ri - lbound > rbound - li) + { + sp.l = lbound; + sp.r = ri; + lbound = li; + } + else + { + sp.l = li; + sp.r = rbound; + rbound = ri; + } + ++sp; + } else { + // Use insertion sort + for (ri = lbound, li = lbound + elem_size; + li < rbound; + ri = li, li += elem_size) + { + for ( ; ti.compare(ri, ri + elem_size) > 0; + ri -= elem_size) + { + ti.swap(ri, ri + elem_size); + if (ri == lbound) + break; + } + } + if (sp != stack.ptr) + { + --sp; + lbound = sp.l; + rbound = sp.r; + } + else + return a; + } + } +} + +void[] _d_arraycast(size_t tsize, size_t fsize, void[] a) +{ + auto length = a.length; + auto nbytes = length * fsize; + + if(nbytes % tsize != 0) + throw new Exception("array cast misalignment"); + + length = nbytes / tsize; + *cast(size_t *)&a = length; // jam new length + return a; +} + +byte[] _d_arraycopy(size_t size, byte[] from, byte[] to) +{ + if(to.length != from.length) + throw new Exception("lengths don't match for array copy"); + else if(cast(byte *)to + to.length * size <= cast(byte *)from || cast(byte *)from + from.length * size <= cast(byte *)to) + memcpy(cast(byte *)to, cast(byte *)from, to.length * size); + else + throw new Exception("overlapping array copy"); + + return to; +} + +} diff --git a/kernel/runtime/gcc/builtins.d b/kernel/runtime/gcc/builtins.d new file mode 100644 index 0000000..749d8af --- /dev/null +++ b/kernel/runtime/gcc/builtins.d @@ -0,0 +1,41 @@ +/* GDC -- D front-end for GCC + Copyright (C) 2004 David Friedman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/** + Declarations are automatically created by the compiler. All + declarations start with "__builtin_". Refer to _builtins.def in the + GCC source for a list of functions. Not all of the functions are + supported. + + In addition to built-in functions, the following types are defined. + + $(TABLE + $(TR $(TD ___builtin_va_list) $(TD The target's va_list type )) + $(TR $(TD ___builtin_Clong ) $(TD The D equivalent of the target's + C "long" type )) + $(TR $(TD ___builtin_Culong ) $(TD The D equivalent of the target's + C "unsigned long" type )) + $(TR $(TD ___builtin_machine_int ) $(TD Signed word-sized integer )) + $(TR $(TD ___builtin_machine_uint) $(TD Unsigned word-sized integer )) + $(TR $(TD ___builtin_pointer_int ) $(TD Signed pointer-sized integer )) + $(TR $(TD ___builtin_pointer_uint) $(TD Unsigned pointer-sized integer )) + ) +*/ + +module gcc.builtins; diff --git a/kernel/runtime/invariant.d b/kernel/runtime/invariant.d new file mode 100644 index 0000000..0b03e5c --- /dev/null +++ b/kernel/runtime/invariant.d @@ -0,0 +1,28 @@ + +/* + * Placed into the Public Domain + * written by Walter Bright + * www.digitalmars.com + */ + +void _d_invariant(Object o) +{ + ClassInfo c; + + //printf("__d_invariant(%p)\n", o); + + // BUG: needs to be filename/line of caller, not library routine + assert(o !is null); // just do null check, not invariant check + + c = o.classinfo; + + do + { + if(c.classInvariant) + { + (*c.classInvariant)(o); + } + + c = c.base; + } while(c) +} diff --git a/kernel/runtime/object.d b/kernel/runtime/object.d new file mode 100644 index 0000000..242d677 --- /dev/null +++ b/kernel/runtime/object.d @@ -0,0 +1,1053 @@ + +/** + * Part of the D programming language runtime library. + * Forms the symbols available to all D programs. Includes + * Object, which is the root of the class object hierarchy. + * + * This module is implicitly imported. + * Macros: + * WIKI = Phobos/Object + */ + +/* + * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + + +module object; + +// Imports necessary routines used by the runtime +import kernel.runtime.util; + +extern(C) Object _d_newclass(ClassInfo ci); + +/// Standard boolean type. +alias bool bit; + +version (X86_64) +{ + /** + * An unsigned integral type large enough to span the memory space. Use for + * array indices and pointer offsets for maximal portability to + * architectures that have different memory address ranges. This is + * analogous to C's size_t. + */ + alias ulong size_t; + + /** + * A signed integral type large enough to span the memory space. Use for + * pointer differences and for size_t differences for maximal portability to + * architectures that have different memory address ranges. This is + * analogous to C's ptrdiff_t. + */ + alias long ptrdiff_t; + + alias ulong hash_t; +} +else +{ + alias uint size_t; + alias int ptrdiff_t; + alias uint hash_t; +} + +/* ************************* + * Internal struct pointed to by the hidden .monitor member. + */ +struct Monitor +{ + void delegate(Object)[] delegates; + + /* More stuff goes here defined by internal/monitor.c */ +} + +/****************** + * All D class objects inherit from Object. + */ +class Object +{ + /** + * Convert Object to a human readable string. + */ + char[] toString() + { + return this.classinfo.name; + } + + /** + * Compute hash function for Object. + */ + hash_t toHash() + { + // BUG: this prevents a compacting GC from working, needs to be fixed + return cast(uint)cast(void *)this; + } + + /** + * Compare with another Object obj. + * Returns: + * $(TABLE + * $(TR $(TD this < obj) $(TD < 0)) + * $(TR $(TD this == obj) $(TD 0)) + * $(TR $(TD this > obj) $(TD > 0)) + * ) + */ + int opCmp(Object o) + { + // BUG: this prevents a compacting GC from working, needs to be fixed + //return cast(int)cast(void *)this - cast(int)cast(void *)o; + + throw new Error("need opCmp for class " ~ this.classinfo.name); + } + + /** + * Returns !=0 if this object does have the same contents as obj. + */ + int opEquals(Object o) + { + return cast(int)(this is o); + } + + /* ** + * Call delegate dg, passing this to it, when this object gets destroyed. + * Use extreme caution, as the list of delegates is stored in a place + * not known to the gc. Thus, if any objects pointed to by one of these + * delegates gets freed by the gc, calling the delegate will cause a + * crash. + * This is only for use by library developers, as it will need to be + * redone if weak pointers are added or a moving gc is developed. + */ + /*final void notifyRegister(void delegate(Object) dg) + { + //printf("notifyRegister(dg = %llx, o = %p)\n", dg, this); + synchronized (this) + { + Monitor* m = cast(Monitor*)(cast(void**)this)[1]; + foreach (inout x; m.delegates) + { + if (!x || x == dg) + { x = dg; + return; + } + } + + // Increase size of delegates[] + auto len = m.delegates.length; + auto startlen = len; + if (len == 0) + { + len = 4; + auto p = calloc((void delegate(Object)).sizeof, len); + if (!p) + _d_OutOfMemory(); + m.delegates = (cast(void delegate(Object)*)p)[0 .. len]; + } + else + { + len += len + 4; + auto p = realloc(m.delegates.ptr, (void delegate(Object)).sizeof * len); + if (!p) + _d_OutOfMemory(); + m.delegates = (cast(void delegate(Object)*)p)[0 .. len]; + m.delegates[startlen .. len] = null; + } + m.delegates[startlen] = dg; + } + }*/ + + /* ** + * Remove delegate dg from the notify list. + * This is only for use by library developers, as it will need to be + * redone if weak pointers are added or a moving gc is developed. + */ + /*final void notifyUnRegister(void delegate(Object) dg) + { + synchronized (this) + { + Monitor* m = cast(Monitor*)(cast(void**)this)[1]; + foreach (inout x; m.delegates) + { + if (x == dg) + x = null; + } + } + }*/ + + /****** + * Create instance of class specified by classname. + * The class must either have no constructors or have + * a default constructor. + * Returns: + * null if failed + */ + /*static Object factory(char[] classname) + { + auto ci = ClassInfo.find(classname); + if (ci) + { + return ci.create(); + } + return null; + }*/ +} + +/* +extern (C) void _d_notify_release(Object o) +{ + //printf("_d_notify_release(o = %p)\n", o); + Monitor* m = cast(Monitor*)(cast(void**)o)[1]; + if (m.delegates.length) + { + auto dgs = m.delegates; + synchronized (o) + { + dgs = m.delegates; + m.delegates = null; + } + + foreach (dg; dgs) + { + if (dg) + { //printf("calling dg = %llx (%p)\n", dg, o); + dg(o); + } + } + + free(dgs.ptr); + } +} +*/ + +/** + * Information about an interface. + * A pointer to this appears as the first entry in the interface's vtbl[]. + */ +struct Interface +{ + ClassInfo classinfo; /// .classinfo for this interface (not for containing class) + void *[] vtbl; + int offset; /// offset to Interface 'this' from Object 'this' +} + +//import std.moduleinit; +/** + * Runtime type information about a class. Can be retrieved for any class type + * or instance by using the .classinfo property. + * A pointer to this appears as the first entry in the class's vtbl[]. + */ +class ClassInfo : Object +{ + byte[] init; /** class static initializer + * (init.length gives size in bytes of class) + */ + char[] name; /// class name + void *[] vtbl; /// virtual function pointer table + Interface[] interfaces; /// interfaces this class implements + ClassInfo base; /// base class + void *destructor; + void (*classInvariant)(Object); + uint flags; + // 1: // IUnknown + // 2: // has no possible pointers into GC memory + // 4: // has offTi[] member + // 8: // has constructors + void *deallocator; + OffsetTypeInfo[] offTi; + void function(Object) defaultConstructor; // default Constructor + + /************* + * Search all modules for ClassInfo corresponding to classname. + * Returns: null if not found + */ + /*static ClassInfo find(char[] classname) + { + foreach (m; ModuleInfo.modules()) + { + //writefln("module %s, %d", m.name, m.localClasses.length); + foreach (c; m.localClasses) + { + //writefln("\tclass %s", c.name); + if (c.name == classname) + return c; + } + } + return null; + }*/ + + /******************** + * Create instance of Object represented by 'this'. + */ + Object create() + { + if (flags & 8 && !defaultConstructor) + return null; + Object o = _d_newclass(this); + if (flags & 8 && defaultConstructor) + { + defaultConstructor(o); + } + return o; + } +} + +//private import std.string; + +/** + * Array of pairs giving the offset and type information for each + * member in an aggregate. + */ +struct OffsetTypeInfo +{ + size_t offset; /// Offset of member from start of object + TypeInfo ti; /// TypeInfo for this member +} + + +/** + * Runtime type information about a type. + * Can be retrieved for any type using a + * TypeidExpression. + */ +class TypeInfo +{ + hash_t toHash() + { hash_t hash; + + foreach (char c; this.toString()) + hash = hash * 9 + c; + return hash; + } + + int opCmp(Object o) + { + if (this is o) + return 0; + TypeInfo ti = cast(TypeInfo)o; + if (ti is null) + return 1; + + char[] t = this.toString(); + char[] other = this.toString(); + + typeid(typeof(this.toString())).compare(&t, &other); + } + + int opEquals(Object o) + { + /* TypeInfo instances are singletons, but duplicates can exist + * across DLL's. Therefore, comparing for a name match is + * sufficient. + */ + if (this is o) + return 1; + TypeInfo ti = cast(TypeInfo)o; + return cast(int)(ti && this.toString() == ti.toString()); + } + + /// Returns a hash of the instance of a type. + hash_t getHash(void *p) { return cast(uint)p; } + + /// Compares two instances for equality. + int equals(void *p1, void *p2) { return cast(int)(p1 == p2); } + + /// Compares two instances for <, ==, or >. + int compare(void *p1, void *p2) { return 0; } + + /// Returns size of the type. + size_t tsize() { return 0; } + + /// Swaps two instances of the type. + void swap(void *p1, void *p2) + { + size_t n = tsize(); + for (size_t i = 0; i < n; i++) + { byte t; + + t = (cast(byte *)p1)[i]; + (cast(byte *)p1)[i] = (cast(byte *)p2)[i]; + (cast(byte *)p2)[i] = t; + } + } + + /// Get TypeInfo for 'next' type, as defined by what kind of type this is, + /// null if none. + TypeInfo next() { return null; } + + /// Return default initializer, null if default initialize to 0 + void[] init() { return null; } + + /// Get flags for type: 1 means GC should scan for pointers + uint flags() { return 0; } + + /// Get type information on the contents of the type; null if not available + OffsetTypeInfo[] offTi() { return null; } +} + +class TypeInfo_Typedef : TypeInfo +{ + char[] toString() { return name; } + + int opEquals(Object o) + { TypeInfo_Typedef c; + + return cast(int) + (this is o || + ((c = cast(TypeInfo_Typedef)o) !is null && + this.name == c.name && + this.base == c.base)); + } + + hash_t getHash(void *p) { return base.getHash(p); } + int equals(void *p1, void *p2) { return base.equals(p1, p2); } + int compare(void *p1, void *p2) { return base.compare(p1, p2); } + size_t tsize() { return base.tsize(); } + void swap(void *p1, void *p2) { return base.swap(p1, p2); } + + TypeInfo next() { return base.next(); } + uint flags() { return base.flags(); } + void[] init() { return m_init.length ? m_init : base.init(); } + + TypeInfo base; + char[] name; + void[] m_init; +} + +class TypeInfo_Enum : TypeInfo_Typedef +{ +} + +class TypeInfo_Pointer : TypeInfo +{ + char[] toString() { return m_next.toString() ~ "*"; } + + int opEquals(Object o) + { TypeInfo_Pointer c; + + return this is o || + ((c = cast(TypeInfo_Pointer)o) !is null && + this.m_next == c.m_next); + } + + hash_t getHash(void *p) + { + return cast(uint)*cast(void* *)p; + } + + int equals(void *p1, void *p2) + { + return cast(int)(*cast(void* *)p1 == *cast(void* *)p2); + } + + int compare(void *p1, void *p2) + { + if (*cast(void* *)p1 < *cast(void* *)p2) + return -1; + else if (*cast(void* *)p1 > *cast(void* *)p2) + return 1; + else + return 0; + } + + size_t tsize() + { + return (void*).sizeof; + } + + void swap(void *p1, void *p2) + { void* tmp; + tmp = *cast(void**)p1; + *cast(void**)p1 = *cast(void**)p2; + *cast(void**)p2 = tmp; + } + + TypeInfo next() { return m_next; } + uint flags() { return 1; } + + TypeInfo m_next; +} + +class TypeInfo_Array : TypeInfo +{ + char[] toString() { return value.toString() ~ "[]"; } + + int opEquals(Object o) + { TypeInfo_Array c; + + return cast(int) + (this is o || + ((c = cast(TypeInfo_Array)o) !is null && + this.value == c.value)); + } + + hash_t getHash(void *p) + { size_t sz = value.tsize(); + hash_t hash = 0; + void[] a = *cast(void[]*)p; + for (size_t i = 0; i < a.length; i++) + hash += value.getHash(a.ptr + i * sz); + return hash; + } + + int equals(void *p1, void *p2) + { + void[] a1 = *cast(void[]*)p1; + void[] a2 = *cast(void[]*)p2; + if (a1.length != a2.length) + return 0; + size_t sz = value.tsize(); + for (size_t i = 0; i < a1.length; i++) + { + if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + void[] a1 = *cast(void[]*)p1; + void[] a2 = *cast(void[]*)p2; + size_t sz = value.tsize(); + size_t len = a1.length; + + if (a2.length < len) + len = a2.length; + for (size_t u = 0; u < len; u++) + { + int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); + if (result) + return result; + } + return cast(int)a1.length - cast(int)a2.length; + } + + size_t tsize() + { + return (void[]).sizeof; + } + + void swap(void *p1, void *p2) + { void[] tmp; + tmp = *cast(void[]*)p1; + *cast(void[]*)p1 = *cast(void[]*)p2; + *cast(void[]*)p2 = tmp; + } + + TypeInfo value; + + TypeInfo next() + { + return value; + } + + uint flags() { return 1; } +} + +class TypeInfo_StaticArray : TypeInfo +{ + char[] toString() + { + char[20] buf; + return value.toString() ~ "[" ~ itoa(buf, 'd', len) ~ "]"; + } + + int opEquals(Object o) + { TypeInfo_StaticArray c; + + return cast(int) + (this is o || + ((c = cast(TypeInfo_StaticArray)o) !is null && + this.len == c.len && + this.value == c.value)); + } + + hash_t getHash(void *p) + { size_t sz = value.tsize(); + hash_t hash = 0; + for (size_t i = 0; i < len; i++) + hash += value.getHash(p + i * sz); + return hash; + } + + int equals(void *p1, void *p2) + { + size_t sz = value.tsize(); + + for (size_t u = 0; u < len; u++) + { + if (!value.equals(p1 + u * sz, p2 + u * sz)) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + size_t sz = value.tsize(); + + for (size_t u = 0; u < len; u++) + { + int result = value.compare(p1 + u * sz, p2 + u * sz); + if (result) + return result; + } + return 0; + } + + size_t tsize() + { + return len * value.tsize(); + } + + void swap(void *p1, void *p2) + { void* tmp; + size_t sz = value.tsize(); + ubyte[16] buffer; + void* pbuffer; + + if (sz < buffer.sizeof) + tmp = buffer.ptr; + else + tmp = pbuffer = (new void[sz]).ptr; + + for (size_t u = 0; u < len; u += sz) + { size_t o = u * sz; + tmp[0 .. sz] = (p1 + o)[0 .. sz]; + (p1 + o)[0 .. sz] = (p2 + o)[0 .. sz]; + (p2 + o)[0 .. sz] = tmp[0 .. sz]; + } + if (pbuffer) + delete pbuffer; + } + + void[] init() { return value.init(); } + TypeInfo next() { return value; } + uint flags() { return value.flags(); } + + TypeInfo value; + size_t len; +} + +class TypeInfo_AssociativeArray : TypeInfo +{ + char[] toString() + { + return value.toString() ~ "[" ~ key.toString() ~ "]"; + } + + int opEquals(Object o) + { TypeInfo_AssociativeArray c; + + return this is o || + ((c = cast(TypeInfo_AssociativeArray)o) !is null && + this.key == c.key && + this.value == c.value); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { + return (char[int]).sizeof; + } + + TypeInfo next() { return value; } + uint flags() { return 1; } + + TypeInfo value; + TypeInfo key; +} + +class TypeInfo_Function : TypeInfo +{ + char[] toString() + { + return next.toString() ~ "()"; + } + + int opEquals(Object o) + { TypeInfo_Function c; + + return this is o || + ((c = cast(TypeInfo_Function)o) !is null && + this.next == c.next); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { + return 0; // no size for functions + } + + TypeInfo next; +} + +class TypeInfo_Delegate : TypeInfo +{ + char[] toString() + { + return next.toString() ~ " delegate()"; + } + + int opEquals(Object o) + { TypeInfo_Delegate c; + + return this is o || + ((c = cast(TypeInfo_Delegate)o) !is null && + this.next == c.next); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { alias int delegate() dg; + return dg.sizeof; + } + + uint flags() { return 1; } + + TypeInfo next; +} + +class TypeInfo_Class : TypeInfo +{ + char[] toString() { return info.name; } + + int opEquals(Object o) + { TypeInfo_Class c; + + return this is o || + ((c = cast(TypeInfo_Class)o) !is null && + this.info.name == c.classinfo.name); + } + + hash_t getHash(void *p) + { + Object o = *cast(Object*)p; + assert(o); + return o.toHash(); + } + + int equals(void *p1, void *p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + + return (o1 is o2) || (o1 && o1.opEquals(o2)); + } + + int compare(void *p1, void *p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + int c = 0; + + // Regard null references as always being "less than" + if (o1 !is o2) + { + if (o1) + { if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() { return 1; } + + OffsetTypeInfo[] offTi() + { + return (info.flags & 4) ? info.offTi : null; + } + + ClassInfo info; +} + +class TypeInfo_Interface : TypeInfo +{ + char[] toString() { return info.name; } + + int opEquals(Object o) + { TypeInfo_Interface c; + + return this is o || + ((c = cast(TypeInfo_Interface)o) !is null && + this.info.name == c.classinfo.name); + } + + hash_t getHash(void *p) + { + Interface* pi = **cast(Interface ***)*cast(void**)p; + Object o = cast(Object)(*cast(void**)p - pi.offset); + assert(o); + return o.toHash(); + } + + int equals(void *p1, void *p2) + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + + return o1 == o2 || (o1 && o1.opCmp(o2) == 0); + } + + int compare(void *p1, void *p2) + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + int c = 0; + + // Regard null references as always being "less than" + if (o1 != o2) + { + if (o1) + { if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() { return 1; } + + ClassInfo info; +} + +class TypeInfo_Struct : TypeInfo +{ + char[] toString() { return name; } + + int opEquals(Object o) + { TypeInfo_Struct s; + + return this is o || + ((s = cast(TypeInfo_Struct)o) !is null && + this.name == s.name && + this.init.length == s.init.length); + } + + hash_t getHash(void *p) + { hash_t h; + + assert(p); + if (xtoHash) + { //printf("getHash() using xtoHash\n"); + h = (*xtoHash)(p); + } + else + { + //printf("getHash() using default hash\n"); + // A sorry hash algorithm. + // Should use the one for strings. + // BUG: relies on the GC not moving objects + for (size_t i = 0; i < init.length; i++) + { h = h * 9 + *cast(ubyte*)p; + p++; + } + } + return h; + } + + int equals(void *p2, void *p1) + { int c; + + if (p1 == p2) + c = 1; + else if (!p1 || !p2) + c = 0; + else if (xopEquals) + c = (*xopEquals)(p1, p2); + else + // BUG: relies on the GC not moving objects + c = (memcmp(cast(ubyte*)p1, cast(ubyte*)p2, init.length) == 0); + return c; + } + + int compare(void *p2, void *p1) + { + int c = 0; + + // Regard null references as always being "less than" + if (p1 != p2) + { + if (p1) + { if (!p2) + c = 1; + else if (xopCmp) + c = (*xopCmp)(p1, p2); + else + // BUG: relies on the GC not moving objects + c = memcmp(cast(ubyte*)p1, cast(ubyte*)p2, init.length); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return init.length; + } + + void[] init() { return m_init; } + + uint flags() { return m_flags; } + + char[] name; + void[] m_init; // initializer; init.ptr == null if 0 initialize + + hash_t function(void*) xtoHash; + int function(void*,void*) xopEquals; + int function(void*,void*) xopCmp; + char[] function(void*) xtoString; + + uint m_flags; +} + +class TypeInfo_Tuple : TypeInfo +{ + TypeInfo[] elements; + + char[] toString() + { + char[] s; + s = "("; + foreach (i, element; elements) + { + if (i) + s ~= ','; + s ~= element.toString(); + } + s ~= ")"; + return s; + } + + int opEquals(Object o) + { + if (this is o) + return 1; + + auto t = cast(TypeInfo_Tuple)o; + if (t && elements.length == t.elements.length) + { + for (size_t i = 0; i < elements.length; i++) + { + if (elements[i] != t.elements[i]) + return 0; + } + return 1; + } + return 0; + } + + hash_t getHash(void *p) + { + assert(0); + } + + int equals(void *p1, void *p2) + { + assert(0); + } + + int compare(void *p1, void *p2) + { + assert(0); + } + + size_t tsize() + { + assert(0); + } + + void swap(void *p1, void *p2) + { + assert(0); + } +} + +/** + * All recoverable exceptions should be derived from class Exception. + */ +class Exception : Object +{ + char[] msg; + + /** + * Constructor; msg is a descriptive message for the exception. + */ + this(char[] msg) + { + this.msg = msg; + } + + char[] toString() { return msg; } +} + +/** + * All irrecoverable exceptions should be derived from class Error. + */ +class Error : Exception +{ + Error next; + + /** + * Constructor; msg is a descriptive message for the exception. + */ + this(char[] msg) + { + super(msg); + } + + this(char[] msg, Error next) + { + super(msg); + this.next = next; + } +} + +//extern (C) int nullext = 0; + diff --git a/kernel/runtime/std/c/stdarg.d b/kernel/runtime/std/c/stdarg.d new file mode 100644 index 0000000..8c05001 --- /dev/null +++ b/kernel/runtime/std/c/stdarg.d @@ -0,0 +1,34 @@ + +/* + * Placed in public domain. + * Written by Hauke Duden and Walter Bright + */ + +/* This is for use with variable argument lists with extern(D) linkage. */ + +module std.c.stdarg; + +private import gcc.builtins; +alias __builtin_va_list va_list; +alias __builtin_va_end va_end; +alias __builtin_va_copy va_copy; + +// The va_start and va_arg template functions are magically +// handled by the compiler. + +template va_start(T) +{ + void va_start(out va_list ap, inout T parmn) + { + + } +} + +template va_arg(T) +{ + T va_arg(ref va_list _argptr) + { + return T.init; + } +} + diff --git a/kernel/runtime/std/intrinsic.d b/kernel/runtime/std/intrinsic.d new file mode 100644 index 0000000..4a62f41 --- /dev/null +++ b/kernel/runtime/std/intrinsic.d @@ -0,0 +1,264 @@ + + +// written by Walter Bright +// www.digitalmars.com +// Placed into the public domain + +/* NOTE: This file has been patched from the original DMD distribution to + work with the GDC compiler. + + Modified by David Friedman, May 2006 +*/ + +/** These functions are built-in intrinsics to the compiler. + * + Intrinsic functions are functions built in to the compiler, + usually to take advantage of specific CPU features that + are inefficient to handle via external functions. + The compiler's optimizer and code generator are fully + integrated in with intrinsic functions, bringing to bear + their full power on them. + This can result in some surprising speedups. + * Macros: + * WIKI=Phobos/StdIntrinsic + */ + +module std.intrinsic; + +/** + * Scans the bits in v starting with bit 0, looking + * for the first set bit. + * Returns: + * The bit number of the first bit set. + * The return value is undefined if v is zero. + */ +version (GNU) + int bsf(uint v) + { + uint m = 1; + uint i; + for (i = 0; i < 32; i++,m<<=1) { + if (v&m) + return i; + } + return i; // supposed to be undefined + } +else + int bsf(uint v); + +/** + * Scans the bits in v from the most significant bit + * to the least significant bit, looking + * for the first set bit. + * Returns: + * The bit number of the first bit set. + * The return value is undefined if v is zero. + * Example: + * --- + * import std.intrinsic; + * + * int main() + * { + * uint v; + * int x; + * + * v = 0x21; + * x = bsf(v); + * printf("bsf(x%x) = %d\n", v, x); + * x = bsr(v); + * printf("bsr(x%x) = %d\n", v, x); + * return 0; + * } + * --- + * Output: + * bsf(x21) = 0
+ * bsr(x21) = 5 + */ +version (GNU) +int bsr(uint v) +{ + uint m = 0x80000000; + uint i; + for (i = 32; i ; i--,m>>>=1) { + if (v&m) + return i-1; + } + return i; // supposed to be undefined +} +else + int bsr(uint v); + +/** + * Tests the bit. + */ +version (GNU) +int bt(uint *p, uint bitnum) +{ + return (p[bitnum / (uint.sizeof*8)] & (1<<(bitnum & ((uint.sizeof*8)-1)))) ? -1 : 0 ; +} +else + int bt(uint *p, uint bitnum); + +/** + * Tests and complements the bit. + */ +version (GNU) +int btc(uint *p, uint bitnum) +{ + uint * q = p + (bitnum / (uint.sizeof*8)); + uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1)); + int result = *q & mask; + *q ^= mask; + return result ? -1 : 0; +} +else +int btc(uint *p, uint bitnum); + +/** + * Tests and resets (sets to 0) the bit. + */ +version (GNU) +int btr(uint *p, uint bitnum) +{ + uint * q = p + (bitnum / (uint.sizeof*8)); + uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1)); + int result = *q & mask; + *q &= ~mask; + return result ? -1 : 0; +} +else + int btr(uint *p, uint bitnum); + +/** + * Tests and sets the bit. + * Params: + * p = a non-NULL pointer to an array of uints. + * index = a bit number, starting with bit 0 of p[0], + * and progressing. It addresses bits like the expression: +--- +p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1))) +--- + * Returns: + * A non-zero value if the bit was set, and a zero + * if it was clear. + * + * Example: + * --- +import std.intrinsic; + +int main() +{ + uint array[2]; + + array[0] = 2; + array[1] = 0x100; + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btc(array, 35) = %d\n", btc(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bts(array, 35) = %d\n", bts(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btr(array, 35) = %d\n", btr(array, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bt(array, 1) = %d\n", bt(array, 1)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + return 0; +} + * --- + * Output: +
+btc(array, 35) = 0
+array = [0]:x2, [1]:x108
+btc(array, 35) = -1
+array = [0]:x2, [1]:x100
+bts(array, 35) = 0
+array = [0]:x2, [1]:x108
+btr(array, 35) = -1
+array = [0]:x2, [1]:x100
+bt(array, 1) = -1
+array = [0]:x2, [1]:x100
+
+ */ +version (GNU) +int bts(uint *p, uint bitnum) +{ + uint * q = p + (bitnum / (uint.sizeof*8)); + uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1)); + int result = *q & mask; + *q |= mask; + return result ? -1 : 0; +} +else + int bts(uint *p, uint bitnum); + + +/** + * Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes + byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3 + becomes byte 0. + */ +version (GNU) +uint bswap(uint v) +{ + return ((v&0xFF)<<24)|((v&0xFF00)<<8)|((v&0xFF0000)>>>8)|((v&0xFF000000)>>>24); +} +else + uint bswap(uint v); + + +/** + * Reads I/O port at port_address. + */ +version (GNU) + ubyte inp(uint p) { return 0; } +else + ubyte inp(uint port_address); + +/** + * ditto + */ +version (GNU) + ushort inpw(uint p) { return 0; } +else + ushort inpw(uint port_address); + +/** + * ditto + */ +version (GNU) + uint inpl(uint p) { return 0; } +else + uint inpl(uint port_address); + + +/** + * Writes and returns value to I/O port at port_address. + */ +version (GNU) + ubyte outp(uint p, ubyte v) { return v; } +else + ubyte outp(uint port_address, ubyte value); + +/** + * ditto + */ +version (GNU) + ushort outpw(uint p, ushort v) { return v; } +else + ushort outpw(uint port_address, ushort value); + +/** + * ditto + */ +version (GNU) + uint outpl(uint p, uint v) { return v; } +else + uint outpl(uint port_address, uint value); + + diff --git a/kernel/runtime/std/stdarg.d b/kernel/runtime/std/stdarg.d new file mode 100644 index 0000000..6bac4e5 --- /dev/null +++ b/kernel/runtime/std/stdarg.d @@ -0,0 +1,43 @@ + +/* + * Placed in public domain. + * Written by Hauke Duden and Walter Bright + */ + +/* This is for use with variable argument lists with extern(D) linkage. */ + +/* NOTE: This file has been patched from the original DMD distribution to + work with the GDC compiler. + + Modified by David Friedman, September 2004 +*/ + +module std.stdarg; + +version (GNU) { + // va_list might be a pointer, but assuming so is not portable. + private import gcc.builtins; + alias __builtin_va_list va_list; + + // va_arg is handled magically by the compiler +} else { + alias void* va_list; +} + +template va_arg(T) +{ + T va_arg(inout va_list _argptr) + { + /* + T arg = *cast(T*)_argptr; + _argptr = _argptr + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)); + return arg; + */ + T t; return t; + } +} + +private import std.c.stdarg; +/* The existence of std.stdarg.va_copy isn't standard. Prevent + conflicts by using '__'. */ +alias std.c.stdarg.va_copy __va_copy; diff --git a/kernel/runtime/std/typeinfo/ti_AC.d b/kernel/runtime/std/typeinfo/ti_AC.d new file mode 100644 index 0000000..aa49f27 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_AC.d @@ -0,0 +1,96 @@ +module std.typeinfo.ti_AC; + +// Object[] + +class TypeInfo_AC : TypeInfo +{ + hash_t getHash(void *p) + { Object[] s = *cast(Object[]*)p; + hash_t hash = 0; + + foreach (Object o; s) + { + if (o) + hash += o.toHash(); + } + return hash; + } + + int equals(void *p1, void *p2) + { + Object[] s1 = *cast(Object[]*)p1; + Object[] s2 = *cast(Object[]*)p2; + + if (s1.length == s2.length) + { + for (size_t u = 0; u < s1.length; u++) + { Object o1 = s1[u]; + Object o2 = s2[u]; + + // Do not pass null's to Object.opEquals() + if (o1 is o2 || + (!(o1 is null) && !(o2 is null) && o1.opEquals(o2))) + continue; + return 0; + } + return 1; + } + return 0; + } + + int compare(void *p1, void *p2) + { + Object[] s1 = *cast(Object[]*)p1; + Object[] s2 = *cast(Object[]*)p2; + ptrdiff_t c; + + c = cast(ptrdiff_t)s1.length - cast(ptrdiff_t)s2.length; + if (c == 0) + { + for (size_t u = 0; u < s1.length; u++) + { Object o1 = s1[u]; + Object o2 = s2[u]; + + if (o1 is o2) + continue; + + // Regard null references as always being "less than" + if (o1) + { + if (!o2) + { c = 1; + break; + } + c = o1.opCmp(o2); + if (c) + break; + } + else + { c = -1; + break; + } + } + } + if (c < 0) + c = -1; + else if (c > 0) + c = 1; + return c; + } + + size_t tsize() + { + return (Object[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(Object); + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_Acdouble.d b/kernel/runtime/std/typeinfo/ti_Acdouble.d new file mode 100644 index 0000000..6057d63 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Acdouble.d @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module std.typeinfo.ti_Acdouble; + +private import std.typeinfo.ti_cdouble; + +// cdouble[] + +class TypeInfo_Ar : TypeInfo +{ + char[] toString() { return "cdouble[]"; } + + hash_t getHash(void *p) + { cdouble[] s = *cast(cdouble[]*)p; + size_t len = s.length; + cdouble *str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += (cast(uint *)str)[0]; + hash += (cast(uint *)str)[1]; + hash += (cast(uint *)str)[2]; + hash += (cast(uint *)str)[3]; + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + cdouble[] s1 = *cast(cdouble[]*)p1; + cdouble[] s2 = *cast(cdouble[]*)p2; + size_t len = s1.length; + + if (len != s2.length) + return 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_r._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + cdouble[] s1 = *cast(cdouble[]*)p1; + cdouble[] s2 = *cast(cdouble[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_r._compare(s1[u], s2[u]); + if (c) + return c; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (cdouble[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(cdouble); + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_Acfloat.d b/kernel/runtime/std/typeinfo/ti_Acfloat.d new file mode 100644 index 0000000..88639f4 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Acfloat.d @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module std.typeinfo.ti_Acfloat; + +private import std.typeinfo.ti_cfloat; + +// cfloat[] + +class TypeInfo_Aq : TypeInfo +{ + char[] toString() { return "cfloat[]"; } + + hash_t getHash(void *p) + { cfloat[] s = *cast(cfloat[]*)p; + size_t len = s.length; + cfloat *str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += (cast(uint *)str)[0]; + hash += (cast(uint *)str)[1]; + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + cfloat[] s1 = *cast(cfloat[]*)p1; + cfloat[] s2 = *cast(cfloat[]*)p2; + size_t len = s1.length; + + if (len != s2.length) + return 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_q._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + cfloat[] s1 = *cast(cfloat[]*)p1; + cfloat[] s2 = *cast(cfloat[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_q._compare(s1[u], s2[u]); + if (c) + return c; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (cfloat[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(cfloat); + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_Acreal.d b/kernel/runtime/std/typeinfo/ti_Acreal.d new file mode 100644 index 0000000..0514c9e --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Acreal.d @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module std.typeinfo.ti_Acreal; + +private import std.typeinfo.ti_creal; + +// creal[] + +class TypeInfo_Ac : TypeInfo +{ + char[] toString() { return "creal[]"; } + + hash_t getHash(void *p) + { creal[] s = *cast(creal[]*)p; + size_t len = s.length; + creal *str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += (cast(uint *)str)[0]; + hash += (cast(uint *)str)[1]; + hash += (cast(uint *)str)[2]; + hash += (cast(uint *)str)[3]; + hash += (cast(uint *)str)[4]; + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + creal[] s1 = *cast(creal[]*)p1; + creal[] s2 = *cast(creal[]*)p2; + size_t len = s1.length; + + if (len != s2.length) + return 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_c._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + creal[] s1 = *cast(creal[]*)p1; + creal[] s2 = *cast(creal[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_c._compare(s1[u], s2[u]); + if (c) + return c; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (creal[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(creal); + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_Adouble.d b/kernel/runtime/std/typeinfo/ti_Adouble.d new file mode 100644 index 0000000..c348913 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Adouble.d @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module std.typeinfo.ti_Adouble; + +private import std.typeinfo.ti_double; + +// double[] + +class TypeInfo_Ad : TypeInfo +{ + char[] toString() { return "double[]"; } + + hash_t getHash(void *p) + { double[] s = *cast(double[]*)p; + size_t len = s.length; + auto str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += (cast(uint *)str)[0]; + hash += (cast(uint *)str)[1]; + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + double[] s1 = *cast(double[]*)p1; + double[] s2 = *cast(double[]*)p2; + size_t len = s1.length; + + if (len != s2.length) + return 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_d._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + double[] s1 = *cast(double[]*)p1; + double[] s2 = *cast(double[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_d._compare(s1[u], s2[u]); + if (c) + return c; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (double[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(double); + } +} + +// idouble[] + +class TypeInfo_Ap : TypeInfo_Ad +{ + char[] toString() { return "idouble[]"; } + + TypeInfo next() + { + return typeid(idouble); + } +} diff --git a/kernel/runtime/std/typeinfo/ti_Afloat.d b/kernel/runtime/std/typeinfo/ti_Afloat.d new file mode 100644 index 0000000..fa8bef5 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Afloat.d @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module std.typeinfo.ti_Afloat; + +private import std.typeinfo.ti_float; + +// float[] + +class TypeInfo_Af : TypeInfo +{ + char[] toString() { return "float[]"; } + + hash_t getHash(void *p) + { float[] s = *cast(float[]*)p; + size_t len = s.length; + auto str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += *cast(uint *)str; + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + float[] s1 = *cast(float[]*)p1; + float[] s2 = *cast(float[]*)p2; + size_t len = s1.length; + + if (len != s2.length) + return 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_f._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + float[] s1 = *cast(float[]*)p1; + float[] s2 = *cast(float[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_f._compare(s1[u], s2[u]); + if (c) + return c; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (float[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(float); + } +} + +// ifloat[] + +class TypeInfo_Ao : TypeInfo_Af +{ + char[] toString() { return "ifloat[]"; } + + TypeInfo next() + { + return typeid(ifloat); + } +} diff --git a/kernel/runtime/std/typeinfo/ti_Ag.d b/kernel/runtime/std/typeinfo/ti_Ag.d new file mode 100644 index 0000000..eb94d30 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Ag.d @@ -0,0 +1,204 @@ + +module std.typeinfo.ti_Ag; +import kernel.runtime.util; + +// byte[] + +class TypeInfo_Ag : TypeInfo +{ + char[] toString() { return "byte[]"; } + + hash_t getHash(void *p) + { byte[] s = *cast(byte[]*)p; + size_t len = s.length; + byte *str = s.ptr; + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 9; + hash += *cast(ubyte *)str; + return hash; + + case 2: + hash *= 9; + hash += *cast(ushort *)str; + return hash; + + case 3: + hash *= 9; + hash += (*cast(ushort *)str << 8) + + (cast(ubyte *)str)[2]; + return hash; + + default: + hash *= 9; + hash += *cast(uint *)str; + str += 4; + len -= 4; + break; + } + } + + return hash; + } + + int equals(void *p1, void *p2) + { + ubyte[] s1 = *cast(ubyte[]*)p1; + ubyte[] s2 = *cast(ubyte[]*)p2; + + return s1.length == s2.length && + memcmp(s1.ptr, s2.ptr, s1.length) == 0; + } + + int compare(void *p1, void *p2) + { + byte[] s1 = *cast(byte[]*)p1; + byte[] s2 = *cast(byte[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int result = s1[u] - s2[u]; + if (result) + return result; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (byte[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(byte); + } +} + + +// ubyte[] + +class TypeInfo_Ah : TypeInfo_Ag +{ + char[] toString() { return "ubyte[]"; } + + int compare(void *p1, void *p2) + { + ubyte[] s1 = *cast(ubyte[]*)p1; + ubyte[] s2 = *cast(ubyte[]*)p2; + + return memcmp(s1.ptr, s2.ptr, s1.length); + } + + TypeInfo next() + { + return typeid(ubyte); + } +} + +// void[] + +class TypeInfo_Av : TypeInfo_Ah +{ + char[] toString() { return "void[]"; } + + TypeInfo next() + { + return typeid(void); + } +} + +// bool[] + +class TypeInfo_Ab : TypeInfo_Ah +{ + char[] toString() { return "bool[]"; } + + TypeInfo next() + { + return typeid(bool); + } +} + +// char[] + +class TypeInfo_Aa : TypeInfo_Ag +{ + char[] toString() { return "char[]"; } + + hash_t getHash(void *p) + { char[] s = *cast(char[]*)p; + hash_t hash = 0; + +version (all) +{ + foreach (char c; s) + hash = hash * 11 + c; +} +else +{ + size_t len = s.length; + char *str = s; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 9; + hash += *cast(ubyte *)str; + return hash; + + case 2: + hash *= 9; + hash += *cast(ushort *)str; + return hash; + + case 3: + hash *= 9; + hash += (*cast(ushort *)str << 8) + + (cast(ubyte *)str)[2]; + return hash; + + default: + hash *= 9; + hash += *cast(uint *)str; + str += 4; + len -= 4; + break; + } + } +} + return hash; + } + + TypeInfo next() + { + return typeid(char); + } +} + + diff --git a/kernel/runtime/std/typeinfo/ti_Aint.d b/kernel/runtime/std/typeinfo/ti_Aint.d new file mode 100644 index 0000000..8cfc2b6 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Aint.d @@ -0,0 +1,119 @@ + +module std.typeinfo.ti_Aint; + +import kernel.runtime.util; + +// int[] + +class TypeInfo_Ai : TypeInfo +{ + char[] toString() { return "int[]"; } + + hash_t getHash(void *p) + { int[] s = *cast(int[]*)p; + auto len = s.length; + auto str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += *cast(uint *)str; + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + int[] s1 = *cast(int[]*)p1; + int[] s2 = *cast(int[]*)p2; + + return s1.length == s2.length && + memcmp(cast(ubyte*)s1.ptr, cast(ubyte*)s2.ptr, s1.length * int.sizeof) == 0; + } + + int compare(void *p1, void *p2) + { + int[] s1 = *cast(int[]*)p1; + int[] s2 = *cast(int[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int result = s1[u] - s2[u]; + if (result) + return result; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (int[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(int); + } +} + +// uint[] + +class TypeInfo_Ak : TypeInfo_Ai +{ + char[] toString() { return "uint[]"; } + + int compare(void *p1, void *p2) + { + uint[] s1 = *cast(uint[]*)p1; + uint[] s2 = *cast(uint[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int result = s1[u] - s2[u]; + if (result) + return result; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + TypeInfo next() + { + return typeid(uint); + } +} + +// dchar[] + +class TypeInfo_Aw : TypeInfo_Ak +{ + char[] toString() { return "dchar[]"; } + + TypeInfo next() + { + return typeid(dchar); + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_Along.d b/kernel/runtime/std/typeinfo/ti_Along.d new file mode 100644 index 0000000..7fe1710 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Along.d @@ -0,0 +1,111 @@ + +module std.typeinfo.ti_Along; + +import kernel.runtime.util; + +// long[] + +class TypeInfo_Al : TypeInfo +{ + char[] toString() { return "long[]"; } + + hash_t getHash(void *p) + { long[] s = *cast(long[]*)p; + size_t len = s.length; + auto str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += *cast(uint *)str + *(cast(uint *)str + 1); + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + long[] s1 = *cast(long[]*)p1; + long[] s2 = *cast(long[]*)p2; + + return s1.length == s2.length && + memcmp(cast(ubyte*)s1.ptr, cast(ubyte*)s2.ptr, s1.length * long.sizeof) == 0; + } + + int compare(void *p1, void *p2) + { + long[] s1 = *cast(long[]*)p1; + long[] s2 = *cast(long[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + if (s1[u] < s2[u]) + return -1; + else if (s1[u] > s2[u]) + return 1; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (long[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(long); + } +} + + +// ulong[] + +class TypeInfo_Am : TypeInfo_Al +{ + char[] toString() { return "ulong[]"; } + + int compare(void *p1, void *p2) + { + ulong[] s1 = *cast(ulong[]*)p1; + ulong[] s2 = *cast(ulong[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + if (s1[u] < s2[u]) + return -1; + else if (s1[u] > s2[u]) + return 1; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + TypeInfo next() + { + return typeid(ulong); + } +} + + diff --git a/kernel/runtime/std/typeinfo/ti_Areal.d b/kernel/runtime/std/typeinfo/ti_Areal.d new file mode 100644 index 0000000..f68af32 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Areal.d @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module std.typeinfo.ti_Areal; + +private import std.typeinfo.ti_real; + +// real[] + +class TypeInfo_Ae : TypeInfo +{ + char[] toString() { return "real[]"; } + + hash_t getHash(void *p) + { real[] s = *cast(real[]*)p; + size_t len = s.length; + auto str = s.ptr; + hash_t hash = 0; + + while (len) + { + hash *= 9; + hash += (cast(uint *)str)[0]; + hash += (cast(uint *)str)[1]; + hash += (cast(ushort *)str)[4]; + str++; + len--; + } + + return hash; + } + + int equals(void *p1, void *p2) + { + real[] s1 = *cast(real[]*)p1; + real[] s2 = *cast(real[]*)p2; + size_t len = s1.length; + + if (len != s2.length) + return 0; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_e._equals(s1[u], s2[u]); + if (c == 0) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + real[] s1 = *cast(real[]*)p1; + real[] s2 = *cast(real[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int c = TypeInfo_e._compare(s1[u], s2[u]); + if (c) + return c; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (real[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(real); + } +} + +// ireal[] + +class TypeInfo_Aj : TypeInfo_Ae +{ + char[] toString() { return "ireal[]"; } + + TypeInfo next() + { + return typeid(ireal); + } +} diff --git a/kernel/runtime/std/typeinfo/ti_Ashort.d b/kernel/runtime/std/typeinfo/ti_Ashort.d new file mode 100644 index 0000000..39a4672 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_Ashort.d @@ -0,0 +1,134 @@ + +module std.typeinfo.ti_Ashort; + +import kernel.runtime.util; + +// short[] + +class TypeInfo_As : TypeInfo +{ + char[] toString() { return "short[]"; } + + hash_t getHash(void *p) + { short[] s = *cast(short[]*)p; + size_t len = s.length; + short *str = s.ptr; + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 9; + hash += *cast(ushort *)str; + return hash; + + default: + hash *= 9; + hash += *cast(uint *)str; + str += 2; + len -= 2; + break; + } + } + + return hash; + } + + int equals(void *p1, void *p2) + { + short[] s1 = *cast(short[]*)p1; + short[] s2 = *cast(short[]*)p2; + + return s1.length == s2.length && + memcmp(cast(ubyte*)s1.ptr, cast(ubyte*)s2.ptr, s1.length * short.sizeof) == 0; + } + + int compare(void *p1, void *p2) + { + short[] s1 = *cast(short[]*)p1; + short[] s2 = *cast(short[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int result = s1[u] - s2[u]; + if (result) + return result; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + size_t tsize() + { + return (short[]).sizeof; + } + + uint flags() + { + return 1; + } + + TypeInfo next() + { + return typeid(short); + } +} + + +// ushort[] + +class TypeInfo_At : TypeInfo_As +{ + char[] toString() { return "ushort[]"; } + + int compare(void *p1, void *p2) + { + ushort[] s1 = *cast(ushort[]*)p1; + ushort[] s2 = *cast(ushort[]*)p2; + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + int result = s1[u] - s2[u]; + if (result) + return result; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + + TypeInfo next() + { + return typeid(ushort); + } +} + +// wchar[] + +class TypeInfo_Au : TypeInfo_At +{ + char[] toString() { return "wchar[]"; } + + TypeInfo next() + { + return typeid(wchar); + } +} + + diff --git a/kernel/runtime/std/typeinfo/ti_C.d b/kernel/runtime/std/typeinfo/ti_C.d new file mode 100644 index 0000000..79f161c --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_C.d @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +module std.typeinfo.ti_C; + +// Object + +class TypeInfo_C : TypeInfo +{ + hash_t getHash(void *p) + { + Object o = *cast(Object*)p; + assert(o); + return o.toHash(); + } + + int equals(void *p1, void *p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + + return o1 == o2; + } + + int compare(void *p1, void *p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + int c = 0; + + // Regard null references as always being "less than" + if (!(o1 is o2)) + { + if (o1) + { if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() + { + return 1; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_byte.d b/kernel/runtime/std/typeinfo/ti_byte.d new file mode 100644 index 0000000..e273a49 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_byte.d @@ -0,0 +1,39 @@ + +// byte + +module std.typeinfo.ti_byte; + +class TypeInfo_g : TypeInfo +{ + char[] toString() { return "byte"; } + + hash_t getHash(void *p) + { + return *cast(byte *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(byte *)p1 == *cast(byte *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(byte *)p1 - *cast(byte *)p2; + } + + size_t tsize() + { + return byte.sizeof; + } + + void swap(void *p1, void *p2) + { + byte t; + + t = *cast(byte *)p1; + *cast(byte *)p1 = *cast(byte *)p2; + *cast(byte *)p2 = t; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_cdouble.d b/kernel/runtime/std/typeinfo/ti_cdouble.d new file mode 100644 index 0000000..e506d8c --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_cdouble.d @@ -0,0 +1,67 @@ + +// cdouble + +module std.typeinfo.ti_cdouble; + +class TypeInfo_r : TypeInfo +{ + char[] toString() { return "cdouble"; } + + hash_t getHash(void *p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1] + + (cast(uint *)p)[2] + (cast(uint *)p)[3]; + } + + static int _equals(cdouble f1, cdouble f2) + { + return f1 == f2; + } + + static int _compare(cdouble f1, cdouble f2) + { int result; + + if (f1.re < f2.re) + result = -1; + else if (f1.re > f2.re) + result = 1; + else if (f1.im < f2.im) + result = -1; + else if (f1.im > f2.im) + result = 1; + else + result = 0; + return result; + } + + int equals(void *p1, void *p2) + { + return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2); + } + + int compare(void *p1, void *p2) + { + return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2); + } + + size_t tsize() + { + return cdouble.sizeof; + } + + void swap(void *p1, void *p2) + { + cdouble t; + + t = *cast(cdouble *)p1; + *cast(cdouble *)p1 = *cast(cdouble *)p2; + *cast(cdouble *)p2 = t; + } + + void[] init() + { static cdouble r; + + return (cast(cdouble *)&r)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_cfloat.d b/kernel/runtime/std/typeinfo/ti_cfloat.d new file mode 100644 index 0000000..d4c6161 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_cfloat.d @@ -0,0 +1,66 @@ + +// cfloat + +module std.typeinfo.ti_cfloat; + +class TypeInfo_q : TypeInfo +{ + char[] toString() { return "cfloat"; } + + hash_t getHash(void *p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1]; + } + + static int _equals(cfloat f1, cfloat f2) + { + return f1 == f2; + } + + static int _compare(cfloat f1, cfloat f2) + { int result; + + if (f1.re < f2.re) + result = -1; + else if (f1.re > f2.re) + result = 1; + else if (f1.im < f2.im) + result = -1; + else if (f1.im > f2.im) + result = 1; + else + result = 0; + return result; + } + + int equals(void *p1, void *p2) + { + return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2); + } + + int compare(void *p1, void *p2) + { + return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2); + } + + size_t tsize() + { + return cfloat.sizeof; + } + + void swap(void *p1, void *p2) + { + cfloat t; + + t = *cast(cfloat *)p1; + *cast(cfloat *)p1 = *cast(cfloat *)p2; + *cast(cfloat *)p2 = t; + } + + void[] init() + { static cfloat r; + + return (cast(cfloat *)&r)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_char.d b/kernel/runtime/std/typeinfo/ti_char.d new file mode 100644 index 0000000..389d579 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_char.d @@ -0,0 +1,43 @@ + +module std.typeinfo.ti_char; + +class TypeInfo_a : TypeInfo +{ + char[] toString() { return "char"; } + + hash_t getHash(void *p) + { + return *cast(char *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(char *)p1 == *cast(char *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(char *)p1 - *cast(char *)p2; + } + + size_t tsize() + { + return char.sizeof; + } + + void swap(void *p1, void *p2) + { + char t; + + t = *cast(char *)p1; + *cast(char *)p1 = *cast(char *)p2; + *cast(char *)p2 = t; + } + + void[] init() + { static char c; + + return (cast(char *)&c)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_creal.d b/kernel/runtime/std/typeinfo/ti_creal.d new file mode 100644 index 0000000..9bd00cd --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_creal.d @@ -0,0 +1,68 @@ + +// creal + +module std.typeinfo.ti_creal; + +class TypeInfo_c : TypeInfo +{ + char[] toString() { return "creal"; } + + hash_t getHash(void *p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1] + + (cast(uint *)p)[2] + (cast(uint *)p)[3] + + (cast(uint *)p)[4]; + } + + static int _equals(creal f1, creal f2) + { + return f1 == f2; + } + + static int _compare(creal f1, creal f2) + { int result; + + if (f1.re < f2.re) + result = -1; + else if (f1.re > f2.re) + result = 1; + else if (f1.im < f2.im) + result = -1; + else if (f1.im > f2.im) + result = 1; + else + result = 0; + return result; + } + + int equals(void *p1, void *p2) + { + return _equals(*cast(creal *)p1, *cast(creal *)p2); + } + + int compare(void *p1, void *p2) + { + return _compare(*cast(creal *)p1, *cast(creal *)p2); + } + + size_t tsize() + { + return creal.sizeof; + } + + void swap(void *p1, void *p2) + { + creal t; + + t = *cast(creal *)p1; + *cast(creal *)p1 = *cast(creal *)p2; + *cast(creal *)p2 = t; + } + + void[] init() + { static creal r; + + return (cast(creal *)&r)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_dchar.d b/kernel/runtime/std/typeinfo/ti_dchar.d new file mode 100644 index 0000000..ae2d94a --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_dchar.d @@ -0,0 +1,45 @@ + +// dchar + +module std.typeinfo.ti_dchar; + +class TypeInfo_w : TypeInfo +{ + char[] toString() { return "dchar"; } + + hash_t getHash(void *p) + { + return *cast(dchar *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(dchar *)p1 == *cast(dchar *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(dchar *)p1 - *cast(dchar *)p2; + } + + size_t tsize() + { + return dchar.sizeof; + } + + void swap(void *p1, void *p2) + { + dchar t; + + t = *cast(dchar *)p1; + *cast(dchar *)p1 = *cast(dchar *)p2; + *cast(dchar *)p2 = t; + } + + void[] init() + { static dchar c; + + return (cast(dchar *)&c)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_delegate.d b/kernel/runtime/std/typeinfo/ti_delegate.d new file mode 100644 index 0000000..7ff8fa2 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_delegate.d @@ -0,0 +1,40 @@ + +// delegate + +module std.typeinfo.ti_delegate; + +alias void delegate(int) dg; + +class TypeInfo_D : TypeInfo +{ + hash_t getHash(void *p) + { long l = *cast(long *)p; + + return cast(uint)(l + (l >> 32)); + } + + int equals(void *p1, void *p2) + { + return *cast(dg *)p1 == *cast(dg *)p2; + } + + size_t tsize() + { + return dg.sizeof; + } + + void swap(void *p1, void *p2) + { + dg t; + + t = *cast(dg *)p1; + *cast(dg *)p1 = *cast(dg *)p2; + *cast(dg *)p2 = t; + } + + uint flags() + { + return 1; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_double.d b/kernel/runtime/std/typeinfo/ti_double.d new file mode 100644 index 0000000..0c7e0ab --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_double.d @@ -0,0 +1,68 @@ + +// double + +module std.typeinfo.ti_double; + +import kernel.runtime.util; +//private import std.math; + +class TypeInfo_d : TypeInfo +{ + char[] toString() { return "double"; } + + hash_t getHash(void *p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1]; + } + + static int _equals(double f1, double f2) + { + return f1 == f2 || + (isnan(f1) && isnan(f2)); + } + + static int _compare(double d1, double d2) + { + if (d1 !<>= d2) // if either are NaN + { + if (isnan(d1)) + { if (isnan(d2)) + return 0; + return -1; + } + return 1; + } + return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); + } + + int equals(void *p1, void *p2) + { + return _equals(*cast(double *)p1, *cast(double *)p2); + } + + int compare(void *p1, void *p2) + { + return _compare(*cast(double *)p1, *cast(double *)p2); + } + + size_t tsize() + { + return double.sizeof; + } + + void swap(void *p1, void *p2) + { + double t; + + t = *cast(double *)p1; + *cast(double *)p1 = *cast(double *)p2; + *cast(double *)p2 = t; + } + + void[] init() + { static double r; + + return (cast(double *)&r)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_float.d b/kernel/runtime/std/typeinfo/ti_float.d new file mode 100644 index 0000000..bad76a3 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_float.d @@ -0,0 +1,68 @@ + +// float + +module std.typeinfo.ti_float; + +import kernel.runtime.util; +//private import std.math; + +class TypeInfo_f : TypeInfo +{ + char[] toString() { return "float"; } + + hash_t getHash(void *p) + { + return *cast(uint *)p; + } + + static int _equals(float f1, float f2) + { + return f1 == f2 || + (isnan(f1) && isnan(f2)); + } + + static int _compare(float d1, float d2) + { + if (d1 !<>= d2) // if either are NaN + { + if (isnan(d1)) + { if (isnan(d2)) + return 0; + return -1; + } + return 1; + } + return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); + } + + int equals(void *p1, void *p2) + { + return _equals(*cast(float *)p1, *cast(float *)p2); + } + + int compare(void *p1, void *p2) + { + return _compare(*cast(float *)p1, *cast(float *)p2); + } + + size_t tsize() + { + return float.sizeof; + } + + void swap(void *p1, void *p2) + { + float t; + + t = *cast(float *)p1; + *cast(float *)p1 = *cast(float *)p2; + *cast(float *)p2 = t; + } + + void[] init() + { static float r; + + return (cast(float *)&r)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_idouble.d b/kernel/runtime/std/typeinfo/ti_idouble.d new file mode 100644 index 0000000..4db37fa --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_idouble.d @@ -0,0 +1,12 @@ + +// idouble + +module std.typeinfo.ti_idouble; + +private import std.typeinfo.ti_double; + +class TypeInfo_p : TypeInfo_d +{ + char[] toString() { return "idouble"; } +} + diff --git a/kernel/runtime/std/typeinfo/ti_ifloat.d b/kernel/runtime/std/typeinfo/ti_ifloat.d new file mode 100644 index 0000000..877ba3e --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_ifloat.d @@ -0,0 +1,12 @@ + +// ifloat + +module std.typeinfo.ti_ifloat; + +private import std.typeinfo.ti_float; + +class TypeInfo_o : TypeInfo_f +{ + char[] toString() { return "ifloat"; } +} + diff --git a/kernel/runtime/std/typeinfo/ti_int.d b/kernel/runtime/std/typeinfo/ti_int.d new file mode 100644 index 0000000..0a94be4 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_int.d @@ -0,0 +1,43 @@ + +// int + +module std.typeinfo.ti_int; + +class TypeInfo_i : TypeInfo +{ + char[] toString() { return "int"; } + + hash_t getHash(void *p) + { + return *cast(uint *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(uint *)p1 == *cast(uint *)p2; + } + + int compare(void *p1, void *p2) + { + if (*cast(int*) p1 < *cast(int*) p2) + return -1; + else if (*cast(int*) p1 > *cast(int*) p2) + return 1; + return 0; + } + + size_t tsize() + { + return int.sizeof; + } + + void swap(void *p1, void *p2) + { + int t; + + t = *cast(int *)p1; + *cast(int *)p1 = *cast(int *)p2; + *cast(int *)p2 = t; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_ireal.d b/kernel/runtime/std/typeinfo/ti_ireal.d new file mode 100644 index 0000000..9dd139f --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_ireal.d @@ -0,0 +1,12 @@ + +// ireal + +module std.typeinfo.ti_ireal; + +private import std.typeinfo.ti_real; + +class TypeInfo_j : TypeInfo_e +{ + char[] toString() { return "ireal"; } +} + diff --git a/kernel/runtime/std/typeinfo/ti_long.d b/kernel/runtime/std/typeinfo/ti_long.d new file mode 100644 index 0000000..e7cfa11 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_long.d @@ -0,0 +1,43 @@ + +// long + +module std.typeinfo.ti_long; + +class TypeInfo_l : TypeInfo +{ + char[] toString() { return "long"; } + + hash_t getHash(void *p) + { + return *cast(uint *)p + (cast(uint *)p)[1]; + } + + int equals(void *p1, void *p2) + { + return *cast(long *)p1 == *cast(long *)p2; + } + + int compare(void *p1, void *p2) + { + if (*cast(long *)p1 < *cast(long *)p2) + return -1; + else if (*cast(long *)p1 > *cast(long *)p2) + return 1; + return 0; + } + + size_t tsize() + { + return long.sizeof; + } + + void swap(void *p1, void *p2) + { + long t; + + t = *cast(long *)p1; + *cast(long *)p1 = *cast(long *)p2; + *cast(long *)p2 = t; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_ptr.d b/kernel/runtime/std/typeinfo/ti_ptr.d new file mode 100644 index 0000000..7e8844a --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_ptr.d @@ -0,0 +1,47 @@ + +// pointer + +module std.typeinfo.ti_ptr; + +class TypeInfo_P : TypeInfo +{ + hash_t getHash(void *p) + { + return cast(uint)*cast(void* *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(void* *)p1 == *cast(void* *)p2; + } + + int compare(void *p1, void *p2) + { + auto c = *cast(void* *)p1 - *cast(void* *)p2; + if (c < 0) + return -1; + else if (c > 0) + return 1; + return 0; + } + + size_t tsize() + { + return (void*).sizeof; + } + + void swap(void *p1, void *p2) + { + void* t; + + t = *cast(void* *)p1; + *cast(void* *)p1 = *cast(void* *)p2; + *cast(void* *)p2 = t; + } + + uint flags() + { + return 1; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_real.d b/kernel/runtime/std/typeinfo/ti_real.d new file mode 100644 index 0000000..19c0d48 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_real.d @@ -0,0 +1,68 @@ + +// real + +module std.typeinfo.ti_real; + +import kernel.runtime.util; +//private import std.math; + +class TypeInfo_e : TypeInfo +{ + char[] toString() { return "real"; } + + hash_t getHash(void *p) + { + return (cast(uint *)p)[0] + (cast(uint *)p)[1] + (cast(ushort *)p)[4]; + } + + static int _equals(real f1, real f2) + { + return f1 == f2 || + (isnan(f1) && isnan(f2)); + } + + static int _compare(real d1, real d2) + { + if (d1 !<>= d2) // if either are NaN + { + if (isnan(d1)) + { if (isnan(d2)) + return 0; + return -1; + } + return 1; + } + return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); + } + + int equals(void *p1, void *p2) + { + return _equals(*cast(real *)p1, *cast(real *)p2); + } + + int compare(void *p1, void *p2) + { + return _compare(*cast(real *)p1, *cast(real *)p2); + } + + size_t tsize() + { + return real.sizeof; + } + + void swap(void *p1, void *p2) + { + real t; + + t = *cast(real *)p1; + *cast(real *)p1 = *cast(real *)p2; + *cast(real *)p2 = t; + } + + void[] init() + { static real r; + + return (cast(real *)&r)[0 .. 1]; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_short.d b/kernel/runtime/std/typeinfo/ti_short.d new file mode 100644 index 0000000..6edbbb0 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_short.d @@ -0,0 +1,39 @@ + +// short + +module std.typeinfo.ti_short; + +class TypeInfo_s : TypeInfo +{ + char[] toString() { return "short"; } + + hash_t getHash(void *p) + { + return *cast(short *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(short *)p1 == *cast(short *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(short *)p1 - *cast(short *)p2; + } + + size_t tsize() + { + return short.sizeof; + } + + void swap(void *p1, void *p2) + { + short t; + + t = *cast(short *)p1; + *cast(short *)p1 = *cast(short *)p2; + *cast(short *)p2 = t; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_ubyte.d b/kernel/runtime/std/typeinfo/ti_ubyte.d new file mode 100644 index 0000000..e4df88f --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_ubyte.d @@ -0,0 +1,43 @@ + +// ubyte + +module std.typeinfo.ti_ubyte; + +class TypeInfo_h : TypeInfo +{ + char[] toString() { return "ubyte"; } + + hash_t getHash(void *p) + { + return *cast(ubyte *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(ubyte *)p1 == *cast(ubyte *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(ubyte *)p1 - *cast(ubyte *)p2; + } + + size_t tsize() + { + return ubyte.sizeof; + } + + void swap(void *p1, void *p2) + { + ubyte t; + + t = *cast(ubyte *)p1; + *cast(ubyte *)p1 = *cast(ubyte *)p2; + *cast(ubyte *)p2 = t; + } +} + +class TypeInfo_b : TypeInfo_h +{ + char[] toString() { return "bool"; } +} diff --git a/kernel/runtime/std/typeinfo/ti_uint.d b/kernel/runtime/std/typeinfo/ti_uint.d new file mode 100644 index 0000000..d24850e --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_uint.d @@ -0,0 +1,43 @@ + +// uint + +module std.typeinfo.ti_uint; + +class TypeInfo_k : TypeInfo +{ + char[] toString() { return "uint"; } + + hash_t getHash(void *p) + { + return *cast(uint *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(uint *)p1 == *cast(uint *)p2; + } + + int compare(void *p1, void *p2) + { + if (*cast(uint*) p1 < *cast(uint*) p2) + return -1; + else if (*cast(uint*) p1 > *cast(uint*) p2) + return 1; + return 0; + } + + size_t tsize() + { + return uint.sizeof; + } + + void swap(void *p1, void *p2) + { + int t; + + t = *cast(uint *)p1; + *cast(uint *)p1 = *cast(uint *)p2; + *cast(uint *)p2 = t; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_ulong.d b/kernel/runtime/std/typeinfo/ti_ulong.d new file mode 100644 index 0000000..d54c605 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_ulong.d @@ -0,0 +1,43 @@ + +// ulong + +module std.typeinfo.ti_ulong; + +class TypeInfo_m : TypeInfo +{ + char[] toString() { return "ulong"; } + + hash_t getHash(void *p) + { + return *cast(uint *)p + (cast(uint *)p)[1]; + } + + int equals(void *p1, void *p2) + { + return *cast(ulong *)p1 == *cast(ulong *)p2; + } + + int compare(void *p1, void *p2) + { + if (*cast(ulong *)p1 < *cast(ulong *)p2) + return -1; + else if (*cast(ulong *)p1 > *cast(ulong *)p2) + return 1; + return 0; + } + + size_t tsize() + { + return ulong.sizeof; + } + + void swap(void *p1, void *p2) + { + ulong t; + + t = *cast(ulong *)p1; + *cast(ulong *)p1 = *cast(ulong *)p2; + *cast(ulong *)p2 = t; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_ushort.d b/kernel/runtime/std/typeinfo/ti_ushort.d new file mode 100644 index 0000000..6b7bd8a --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_ushort.d @@ -0,0 +1,39 @@ + +// ushort + +module std.typeinfo.ti_ushort; + +class TypeInfo_t : TypeInfo +{ + char[] toString() { return "ushort"; } + + hash_t getHash(void *p) + { + return *cast(ushort *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(ushort *)p1 == *cast(ushort *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(ushort *)p1 - *cast(ushort *)p2; + } + + size_t tsize() + { + return ushort.sizeof; + } + + void swap(void *p1, void *p2) + { + ushort t; + + t = *cast(ushort *)p1; + *cast(ushort *)p1 = *cast(ushort *)p2; + *cast(ushort *)p2 = t; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_void.d b/kernel/runtime/std/typeinfo/ti_void.d new file mode 100644 index 0000000..dd4020d --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_void.d @@ -0,0 +1,44 @@ + +// void + +module std.typeinfo.ti_void; + +class TypeInfo_v : TypeInfo +{ + char[] toString() { return "void"; } + + hash_t getHash(void *p) + { + assert(0); + } + + int equals(void *p1, void *p2) + { + return *cast(byte *)p1 == *cast(byte *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(byte *)p1 - *cast(byte *)p2; + } + + size_t tsize() + { + return void.sizeof; + } + + void swap(void *p1, void *p2) + { + byte t; + + t = *cast(byte *)p1; + *cast(byte *)p1 = *cast(byte *)p2; + *cast(byte *)p2 = t; + } + + uint flags() + { + return 1; + } +} + diff --git a/kernel/runtime/std/typeinfo/ti_wchar.d b/kernel/runtime/std/typeinfo/ti_wchar.d new file mode 100644 index 0000000..95a71e2 --- /dev/null +++ b/kernel/runtime/std/typeinfo/ti_wchar.d @@ -0,0 +1,44 @@ + +module std.typeinfo.ti_wchar; + + +class TypeInfo_u : TypeInfo +{ + char[] toString() { return "wchar"; } + + hash_t getHash(void *p) + { + return *cast(wchar *)p; + } + + int equals(void *p1, void *p2) + { + return *cast(wchar *)p1 == *cast(wchar *)p2; + } + + int compare(void *p1, void *p2) + { + return *cast(wchar *)p1 - *cast(wchar *)p2; + } + + size_t tsize() + { + return wchar.sizeof; + } + + void swap(void *p1, void *p2) + { + wchar t; + + t = *cast(wchar *)p1; + *cast(wchar *)p1 = *cast(wchar *)p2; + *cast(wchar *)p2 = t; + } + + void[] init() + { static wchar c; + + return (cast(wchar *)&c)[0 .. 1]; + } +} + diff --git a/kernel/runtime/util.d b/kernel/runtime/util.d new file mode 100644 index 0000000..aa930d3 --- /dev/null +++ b/kernel/runtime/util.d @@ -0,0 +1,163 @@ +// This module contains helpful functions found necessary by the runtime and gcc. + +// contains: itoa, memcpy, memset, memmove, memcmp, strlen, isnan, toString + +module kernel.runtime.util; + +/** +This function converts an integer to a string, depending on the base passed in. + Params: + buf = The function will save the translated string into this character array. + base = The base of the integer value. If "d," it will be assumed to be decimal. If "x," the integer + will be hexadecimal. + d = The integer to translate. + Returns: The translated string in a character array. +*/ +char[] itoa(char[] buf, char base, long d) +{ + size_t p = buf.length - 1; + size_t startIdx = 0; + ulong ud = d; + bool negative = false; + + int divisor = 10; + + // If %d is specified and D is minus, put `-' in the head. + if(base == 'd' && d < 0) + { + negative = true; + ud = -d; + } + else if(base == 'x') + divisor = 16; + + // Divide UD by DIVISOR until UD == 0. + do + { + int remainder = ud % divisor; + buf[p--] = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; + } + while (ud /= divisor) + + if(negative) + buf[p--] = '-'; + + return buf[p + 1 .. $]; +} + +/** +This function copies data from a source piece of memory to a destination piece of memory. + Params: + dest = A pointer to the piece of memory serving as the copy destination. + src = A pointer to the piece of memory serving as the copy source. + count = The number of bytes to copy form src to dest. + Returns: A void pointer to the start of the destination data (dest). +*/ +extern(C) void* memcpy(void* dest, void* src, size_t count) +{ + ubyte* d = cast(ubyte*)dest; + ubyte* s = cast(ubyte*)src; + + for(size_t i = count; count; count--, d++, s++) + *d = *s; + + return dest; +} + +/** +Memcpy and memmove only really have differences at the user level, where they have slightly +different semantics. Here, they're pretty much the same. +*/ +extern(C) void* memmove(void* dest, void* src, size_t count) +{ + ubyte* d = cast(ubyte*)dest; + ubyte* s = cast(ubyte*)src; + + for(size_t i = count; count; count--, d++, s++) + *d = *s; + + return dest; +} + +/** +Compare two blocks of memory. + +Params: + a = Pointer to the first block. + b = Pointer to the second block. + n = The number of bytes to compare. + +Returns: + 0 if they are equal, < 0 if a is less than b, and > 0 if a is greater than b. +*/ +long memcmp(void* a, void* b, size_t n) +{ + ubyte* str_a = cast(ubyte*)a; + ubyte* str_b = cast(ubyte*)b; + + for(size_t i = 0; i < n; i++) + { + if(*str_a != *str_b) + return *str_a - *str_b; + + str_a++; + str_b++; + } + + return 0; +} + +/** +This function sets a particular piece of memory to a particular value. + Params: + addr = The address of the piece of memory you wish to write. + val = The value you wish to write to memory. + numBytes = The number of bytes you would like to write to memory. +*/ +void memset(void *addr, ubyte val, uint numBytes){ + ubyte *data = cast(ubyte*) addr; + + for(int i = 0; i < numBytes; i++){ + data[i] = val; + } +} + +/** +This function determines the size of a passed-in string. + Params: + s = A pointer to the beginning of a character array, declaring a string. + Returns: The size of the string in size_t format. +*/ +size_t strlen(char* s) +{ + size_t i = 0; + for( ; *s != 0; i++, s++){} + return i; +} + +/** +This function takes in a character pointer and returns a character array, or a string. + Params: + s = A pointer to the character(s) you wish to translate to a string. + Returns: A character array (string) containing the information. +*/ +char[] toString(char* s) +{ + return s[0 .. strlen(s)]; +} + +/** +This function checks to see if a floating point number is a NaN. + Params: + e = The value / piece of information you would like to check for number status. + Returns: + 0 if it isn't a NaN, non-zero if it is. +*/ +int isnan(real e) +{ + ushort* pe = cast(ushort *)&e; + ulong* ps = cast(ulong *)&e; + + return (pe[4] & 0x7FFF) == 0x7FFF && + *ps & 0x7FFFFFFFFFFFFFFF; +}