1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#pragma once
#include "Named.h"
#include "NamedThread.h"
#include "RunOn.h"
#include "Code/OffsetReference.h"
#include "Core/Fn.h"
#include "Core/Variant.h"
namespace storm {
STORM_PKG(core.lang);
class Function;
/**
* Describes some kind of variable. It is a member variable if it takes a parameter, otherwise
* it is some kind of global variable.
*/
class Variable : public Named {
STORM_CLASS;
public:
// Our type.
Value type;
// To string.
virtual void STORM_FN toS(StrBuf *to) const;
protected:
// Create a variable, either as a member or as a non-member.
STORM_CTOR Variable(SrcPos pos, Str *name, Value type);
STORM_CTOR Variable(SrcPos pos, Str *name, Value type, Type *member);
};
/**
* Represents a member-variable to some kind of type. The variable is uniquely identified by its
* offset relative to the start of the object.
*/
class MemberVar : public Variable {
STORM_CLASS;
public:
// Create.
STORM_CTOR MemberVar(Str *name, Value type, Type *memberOf);
STORM_CTOR MemberVar(SrcPos pos, Str *name, Value type, Type *memberOf);
// Get a reference to this variable. Use the reference whenever storing the offset for more
// than a couple of function calls, as it might change during reloads.
code::OffsetRef STORM_FN offset() const;
// Get our parent type.
Type *STORM_FN owner() const;
// Get the raw offset. Prefer to use the reference whenever possible.
Offset STORM_FN rawOffset() const;
// Set our offset.
void setOffset(Offset off);
// Initializer, if any.
MAYBE(Function *) STORM_FN initializer() { return initFn; }
void STORM_ASSIGN initializer(MAYBE(Function *) fn);
// Keep track of the source of the initializer.
void STORM_FN discardSource();
// Check if it is possible to update.
virtual MAYBE(Str *) STORM_FN canReplace(Named *old, ReplaceContext *ctx);
protected:
// Replace with another variable.
virtual void STORM_FN doReplace(Named *old, ReplaceTasks *tasks, ReplaceContext *context);
private:
// The actual offset. Updated by 'layout'.
Offset off;
// Reference for the offset.
code::OffsetSource *ref;
// Initializer.
MAYBE(Function *) initFn;
// Has the layout been produced?
Bool hasLayout;
};
/**
* A global variable stored in the name tree. Global variables are only supposed to be
* accessible from their associated thread, so that proper synchronization is enforced by the
* compiler. Consider two global variables that form a single state together. Disallowing access
* from other threads than the "owning" thread forces the programmer to write accessor functions
* on the proper thread, which ensures that any updates to the state happen as intended. Having
* multiple threads accessing the global variables could cause unintended race conditions.
*
* The variable is initialized the first time it is accessed, or the first time 'create' is called.
*
* TODO: Expose 'dataPtr' to Storm in a good way. We have Engine::ref so that ASM can access it
* at least.
*/
class GlobalVar : public Variable {
STORM_CLASS;
public:
// Create. Initialize the variable to whatever is returned by 'initializer'. 'initializer'
// is evaluated on the thread specified by 'thread'.
STORM_CTOR GlobalVar(Str *name, Value type, NamedThread *thread, FnBase *initializer);
STORM_CTOR GlobalVar(SrcPos pos, Str *name, Value type, NamedThread *thread, FnBase *initializer);
// Owning thread.
NamedThread *owner;
// Assuming we're running on 'thread', may we access this variable?
Bool STORM_FN accessibleFrom(RunOn thread);
// Make sure the variable is created.
void STORM_FN create();
// Compile this entity. Synonymous with 'create'.
virtual void STORM_FN compile();
// Get the pointer to the data. Safe to call from any thread.
void *CODECALL dataPtr();
// Get the raw pointer to the data. Safe to call from any thread.
void *CODECALL rawDataPtr();
// Get a string representation of the value.
Str *STORM_FN strValue() const;
// Get a Variant that represents the value.
Variant STORM_FN value();
// Output.
virtual void STORM_FN toS(StrBuf *to) const;
private:
// Initializer for the variable. If 'null', that means we have already initialized the
// variable.
FnBase *initializer;
// The data stored in the variable. If the variable is an Object or a TObject, this is just
// a pointer to the object itself. If it is a value type, this is a pointer to an array of
// size 1 which contains the object.
UNKNOWN(PTR_GC) void *data;
// Do we have an array for this type?
Bool hasArray;
// Created?
inline Bool created() { return initializer == null; }
};
}
|