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); 23 24 protected: 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 31 virtual ~PropertyHandlerCompiler() {} 32 33 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 34 Label* miss, ReturnHolder return_what) { 35 UNREACHABLE(); 36 return receiver(); 37 } 38 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. 49 void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); } 50 void PushVectorAndSlot(Register vector, Register slot); 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, Handle<Name> name); 102 void set_holder(Handle<JSObject> holder) { holder_ = holder; } 103 Handle<Map> map() const { return map_; } 104 void set_map(Handle<Map> map) { map_ = map; } 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: 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 121 virtual ~NamedLoadHandlerCompiler() {} 122 123 Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index); 124 125 Handle<Code> CompileLoadCallback(Handle<Name> name, 126 Handle<AccessorInfo> 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 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, Handle<AccessorInfo> callback); 184 void GenerateLoadCallback(const CallOptimization& call_optimization, 185 Handle<Map> receiver_map); 186 187 // Helper emits no code if vector-ics are disabled. 188 void InterceptorVectorSlotPush(Register holder_reg); 189 enum PopMode { POP, DISCARD }; 190 void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP); 191 192 void GenerateLoadInterceptor(Register holder_reg); 193 void GenerateLoadInterceptorWithFollowup(LookupIterator* it, 194 Register holder_reg); 195 void GenerateLoadPostInterceptor(LookupIterator* it, Register reg); 196 197 // Generates prototype loading code that uses the objects from the 198 // context we were in when this function was called. If the context 199 // has changed, a jump to miss is performed. This ties the generated 200 // code to a particular context and so must not be used in cases 201 // where the generated code is not allowed to have references to 202 // objects from a context. 203 static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, 204 int index, 205 Register prototype, 206 Label* miss); 207 208 Register scratch3() { return registers_[4]; } 209 }; 210 211 212 class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { 213 public: 214 explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map, 215 Handle<JSObject> holder) 216 : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder, 217 kCacheOnReceiver) {} 218 219 virtual ~NamedStoreHandlerCompiler() {} 220 221 Handle<Code> CompileStoreTransition(Handle<Map> transition, 222 Handle<Name> name); 223 Handle<Code> CompileStoreField(LookupIterator* it); 224 Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, 225 Handle<AccessorInfo> callback, 226 LanguageMode language_mode); 227 Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, 228 const CallOptimization& call_optimization, 229 int accessor_index); 230 Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name, 231 int accessor_index, 232 int expected_arguments); 233 234 static void GenerateStoreViaSetter(MacroAssembler* masm, Handle<Map> map, 235 Register receiver, Register holder, 236 int accessor_index, int expected_arguments, 237 Register scratch); 238 239 static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) { 240 GenerateStoreViaSetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1, 241 no_reg); 242 } 243 244 static void GenerateSlow(MacroAssembler* masm); 245 246 protected: 247 virtual Register FrontendHeader(Register object_reg, Handle<Name> name, 248 Label* miss, ReturnHolder return_what); 249 250 virtual void FrontendFooter(Handle<Name> name, Label* miss); 251 void GenerateRestoreName(Label* label, Handle<Name> name); 252 253 // Pop the vector and slot into appropriate registers, moving the map in 254 // the process. (This is an accomodation for register pressure on ia32). 255 void RearrangeVectorAndSlot(Register current_map, Register destination_map); 256 257 private: 258 void GenerateRestoreName(Handle<Name> name); 259 void GenerateRestoreMap(Handle<Map> transition, Register map_reg, 260 Register scratch, Label* miss); 261 262 void GenerateConstantCheck(Register map_reg, int descriptor, 263 Register value_reg, Register scratch, 264 Label* miss_label); 265 266 bool RequiresFieldTypeChecks(FieldType* field_type) const; 267 void GenerateFieldTypeChecks(FieldType* field_type, Register value_reg, 268 Label* miss_label); 269 270 static Builtins::Name SlowBuiltin(Code::Kind kind) { 271 switch (kind) { 272 case Code::STORE_IC: 273 return Builtins::kStoreIC_Slow; 274 case Code::KEYED_STORE_IC: 275 return Builtins::kKeyedStoreIC_Slow; 276 default: 277 UNREACHABLE(); 278 } 279 return Builtins::kStoreIC_Slow; 280 } 281 282 static Register value(); 283 }; 284 285 286 class ElementHandlerCompiler : public PropertyHandlerCompiler { 287 public: 288 explicit ElementHandlerCompiler(Isolate* isolate) 289 : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC, 290 Handle<Map>::null(), Handle<JSObject>::null(), 291 kCacheOnReceiver) {} 292 293 virtual ~ElementHandlerCompiler() {} 294 295 void CompileElementHandlers(MapHandleList* receiver_maps, 296 CodeHandleList* handlers); 297 298 static void GenerateStoreSlow(MacroAssembler* masm); 299 }; 300 } // namespace internal 301 } // namespace v8 302 303 #endif // V8_IC_HANDLER_COMPILER_H_ 304