diff --git a/doc/changelog.md b/doc/changelog.md index 9ad47ebc04..799671ebc6 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -44,4 +44,6 @@ - Creating a field of 128-bit value type no longer causes a compiler crash - 128-bit fields are inspected as `` - Static fields can now contain floating point values -- Fixed a bug where loading a float from an object and immediately using it math would cause a compiler crash \ No newline at end of file +- Fixed a bug where loading a float from an object and immediately using it math would cause a compiler crash + +- Arrays of value types can be created on the stack with `new`. \ No newline at end of file diff --git a/doc/goal_doc.md b/doc/goal_doc.md index 1535156eec..3e855068b9 100644 --- a/doc/goal_doc.md +++ b/doc/goal_doc.md @@ -605,7 +605,10 @@ Get element from pair The type of the result is always `object`, as pairs can hold any `object`. The type-check for `car` and `cdr` is relaxed - it allows it to be applied to any `pair` or `object`. The reason for allowing `object` is so you can write `(car (car x))` instead of `(car (the pair (car x)))`. However, if the argument to `car` is not a `pair`, you will get garbage or a crash. ## `new` -See section on creating new GOAL objects +```lisp +(new [allocation] [new-type-specification] [args]) +``` +See section on creating new GOAL objects. ## `print-type` Print the type of some GOAL expression at compile time. @@ -863,6 +866,38 @@ These can differ by padding for alignment. ## Built-in Methods ## New - How To Create GOAL Objects +GOAL has several different ways to create objects, all using the `new` form. + +### Heap Allocated Objects +A new object can be allocated on a heap with `(new 'global 'obj-type [new-method-arguments])`. +This simply calls the `new` method of the given type. You can also replace `'global` with `'debug` to allocate on the debug heap. +Currently these are the only two heaps supported, in the future you will be able to call the new method with other arguments +to allow you to do an "in place new" or allocate on a different heap. + +This will only work on structures and basics. If you want a heap allocated float/integer/pointer, create an array of size 1. +This will work on dynamically sized items. + +### Heap Allocated Arrays +You can construct a heap array with `(new 'global 'inline-array 'obj-type count)` or `(new 'global 'array 'obj-type count)`. +These objects are not initialized. Note that the `array` version creates a `(pointer obj-type)` plain array, +__not__ a GOAL `array` type fancy array. In the future this may change because it is confusing. + +Because these objects are uninitialized, you cannot provide constructor arguments. +You cannot use this on dynamically sized member types. However, the array size can be determined at runtime. + +### Static Objects +You can create a static object with `(new 'static 'obj-type [field-def]...)`. For now it must be a structure or basic. +Each field def looks like `:field-name field-value`. The `field-value` is evaluated at compile time. For now, fields +can only be integers, floats, or symbols. + +Fields which aren't explicitly initialized are zeroed, except for the type field of basics, which is properly initialized to the correct type. + +This does not work on dynamically sized structures. + +### Stack Allocated Objects +Currently only arrays of integers, floats, or pointers can be stack allocated. +For example, use `(new 'array 'int32 1)` to get a `(pointer int32)`. Unlike heap allocated arrays, these stack arrays +must have a size that can be determined at compile time. ## Defining a `new` Method diff --git a/goalc/compiler/CodeGenerator.cpp b/goalc/compiler/CodeGenerator.cpp index 3332abcd9f..22d6f6ccd6 100644 --- a/goalc/compiler/CodeGenerator.cpp +++ b/goalc/compiler/CodeGenerator.cpp @@ -83,8 +83,9 @@ void CodeGenerator::do_function(FunctionEnv* env, int f_idx) { // do we include an extra push to get 8 more bytes to keep the stack aligned? bool bonus_push = false; - // the offset to add directly to rsp for stack variables (no push/pop) - int manually_added_stack_offset = GPR_SIZE * allocs.stack_slots; + // the offset to add directly to rsp for stack variables or spills (no push/pop) + int manually_added_stack_offset = + GPR_SIZE * (allocs.stack_slots_for_spills + allocs.stack_slots_for_vars); stack_offset += manually_added_stack_offset; // do we need to align or manually offset? diff --git a/goalc/compiler/Compiler.cpp b/goalc/compiler/Compiler.cpp index 029fb5cec2..d6953926a9 100644 --- a/goalc/compiler/Compiler.cpp +++ b/goalc/compiler/Compiler.cpp @@ -165,6 +165,7 @@ void Compiler::color_object_file(FileEnv* env) { input.max_vars = f->max_vars(); input.constraints = f->constraints(); + input.stack_slots_for_stack_vars = f->stack_slots_used_for_stack_vars(); if (m_settings.debug_print_regalloc) { input.debug_settings.print_input = true; diff --git a/goalc/compiler/Env.cpp b/goalc/compiler/Env.cpp index a7e06fff4d..43db177cfe 100644 --- a/goalc/compiler/Env.cpp +++ b/goalc/compiler/Env.cpp @@ -261,6 +261,14 @@ RegVal* FunctionEnv::lexical_lookup(goos::Object sym) { return kv->second; } +StackVarAddrVal* FunctionEnv::allocate_stack_variable(const TypeSpec& ts, int size_bytes) { + require_aligned_stack(); + int slots_used = (size_bytes + emitter::GPR_SIZE - 1) / emitter::GPR_SIZE; + auto result = alloc_val(ts, m_stack_var_slots_used, slots_used); + m_stack_var_slots_used += slots_used; + return result; +} + /////////////////// // LexicalEnv /////////////////// diff --git a/goalc/compiler/Env.h b/goalc/compiler/Env.h index ca92cf2e85..e49800815a 100644 --- a/goalc/compiler/Env.h +++ b/goalc/compiler/Env.h @@ -157,19 +157,18 @@ class FunctionEnv : public DeclareEnv { void constrain(const IRegConstraint& c) { m_constraints.push_back(c); } void set_allocations(const AllocationResult& result) { m_regalloc_result = result; } RegVal* lexical_lookup(goos::Object sym) override; - const AllocationResult& alloc_result() { return m_regalloc_result; } - bool needs_aligned_stack() const { return m_aligned_stack_required; } void require_aligned_stack() { m_aligned_stack_required = true; } - Label* alloc_unnamed_label() { m_unnamed_labels.emplace_back(std::make_unique