raw-schema.h (8851B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #pragma once 23 24 #include "common.h" // for uint and friends 25 26 #if _MSC_VER && !defined(__clang__) 27 #include <atomic> 28 #endif 29 30 CAPNP_BEGIN_HEADER 31 32 namespace capnp { 33 namespace _ { // private 34 35 struct RawSchema; 36 37 struct RawBrandedSchema { 38 // Represents a combination of a schema and bindings for its generic parameters. 39 // 40 // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for 41 // every _instance_ of a generic type -- or, at least, every instance that is actually used. For 42 // generated-code types, we use template magic to initialize these. 43 44 const RawSchema* generic; 45 // Generic type which we're branding. 46 47 struct Binding { 48 uint8_t which; // Numeric value of one of schema::Type::Which. 49 50 bool isImplicitParameter; 51 // For AnyPointer, true if it's an implicit method parameter. 52 53 uint16_t listDepth; // Number of times to wrap the base type in List(). 54 55 uint16_t paramIndex; 56 // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter 57 // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric 58 // value of one of schema::Type::AnyPointer::Unconstrained::Which. 59 60 union { 61 const RawBrandedSchema* schema; // for struct, enum, interface 62 uint64_t scopeId; // for AnyPointer, if it's a type parameter 63 }; 64 65 Binding() = default; 66 inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema) 67 : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0), 68 schema(schema) {} 69 inline constexpr Binding(uint8_t which, uint16_t listDepth, 70 uint64_t scopeId, uint16_t paramIndex) 71 : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex), 72 scopeId(scopeId) {} 73 inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex) 74 : which(which), isImplicitParameter(true), listDepth(listDepth), 75 paramIndex(implicitParamIndex), scopeId(0) {} 76 }; 77 78 struct Scope { 79 uint64_t typeId; 80 // Type ID whose parameters are being bound. 81 82 const Binding* bindings; 83 uint bindingCount; 84 // Bindings for those parameters. 85 86 bool isUnbound; 87 // This scope is unbound, in the sense of SchemaLoader::getUnbound(). 88 }; 89 90 const Scope* scopes; 91 // Array of enclosing scopes for which generic variables have been bound, sorted by type ID. 92 93 struct Dependency { 94 uint location; 95 const RawBrandedSchema* schema; 96 }; 97 98 const Dependency* dependencies; 99 // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that 100 // are branded are included in this map; if a dependency is missing, use its `defaultBrand`. 101 102 uint32_t scopeCount; 103 uint32_t dependencyCount; 104 105 enum class DepKind { 106 // Component of a Dependency::location. Specifies what sort of dependency this is. 107 108 INVALID, 109 // Mostly defined to ensure that zero is not a valid location. 110 111 FIELD, 112 // Binding needed for a field's type. The index is the field index (NOT ordinal!). 113 114 METHOD_PARAMS, 115 // Bindings needed for a method's params type. The index is the method number. 116 117 METHOD_RESULTS, 118 // Bindings needed for a method's results type. The index is the method ordinal. 119 120 SUPERCLASS, 121 // Bindings needed for a superclass type. The index is the superclass's index in the 122 // "extends" list. 123 124 CONST_TYPE 125 // Bindings needed for the type of a constant. The index is zero. 126 }; 127 128 static inline uint makeDepLocation(DepKind kind, uint index) { 129 // Make a number representing the location of a particular dependency within its parent 130 // schema. 131 132 return (static_cast<uint>(kind) << 24) | index; 133 } 134 135 class Initializer { 136 public: 137 virtual void init(const RawBrandedSchema* generic) const = 0; 138 }; 139 140 const Initializer* lazyInitializer; 141 // Lazy initializer, invoked by ensureInitialized(). 142 143 inline void ensureInitialized() const { 144 // Lazy initialization support. Invoke to ensure that initialization has taken place. This 145 // is required in particular when traversing the dependency list. RawSchemas for compiled-in 146 // types are always initialized; only dynamically-loaded schemas may be lazy. 147 148 #if __GNUC__ || defined(__clang__) 149 const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); 150 #elif _MSC_VER 151 const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer); 152 std::atomic_thread_fence(std::memory_order_acquire); 153 #else 154 #error "Platform not supported" 155 #endif 156 if (i != nullptr) i->init(this); 157 } 158 159 inline bool isUnbound() const; 160 // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case 161 // binding lookups need to be handled specially. 162 }; 163 164 struct RawSchema { 165 // The generated code defines a constant RawSchema for every compiled declaration. 166 // 167 // This is an internal structure which could change in the future. 168 169 uint64_t id; 170 171 const word* encodedNode; 172 // Encoded SchemaNode, readable via readMessageUnchecked<schema::Node>(encodedNode). 173 174 uint32_t encodedSize; 175 // Size of encodedNode, in words. 176 177 const RawSchema* const* dependencies; 178 // Pointers to other types on which this one depends, sorted by ID. The schemas in this table 179 // may be uninitialized -- you must call ensureInitialized() on the one you wish to use before 180 // using it. 181 // 182 // TODO(someday): Make this a hashtable. 183 184 const uint16_t* membersByName; 185 // Indexes of members sorted by name. Used to implement name lookup. 186 // TODO(someday): Make this a hashtable. 187 188 uint32_t dependencyCount; 189 uint32_t memberCount; 190 // Sizes of above tables. 191 192 const uint16_t* membersByDiscriminant; 193 // List of all member indexes ordered by discriminant value. Those which don't have a 194 // discriminant value are listed at the end, in order by ordinal. 195 196 const RawSchema* canCastTo; 197 // Points to the RawSchema of a compiled-in type to which it is safe to cast any DynamicValue 198 // with this schema. This is null for all compiled-in types; it is only set by SchemaLoader on 199 // dynamically-loaded types. 200 201 class Initializer { 202 public: 203 virtual void init(const RawSchema* schema) const = 0; 204 }; 205 206 const Initializer* lazyInitializer; 207 // Lazy initializer, invoked by ensureInitialized(). 208 209 inline void ensureInitialized() const { 210 // Lazy initialization support. Invoke to ensure that initialization has taken place. This 211 // is required in particular when traversing the dependency list. RawSchemas for compiled-in 212 // types are always initialized; only dynamically-loaded schemas may be lazy. 213 214 #if __GNUC__ || defined(__clang__) 215 const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); 216 #elif _MSC_VER 217 const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer); 218 std::atomic_thread_fence(std::memory_order_acquire); 219 #else 220 #error "Platform not supported" 221 #endif 222 if (i != nullptr) i->init(this); 223 } 224 225 RawBrandedSchema defaultBrand; 226 // Specifies the brand to use for this schema if no generic parameters have been bound to 227 // anything. Generally, in the default brand, all generic parameters are treated as if they were 228 // bound to `AnyPointer`. 229 }; 230 231 inline bool RawBrandedSchema::isUnbound() const { 232 // The unbound schema is the only one that has no scopes but is not the default schema. 233 return scopeCount == 0 && this != &generic->defaultBrand; 234 } 235 236 } // namespace _ (private) 237 } // namespace capnp 238 239 CAPNP_END_HEADER