Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1 | // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef V8_CODE_STUB_ASSEMBLER_H_ |
| 6 | #define V8_CODE_STUB_ASSEMBLER_H_ |
| 7 | |
| 8 | #include "src/compiler/code-assembler.h" |
| 9 | #include "src/objects.h" |
| 10 | |
| 11 | namespace v8 { |
| 12 | namespace internal { |
| 13 | |
| 14 | class CallInterfaceDescriptor; |
| 15 | |
| 16 | // Provides JavaScript-specific "macro-assembler" functionality on top of the |
| 17 | // CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler, |
| 18 | // it's possible to add JavaScript-specific useful CodeAssembler "macros" |
| 19 | // without modifying files in the compiler directory (and requiring a review |
| 20 | // from a compiler directory OWNER). |
| 21 | class CodeStubAssembler : public compiler::CodeAssembler { |
| 22 | public: |
| 23 | // Create with CallStub linkage. |
| 24 | // |result_size| specifies the number of results returned by the stub. |
| 25 | // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor. |
| 26 | CodeStubAssembler(Isolate* isolate, Zone* zone, |
| 27 | const CallInterfaceDescriptor& descriptor, |
| 28 | Code::Flags flags, const char* name, |
| 29 | size_t result_size = 1); |
| 30 | |
| 31 | // Create with JSCall linkage. |
| 32 | CodeStubAssembler(Isolate* isolate, Zone* zone, int parameter_count, |
| 33 | Code::Flags flags, const char* name); |
| 34 | |
| 35 | enum ParameterMode { INTEGER_PARAMETERS, SMI_PARAMETERS }; |
| 36 | |
| 37 | compiler::Node* BooleanMapConstant(); |
| 38 | compiler::Node* EmptyStringConstant(); |
| 39 | compiler::Node* HeapNumberMapConstant(); |
| 40 | compiler::Node* NoContextConstant(); |
| 41 | compiler::Node* NullConstant(); |
| 42 | compiler::Node* UndefinedConstant(); |
| 43 | compiler::Node* StaleRegisterConstant(); |
| 44 | |
| 45 | // Float64 operations. |
| 46 | compiler::Node* Float64Ceil(compiler::Node* x); |
| 47 | compiler::Node* Float64Floor(compiler::Node* x); |
| 48 | compiler::Node* Float64Round(compiler::Node* x); |
| 49 | compiler::Node* Float64Trunc(compiler::Node* x); |
| 50 | |
| 51 | // Tag a Word as a Smi value. |
| 52 | compiler::Node* SmiTag(compiler::Node* value); |
| 53 | // Untag a Smi value as a Word. |
| 54 | compiler::Node* SmiUntag(compiler::Node* value); |
| 55 | |
| 56 | // Smi conversions. |
| 57 | compiler::Node* SmiToFloat64(compiler::Node* value); |
| 58 | compiler::Node* SmiFromWord32(compiler::Node* value); |
| 59 | compiler::Node* SmiToWord(compiler::Node* value) { return SmiUntag(value); } |
| 60 | compiler::Node* SmiToWord32(compiler::Node* value); |
| 61 | |
| 62 | // Smi operations. |
| 63 | compiler::Node* SmiAdd(compiler::Node* a, compiler::Node* b); |
| 64 | compiler::Node* SmiAddWithOverflow(compiler::Node* a, compiler::Node* b); |
| 65 | compiler::Node* SmiSub(compiler::Node* a, compiler::Node* b); |
| 66 | compiler::Node* SmiSubWithOverflow(compiler::Node* a, compiler::Node* b); |
| 67 | compiler::Node* SmiEqual(compiler::Node* a, compiler::Node* b); |
| 68 | compiler::Node* SmiAboveOrEqual(compiler::Node* a, compiler::Node* b); |
| 69 | compiler::Node* SmiLessThan(compiler::Node* a, compiler::Node* b); |
| 70 | compiler::Node* SmiLessThanOrEqual(compiler::Node* a, compiler::Node* b); |
| 71 | compiler::Node* SmiMin(compiler::Node* a, compiler::Node* b); |
| 72 | |
| 73 | // Allocate an object of the given size. |
| 74 | compiler::Node* Allocate(compiler::Node* size, AllocationFlags flags = kNone); |
| 75 | compiler::Node* Allocate(int size, AllocationFlags flags = kNone); |
| 76 | compiler::Node* InnerAllocate(compiler::Node* previous, int offset); |
| 77 | compiler::Node* InnerAllocate(compiler::Node* previous, |
| 78 | compiler::Node* offset); |
| 79 | |
| 80 | // Check a value for smi-ness |
| 81 | compiler::Node* WordIsSmi(compiler::Node* a); |
| 82 | // Check that the value is a positive smi. |
| 83 | compiler::Node* WordIsPositiveSmi(compiler::Node* a); |
| 84 | |
| 85 | void BranchIfSmiLessThan(compiler::Node* a, compiler::Node* b, Label* if_true, |
| 86 | Label* if_false) { |
| 87 | BranchIf(SmiLessThan(a, b), if_true, if_false); |
| 88 | } |
| 89 | |
| 90 | void BranchIfSmiLessThanOrEqual(compiler::Node* a, compiler::Node* b, |
| 91 | Label* if_true, Label* if_false) { |
| 92 | BranchIf(SmiLessThanOrEqual(a, b), if_true, if_false); |
| 93 | } |
| 94 | |
| 95 | void BranchIfFloat64IsNaN(compiler::Node* value, Label* if_true, |
| 96 | Label* if_false) { |
| 97 | BranchIfFloat64Equal(value, value, if_false, if_true); |
| 98 | } |
| 99 | |
| 100 | // Load an object pointer from a buffer that isn't in the heap. |
| 101 | compiler::Node* LoadBufferObject(compiler::Node* buffer, int offset, |
| 102 | MachineType rep = MachineType::AnyTagged()); |
| 103 | // Load a field from an object on the heap. |
| 104 | compiler::Node* LoadObjectField(compiler::Node* object, int offset, |
| 105 | MachineType rep = MachineType::AnyTagged()); |
| 106 | // Load the floating point value of a HeapNumber. |
| 107 | compiler::Node* LoadHeapNumberValue(compiler::Node* object); |
| 108 | // Load the Map of an HeapObject. |
| 109 | compiler::Node* LoadMap(compiler::Node* object); |
| 110 | // Load the instance type of an HeapObject. |
| 111 | compiler::Node* LoadInstanceType(compiler::Node* object); |
| 112 | // Load the elements backing store of a JSObject. |
| 113 | compiler::Node* LoadElements(compiler::Node* object); |
| 114 | // Load the length of a fixed array base instance. |
| 115 | compiler::Node* LoadFixedArrayBaseLength(compiler::Node* array); |
| 116 | // Load the bit field of a Map. |
| 117 | compiler::Node* LoadMapBitField(compiler::Node* map); |
| 118 | // Load bit field 2 of a map. |
| 119 | compiler::Node* LoadMapBitField2(compiler::Node* map); |
| 120 | // Load bit field 3 of a map. |
| 121 | compiler::Node* LoadMapBitField3(compiler::Node* map); |
| 122 | // Load the instance type of a map. |
| 123 | compiler::Node* LoadMapInstanceType(compiler::Node* map); |
| 124 | // Load the instance descriptors of a map. |
| 125 | compiler::Node* LoadMapDescriptors(compiler::Node* map); |
| 126 | // Load the prototype of a map. |
| 127 | compiler::Node* LoadMapPrototype(compiler::Node* map); |
| 128 | |
| 129 | // Load the hash field of a name. |
| 130 | compiler::Node* LoadNameHash(compiler::Node* name); |
| 131 | // Load the instance size of a Map. |
| 132 | compiler::Node* LoadMapInstanceSize(compiler::Node* map); |
| 133 | |
| 134 | compiler::Node* AllocateUninitializedFixedArray(compiler::Node* length); |
| 135 | |
| 136 | // Load an array element from a FixedArray. |
| 137 | compiler::Node* LoadFixedArrayElement( |
| 138 | compiler::Node* object, compiler::Node* int32_index, |
| 139 | int additional_offset = 0, |
| 140 | ParameterMode parameter_mode = INTEGER_PARAMETERS); |
| 141 | |
| 142 | // Context manipulation |
| 143 | compiler::Node* LoadNativeContext(compiler::Node* context); |
| 144 | |
| 145 | compiler::Node* LoadJSArrayElementsMap(ElementsKind kind, |
| 146 | compiler::Node* native_context); |
| 147 | |
| 148 | // Store the floating point value of a HeapNumber. |
| 149 | compiler::Node* StoreHeapNumberValue(compiler::Node* object, |
| 150 | compiler::Node* value); |
| 151 | // Store a field to an object on the heap. |
| 152 | compiler::Node* StoreObjectField( |
| 153 | compiler::Node* object, int offset, compiler::Node* value); |
| 154 | compiler::Node* StoreObjectFieldNoWriteBarrier( |
| 155 | compiler::Node* object, int offset, compiler::Node* value, |
| 156 | MachineRepresentation rep = MachineRepresentation::kTagged); |
| 157 | // Store the Map of an HeapObject. |
| 158 | compiler::Node* StoreMapNoWriteBarrier(compiler::Node* object, |
| 159 | compiler::Node* map); |
| 160 | // Store an array element to a FixedArray. |
| 161 | compiler::Node* StoreFixedArrayElement( |
| 162 | compiler::Node* object, compiler::Node* index, compiler::Node* value, |
| 163 | WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, |
| 164 | ParameterMode parameter_mode = INTEGER_PARAMETERS); |
| 165 | |
| 166 | compiler::Node* StoreFixedDoubleArrayElement( |
| 167 | compiler::Node* object, compiler::Node* index, compiler::Node* value, |
| 168 | ParameterMode parameter_mode = INTEGER_PARAMETERS); |
| 169 | |
| 170 | // Allocate a HeapNumber without initializing its value. |
| 171 | compiler::Node* AllocateHeapNumber(); |
| 172 | // Allocate a HeapNumber with a specific value. |
| 173 | compiler::Node* AllocateHeapNumberWithValue(compiler::Node* value); |
| 174 | // Allocate a SeqOneByteString with the given length. |
| 175 | compiler::Node* AllocateSeqOneByteString(int length); |
| 176 | // Allocate a SeqTwoByteString with the given length. |
| 177 | compiler::Node* AllocateSeqTwoByteString(int length); |
| 178 | // Allocated an JSArray |
| 179 | compiler::Node* AllocateJSArray(ElementsKind kind, compiler::Node* array_map, |
| 180 | compiler::Node* capacity, |
| 181 | compiler::Node* length, |
| 182 | compiler::Node* allocation_site = nullptr, |
| 183 | ParameterMode mode = INTEGER_PARAMETERS); |
| 184 | |
| 185 | // Allocation site manipulation |
| 186 | void InitializeAllocationMemento(compiler::Node* base_allocation, |
| 187 | int base_allocation_size, |
| 188 | compiler::Node* allocation_site); |
| 189 | |
| 190 | compiler::Node* TruncateTaggedToFloat64(compiler::Node* context, |
| 191 | compiler::Node* value); |
| 192 | compiler::Node* TruncateTaggedToWord32(compiler::Node* context, |
| 193 | compiler::Node* value); |
| 194 | // Truncate the floating point value of a HeapNumber to an Int32. |
| 195 | compiler::Node* TruncateHeapNumberValueToWord32(compiler::Node* object); |
| 196 | |
| 197 | // Conversions. |
| 198 | compiler::Node* ChangeFloat64ToTagged(compiler::Node* value); |
| 199 | compiler::Node* ChangeInt32ToTagged(compiler::Node* value); |
| 200 | compiler::Node* ChangeUint32ToTagged(compiler::Node* value); |
| 201 | |
| 202 | // Type conversions. |
| 203 | // Throws a TypeError for {method_name} if {value} is not coercible to Object, |
| 204 | // or returns the {value} converted to a String otherwise. |
| 205 | compiler::Node* ToThisString(compiler::Node* context, compiler::Node* value, |
| 206 | char const* method_name); |
| 207 | |
| 208 | // String helpers. |
| 209 | // Load a character from a String (might flatten a ConsString). |
| 210 | compiler::Node* StringCharCodeAt(compiler::Node* string, |
| 211 | compiler::Node* smi_index); |
| 212 | // Return the single character string with only {code}. |
| 213 | compiler::Node* StringFromCharCode(compiler::Node* code); |
| 214 | |
| 215 | // Returns a node that is true if the given bit is set in |word32|. |
| 216 | template <typename T> |
| 217 | compiler::Node* BitFieldDecode(compiler::Node* word32) { |
| 218 | return BitFieldDecode(word32, T::kShift, T::kMask); |
| 219 | } |
| 220 | |
| 221 | compiler::Node* BitFieldDecode(compiler::Node* word32, uint32_t shift, |
| 222 | uint32_t mask); |
| 223 | |
| 224 | // Various building blocks for stubs doing property lookups. |
| 225 | void TryToName(compiler::Node* key, Label* if_keyisindex, Variable* var_index, |
| 226 | Label* if_keyisunique, Label* call_runtime); |
| 227 | |
| 228 | void TryLookupProperty(compiler::Node* object, compiler::Node* map, |
| 229 | compiler::Node* instance_type, compiler::Node* name, |
| 230 | Label* if_found, Label* if_not_found, |
| 231 | Label* call_runtime); |
| 232 | |
| 233 | void TryLookupElement(compiler::Node* object, compiler::Node* map, |
| 234 | compiler::Node* instance_type, compiler::Node* index, |
| 235 | Label* if_found, Label* if_not_found, |
| 236 | Label* call_runtime); |
| 237 | |
| 238 | // Instanceof helpers. |
| 239 | // ES6 section 7.3.19 OrdinaryHasInstance (C, O) |
| 240 | compiler::Node* OrdinaryHasInstance(compiler::Node* context, |
| 241 | compiler::Node* callable, |
| 242 | compiler::Node* object); |
| 243 | |
| 244 | private: |
| 245 | compiler::Node* ElementOffsetFromIndex(compiler::Node* index, |
| 246 | ElementsKind kind, ParameterMode mode, |
| 247 | int base_size = 0); |
| 248 | |
| 249 | compiler::Node* AllocateRawAligned(compiler::Node* size_in_bytes, |
| 250 | AllocationFlags flags, |
| 251 | compiler::Node* top_address, |
| 252 | compiler::Node* limit_address); |
| 253 | compiler::Node* AllocateRawUnaligned(compiler::Node* size_in_bytes, |
| 254 | AllocationFlags flags, |
| 255 | compiler::Node* top_adddress, |
| 256 | compiler::Node* limit_address); |
| 257 | |
| 258 | static const int kElementLoopUnrollThreshold = 8; |
| 259 | }; |
| 260 | |
| 261 | } // namespace internal |
| 262 | } // namespace v8 |
| 263 | |
| 264 | #endif // V8_CODE_STUB_ASSEMBLER_H_ |