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