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_SRC_IC_ACCESSOR_ASSEMBLER_H_ 6 #define V8_SRC_IC_ACCESSOR_ASSEMBLER_H_ 7 8 #include "src/code-stub-assembler.h" 9 10 namespace v8 { 11 namespace internal { 12 13 namespace compiler { 14 class CodeAssemblerState; 15 } 16 17 class ExitPoint; 18 19 class AccessorAssembler : public CodeStubAssembler { 20 public: 21 typedef compiler::Node Node; 22 AccessorAssembler(compiler::CodeAssemblerState * state)23 explicit AccessorAssembler(compiler::CodeAssemblerState* state) 24 : CodeStubAssembler(state) {} 25 26 void GenerateLoadIC(); 27 void GenerateLoadField(); 28 void GenerateLoadICTrampoline(); 29 void GenerateKeyedLoadIC(); 30 void GenerateKeyedLoadICTrampoline(); 31 void GenerateKeyedLoadIC_Megamorphic(); 32 void GenerateStoreIC(); 33 void GenerateStoreICTrampoline(); 34 35 void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent); 36 37 void GenerateLoadGlobalIC(TypeofMode typeof_mode); 38 void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode); 39 40 void GenerateKeyedStoreIC(LanguageMode language_mode); 41 void GenerateKeyedStoreICTrampoline(LanguageMode language_mode); 42 43 void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name, 44 Label* if_handler, Variable* var_handler, 45 Label* if_miss); 46 StubCachePrimaryOffsetForTesting(Node * name,Node * map)47 Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) { 48 return StubCachePrimaryOffset(name, map); 49 } StubCacheSecondaryOffsetForTesting(Node * name,Node * map)50 Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) { 51 return StubCacheSecondaryOffset(name, map); 52 } 53 54 struct LoadICParameters { LoadICParametersLoadICParameters55 LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot, 56 Node* vector) 57 : context(context), 58 receiver(receiver), 59 name(name), 60 slot(slot), 61 vector(vector) {} 62 63 Node* context; 64 Node* receiver; 65 Node* name; 66 Node* slot; 67 Node* vector; 68 }; 69 70 void LoadGlobalIC_TryPropertyCellCase( 71 Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler, 72 Label* miss, ParameterMode slot_mode = SMI_PARAMETERS); 73 void LoadGlobalIC_TryHandlerCase(const LoadICParameters* p, 74 TypeofMode typeof_mode, 75 ExitPoint* exit_point, Label* miss); 76 void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point); 77 78 protected: 79 struct StoreICParameters : public LoadICParameters { StoreICParametersStoreICParameters80 StoreICParameters(Node* context, Node* receiver, Node* name, Node* value, 81 Node* slot, Node* vector) 82 : LoadICParameters(context, receiver, name, slot, vector), 83 value(value) {} 84 Node* value; 85 }; 86 87 enum ElementSupport { kOnlyProperties, kSupportElements }; 88 void HandleStoreICHandlerCase( 89 const StoreICParameters* p, Node* handler, Label* miss, 90 ElementSupport support_elements = kOnlyProperties); 91 92 private: 93 // Stub generation entry points. 94 95 void LoadIC(const LoadICParameters* p); 96 void LoadICProtoArray(const LoadICParameters* p, Node* handler, 97 bool throw_reference_error_if_nonexistent); 98 void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode); 99 void KeyedLoadIC(const LoadICParameters* p); 100 void KeyedLoadICGeneric(const LoadICParameters* p); 101 void StoreIC(const StoreICParameters* p); 102 void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode); 103 104 // IC dispatcher behavior. 105 106 // Checks monomorphic case. Returns {feedback} entry of the vector. 107 Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map, 108 Label* if_handler, Variable* var_handler, 109 Label* if_miss); 110 void HandlePolymorphicCase(Node* receiver_map, Node* feedback, 111 Label* if_handler, Variable* var_handler, 112 Label* if_miss, int unroll_count); 113 void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback, 114 Label* if_handler, Variable* var_handler, 115 Label* if_transition_handler, 116 Variable* var_transition_map_cell, 117 Label* if_miss); 118 119 // LoadIC implementation. 120 121 void HandleLoadICHandlerCase( 122 const LoadICParameters* p, Node* handler, Label* miss, 123 ElementSupport support_elements = kOnlyProperties); 124 125 void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, 126 Node* smi_handler, Label* miss, 127 ExitPoint* exit_point, 128 ElementSupport support_elements); 129 130 void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler, 131 Variable* var_holder, 132 Variable* var_smi_handler, 133 Label* if_smi_handler, Label* miss, 134 ExitPoint* exit_point, 135 bool throw_reference_error_if_nonexistent); 136 137 Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler, 138 Node* handler_length, Node* handler_flags, 139 Label* miss, 140 bool throw_reference_error_if_nonexistent); 141 142 // LoadGlobalIC implementation. 143 144 void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler, 145 Label* miss, ExitPoint* exit_point, 146 bool throw_reference_error_if_nonexistent); 147 148 // StoreIC implementation. 149 150 void HandleStoreICElementHandlerCase(const StoreICParameters* p, 151 Node* handler, Label* miss); 152 153 void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler, 154 Label* miss); 155 // If |transition| is nullptr then the normal field store is generated or 156 // transitioning store otherwise. 157 void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder, 158 Node* value, Node* transition, Label* miss); 159 // If |transition| is nullptr then the normal field store is generated or 160 // transitioning store otherwise. 161 void HandleStoreFieldAndReturn(Node* handler_word, Node* holder, 162 Representation representation, Node* value, 163 Node* transition, Label* miss); 164 165 // KeyedLoadIC_Generic implementation. 166 167 void GenericElementLoad(Node* receiver, Node* receiver_map, 168 Node* instance_type, Node* index, Label* slow); 169 170 void GenericPropertyLoad(Node* receiver, Node* receiver_map, 171 Node* instance_type, Node* key, 172 const LoadICParameters* p, Label* slow); 173 174 // Low-level helpers. 175 176 Node* PrepareValueForStore(Node* handler_word, Node* holder, 177 Representation representation, Node* transition, 178 Node* value, Label* bailout); 179 180 // Extends properties backing store by JSObject::kFieldsAdded elements. 181 void ExtendPropertiesBackingStore(Node* object); 182 183 void StoreNamedField(Node* handler_word, Node* object, bool is_inobject, 184 Representation representation, Node* value, 185 bool transition_to_field, Label* bailout); 186 187 void EmitFastElementsBoundsCheck(Node* object, Node* elements, 188 Node* intptr_index, 189 Node* is_jsarray_condition, Label* miss); 190 void EmitElementLoad(Node* object, Node* elements, Node* elements_kind, 191 Node* key, Node* is_jsarray_condition, Label* if_hole, 192 Label* rebox_double, Variable* var_double_value, 193 Label* unimplemented_elements_kind, Label* out_of_bounds, 194 Label* miss, ExitPoint* exit_point); 195 void CheckPrototype(Node* prototype_cell, Node* name, Label* miss); 196 void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss); 197 198 // Stub cache access helpers. 199 200 // This enum is used here as a replacement for StubCache::Table to avoid 201 // including stub cache header. 202 enum StubCacheTable : int; 203 204 Node* StubCachePrimaryOffset(Node* name, Node* map); 205 Node* StubCacheSecondaryOffset(Node* name, Node* seed); 206 207 void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id, 208 Node* entry_offset, Node* name, Node* map, 209 Label* if_handler, Variable* var_handler, 210 Label* if_miss); 211 }; 212 213 // Abstraction over direct and indirect exit points. Direct exits correspond to 214 // tailcalls and Return, while indirect exits store the result in a variable 215 // and then jump to an exit label. 216 class ExitPoint { 217 private: 218 typedef compiler::Node Node; 219 typedef compiler::CodeAssemblerLabel CodeAssemblerLabel; 220 typedef compiler::CodeAssemblerVariable CodeAssemblerVariable; 221 222 public: ExitPoint(CodeStubAssembler * assembler)223 explicit ExitPoint(CodeStubAssembler* assembler) 224 : ExitPoint(assembler, nullptr, nullptr) {} ExitPoint(CodeStubAssembler * assembler,CodeAssemblerLabel * out,CodeAssemblerVariable * var_result)225 ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out, 226 CodeAssemblerVariable* var_result) 227 : out_(out), var_result_(var_result), asm_(assembler) { 228 DCHECK_EQ(out != nullptr, var_result != nullptr); 229 } 230 231 template <class... TArgs> ReturnCallRuntime(Runtime::FunctionId function,Node * context,TArgs...args)232 void ReturnCallRuntime(Runtime::FunctionId function, Node* context, 233 TArgs... args) { 234 if (IsDirect()) { 235 asm_->TailCallRuntime(function, context, args...); 236 } else { 237 IndirectReturn(asm_->CallRuntime(function, context, args...)); 238 } 239 } 240 241 template <class... TArgs> ReturnCallStub(Callable const & callable,Node * context,TArgs...args)242 void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) { 243 if (IsDirect()) { 244 asm_->TailCallStub(callable, context, args...); 245 } else { 246 IndirectReturn(asm_->CallStub(callable, context, args...)); 247 } 248 } 249 250 template <class... TArgs> ReturnCallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,TArgs...args)251 void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target, 252 Node* context, TArgs... args) { 253 if (IsDirect()) { 254 asm_->TailCallStub(descriptor, target, context, args...); 255 } else { 256 IndirectReturn(asm_->CallStub(descriptor, target, context, args...)); 257 } 258 } 259 Return(Node * const result)260 void Return(Node* const result) { 261 if (IsDirect()) { 262 asm_->Return(result); 263 } else { 264 IndirectReturn(result); 265 } 266 } 267 IsDirect()268 bool IsDirect() const { return out_ == nullptr; } 269 270 private: IndirectReturn(Node * const result)271 void IndirectReturn(Node* const result) { 272 var_result_->Bind(result); 273 asm_->Goto(out_); 274 } 275 276 CodeAssemblerLabel* const out_; 277 CodeAssemblerVariable* const var_result_; 278 CodeStubAssembler* const asm_; 279 }; 280 281 } // namespace internal 282 } // namespace v8 283 284 #endif // V8_SRC_IC_ACCESSOR_ASSEMBLER_H_ 285