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 PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; 17 enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING }; 18 19 class PropertyHandlerCompiler : public PropertyAccessCompiler { 20 public: 21 static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind, 22 CacheHolderFlag cache_holder, Code::StubType type); 23 24 protected: PropertyHandlerCompiler(Isolate * isolate,Code::Kind kind,Handle<Map> map,Handle<JSObject> holder,CacheHolderFlag cache_holder)25 PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map, 26 Handle<JSObject> holder, CacheHolderFlag cache_holder) 27 : PropertyAccessCompiler(isolate, kind, cache_holder), 28 map_(map), 29 holder_(holder) {} 30 ~PropertyHandlerCompiler()31 virtual ~PropertyHandlerCompiler() {} 32 FrontendHeader(Register object_reg,Handle<Name> name,Label * miss,ReturnHolder return_what)33 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 34 Label* miss, ReturnHolder return_what) { 35 UNREACHABLE(); 36 return receiver(); 37 } 38 FrontendFooter(Handle<Name> name,Label * miss)39 virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); } 40 41 // Frontend loads from receiver(), returns holder register which may be 42 // different. 43 Register Frontend(Handle<Name> name); 44 void NonexistentFrontendHeader(Handle<Name> name, Label* miss, 45 Register scratch1, Register scratch2); 46 47 // When FLAG_vector_ics is true, handlers that have the possibility of missing 48 // will need to save and pass these to miss handlers. PushVectorAndSlot()49 void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); } 50 void PushVectorAndSlot(Register vector, Register slot); PopVectorAndSlot()51 void PopVectorAndSlot() { PopVectorAndSlot(vector(), slot()); } 52 void PopVectorAndSlot(Register vector, Register slot); 53 54 void DiscardVectorAndSlot(); 55 56 // TODO(verwaest): Make non-static. 57 static void GenerateApiAccessorCall(MacroAssembler* masm, 58 const CallOptimization& optimization, 59 Handle<Map> receiver_map, 60 Register receiver, Register scratch, 61 bool is_store, Register store_parameter, 62 Register accessor_holder, 63 int accessor_index); 64 65 // Helper function used to check that the dictionary doesn't contain 66 // the property. This function may return false negatives, so miss_label 67 // must always call a backup property check that is complete. 68 // This function is safe to call if the receiver has fast properties. 69 // Name must be unique and receiver must be a heap object. 70 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, 71 Label* miss_label, 72 Register receiver, 73 Handle<Name> name, Register r0, 74 Register r1); 75 76 // Generate code to check that a global property cell is empty. Create 77 // the property cell at compilation time if no cell exists for the 78 // property. 79 static void GenerateCheckPropertyCell(MacroAssembler* masm, 80 Handle<JSGlobalObject> global, 81 Handle<Name> name, Register scratch, 82 Label* miss); 83 84 // Generates code that verifies that the property holder has not changed 85 // (checking maps of objects in the prototype chain for fast and global 86 // objects or doing negative lookup for slow objects, ensures that the 87 // property cells for global objects are still empty) and checks that the map 88 // of the holder has not changed. If necessary the function also generates 89 // code for security check in case of global object holders. Helps to make 90 // sure that the current IC is still valid. 91 // 92 // The scratch and holder registers are always clobbered, but the object 93 // register is only clobbered if it the same as the holder register. The 94 // function returns a register containing the holder - either object_reg or 95 // holder_reg. 96 Register CheckPrototypes(Register object_reg, Register holder_reg, 97 Register scratch1, Register scratch2, 98 Handle<Name> name, Label* miss, 99 PrototypeCheckType check, ReturnHolder return_what); 100 101 Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name); set_holder(Handle<JSObject> holder)102 void set_holder(Handle<JSObject> holder) { holder_ = holder; } map()103 Handle<Map> map() const { return map_; } set_map(Handle<Map> map)104 void set_map(Handle<Map> map) { map_ = map; } holder()105 Handle<JSObject> holder() const { return holder_; } 106 107 private: 108 Handle<Map> map_; 109 Handle<JSObject> holder_; 110 }; 111 112 113 class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { 114 public: NamedLoadHandlerCompiler(Isolate * isolate,Handle<Map> map,Handle<JSObject> holder,CacheHolderFlag cache_holder)115 NamedLoadHandlerCompiler(Isolate* isolate, Handle<Map> map, 116 Handle<JSObject> holder, 117 CacheHolderFlag cache_holder) 118 : PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder, 119 cache_holder) {} 120 ~NamedLoadHandlerCompiler()121 virtual ~NamedLoadHandlerCompiler() {} 122 123 Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index); 124 125 Handle<Code> CompileLoadCallback(Handle<Name> name, 126 Handle<ExecutableAccessorInfo> callback); 127 128 Handle<Code> CompileLoadCallback(Handle<Name> name, 129 const CallOptimization& call_optimization, 130 int accessor_index); 131 132 Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index); 133 134 // The LookupIterator is used to perform a lookup behind the interceptor. If 135 // the iterator points to a LookupIterator::PROPERTY, its access will be 136 // inlined. 137 Handle<Code> CompileLoadInterceptor(LookupIterator* it); 138 139 Handle<Code> CompileLoadViaGetter(Handle<Name> name, int accessor_index, 140 int expected_arguments); 141 142 Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name, 143 bool is_configurable); 144 145 // Static interface 146 static Handle<Code> ComputeLoadNonexistent(Handle<Name> name, 147 Handle<Map> map); 148 149 static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map, 150 Register receiver, Register holder, 151 int accessor_index, int expected_arguments, 152 Register scratch); 153 GenerateLoadViaGetterForDeopt(MacroAssembler * masm)154 static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) { 155 GenerateLoadViaGetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1, 156 no_reg); 157 } 158 159 static void GenerateLoadFunctionPrototype(MacroAssembler* masm, 160 Register receiver, 161 Register scratch1, 162 Register scratch2, 163 Label* miss_label); 164 165 // These constants describe the structure of the interceptor arguments on the 166 // stack. The arguments are pushed by the (platform-specific) 167 // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and 168 // LoadWithInterceptor. 169 static const int kInterceptorArgsNameIndex = 0; 170 static const int kInterceptorArgsThisIndex = 1; 171 static const int kInterceptorArgsHolderIndex = 2; 172 static const int kInterceptorArgsLength = 3; 173 174 protected: 175 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 176 Label* miss, ReturnHolder return_what); 177 178 virtual void FrontendFooter(Handle<Name> name, Label* miss); 179 180 private: 181 Handle<Code> CompileLoadNonexistent(Handle<Name> name); 182 void GenerateLoadConstant(Handle<Object> value); 183 void GenerateLoadCallback(Register reg, 184 Handle<ExecutableAccessorInfo> callback); 185 void GenerateLoadCallback(const CallOptimization& call_optimization, 186 Handle<Map> receiver_map); 187 188 // Helper emits no code if vector-ics are disabled. 189 void InterceptorVectorSlotPush(Register holder_reg); 190 enum PopMode { POP, DISCARD }; 191 void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP); 192 193 void GenerateLoadInterceptor(Register holder_reg); 194 void GenerateLoadInterceptorWithFollowup(LookupIterator* it, 195 Register holder_reg); 196 void GenerateLoadPostInterceptor(LookupIterator* it, Register reg); 197 198 // Generates prototype loading code that uses the objects from the 199 // context we were in when this function was called. If the context 200 // has changed, a jump to miss is performed. This ties the generated 201 // code to a particular context and so must not be used in cases 202 // where the generated code is not allowed to have references to 203 // objects from a context. 204 static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, 205 int index, 206 Register prototype, 207 Label* miss); 208 209 scratch4()210 Register scratch4() { return registers_[5]; } 211 }; 212 213 214 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { 215 public: NamedStoreHandlerCompiler(Isolate * isolate,Handle<Map> map,Handle<JSObject> holder)216 explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map, 217 Handle<JSObject> holder) 218 : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder, 219 kCacheOnReceiver) {} 220 ~NamedStoreHandlerCompiler()221 virtual ~NamedStoreHandlerCompiler() {} 222 223 Handle<Code> CompileStoreTransition(Handle<Map> transition, 224 Handle<Name> name); 225 Handle<Code> CompileStoreField(LookupIterator* it); 226 Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, 227 Handle<ExecutableAccessorInfo> callback); 228 Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, 229 const CallOptimization& call_optimization, 230 int accessor_index); 231 Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name, 232 int accessor_index, 233 int expected_arguments); 234 Handle<Code> CompileStoreInterceptor(Handle<Name> name); 235 236 static void GenerateStoreViaSetter(MacroAssembler* masm, Handle<Map> map, 237 Register receiver, Register holder, 238 int accessor_index, int expected_arguments, 239 Register scratch); 240 GenerateStoreViaSetterForDeopt(MacroAssembler * masm)241 static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) { 242 GenerateStoreViaSetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1, 243 no_reg); 244 } 245 246 static void GenerateSlow(MacroAssembler* masm); 247 248 protected: 249 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 250 Label* miss, ReturnHolder return_what); 251 252 virtual void FrontendFooter(Handle<Name> name, Label* miss); 253 void GenerateRestoreName(Label* label, Handle<Name> name); 254 255 // Pop the vector and slot into appropriate registers, moving the map in 256 // the process. (This is an accomodation for register pressure on ia32). 257 void RearrangeVectorAndSlot(Register current_map, Register destination_map); 258 259 private: 260 void GenerateRestoreName(Handle<Name> name); 261 void GenerateRestoreMap(Handle<Map> transition, Register map_reg, 262 Register scratch, Label* miss); 263 264 void GenerateConstantCheck(Register map_reg, int descriptor, 265 Register value_reg, Register scratch, 266 Label* miss_label); 267 268 bool RequiresFieldTypeChecks(HeapType* field_type) const; 269 void GenerateFieldTypeChecks(HeapType* field_type, Register value_reg, 270 Label* miss_label); 271 SlowBuiltin(Code::Kind kind)272 static Builtins::Name SlowBuiltin(Code::Kind kind) { 273 switch (kind) { 274 case Code::STORE_IC: 275 return Builtins::kStoreIC_Slow; 276 case Code::KEYED_STORE_IC: 277 return Builtins::kKeyedStoreIC_Slow; 278 default: 279 UNREACHABLE(); 280 } 281 return Builtins::kStoreIC_Slow; 282 } 283 284 static Register value(); 285 }; 286 287 288 class ElementHandlerCompiler : public PropertyHandlerCompiler { 289 public: ElementHandlerCompiler(Isolate * isolate)290 explicit ElementHandlerCompiler(Isolate* isolate) 291 : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC, 292 Handle<Map>::null(), Handle<JSObject>::null(), 293 kCacheOnReceiver) {} 294 ~ElementHandlerCompiler()295 virtual ~ElementHandlerCompiler() {} 296 297 void CompileElementHandlers(MapHandleList* receiver_maps, 298 CodeHandleList* handlers, 299 LanguageMode language_mode); 300 301 static void GenerateStoreSlow(MacroAssembler* masm); 302 }; 303 } // namespace internal 304 } // namespace v8 305 306 #endif // V8_IC_HANDLER_COMPILER_H_ 307