V8 Project
handler-compiler.cc
Go to the documentation of this file.
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 #include "src/v8.h"
6 
9 #include "src/ic/ic.h"
10 #include "src/ic/ic-inl.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 
17  Handle<Map> stub_holder,
18  Code::Kind kind,
19  CacheHolderFlag cache_holder,
20  Code::StubType type) {
21  Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
22  Object* probe = stub_holder->FindInCodeCache(*name, flags);
23  if (probe->IsCode()) return handle(Code::cast(probe));
24  return Handle<Code>::null();
25 }
26 
27 
30  Isolate* isolate = name->GetIsolate();
31  Handle<Map> receiver_map = IC::TypeToMap(*type, isolate);
32  if (receiver_map->prototype()->IsNull()) {
33  // TODO(jkummerow/verwaest): If there is no prototype and the property
34  // is nonexistent, introduce a builtin to handle this (fast properties
35  // -> return undefined, dictionary properties -> do negative lookup).
36  return Handle<Code>();
37  }
39  Handle<Map> stub_holder_map =
40  IC::GetHandlerCacheHolder(*type, false, isolate, &flag);
41 
42  // If no dictionary mode objects are present in the prototype chain, the load
43  // nonexistent IC stub can be shared for all names for a given map and we use
44  // the empty string for the map cache in that case. If there are dictionary
45  // mode objects involved, we need to do negative lookups in the stub and
46  // therefore the stub will be specific to the name.
47  Handle<Name> cache_name =
48  receiver_map->is_dictionary_map()
49  ? name
50  : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
51  Handle<Map> current_map = stub_holder_map;
52  Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
53  while (true) {
54  if (current_map->is_dictionary_map()) cache_name = name;
55  if (current_map->prototype()->IsNull()) break;
56  last = handle(JSObject::cast(current_map->prototype()));
57  current_map = handle(last->map());
58  }
59  // Compile the stub that is either shared for all names or
60  // name specific if there are global objects involved.
62  cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
63  if (!handler.is_null()) return handler;
64 
65  NamedLoadHandlerCompiler compiler(isolate, type, last, flag);
66  handler = compiler.CompileLoadNonexistent(cache_name);
67  Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
68  return handler;
69 }
70 
71 
73  Code::StubType type,
75  Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder());
76  Handle<Code> code = GetCodeWithFlags(flags, name);
77  PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name));
78  return code;
79 }
80 
81 
83  type_ = IC::CurrentTypeOf(object, isolate());
84 }
85 
86 
87 #define __ ACCESS_MASM(masm())
88 
89 
92  Label* miss) {
94  int function_index = -1;
95  if (type()->Is(HeapType::String())) {
96  function_index = Context::STRING_FUNCTION_INDEX;
97  } else if (type()->Is(HeapType::Symbol())) {
98  function_index = Context::SYMBOL_FUNCTION_INDEX;
99  } else if (type()->Is(HeapType::Number())) {
100  function_index = Context::NUMBER_FUNCTION_INDEX;
101  } else if (type()->Is(HeapType::Boolean())) {
102  function_index = Context::BOOLEAN_FUNCTION_INDEX;
103  } else {
104  check_type = SKIP_RECEIVER;
105  }
106 
107  if (check_type == CHECK_ALL_MAPS) {
108  GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
109  scratch1(), miss);
110  Object* function = isolate()->native_context()->get(function_index);
111  Object* prototype = JSFunction::cast(function)->instance_prototype();
112  set_type_for_object(handle(prototype, isolate()));
113  object_reg = scratch1();
114  }
115 
116  // Check that the maps starting from the prototype haven't changed.
117  return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
118  miss, check_type);
119 }
120 
121 
122 // Frontend for store uses the name register. It has to be restored before a
123 // miss.
126  Label* miss) {
127  return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
128  miss, SKIP_RECEIVER);
129 }
130 
131 
133  Handle<Name> name) {
134  Label miss;
135  Register reg = FrontendHeader(object_reg, name, &miss);
136  FrontendFooter(name, &miss);
137  return reg;
138 }
139 
140 
142  Label* miss,
143  Register scratch1,
144  Register scratch2) {
145  Register holder_reg;
146  Handle<Map> last_map;
147  if (holder().is_null()) {
148  holder_reg = receiver();
149  last_map = IC::TypeToMap(*type(), isolate());
150  // If |type| has null as its prototype, |holder()| is
151  // Handle<JSObject>::null().
152  DCHECK(last_map->prototype() == isolate()->heap()->null_value());
153  } else {
154  holder_reg = FrontendHeader(receiver(), name, miss);
155  last_map = handle(holder()->map());
156  }
157 
158  if (last_map->is_dictionary_map()) {
159  if (last_map->IsJSGlobalObjectMap()) {
160  Handle<JSGlobalObject> global =
161  holder().is_null()
162  ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
164  GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
165  } else {
166  if (!name->IsUniqueName()) {
167  DCHECK(name->IsString());
168  name = factory()->InternalizeString(Handle<String>::cast(name));
169  }
170  DCHECK(holder().is_null() ||
171  holder()->property_dictionary()->FindEntry(name) ==
173  GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
174  scratch2);
175  }
176  }
177 }
178 
179 
181  FieldIndex field) {
182  Register reg = Frontend(receiver(), name);
183  __ Move(receiver(), reg);
184  LoadFieldStub stub(isolate(), field);
185  GenerateTailCall(masm(), stub.GetCode());
186  return GetCode(kind(), Code::FAST, name);
187 }
188 
189 
191  int constant_index) {
192  Register reg = Frontend(receiver(), name);
193  __ Move(receiver(), reg);
194  LoadConstantStub stub(isolate(), constant_index);
195  GenerateTailCall(masm(), stub.GetCode());
196  return GetCode(kind(), Code::FAST, name);
197 }
198 
199 
201  Handle<Name> name) {
202  Label miss;
203  NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
204  GenerateLoadConstant(isolate()->factory()->undefined_value());
205  FrontendFooter(name, &miss);
206  return GetCode(kind(), Code::FAST, name);
207 }
208 
209 
212  Register reg = Frontend(receiver(), name);
213  GenerateLoadCallback(reg, callback);
214  return GetCode(kind(), Code::FAST, name);
215 }
216 
217 
219  Handle<Name> name, const CallOptimization& call_optimization) {
220  DCHECK(call_optimization.is_simple_api_call());
221  Frontend(receiver(), name);
222  Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
223  GenerateFastApiCall(masm(), call_optimization, receiver_map, receiver(),
224  scratch1(), false, 0, NULL);
225  return GetCode(kind(), Code::FAST, name);
226 }
227 
228 
230  LookupIterator* it) {
231  // So far the most popular follow ups for interceptor loads are FIELD and
232  // ExecutableAccessorInfo, so inline only them. Other cases may be added
233  // later.
234  bool inline_followup = false;
235  switch (it->state()) {
236  case LookupIterator::TRANSITION:
237  UNREACHABLE();
238  case LookupIterator::ACCESS_CHECK:
239  case LookupIterator::INTERCEPTOR:
240  case LookupIterator::JSPROXY:
241  case LookupIterator::NOT_FOUND:
242  break;
243  case LookupIterator::DATA:
244  inline_followup = it->property_details().type() == FIELD;
245  break;
247  Handle<Object> accessors = it->GetAccessors();
248  inline_followup = accessors->IsExecutableAccessorInfo();
249  if (!inline_followup) break;
252  inline_followup = info->getter() != NULL &&
254  isolate(), info, type());
255  }
256  }
257 
258  Register reg = Frontend(receiver(), it->name());
259  if (inline_followup) {
260  // TODO(368): Compile in the whole chain: all the interceptors in
261  // prototypes and ultimate answer.
263  } else {
265  }
266  return GetCode(kind(), Code::FAST, it->name());
267 }
268 
269 
271  LookupIterator* it, Register interceptor_reg) {
272  Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
273 
275  set_holder(real_named_property_holder);
276  Register reg = Frontend(interceptor_reg, it->name());
277 
278  switch (it->state()) {
279  case LookupIterator::ACCESS_CHECK:
280  case LookupIterator::INTERCEPTOR:
281  case LookupIterator::JSPROXY:
282  case LookupIterator::NOT_FOUND:
283  case LookupIterator::TRANSITION:
284  UNREACHABLE();
285  case LookupIterator::DATA: {
286  DCHECK_EQ(FIELD, it->property_details().type());
287  __ Move(receiver(), reg);
288  LoadFieldStub stub(isolate(), it->GetFieldIndex());
289  GenerateTailCall(masm(), stub.GetCode());
290  break;
291  }
294  Handle<ExecutableAccessorInfo>::cast(it->GetAccessors());
295  DCHECK_NE(NULL, info->getter());
296  GenerateLoadCallback(reg, info);
297  }
298 }
299 
300 
303  Frontend(receiver(), name);
304  GenerateLoadViaGetter(masm(), type(), receiver(), getter);
305  return GetCode(kind(), Code::FAST, name);
306 }
307 
308 
309 // TODO(verwaest): Cleanup. holder() is actually the receiver.
311  Handle<Map> transition, Handle<Name> name) {
312  Label miss, slow;
313 
314  // Ensure no transitions to deprecated maps are followed.
315  __ CheckMapDeprecated(transition, scratch1(), &miss);
316 
317  // Check that we are allowed to write this.
318  bool is_nonexistent = holder()->map() == transition->GetBackPointer();
319  if (is_nonexistent) {
320  // Find the top object.
321  Handle<JSObject> last;
322  PrototypeIterator iter(isolate(), holder());
323  while (!iter.IsAtEnd()) {
325  iter.Advance();
326  }
327  if (!last.is_null()) set_holder(last);
328  NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
329  } else {
330  FrontendHeader(receiver(), name, &miss);
331  DCHECK(holder()->HasFastProperties());
332  }
333 
334  GenerateStoreTransition(transition, name, receiver(), this->name(), value(),
335  scratch1(), scratch2(), scratch3(), &miss, &slow);
336 
337  GenerateRestoreName(&miss, name);
338  TailCallBuiltin(masm(), MissBuiltin(kind()));
339 
340  GenerateRestoreName(&slow, name);
341  TailCallBuiltin(masm(), SlowBuiltin(kind()));
342  return GetCode(kind(), Code::FAST, name);
343 }
344 
345 
347  Label miss;
348  GenerateStoreField(it, value(), &miss);
349  __ bind(&miss);
350  TailCallBuiltin(masm(), MissBuiltin(kind()));
351  return GetCode(kind(), Code::FAST, it->name());
352 }
353 
354 
357  Frontend(receiver(), name);
358  GenerateStoreViaSetter(masm(), type(), receiver(), setter);
359 
360  return GetCode(kind(), Code::FAST, name);
361 }
362 
363 
366  const CallOptimization& call_optimization) {
367  Frontend(receiver(), name);
368  Register values[] = {value()};
369  GenerateFastApiCall(masm(), call_optimization, handle(object->map()),
370  receiver(), scratch1(), true, 1, values);
371  return GetCode(kind(), Code::FAST, name);
372 }
373 
374 
375 #undef __
376 
377 
379  MapHandleList* receiver_maps, CodeHandleList* handlers) {
380  for (int i = 0; i < receiver_maps->length(); ++i) {
381  Handle<Map> receiver_map = receiver_maps->at(i);
382  Handle<Code> cached_stub;
383 
384  if ((receiver_map->instance_type() & kNotStringTag) == 0) {
385  cached_stub = isolate()->builtins()->KeyedLoadIC_String();
386  } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
387  cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
388  } else {
389  bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
390  ElementsKind elements_kind = receiver_map->elements_kind();
391  if (receiver_map->has_indexed_interceptor()) {
392  cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
393  } else if (IsSloppyArgumentsElements(elements_kind)) {
394  cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
395  } else if (IsFastElementsKind(elements_kind) ||
396  IsExternalArrayElementsKind(elements_kind) ||
397  IsFixedTypedArrayElementsKind(elements_kind)) {
398  cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind)
399  .GetCode();
400  } else {
401  DCHECK(elements_kind == DICTIONARY_ELEMENTS);
402  cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
403  }
404  }
405 
406  handlers->Add(cached_stub);
407  }
408 }
409 }
410 } // namespace v8::internal
The superclass of all JavaScript values and objects.
Definition: v8.h:1440
static bool IsCompatibleReceiverType(Isolate *isolate, Handle< AccessorInfo > info, Handle< HeapType > type)
Definition: objects.cc:467
static Flags ComputeHandlerFlags(Kind handler_kind, StubType type=NORMAL, CacheHolderFlag holder=kCacheOnReceiver)
Definition: objects-inl.h:4975
void CompileElementHandlers(MapHandleList *receiver_maps, CodeHandleList *handlers)
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
bool is_null() const
Definition: handles.h:124
static Handle< T > null()
Definition: handles.h:123
static const int kNotFound
Definition: objects.h:3283
static Handle< Map > TypeToMap(HeapType *type, Isolate *isolate)
Definition: ic.cc:719
static Handle< HeapType > CurrentTypeOf(Handle< Object > object, Isolate *isolate)
Definition: ic.cc:712
static Handle< Map > GetHandlerCacheHolder(HeapType *type, bool receiver_is_holder, Isolate *isolate, CacheHolderFlag *flag)
Definition: ic-inl.h:177
Factory * factory()
Definition: isolate.h:982
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:17
T & at(int i) const
Definition: list.h:69
static void UpdateCodeCache(Handle< Map > map, Handle< Name > name, Handle< Code > code)
Definition: objects.cc:7030
static Handle< Code > ComputeLoadNonexistent(Handle< Name > name, Handle< HeapType > type)
Handle< Code > CompileLoadCallback(Handle< Name > name, Handle< ExecutableAccessorInfo > callback)
virtual void FrontendFooter(Handle< Name > name, Label *miss)
Handle< Code > CompileLoadField(Handle< Name > name, FieldIndex index)
Handle< Code > CompileLoadNonexistent(Handle< Name > name)
static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler *masm, int index, Register prototype, Label *miss)
void GenerateLoadInterceptorWithFollowup(LookupIterator *it, Register holder_reg)
Handle< Code > CompileLoadInterceptor(LookupIterator *it)
virtual Register FrontendHeader(Register object_reg, Handle< Name > name, Label *miss)
void GenerateLoadConstant(Handle< Object > value)
Handle< Code > CompileLoadViaGetter(Handle< Name > name, Handle< JSFunction > getter)
void GenerateLoadInterceptor(Register holder_reg)
Handle< Code > CompileLoadConstant(Handle< Name > name, int constant_index)
void GenerateLoadPostInterceptor(LookupIterator *it, Register reg)
static void GenerateLoadViaGetter(MacroAssembler *masm, Handle< HeapType > type, Register receiver, Handle< JSFunction > getter)
void GenerateLoadCallback(Register reg, Handle< ExecutableAccessorInfo > callback)
Handle< Code > CompileStoreViaSetter(Handle< JSObject > object, Handle< Name > name, Handle< JSFunction > setter)
void GenerateStoreField(LookupIterator *lookup, Register value_reg, Label *miss_label)
Handle< Code > CompileStoreCallback(Handle< JSObject > object, Handle< Name > name, Handle< ExecutableAccessorInfo > callback)
void GenerateRestoreName(Label *label, Handle< Name > name)
Handle< Code > CompileStoreField(LookupIterator *it)
static Builtins::Name SlowBuiltin(Code::Kind kind)
void GenerateStoreTransition(Handle< Map > transition, Handle< Name > name, Register receiver_reg, Register name_reg, Register value_reg, Register scratch1, Register scratch2, Register scratch3, Label *miss_label, Label *slow)
static void GenerateStoreViaSetter(MacroAssembler *masm, Handle< HeapType > type, Register receiver, Handle< JSFunction > setter)
virtual Register FrontendHeader(Register object_reg, Handle< Name > name, Label *miss)
Handle< Code > CompileStoreTransition(Handle< Map > transition, Handle< Name > name)
Handle< JSObject > holder() const
void NonexistentFrontendHeader(Handle< Name > name, Label *miss, Register scratch1, Register scratch2)
void set_type_for_object(Handle< Object > object)
virtual void FrontendFooter(Handle< Name > name, Label *miss)
Register CheckPrototypes(Register object_reg, Register holder_reg, Register scratch1, Register scratch2, Handle< Name > name, Label *miss, PrototypeCheckType check=CHECK_ALL_MAPS)
Handle< Code > GetCode(Code::Kind kind, Code::StubType type, Handle< Name > name)
Handle< HeapType > type() const
static Handle< Code > Find(Handle< Name > name, Handle< Map > map, Code::Kind kind, CacheHolderFlag cache_holder, Code::StubType type)
static void GenerateDictionaryNegativeLookup(MacroAssembler *masm, Label *miss_label, Register receiver, Handle< Name > name, Register r0, Register r1)
static void GenerateFastApiCall(MacroAssembler *masm, const CallOptimization &optimization, Handle< Map > receiver_map, Register receiver, Register scratch, bool is_store, int argc, Register *values)
Register Frontend(Register object_reg, Handle< Name > name)
static void GenerateCheckPropertyCell(MacroAssembler *masm, Handle< JSGlobalObject > global, Handle< Name > name, Register scratch, Label *miss)
virtual Register FrontendHeader(Register object_reg, Handle< Name > name, Label *miss)
void set_holder(Handle< JSObject > holder)
A class to uniformly access the prototype of any Object and walk its prototype chain.
Definition: prototype.h:25
bool IsAtEnd(WhereToEnd where_to_end=END_AT_NULL) const
Definition: prototype.h:99
Object * GetCurrent() const
Definition: prototype.h:62
#define PROFILE(IsolateGetter, Call)
Definition: cpu-profiler.h:181
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in name
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define __
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK_NE(v1, v2)
Definition: logging.h:207
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
IN DWORD64 OUT PDWORD64 OUT PIMAGEHLP_SYMBOL64 Symbol
bool IsSloppyArgumentsElements(ElementsKind kind)
Definition: elements-kind.h:90
bool Is(Object *obj)
bool IsExternalArrayElementsKind(ElementsKind kind)
Definition: elements-kind.h:95
const uint32_t kNotStringTag
Definition: objects.h:545
@ JS_ARRAY_TYPE
Definition: objects.h:738
@ FIRST_JS_RECEIVER_TYPE
Definition: objects.h:772
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
bool IsFastElementsKind(ElementsKind kind)
kFeedbackVectorOffset flag
Definition: objects-inl.h:5418
bool IsFixedTypedArrayElementsKind(ElementsKind kind)
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20