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_IC_ACCESSOR_ASSEMBLER_H_ 6 #define V8_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 using Node = compiler::Node; 22 template <class T> 23 using TNode = compiler::TNode<T>; 24 template <class T> 25 using SloppyTNode = compiler::SloppyTNode<T>; 26 AccessorAssembler(compiler::CodeAssemblerState * state)27 explicit AccessorAssembler(compiler::CodeAssemblerState* state) 28 : CodeStubAssembler(state) {} 29 30 void GenerateLoadIC(); 31 void GenerateLoadIC_Noninlined(); 32 void GenerateLoadIC_Uninitialized(); 33 void GenerateLoadICTrampoline(); 34 void GenerateKeyedLoadIC(); 35 void GenerateKeyedLoadICTrampoline(); 36 void GenerateKeyedLoadIC_Megamorphic(); 37 void GenerateKeyedLoadIC_PolymorphicName(); 38 void GenerateStoreIC(); 39 void GenerateStoreICTrampoline(); 40 void GenerateStoreGlobalIC(); 41 void GenerateStoreGlobalICTrampoline(); 42 void GenerateCloneObjectIC(); 43 44 void GenerateLoadGlobalIC(TypeofMode typeof_mode); 45 void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode); 46 47 void GenerateKeyedStoreIC(); 48 void GenerateKeyedStoreICTrampoline(); 49 50 void GenerateStoreInArrayLiteralIC(); 51 52 void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name, 53 Label* if_handler, TVariable<MaybeObject>* var_handler, 54 Label* if_miss); 55 StubCachePrimaryOffsetForTesting(Node * name,Node * map)56 Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) { 57 return StubCachePrimaryOffset(name, map); 58 } StubCacheSecondaryOffsetForTesting(Node * name,Node * map)59 Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) { 60 return StubCacheSecondaryOffset(name, map); 61 } 62 63 struct LoadICParameters { 64 LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot, 65 Node* vector, Node* holder = nullptr) contextLoadICParameters66 : context(context), 67 receiver(receiver), 68 name(name), 69 slot(slot), 70 vector(vector), 71 holder(holder ? holder : receiver) {} 72 73 Node* context; 74 Node* receiver; 75 Node* name; 76 Node* slot; 77 Node* vector; 78 Node* holder; 79 }; 80 81 void LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot, 82 const LazyNode<Context>& lazy_context, 83 const LazyNode<Name>& lazy_name, TypeofMode typeof_mode, 84 ExitPoint* exit_point, 85 ParameterMode slot_mode = SMI_PARAMETERS); 86 87 // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame 88 // construction on common paths. 89 void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point); 90 91 // Loads dataX field from the DataHandler object. 92 TNode<MaybeObject> LoadHandlerDataField(SloppyTNode<DataHandler> handler, 93 int data_index); 94 95 protected: 96 struct StoreICParameters : public LoadICParameters { StoreICParametersStoreICParameters97 StoreICParameters(Node* context, Node* receiver, Node* name, 98 SloppyTNode<Object> value, Node* slot, Node* vector) 99 : LoadICParameters(context, receiver, name, slot, vector), 100 value(value) {} 101 SloppyTNode<Object> value; 102 }; 103 104 enum class ICMode { kNonGlobalIC, kGlobalIC }; 105 enum ElementSupport { kOnlyProperties, kSupportElements }; 106 void HandleStoreICHandlerCase( 107 const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss, 108 ICMode ic_mode, ElementSupport support_elements = kOnlyProperties); 109 void HandleStoreICTransitionMapHandlerCase(const StoreICParameters* p, 110 TNode<Map> transition_map, 111 Label* miss, 112 bool validate_transition_handler); 113 114 void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); 115 116 void BranchIfStrictMode(Node* vector, Node* slot, Label* if_strict); 117 118 void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield2 = nullptr); 119 120 void OverwriteExistingFastDataProperty(Node* object, Node* object_map, 121 Node* descriptors, 122 Node* descriptor_name_index, 123 Node* details, Node* value, 124 Label* slow, 125 bool do_transitioning_store); 126 127 void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index, 128 Node* representation, Node* value, Label* bailout); 129 130 private: 131 // Stub generation entry points. 132 133 // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains 134 // logic not inlined into Ignition bytecode handlers. 135 void LoadIC(const LoadICParameters* p); 136 void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map, 137 TNode<HeapObject> feedback, 138 TVariable<MaybeObject>* var_handler, Label* if_handler, 139 Label* miss, ExitPoint* exit_point); 140 141 TNode<Object> LoadDescriptorValue(TNode<Map> map, Node* descriptor); 142 TNode<MaybeObject> LoadDescriptorValueOrFieldType( 143 TNode<Map> map, SloppyTNode<IntPtrT> descriptor); 144 145 void LoadIC_Uninitialized(const LoadICParameters* p); 146 147 void KeyedLoadIC(const LoadICParameters* p); 148 void KeyedLoadICGeneric(const LoadICParameters* p); 149 void KeyedLoadICPolymorphicName(const LoadICParameters* p); 150 void StoreIC(const StoreICParameters* p); 151 void StoreGlobalIC(const StoreICParameters* p); 152 void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value, 153 ExitPoint* exit_point, Label* miss); 154 void KeyedStoreIC(const StoreICParameters* p); 155 void StoreInArrayLiteralIC(const StoreICParameters* p); 156 157 // IC dispatcher behavior. 158 159 // Checks monomorphic case. Returns {feedback} entry of the vector. 160 TNode<MaybeObject> TryMonomorphicCase(Node* slot, Node* vector, 161 Node* receiver_map, Label* if_handler, 162 TVariable<MaybeObject>* var_handler, 163 Label* if_miss); 164 void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback, 165 Label* if_handler, 166 TVariable<MaybeObject>* var_handler, 167 Label* if_miss, int min_feedback_capacity); 168 169 // LoadIC implementation. 170 void HandleLoadICHandlerCase( 171 const LoadICParameters* p, TNode<Object> handler, Label* miss, 172 ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC, 173 OnNonExistent on_nonexistent = OnNonExistent::kReturnUndefined, 174 ElementSupport support_elements = kOnlyProperties); 175 176 void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, 177 SloppyTNode<Smi> smi_handler, 178 SloppyTNode<Object> handler, Label* miss, 179 ExitPoint* exit_point, 180 OnNonExistent on_nonexistent, 181 ElementSupport support_elements); 182 183 void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler, 184 Variable* var_holder, Variable* var_smi_handler, 185 Label* if_smi_handler, Label* miss, 186 ExitPoint* exit_point, ICMode ic_mode); 187 188 void HandleLoadCallbackProperty(const LoadICParameters* p, 189 TNode<JSObject> holder, 190 TNode<WordT> handler_word, 191 ExitPoint* exit_point); 192 193 void HandleLoadAccessor(const LoadICParameters* p, 194 TNode<CallHandlerInfo> call_handler_info, 195 TNode<WordT> handler_word, TNode<DataHandler> handler, 196 TNode<IntPtrT> handler_kind, ExitPoint* exit_point); 197 198 void HandleLoadField(Node* holder, Node* handler_word, 199 Variable* var_double_value, Label* rebox_double, 200 ExitPoint* exit_point); 201 202 void EmitAccessCheck(Node* expected_native_context, Node* context, 203 Node* receiver, Label* can_access, Label* miss); 204 205 // LoadGlobalIC implementation. 206 207 void LoadGlobalIC_TryPropertyCellCase( 208 TNode<FeedbackVector> vector, Node* slot, 209 const LazyNode<Context>& lazy_context, ExitPoint* exit_point, 210 Label* try_handler, Label* miss, 211 ParameterMode slot_mode = SMI_PARAMETERS); 212 213 void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, Node* slot, 214 const LazyNode<Context>& lazy_context, 215 const LazyNode<Name>& lazy_name, 216 TypeofMode typeof_mode, 217 ExitPoint* exit_point, Label* miss, 218 ParameterMode slot_mode); 219 220 // StoreIC implementation. 221 222 void HandleStoreICProtoHandler(const StoreICParameters* p, 223 TNode<StoreHandler> handler, Label* miss, 224 ICMode ic_mode, 225 ElementSupport support_elements); 226 void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder, 227 Node* value, Label* miss); 228 void HandleStoreFieldAndReturn(Node* handler_word, Node* holder, 229 Representation representation, Node* value, 230 Label* miss); 231 232 void CheckPrototypeValidityCell(Node* maybe_validity_cell, Label* miss); 233 void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder, 234 Node* handler_word); 235 236 void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss, 237 ElementSupport support_elements); 238 239 void HandleStoreAccessor(const StoreICParameters* p, Node* holder, 240 Node* handler_word); 241 242 // KeyedLoadIC_Generic implementation. 243 244 void GenericElementLoad(Node* receiver, Node* receiver_map, 245 SloppyTNode<Int32T> instance_type, Node* index, 246 Label* slow); 247 248 enum UseStubCache { kUseStubCache, kDontUseStubCache }; 249 void GenericPropertyLoad(Node* receiver, Node* receiver_map, 250 SloppyTNode<Int32T> instance_type, 251 const LoadICParameters* p, Label* slow, 252 UseStubCache use_stub_cache = kUseStubCache); 253 254 // Low-level helpers. 255 256 typedef std::function<void(Node* code_handler)> OnCodeHandler; 257 typedef std::function<void(Node* properties, Node* name_index)> 258 OnFoundOnReceiver; 259 260 template <typename ICHandler, typename ICParameters> 261 Node* HandleProtoHandler(const ICParameters* p, Node* handler, 262 const OnCodeHandler& on_code_handler, 263 const OnFoundOnReceiver& on_found_on_receiver, 264 Label* miss, ICMode ic_mode); 265 266 Node* GetLanguageMode(Node* vector, Node* slot); 267 268 Node* PrepareValueForStore(Node* handler_word, Node* holder, 269 Representation representation, Node* value, 270 Label* bailout); 271 272 // Extends properties backing store by JSObject::kFieldsAdded elements, 273 // returns updated properties backing store. 274 Node* ExtendPropertiesBackingStore(Node* object, Node* index); 275 276 void StoreNamedField(Node* handler_word, Node* object, bool is_inobject, 277 Representation representation, Node* value, 278 Label* bailout); 279 280 void EmitFastElementsBoundsCheck(Node* object, Node* elements, 281 Node* intptr_index, 282 Node* is_jsarray_condition, Label* miss); 283 void EmitElementLoad(Node* object, Node* elements, Node* elements_kind, 284 SloppyTNode<IntPtrT> key, Node* is_jsarray_condition, 285 Label* if_hole, Label* rebox_double, 286 Variable* var_double_value, 287 Label* unimplemented_elements_kind, Label* out_of_bounds, 288 Label* miss, ExitPoint* exit_point); 289 void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name, 290 Label* miss); 291 292 // Stub cache access helpers. 293 294 // This enum is used here as a replacement for StubCache::Table to avoid 295 // including stub cache header. 296 enum StubCacheTable : int; 297 298 Node* StubCachePrimaryOffset(Node* name, Node* map); 299 Node* StubCacheSecondaryOffset(Node* name, Node* seed); 300 301 void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id, 302 Node* entry_offset, Node* name, Node* map, 303 Label* if_handler, 304 TVariable<MaybeObject>* var_handler, 305 Label* if_miss); 306 }; 307 308 // Abstraction over direct and indirect exit points. Direct exits correspond to 309 // tailcalls and Return, while indirect exits store the result in a variable 310 // and then jump to an exit label. 311 class ExitPoint { 312 private: 313 typedef compiler::Node Node; 314 typedef compiler::CodeAssemblerLabel CodeAssemblerLabel; 315 typedef compiler::CodeAssemblerVariable CodeAssemblerVariable; 316 317 public: 318 typedef std::function<void(Node* result)> IndirectReturnHandler; 319 ExitPoint(CodeStubAssembler * assembler)320 explicit ExitPoint(CodeStubAssembler* assembler) 321 : ExitPoint(assembler, nullptr) {} 322 ExitPoint(CodeStubAssembler * assembler,const IndirectReturnHandler & indirect_return_handler)323 ExitPoint(CodeStubAssembler* assembler, 324 const IndirectReturnHandler& indirect_return_handler) 325 : asm_(assembler), indirect_return_handler_(indirect_return_handler) {} 326 ExitPoint(CodeStubAssembler * assembler,CodeAssemblerLabel * out,CodeAssemblerVariable * var_result)327 ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out, 328 CodeAssemblerVariable* var_result) 329 : ExitPoint(assembler, [=](Node* result) { 330 var_result->Bind(result); 331 assembler->Goto(out); 332 }) { 333 DCHECK_EQ(out != nullptr, var_result != nullptr); 334 } 335 336 template <class... TArgs> ReturnCallRuntime(Runtime::FunctionId function,Node * context,TArgs...args)337 void ReturnCallRuntime(Runtime::FunctionId function, Node* context, 338 TArgs... args) { 339 if (IsDirect()) { 340 asm_->TailCallRuntime(function, context, args...); 341 } else { 342 indirect_return_handler_(asm_->CallRuntime(function, context, args...)); 343 } 344 } 345 346 template <class... TArgs> ReturnCallStub(Callable const & callable,Node * context,TArgs...args)347 void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) { 348 if (IsDirect()) { 349 asm_->TailCallStub(callable, context, args...); 350 } else { 351 indirect_return_handler_(asm_->CallStub(callable, context, args...)); 352 } 353 } 354 355 template <class... TArgs> ReturnCallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,TArgs...args)356 void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target, 357 Node* context, TArgs... args) { 358 if (IsDirect()) { 359 asm_->TailCallStub(descriptor, target, context, args...); 360 } else { 361 indirect_return_handler_( 362 asm_->CallStub(descriptor, target, context, args...)); 363 } 364 } 365 Return(Node * const result)366 void Return(Node* const result) { 367 if (IsDirect()) { 368 asm_->Return(result); 369 } else { 370 indirect_return_handler_(result); 371 } 372 } 373 IsDirect()374 bool IsDirect() const { return !indirect_return_handler_; } 375 376 private: 377 CodeStubAssembler* const asm_; 378 IndirectReturnHandler indirect_return_handler_; 379 }; 380 381 } // namespace internal 382 } // namespace v8 383 384 #endif // V8_IC_ACCESSOR_ASSEMBLER_H_ 385