Created
November 22, 2013 00:56
-
-
Save tomprimozic/7592841 to your computer and use it in GitHub Desktop.
Playing with Terra - a simple object system with unboxed floats
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
stdlib = terralib.includec("stdlib.h") | |
stdio = terralib.includec("stdio.h") | |
struct void {} | |
any = &&void | |
struct Type {name : rawstring} | |
StringType = global(&Type) | |
IntType = global(&Type) | |
FloatType = global(&Type) | |
local typeof = macro(function(obj) | |
return `[&&Type](obj)[-1] | |
end) | |
-- 64-bit floating point number representation: | |
-- | |
-- | s | eeeeeeeeeee | fff ... fff | | |
-- | |
-- where `s` is the sign bit, `e` are 11 exponent bits, | |
-- and `f` are 52 fraction bits. If all exponent bits are 1, | |
-- the number is a infinity (if fraction is 0) or NaN (otherwise). | |
-- | |
-- On x64 platforms, only one kind of NaN is generated: | |
-- | |
-- NaN = fff8000000000000 | |
-- | |
-- On the other hand, pointers allocated in the user-space memory | |
-- have the first 17 bits set to zero; the "highest" pointer value is | |
-- | |
-- max_ptr = 00007fffffffffff | |
-- | |
-- Therefore, we can overlap doubles, pointers and other data types, | |
-- as long as double's bits are inverted, and we know that | |
-- | |
-- x >= 0007ffffffffffff => (not x) : double | |
-- x <= 00007fffffffffff => x : ptr | |
struct double_and_bits { union { value : double, bits : uint64 } } | |
local double_to_bits = macro(function(obj) | |
return `[double_and_bits]({value = obj}).bits | |
end) | |
local bits_to_double = macro(function(obj) | |
return `[double_and_bits]({bits = obj}).value | |
end) | |
local is_fastdouble = macro(function(obj) | |
return `[bool]([uint64](obj) >= 0x0007ffffffffffffLL) | |
end) | |
local to_fastdouble = macro(function(obj) | |
return `[any](not double_to_bits(obj)) | |
end) | |
local from_fastdouble = macro(function(obj) | |
return `bits_to_double(not [uint64](obj)) | |
end) | |
terra get_type(obj : any) | |
if is_fastdouble(obj) then | |
return FloatType | |
else | |
return typeof(obj) | |
end | |
end | |
terra init() | |
StringType = [&Type](stdlib.malloc(sizeof(Type))) | |
StringType.name = "string" | |
IntType = [&Type](stdlib.malloc(sizeof(Type))) | |
IntType.name = "int" | |
FloatType = [&Type](stdlib.malloc(sizeof(Type))) | |
FloatType.name = "float" | |
end | |
terra alloc_object(t : &Type, size : int64) | |
var memory = stdlib.malloc(size + sizeof([&Type])) | |
var obj = [any](memory) + 1 | |
typeof(obj) = t | |
return obj | |
end | |
terra print_type(obj : any) | |
stdio.printf("type: %s\n", get_type(obj).name) | |
end | |
terra print_any(obj : any) | |
var t = get_type(obj) | |
if t == StringType then | |
stdio.printf("<string> %s\n", obj) | |
elseif t == IntType then | |
stdio.printf("<int> %lld\n", @obj) | |
elseif t == FloatType then | |
stdio.printf("<float> %f\n", from_fastdouble(obj)) | |
else | |
stdio.printf("<unknown type>\n") | |
end | |
end | |
terra main() | |
stdio.printf(" init\n") | |
init() | |
stdio.printf(" alloc\n") | |
var obj_str = alloc_object(StringType, 4) | |
[&int8](obj_str)[0] = 97 -- "a" | |
[&int8](obj_str)[1] = 98 -- "b" | |
[&int8](obj_str)[2] = 99 -- "c" | |
[&int8](obj_str)[3] = 0 -- null terminator | |
var obj_int = alloc_object(IntType, sizeof(int64)) | |
@[&int64](obj_int) = 112 | |
var obj_float = to_fastdouble(1024.125) | |
stdio.printf(" print type\n") | |
print_type(obj_str) | |
print_type(obj_int) | |
print_type(obj_float) | |
stdio.printf(" print object\n") | |
print_any(obj_str) | |
print_any(obj_int) | |
print_any(obj_float) | |
stdio.printf(" end\n") | |
end | |
--main() | |
terralib.saveobj("obj", {main = main}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment