1 // Copyright 2014 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_HANDLER_COMPILER_H_ 6 #define V8_IC_HANDLER_COMPILER_H_ 7 8 #include "src/ic/access-compiler.h" 9 #include "src/ic/ic-state.h" 10 11 namespace v8 { 12 namespace internal { 13 14 class CallOptimization; 15 16 enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING }; 17 18 class PropertyHandlerCompiler : public PropertyAccessCompiler { 19 public: 20 static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind, 21 CacheHolderFlag cache_holder); 22 23 protected: PropertyHandlerCompiler(Isolate * isolate,Code::Kind kind,Handle<Map> map,Handle<JSObject> holder,CacheHolderFlag cache_holder)24 PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map, 25 Handle<JSObject> holder, CacheHolderFlag cache_holder) 26 : PropertyAccessCompiler(isolate, kind, cache_holder), 27 map_(map), 28 holder_(holder) {} 29 ~PropertyHandlerCompiler()30 virtual ~PropertyHandlerCompiler() {} 31 FrontendHeader(Register object_reg,Handle<Name> name,Label * miss,ReturnHolder return_what)32 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 33 Label* miss, ReturnHolder return_what) { 34 UNREACHABLE(); 35 return receiver(); 36 } 37 FrontendFooter(Handle<Name> name,Label * miss)38 virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); } 39 40 // Frontend loads from receiver(), returns holder register which may be 41 // different. 42 Register Frontend(Handle<Name> name); 43 44 // When FLAG_vector_ics is true, handlers that have the possibility of missing 45 // will need to save and pass these to miss handlers. PushVectorAndSlot()46 void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); } 47 void PushVectorAndSlot(Register vector, Register slot); PopVectorAndSlot()48 void PopVectorAndSlot() { PopVectorAndSlot(vector(), slot()); } 49 void PopVectorAndSlot(Register vector, Register slot); 50 51 void DiscardVectorAndSlot(); 52 53 // TODO(verwaest): Make non-static. 54 static void GenerateApiAccessorCall(MacroAssembler* masm, 55 const CallOptimization& optimization, 56 Handle<Map> receiver_map, 57 Register receiver, Register scratch, 58 bool is_store, Register store_parameter, 59 Register accessor_holder, 60 int accessor_index); 61 62 // Helper function used to check that the dictionary doesn't contain 63 // the property. This function may return false negatives, so miss_label 64 // must always call a backup property check that is complete. 65 // This function is safe to call if the receiver has fast properties. 66 // Name must be unique and receiver must be a heap object. 67 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, 68 Label* miss_label, 69 Register receiver, 70 Handle<Name> name, Register r0, 71 Register r1); 72 73 // Generate code to check that a global property cell is empty. Create 74 // the property cell at compilation time if no cell exists for the 75 // property. 76 static void GenerateCheckPropertyCell(MacroAssembler* masm, 77 Handle<JSGlobalObject> global, 78 Handle<Name> name, Register scratch, 79 Label* miss); 80 81 // Generates check that current native context has the same access rights 82 // as the given |native_context_cell|. 83 // If |compare_native_contexts_only| is true then access check is considered 84 // passed if the execution-time native context is equal to contents of 85 // |native_context_cell|. 86 // If |compare_native_contexts_only| is false then access check is considered 87 // passed if the execution-time native context is equal to contents of 88 // |native_context_cell| or security tokens of both contexts are equal. 89 void GenerateAccessCheck(Handle<WeakCell> native_context_cell, 90 Register scratch1, Register scratch2, Label* miss, 91 bool compare_native_contexts_only); 92 93 // Generates code that verifies that the property holder has not changed 94 // (checking maps of objects in the prototype chain for fast and global 95 // objects or doing negative lookup for slow objects, ensures that the 96 // property cells for global objects are still empty) and checks that the map 97 // of the holder has not changed. If necessary the function also generates 98 // code for security check in case of global object holders. Helps to make 99 // sure that the current IC is still valid. 100 // 101 // The scratch and holder registers are always clobbered, but the object 102 // register is only clobbered if it the same as the holder register. The 103 // function returns a register containing the holder - either object_reg or 104 // holder_reg. 105 Register CheckPrototypes(Register object_reg, Register holder_reg, 106 Register scratch1, Register scratch2, 107 Handle<Name> name, Label* miss, 108 ReturnHolder return_what); 109 110 Handle<Code> GetCode(Code::Kind kind, Handle<Name> name); set_holder(Handle<JSObject> holder)111 void set_holder(Handle<JSObject> holder) { holder_ = holder; } map()112 Handle<Map> map() const { return map_; } set_map(Handle<Map> map)113 void set_map(Handle<Map> map) { map_ = map; } holder()114 Handle<JSObject> holder() const { return holder_; } 115 116 private: 117 Handle<Map> map_; 118 Handle<JSObject> holder_; 119 }; 120 121 122 class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { 123 public: NamedLoadHandlerCompiler(Isolate * isolate,Handle<Map> map,Handle<JSObject> holder,CacheHolderFlag cache_holder)124 NamedLoadHandlerCompiler(Isolate* isolate, Handle<Map> map, 125 Handle<JSObject> holder, 126 CacheHolderFlag cache_holder) 127 : PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder, 128 cache_holder) {} 129 ~NamedLoadHandlerCompiler()130 virtual ~NamedLoadHandlerCompiler() {} 131 132 Handle<Code> CompileLoadCallback(Handle<Name> name, 133 Handle<AccessorInfo> callback, 134 Handle<Code> slow_stub); 135 136 Handle<Code> CompileLoadCallback(Handle<Name> name, 137 const CallOptimization& call_optimization, 138 int accessor_index, Handle<Code> slow_stub); 139 140 // The LookupIterator is used to perform a lookup behind the interceptor. If 141 // the iterator points to a LookupIterator::PROPERTY, its access will be 142 // inlined. 143 Handle<Code> CompileLoadInterceptor(LookupIterator* it); 144 145 Handle<Code> CompileLoadViaGetter(Handle<Name> name, int accessor_index, 146 int expected_arguments); 147 148 Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name, 149 bool is_configurable); 150 151 static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map, 152 Register receiver, Register holder, 153 int accessor_index, int expected_arguments, 154 Register scratch); 155 GenerateLoadViaGetterForDeopt(MacroAssembler * masm)156 static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) { 157 GenerateLoadViaGetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1, 158 no_reg); 159 } 160 161 // These constants describe the structure of the interceptor arguments on the 162 // stack. The arguments are pushed by the (platform-specific) 163 // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and 164 // LoadWithInterceptor. 165 static const int kInterceptorArgsNameIndex = 0; 166 static const int kInterceptorArgsThisIndex = 1; 167 static const int kInterceptorArgsHolderIndex = 2; 168 static const int kInterceptorArgsLength = 3; 169 170 protected: 171 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 172 Label* miss, ReturnHolder return_what); 173 174 virtual void FrontendFooter(Handle<Name> name, Label* miss); 175 176 private: 177 void GenerateLoadCallback(Register reg, Handle<AccessorInfo> callback); 178 179 // Helper emits no code if vector-ics are disabled. 180 void InterceptorVectorSlotPush(Register holder_reg); 181 enum PopMode { POP, DISCARD }; 182 void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP); 183 184 void GenerateLoadInterceptor(Register holder_reg); 185 void GenerateLoadInterceptorWithFollowup(LookupIterator* it, 186 Register holder_reg); 187 void GenerateLoadPostInterceptor(LookupIterator* it, Register reg); 188 scratch3()189 Register scratch3() { return registers_[4]; } 190 }; 191 192 193 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { 194 public: 195 // All store handlers use StoreWithVectorDescriptor calling convention. 196 typedef StoreWithVectorDescriptor Descriptor; 197 NamedStoreHandlerCompiler(Isolate * isolate,Handle<Map> map,Handle<JSObject> holder)198 explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map, 199 Handle<JSObject> holder) 200 : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder, 201 kCacheOnReceiver) { 202 #ifdef DEBUG 203 if (Descriptor::kPassLastArgsOnStack) { 204 ZapStackArgumentsRegisterAliases(); 205 } 206 #endif 207 } 208 ~NamedStoreHandlerCompiler()209 virtual ~NamedStoreHandlerCompiler() {} 210 211 void ZapStackArgumentsRegisterAliases(); 212 213 Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, 214 Handle<AccessorInfo> callback, 215 LanguageMode language_mode); 216 Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, 217 const CallOptimization& call_optimization, 218 int accessor_index, Handle<Code> slow_stub); 219 Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name, 220 int accessor_index, 221 int expected_arguments); 222 223 static void GenerateStoreViaSetter(MacroAssembler* masm, Handle<Map> map, 224 Register receiver, Register holder, 225 int accessor_index, int expected_arguments, 226 Register scratch); 227 GenerateStoreViaSetterForDeopt(MacroAssembler * masm)228 static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) { 229 GenerateStoreViaSetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1, 230 no_reg); 231 } 232 233 protected: 234 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 235 Label* miss, ReturnHolder return_what); 236 237 virtual void FrontendFooter(Handle<Name> name, Label* miss); 238 void GenerateRestoreName(Label* label, Handle<Name> name); 239 240 private: 241 static Register value(); 242 }; 243 244 245 class ElementHandlerCompiler : public PropertyHandlerCompiler { 246 public: ElementHandlerCompiler(Isolate * isolate)247 explicit ElementHandlerCompiler(Isolate* isolate) 248 : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC, 249 Handle<Map>::null(), Handle<JSObject>::null(), 250 kCacheOnReceiver) {} 251 ~ElementHandlerCompiler()252 virtual ~ElementHandlerCompiler() {} 253 254 static Handle<Object> GetKeyedLoadHandler(Handle<Map> receiver_map, 255 Isolate* isolate); 256 void CompileElementHandlers(MapHandleList* receiver_maps, 257 List<Handle<Object>>* handlers); 258 }; 259 } // namespace internal 260 } // namespace v8 261 262 #endif // V8_IC_HANDLER_COMPILER_H_ 263