V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
accessor-assembler.cc
1 // Copyright 2016 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/ic/accessor-assembler.h"
6 
7 #include "src/ast/ast.h"
8 #include "src/code-factory.h"
9 #include "src/code-stubs.h"
10 #include "src/counters.h"
11 #include "src/ic/handler-configuration.h"
12 #include "src/ic/ic.h"
13 #include "src/ic/keyed-store-generic.h"
14 #include "src/ic/stub-cache.h"
15 #include "src/objects-inl.h"
16 #include "src/objects/module.h"
17 #include "src/objects/smi.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 using compiler::CodeAssemblerState;
23 using compiler::Node;
24 template <typename T>
25 using TNode = compiler::TNode<T>;
26 template <typename T>
27 using SloppyTNode = compiler::SloppyTNode<T>;
28 
30 
31 // Loads dataX field from the DataHandler object.
32 TNode<MaybeObject> AccessorAssembler::LoadHandlerDataField(
33  SloppyTNode<DataHandler> handler, int data_index) {
34 #ifdef DEBUG
35  TNode<Map> handler_map = LoadMap(handler);
36  TNode<Int32T> instance_type = LoadMapInstanceType(handler_map);
37 #endif
38  CSA_ASSERT(this,
39  Word32Or(InstanceTypeEqual(instance_type, LOAD_HANDLER_TYPE),
40  InstanceTypeEqual(instance_type, STORE_HANDLER_TYPE)));
41  int offset = 0;
42  int minimum_size = 0;
43  switch (data_index) {
44  case 1:
45  offset = DataHandler::kData1Offset;
46  minimum_size = DataHandler::kSizeWithData1;
47  break;
48  case 2:
49  offset = DataHandler::kData2Offset;
50  minimum_size = DataHandler::kSizeWithData2;
51  break;
52  case 3:
53  offset = DataHandler::kData3Offset;
54  minimum_size = DataHandler::kSizeWithData3;
55  break;
56  default:
57  UNREACHABLE();
58  break;
59  }
60  USE(minimum_size);
61  CSA_ASSERT(this, UintPtrGreaterThanOrEqual(
62  LoadMapInstanceSizeInWords(handler_map),
63  IntPtrConstant(minimum_size / kPointerSize)));
64  return LoadMaybeWeakObjectField(handler, offset);
65 }
66 
67 TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase(
68  Node* slot, Node* vector, Node* receiver_map, Label* if_handler,
69  TVariable<MaybeObject>* var_handler, Label* if_miss) {
70  Comment("TryMonomorphicCase");
71  DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
72 
73  // TODO(ishell): add helper class that hides offset computations for a series
74  // of loads.
75  CSA_ASSERT(this, IsFeedbackVector(vector), vector);
76  int32_t header_size = FeedbackVector::kFeedbackSlotsOffset - kHeapObjectTag;
77  // Adding |header_size| with a separate IntPtrAdd rather than passing it
78  // into ElementOffsetFromIndex() allows it to be folded into a single
79  // [base, index, offset] indirect memory access on x64.
80  Node* offset = ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, SMI_PARAMETERS);
81  TNode<MaybeObject> feedback = ReinterpretCast<MaybeObject>(
82  Load(MachineType::AnyTagged(), vector,
83  IntPtrAdd(offset, IntPtrConstant(header_size))));
84 
85  // Try to quickly handle the monomorphic case without knowing for sure
86  // if we have a weak reference in feedback.
87  GotoIf(IsNotWeakReferenceTo(feedback, CAST(receiver_map)), if_miss);
88 
89  TNode<MaybeObject> handler = UncheckedCast<MaybeObject>(
90  Load(MachineType::AnyTagged(), vector,
91  IntPtrAdd(offset, IntPtrConstant(header_size + kPointerSize))));
92 
93  *var_handler = handler;
94  Goto(if_handler);
95  return feedback;
96 }
97 
98 void AccessorAssembler::HandlePolymorphicCase(
99  Node* receiver_map, TNode<WeakFixedArray> feedback, Label* if_handler,
100  TVariable<MaybeObject>* var_handler, Label* if_miss,
101  int min_feedback_capacity) {
102  Comment("HandlePolymorphicCase");
103  DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
104 
105  // Deferred so the unrolled case can omit frame construction in bytecode
106  // handler.
107  Label loop(this, Label::kDeferred);
108 
109  // Iterate {feedback} array.
110  const int kEntrySize = 2;
111 
112  // Loading feedback's length is delayed until we need it when looking past
113  // the first {min_feedback_capacity} (map, handler) pairs.
114  Node* length = nullptr;
115  CSA_ASSERT(this, SmiGreaterThanOrEqual(
116  LoadWeakFixedArrayLength(feedback),
117  SmiConstant(min_feedback_capacity * kEntrySize)));
118 
119  const int kUnrolledIterations = IC::kMaxPolymorphicMapCount;
120  for (int i = 0; i < kUnrolledIterations; i++) {
121  int map_index = i * kEntrySize;
122  int handler_index = i * kEntrySize + 1;
123 
124  if (i >= min_feedback_capacity) {
125  if (length == nullptr) length = LoadWeakFixedArrayLength(feedback);
126  GotoIf(SmiGreaterThanOrEqual(SmiConstant(handler_index), CAST(length)),
127  if_miss);
128  }
129 
130  Label next_entry(this);
131  TNode<MaybeObject> maybe_cached_map =
132  LoadWeakFixedArrayElement(feedback, map_index);
133  CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map));
134  GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)),
135  &next_entry);
136 
137  // Found, now call handler.
138  TNode<MaybeObject> handler =
139  LoadWeakFixedArrayElement(feedback, handler_index);
140  *var_handler = handler;
141  Goto(if_handler);
142 
143  BIND(&next_entry);
144  }
145  Goto(&loop);
146 
147  // Loop from {kUnrolledIterations}*kEntrySize to {length}.
148  BIND(&loop);
149  Node* start_index = IntPtrConstant(kUnrolledIterations * kEntrySize);
150  Node* end_index = LoadAndUntagWeakFixedArrayLength(feedback);
151  BuildFastLoop(
152  start_index, end_index,
153  [this, receiver_map, feedback, if_handler, var_handler](Node* index) {
154  Label next_entry(this);
155  TNode<MaybeObject> maybe_cached_map =
156  LoadWeakFixedArrayElement(feedback, index);
157  CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map));
158  GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)),
159  &next_entry);
160 
161  // Found, now call handler.
162  TNode<MaybeObject> handler =
163  LoadWeakFixedArrayElement(feedback, index, kPointerSize);
164  *var_handler = handler;
165  Goto(if_handler);
166 
167  BIND(&next_entry);
168  },
169  kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
170  // The loop falls through if no handler was found.
171  Goto(if_miss);
172 }
173 
174 void AccessorAssembler::HandleLoadICHandlerCase(
175  const LoadICParameters* p, TNode<Object> handler, Label* miss,
176  ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
177  ElementSupport support_elements) {
178  Comment("have_handler");
179 
180  VARIABLE(var_holder, MachineRepresentation::kTagged, p->holder);
181  VARIABLE(var_smi_handler, MachineRepresentation::kTagged, handler);
182 
183  Variable* vars[] = {&var_holder, &var_smi_handler};
184  Label if_smi_handler(this, 2, vars);
185  Label try_proto_handler(this, Label::kDeferred),
186  call_handler(this, Label::kDeferred);
187 
188  Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
189 
190  // |handler| is a Smi, encoding what to do. See SmiHandler methods
191  // for the encoding format.
192  BIND(&if_smi_handler);
193  {
194  HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
195  handler, miss, exit_point, on_nonexistent,
196  support_elements);
197  }
198 
199  BIND(&try_proto_handler);
200  {
201  GotoIf(IsCodeMap(LoadMap(CAST(handler))), &call_handler);
202  HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler,
203  &if_smi_handler, miss, exit_point, ic_mode);
204  }
205 
206  BIND(&call_handler);
207  {
208  exit_point->ReturnCallStub(LoadWithVectorDescriptor{}, handler, p->context,
209  p->receiver, p->name, p->slot, p->vector);
210  }
211 }
212 
213 void AccessorAssembler::HandleLoadCallbackProperty(const LoadICParameters* p,
214  TNode<JSObject> holder,
215  TNode<WordT> handler_word,
216  ExitPoint* exit_point) {
217  Comment("native_data_property_load");
218  TNode<IntPtrT> descriptor =
219  Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
220 
221  Label runtime(this, Label::kDeferred);
222  Callable callable = CodeFactory::ApiGetter(isolate());
223  TNode<AccessorInfo> accessor_info =
224  CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
225 
226  GotoIf(IsRuntimeCallStatsEnabled(), &runtime);
227  exit_point->ReturnCallStub(callable, p->context, p->receiver, holder,
228  accessor_info);
229 
230  BIND(&runtime);
231  exit_point->ReturnCallRuntime(Runtime::kLoadCallbackProperty, p->context,
232  p->receiver, holder, accessor_info, p->name);
233 }
234 
235 void AccessorAssembler::HandleLoadAccessor(
236  const LoadICParameters* p, TNode<CallHandlerInfo> call_handler_info,
237  TNode<WordT> handler_word, TNode<DataHandler> handler,
238  TNode<IntPtrT> handler_kind, ExitPoint* exit_point) {
239  Comment("api_getter");
240  Label runtime(this, Label::kDeferred);
241  // Context is stored either in data2 or data3 field depending on whether
242  // the access check is enabled for this handler or not.
243  TNode<MaybeObject> maybe_context = Select<MaybeObject>(
244  IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
245  [=] { return LoadHandlerDataField(handler, 3); },
246  [=] { return LoadHandlerDataField(handler, 2); });
247 
248  CSA_ASSERT(this, IsWeakOrCleared(maybe_context));
249  CSA_CHECK(this, IsNotCleared(maybe_context));
250  TNode<Object> context = GetHeapObjectAssumeWeak(maybe_context);
251 
252  GotoIf(IsRuntimeCallStatsEnabled(), &runtime);
253  {
254  TNode<Foreign> foreign = CAST(
255  LoadObjectField(call_handler_info, CallHandlerInfo::kJsCallbackOffset));
256  TNode<WordT> callback = TNode<WordT>::UncheckedCast(LoadObjectField(
257  foreign, Foreign::kForeignAddressOffset, MachineType::Pointer()));
258  TNode<Object> data =
259  LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
260 
261  VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver);
262  Label load(this);
263  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
264  &load);
265 
266  CSA_ASSERT(
267  this,
268  WordEqual(handler_kind,
269  IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)));
270 
271  api_holder.Bind(LoadMapPrototype(LoadMap(p->receiver)));
272  Goto(&load);
273 
274  BIND(&load);
275  Callable callable = CodeFactory::CallApiCallback(isolate(), 0);
276  exit_point->Return(CallStub(callable, nullptr, context, data,
277  api_holder.value(), callback, p->receiver));
278  }
279 
280  BIND(&runtime);
281  exit_point->ReturnCallRuntime(Runtime::kLoadAccessorProperty, context,
282  p->receiver, SmiTag(handler_kind),
283  call_handler_info);
284 }
285 
286 void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
287  Variable* var_double_value,
288  Label* rebox_double,
289  ExitPoint* exit_point) {
290  Comment("field_load");
291  Node* index = DecodeWord<LoadHandler::FieldIndexBits>(handler_word);
292  Node* offset = IntPtrMul(index, IntPtrConstant(kPointerSize));
293 
294  Label inobject(this), out_of_object(this);
295  Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
296  &out_of_object);
297 
298  BIND(&inobject);
299  {
300  Label is_double(this);
301  GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
302  exit_point->Return(LoadObjectField(holder, offset));
303 
304  BIND(&is_double);
305  if (FLAG_unbox_double_fields) {
306  var_double_value->Bind(
307  LoadObjectField(holder, offset, MachineType::Float64()));
308  } else {
309  Node* mutable_heap_number = LoadObjectField(holder, offset);
310  var_double_value->Bind(LoadHeapNumberValue(mutable_heap_number));
311  }
312  Goto(rebox_double);
313  }
314 
315  BIND(&out_of_object);
316  {
317  Label is_double(this);
318  Node* properties = LoadFastProperties(holder);
319  Node* value = LoadObjectField(properties, offset);
320  GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
321  exit_point->Return(value);
322 
323  BIND(&is_double);
324  var_double_value->Bind(LoadHeapNumberValue(value));
325  Goto(rebox_double);
326  }
327 }
328 
329 TNode<Object> AccessorAssembler::LoadDescriptorValue(
330  TNode<Map> map, TNode<IntPtrT> descriptor_entry) {
331  return CAST(LoadDescriptorValueOrFieldType(map, descriptor_entry));
332 }
333 
334 TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType(
335  TNode<Map> map, TNode<IntPtrT> descriptor_entry) {
336  TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
337  return LoadFieldTypeByDescriptorEntry(descriptors, descriptor_entry);
338 }
339 
340 void AccessorAssembler::HandleLoadICSmiHandlerCase(
341  const LoadICParameters* p, Node* holder, SloppyTNode<Smi> smi_handler,
342  SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point,
343  OnNonExistent on_nonexistent, ElementSupport support_elements) {
344  VARIABLE(var_double_value, MachineRepresentation::kFloat64);
345  Label rebox_double(this, &var_double_value);
346 
347  TNode<WordT> handler_word = SmiUntag(smi_handler);
348  TNode<IntPtrT> handler_kind =
349  Signed(DecodeWord<LoadHandler::KindBits>(handler_word));
350  if (support_elements == kSupportElements) {
351  Label if_element(this), if_indexed_string(this), if_property(this);
352  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)),
353  &if_element);
354  Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kIndexedString)),
355  &if_indexed_string, &if_property);
356 
357  BIND(&if_element);
358  Comment("element_load");
359  Node* intptr_index = TryToIntptr(p->name, miss);
360  Node* elements = LoadElements(holder);
361  Node* is_jsarray_condition =
362  IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
363  Node* elements_kind =
364  DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
365  Label if_hole(this), unimplemented_elements_kind(this),
366  if_oob(this, Label::kDeferred);
367  EmitElementLoad(holder, elements, elements_kind, intptr_index,
368  is_jsarray_condition, &if_hole, &rebox_double,
369  &var_double_value, &unimplemented_elements_kind, &if_oob,
370  miss, exit_point);
371 
372  BIND(&unimplemented_elements_kind);
373  {
374  // Smi handlers should only be installed for supported elements kinds.
375  // Crash if we get here.
376  DebugBreak();
377  Goto(miss);
378  }
379 
380  BIND(&if_oob);
381  {
382  Comment("out of bounds elements access");
383  Label return_undefined(this);
384 
385  // Check if we're allowed to handle OOB accesses.
386  Node* allow_out_of_bounds =
387  IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
388  GotoIfNot(allow_out_of_bounds, miss);
389 
390  // Negative indices aren't valid array indices (according to
391  // the ECMAScript specification), and are stored as properties
392  // in V8, not elements. So we cannot handle them here, except
393  // in case of typed arrays, where integer indexed properties
394  // aren't looked up in the prototype chain.
395  GotoIf(IsJSTypedArray(holder), &return_undefined);
396  GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), miss);
397 
398  // For all other receivers we need to check that the prototype chain
399  // doesn't contain any elements.
400  BranchIfPrototypesHaveNoElements(LoadMap(holder), &return_undefined,
401  miss);
402 
403  BIND(&return_undefined);
404  exit_point->Return(UndefinedConstant());
405  }
406 
407  BIND(&if_hole);
408  {
409  Comment("convert hole");
410  GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
411  GotoIf(IsNoElementsProtectorCellInvalid(), miss);
412  exit_point->Return(UndefinedConstant());
413  }
414 
415  BIND(&if_indexed_string);
416  {
417  Label if_oob(this, Label::kDeferred);
418 
419  Comment("indexed string");
420  Node* intptr_index = TryToIntptr(p->name, miss);
421  Node* length = LoadStringLengthAsWord(holder);
422  GotoIf(UintPtrGreaterThanOrEqual(intptr_index, length), &if_oob);
423  TNode<Int32T> code = StringCharCodeAt(holder, intptr_index);
424  TNode<String> result = StringFromSingleCharCode(code);
425  Return(result);
426 
427  BIND(&if_oob);
428  Node* allow_out_of_bounds =
429  IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
430  GotoIfNot(allow_out_of_bounds, miss);
431  GotoIf(IsNoElementsProtectorCellInvalid(), miss);
432  Return(UndefinedConstant());
433  }
434 
435  BIND(&if_property);
436  Comment("property_load");
437  }
438 
439  Label constant(this), field(this), normal(this, Label::kDeferred),
440  interceptor(this, Label::kDeferred), nonexistent(this),
441  accessor(this, Label::kDeferred), global(this, Label::kDeferred),
442  module_export(this, Label::kDeferred), proxy(this, Label::kDeferred),
443  native_data_property(this), api_getter(this);
444  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
445 
446  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
447  &constant);
448 
449  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
450  &nonexistent);
451 
452  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)),
453  &normal);
454 
455  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
456  &accessor);
457 
458  GotoIf(
459  WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNativeDataProperty)),
460  &native_data_property);
461 
462  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
463  &api_getter);
464 
465  GotoIf(WordEqual(handler_kind,
466  IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)),
467  &api_getter);
468 
469  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)),
470  &global);
471 
472  GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy);
473 
474  Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kModuleExport)),
475  &module_export, &interceptor);
476 
477  BIND(&field);
478  HandleLoadField(holder, handler_word, &var_double_value, &rebox_double,
479  exit_point);
480 
481  BIND(&nonexistent);
482  // This is a handler for a load of a non-existent value.
483  if (on_nonexistent == OnNonExistent::kThrowReferenceError) {
484  exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
485  p->name);
486  } else {
487  DCHECK_EQ(OnNonExistent::kReturnUndefined, on_nonexistent);
488  exit_point->Return(UndefinedConstant());
489  }
490 
491  BIND(&constant);
492  {
493  Comment("constant_load");
494  TNode<IntPtrT> descriptor =
495  Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
496  Node* value = LoadDescriptorValue(LoadMap(holder), descriptor);
497 
498  exit_point->Return(value);
499  }
500 
501  BIND(&normal);
502  {
503  Comment("load_normal");
504  TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
505  TVARIABLE(IntPtrT, var_name_index);
506  Label found(this, &var_name_index);
507  NameDictionaryLookup<NameDictionary>(properties, CAST(p->name), &found,
508  &var_name_index, miss);
509  BIND(&found);
510  {
511  VARIABLE(var_details, MachineRepresentation::kWord32);
512  VARIABLE(var_value, MachineRepresentation::kTagged);
513  LoadPropertyFromNameDictionary(properties, var_name_index.value(),
514  &var_details, &var_value);
515  Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
516  p->context, p->receiver, miss);
517  exit_point->Return(value);
518  }
519  }
520 
521  BIND(&accessor);
522  {
523  Comment("accessor_load");
524  TNode<IntPtrT> descriptor =
525  Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
526  Node* accessor_pair = LoadDescriptorValue(LoadMap(holder), descriptor);
527  CSA_ASSERT(this, IsAccessorPair(accessor_pair));
528  Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
529  CSA_ASSERT(this, Word32BinaryNot(IsTheHole(getter)));
530 
531  Callable callable = CodeFactory::Call(isolate());
532  exit_point->Return(CallJS(callable, p->context, getter, p->receiver));
533  }
534 
535  BIND(&native_data_property);
536  HandleLoadCallbackProperty(p, CAST(holder), handler_word, exit_point);
537 
538  BIND(&api_getter);
539  HandleLoadAccessor(p, CAST(holder), handler_word, CAST(handler), handler_kind,
540  exit_point);
541 
542  BIND(&proxy);
543  {
544  VARIABLE(var_index, MachineType::PointerRepresentation());
545  VARIABLE(var_unique, MachineRepresentation::kTagged);
546 
547  Label if_index(this), if_unique_name(this),
548  to_name_failed(this, Label::kDeferred);
549 
550  if (support_elements == kSupportElements) {
551  DCHECK_NE(on_nonexistent, OnNonExistent::kThrowReferenceError);
552 
553  TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
554  &to_name_failed);
555 
556  BIND(&if_unique_name);
557  exit_point->ReturnCallStub(
558  Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
559  p->context, holder, var_unique.value(), p->receiver,
560  SmiConstant(on_nonexistent));
561 
562  BIND(&if_index);
563  // TODO(mslekova): introduce TryToName that doesn't try to compute
564  // the intptr index value
565  Goto(&to_name_failed);
566 
567  BIND(&to_name_failed);
568  exit_point->ReturnCallRuntime(Runtime::kGetPropertyWithReceiver,
569  p->context, holder, p->name, p->receiver,
570  SmiConstant(on_nonexistent));
571  } else {
572  exit_point->ReturnCallStub(
573  Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
574  p->context, holder, p->name, p->receiver,
575  SmiConstant(on_nonexistent));
576  }
577  }
578 
579  BIND(&global);
580  {
581  CSA_ASSERT(this, IsPropertyCell(holder));
582  // Ensure the property cell doesn't contain the hole.
583  Node* value = LoadObjectField(holder, PropertyCell::kValueOffset);
584  Node* details =
585  LoadAndUntagToWord32ObjectField(holder, PropertyCell::kDetailsOffset);
586  GotoIf(IsTheHole(value), miss);
587 
588  exit_point->Return(
589  CallGetterIfAccessor(value, details, p->context, p->receiver, miss));
590  }
591 
592  BIND(&interceptor);
593  {
594  Comment("load_interceptor");
595  exit_point->ReturnCallRuntime(Runtime::kLoadPropertyWithInterceptor,
596  p->context, p->name, p->receiver, holder,
597  p->slot, p->vector);
598  }
599 
600  BIND(&module_export);
601  {
602  Comment("module export");
603  Node* index = DecodeWord<LoadHandler::ExportsIndexBits>(handler_word);
604  Node* module =
605  LoadObjectField(p->receiver, JSModuleNamespace::kModuleOffset,
606  MachineType::TaggedPointer());
607  TNode<ObjectHashTable> exports = CAST(LoadObjectField(
608  module, Module::kExportsOffset, MachineType::TaggedPointer()));
609  Node* cell = LoadFixedArrayElement(exports, index);
610  // The handler is only installed for exports that exist.
611  CSA_ASSERT(this, IsCell(cell));
612  Node* value = LoadCellValue(cell);
613  Label is_the_hole(this, Label::kDeferred);
614  GotoIf(IsTheHole(value), &is_the_hole);
615  exit_point->Return(value);
616 
617  BIND(&is_the_hole);
618  {
619  Node* message = SmiConstant(MessageTemplate::kNotDefined);
620  exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
621  message, p->name);
622  }
623  }
624 
625  BIND(&rebox_double);
626  exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
627 }
628 
629 // Performs actions common to both load and store handlers:
630 // 1. Checks prototype validity cell.
631 // 2. If |on_code_handler| is provided, then it checks if the sub handler is
632 // a smi or code and if it's a code then it calls |on_code_handler| to
633 // generate a code that handles Code handlers.
634 // If |on_code_handler| is not provided, then only smi sub handler are
635 // expected.
636 // 3. Does access check on receiver if ICHandler::DoAccessCheckOnReceiverBits
637 // bit is set in the smi handler.
638 // 4. Does dictionary lookup on receiver if ICHandler::LookupOnReceiverBits bit
639 // is set in the smi handler. If |on_found_on_receiver| is provided then
640 // it calls it to generate a code that handles the "found on receiver case"
641 // or just misses if the |on_found_on_receiver| is not provided.
642 // 5. Falls through in a case of a smi handler which is returned from this
643 // function (tagged!).
644 // TODO(ishell): Remove templatezation once we move common bits from
645 // Load/StoreHandler to the base class.
646 template <typename ICHandler, typename ICParameters>
647 Node* AccessorAssembler::HandleProtoHandler(
648  const ICParameters* p, Node* handler, const OnCodeHandler& on_code_handler,
649  const OnFoundOnReceiver& on_found_on_receiver, Label* miss,
650  ICMode ic_mode) {
651  //
652  // Check prototype validity cell.
653  //
654  {
655  Node* maybe_validity_cell =
656  LoadObjectField(handler, ICHandler::kValidityCellOffset);
657  CheckPrototypeValidityCell(maybe_validity_cell, miss);
658  }
659 
660  //
661  // Check smi handler bits.
662  //
663  {
664  Node* smi_or_code_handler =
665  LoadObjectField(handler, ICHandler::kSmiHandlerOffset);
666  if (on_code_handler) {
667  Label if_smi_handler(this);
668  GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler);
669 
670  CSA_ASSERT(this, IsCodeMap(LoadMap(smi_or_code_handler)));
671  on_code_handler(smi_or_code_handler);
672 
673  BIND(&if_smi_handler);
674  } else {
675  CSA_ASSERT(this, TaggedIsSmi(smi_or_code_handler));
676  }
677  Node* handler_flags = SmiUntag(smi_or_code_handler);
678 
679  // Lookup on receiver and access checks are not necessary for global ICs
680  // because in the former case the validity cell check guards modifications
681  // of the global object and the latter is not applicable to the global
682  // object.
683  int mask = ICHandler::LookupOnReceiverBits::kMask |
684  ICHandler::DoAccessCheckOnReceiverBits::kMask;
685  if (ic_mode == ICMode::kGlobalIC) {
686  CSA_ASSERT(this, IsClearWord(handler_flags, mask));
687  } else {
688  DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
689 
690  Label done(this), if_do_access_check(this), if_lookup_on_receiver(this);
691  GotoIf(IsClearWord(handler_flags, mask), &done);
692  // Only one of the bits can be set at a time.
693  CSA_ASSERT(this,
694  WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
695  IntPtrConstant(mask)));
696  Branch(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
697  &if_do_access_check, &if_lookup_on_receiver);
698 
699  BIND(&if_do_access_check);
700  {
701  TNode<MaybeObject> data2 = LoadHandlerDataField(handler, 2);
702  CSA_ASSERT(this, IsWeakOrCleared(data2));
703  TNode<Object> expected_native_context =
704  GetHeapObjectAssumeWeak(data2, miss);
705  EmitAccessCheck(expected_native_context, p->context, p->receiver, &done,
706  miss);
707  }
708 
709  // Dictionary lookup on receiver is not necessary for Load/StoreGlobalIC
710  // because prototype validity cell check already guards modifications of
711  // the global object.
712  BIND(&if_lookup_on_receiver);
713  {
714  DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
715  CSA_ASSERT(this, Word32BinaryNot(HasInstanceType(
716  p->receiver, JS_GLOBAL_OBJECT_TYPE)));
717 
718  TNode<NameDictionary> properties =
719  CAST(LoadSlowProperties(p->receiver));
720  TVARIABLE(IntPtrT, var_name_index);
721  Label found(this, &var_name_index);
722  NameDictionaryLookup<NameDictionary>(properties, CAST(p->name), &found,
723  &var_name_index, &done);
724  BIND(&found);
725  {
726  if (on_found_on_receiver) {
727  on_found_on_receiver(properties, var_name_index.value());
728  } else {
729  Goto(miss);
730  }
731  }
732  }
733 
734  BIND(&done);
735  }
736  return smi_or_code_handler;
737  }
738 }
739 
740 void AccessorAssembler::HandleLoadICProtoHandler(
741  const LoadICParameters* p, Node* handler, Variable* var_holder,
742  Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
743  ExitPoint* exit_point, ICMode ic_mode) {
744  DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
745  DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
746 
747  Node* smi_handler = HandleProtoHandler<LoadHandler>(
748  p, handler,
749  // Code sub-handlers are not expected in LoadICs, so no |on_code_handler|.
750  nullptr,
751  // on_found_on_receiver
752  [=](Node* properties, Node* name_index) {
753  VARIABLE(var_details, MachineRepresentation::kWord32);
754  VARIABLE(var_value, MachineRepresentation::kTagged);
755  LoadPropertyFromNameDictionary(properties, name_index, &var_details,
756  &var_value);
757  Node* value =
758  CallGetterIfAccessor(var_value.value(), var_details.value(),
759  p->context, p->receiver, miss);
760  exit_point->Return(value);
761  },
762  miss, ic_mode);
763 
764  TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
765 
766  Label load_from_cached_holder(this), done(this);
767 
768  Branch(IsStrongReferenceTo(maybe_holder, NullConstant()), &done,
769  &load_from_cached_holder);
770 
771  BIND(&load_from_cached_holder);
772  {
773  // For regular holders, having passed the receiver map check and the
774  // validity cell check implies that |holder| is alive. However, for global
775  // object receivers, |maybe_holder| may be cleared.
776  CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
777  Node* holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
778 
779  var_holder->Bind(holder);
780  Goto(&done);
781  }
782 
783  BIND(&done);
784  {
785  var_smi_handler->Bind(smi_handler);
786  Goto(if_smi_handler);
787  }
788 }
789 
790 void AccessorAssembler::EmitAccessCheck(Node* expected_native_context,
791  Node* context, Node* receiver,
792  Label* can_access, Label* miss) {
793  CSA_ASSERT(this, IsNativeContext(expected_native_context));
794 
795  Node* native_context = LoadNativeContext(context);
796  GotoIf(WordEqual(expected_native_context, native_context), can_access);
797  // If the receiver is not a JSGlobalProxy then we miss.
798  GotoIfNot(IsJSGlobalProxy(receiver), miss);
799  // For JSGlobalProxy receiver try to compare security tokens of current
800  // and expected native contexts.
801  Node* expected_token = LoadContextElement(expected_native_context,
802  Context::SECURITY_TOKEN_INDEX);
803  Node* current_token =
804  LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
805  Branch(WordEqual(expected_token, current_token), can_access, miss);
806 }
807 
808 void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
809  Label* readonly) {
810  if (readonly) {
811  // Accessor properties never have the READ_ONLY attribute set.
812  GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
813  readonly);
814  } else {
815  CSA_ASSERT(this, IsNotSetWord32(details,
816  PropertyDetails::kAttributesReadOnlyMask));
817  }
818  Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
819  GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
820  // Fall through if it's an accessor property.
821 }
822 
823 void AccessorAssembler::HandleStoreICNativeDataProperty(
824  const StoreICParameters* p, Node* holder, Node* handler_word) {
825  Comment("native_data_property_store");
826  TNode<IntPtrT> descriptor =
827  Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
828  Node* accessor_info = LoadDescriptorValue(LoadMap(holder), descriptor);
829  CSA_CHECK(this, IsAccessorInfo(accessor_info));
830 
831  Node* language_mode = GetLanguageMode(p->vector, p->slot);
832 
833  TailCallRuntime(Runtime::kStoreCallbackProperty, p->context, p->receiver,
834  holder, accessor_info, p->name, p->value, language_mode);
835 }
836 
837 void AccessorAssembler::HandleStoreICHandlerCase(
838  const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
839  ICMode ic_mode, ElementSupport support_elements) {
840  Label if_smi_handler(this), if_nonsmi_handler(this);
841  Label if_proto_handler(this), if_element_handler(this), call_handler(this),
842  store_transition_or_global(this);
843 
844  Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
845 
846  // |handler| is a Smi, encoding what to do. See SmiHandler methods
847  // for the encoding format.
848  BIND(&if_smi_handler);
849  {
850  Node* holder = p->receiver;
851  Node* handler_word = SmiUntag(CAST(handler));
852 
853  Label if_fast_smi(this), if_proxy(this);
854 
855  STATIC_ASSERT(StoreHandler::kGlobalProxy + 1 == StoreHandler::kNormal);
856  STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kProxy);
857  STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
858 
859  Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
860  GotoIf(IntPtrLessThan(handler_kind,
861  IntPtrConstant(StoreHandler::kGlobalProxy)),
862  &if_fast_smi);
863  GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)),
864  &if_proxy);
865  CSA_ASSERT(this,
866  WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)));
867  TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
868 
869  TVARIABLE(IntPtrT, var_name_index);
870  Label dictionary_found(this, &var_name_index);
871  NameDictionaryLookup<NameDictionary>(
872  properties, CAST(p->name), &dictionary_found, &var_name_index, miss);
873  BIND(&dictionary_found);
874  {
875  Node* details = LoadDetailsByKeyIndex<NameDictionary>(
876  properties, var_name_index.value());
877  // Check that the property is a writable data property (no accessor).
878  const int kTypeAndReadOnlyMask = PropertyDetails::KindField::kMask |
879  PropertyDetails::kAttributesReadOnlyMask;
880  STATIC_ASSERT(kData == 0);
881  GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
882 
883  StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
884  p->value);
885  Return(p->value);
886  }
887 
888  BIND(&if_fast_smi);
889  {
890  Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
891 
892  Label data(this), accessor(this), native_data_property(this);
893  GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
894  &accessor);
895  Branch(WordEqual(handler_kind,
896  IntPtrConstant(StoreHandler::kNativeDataProperty)),
897  &native_data_property, &data);
898 
899  BIND(&accessor);
900  HandleStoreAccessor(p, holder, handler_word);
901 
902  BIND(&native_data_property);
903  HandleStoreICNativeDataProperty(p, holder, handler_word);
904 
905  BIND(&data);
906  // Handle non-transitioning field stores.
907  HandleStoreICSmiHandlerCase(handler_word, holder, p->value, miss);
908  }
909 
910  BIND(&if_proxy);
911  HandleStoreToProxy(p, holder, miss, support_elements);
912  }
913 
914  BIND(&if_nonsmi_handler);
915  {
916  GotoIf(IsWeakOrCleared(handler), &store_transition_or_global);
917  TNode<HeapObject> strong_handler = CAST(handler);
918  TNode<Map> handler_map = LoadMap(strong_handler);
919  Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
920 
921  BIND(&if_proto_handler);
922  {
923  HandleStoreICProtoHandler(p, CAST(strong_handler), miss, ic_mode,
924  support_elements);
925  }
926 
927  // |handler| is a heap object. Must be code, call it.
928  BIND(&call_handler);
929  {
930  TailCallStub(StoreWithVectorDescriptor{}, CAST(strong_handler),
931  CAST(p->context), p->receiver, p->name, p->value, p->slot,
932  p->vector);
933  }
934  }
935 
936  BIND(&store_transition_or_global);
937  {
938  // Load value or miss if the {handler} weak cell is cleared.
939  CSA_ASSERT(this, IsWeakOrCleared(handler));
940  TNode<HeapObject> map_or_property_cell =
941  GetHeapObjectAssumeWeak(handler, miss);
942 
943  Label store_global(this), store_transition(this);
944  Branch(IsMap(map_or_property_cell), &store_transition, &store_global);
945 
946  BIND(&store_global);
947  {
948  TNode<PropertyCell> property_cell = CAST(map_or_property_cell);
949  ExitPoint direct_exit(this);
950  StoreGlobalIC_PropertyCellCase(property_cell, p->value, &direct_exit,
951  miss);
952  }
953  BIND(&store_transition);
954  {
955  TNode<Map> map = CAST(map_or_property_cell);
956  HandleStoreICTransitionMapHandlerCase(p, map, miss,
957  kCheckPrototypeValidity);
958  Return(p->value);
959  }
960  }
961 }
962 
963 void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
964  const StoreICParameters* p, TNode<Map> transition_map, Label* miss,
965  StoreTransitionMapFlags flags) {
966  DCHECK_EQ(0, flags & ~kStoreTransitionMapFlagsMask);
967  if (flags & kCheckPrototypeValidity) {
968  Node* maybe_validity_cell =
969  LoadObjectField(transition_map, Map::kPrototypeValidityCellOffset);
970  CheckPrototypeValidityCell(maybe_validity_cell, miss);
971  }
972 
973  TNode<Uint32T> bitfield3 = LoadMapBitField3(transition_map);
974  CSA_ASSERT(this, IsClearWord32<Map::IsDictionaryMapBit>(bitfield3));
975  GotoIf(IsSetWord32<Map::IsDeprecatedBit>(bitfield3), miss);
976 
977  // Load last descriptor details.
978  Node* nof = DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
979  CSA_ASSERT(this, WordNotEqual(nof, IntPtrConstant(0)));
980  TNode<DescriptorArray> descriptors = LoadMapDescriptors(transition_map);
981 
982  Node* factor = IntPtrConstant(DescriptorArray::kEntrySize);
983  TNode<IntPtrT> last_key_index = UncheckedCast<IntPtrT>(IntPtrAdd(
984  IntPtrConstant(DescriptorArray::ToKeyIndex(-1)), IntPtrMul(nof, factor)));
985  if (flags & kValidateTransitionHandler) {
986  TNode<Name> key = LoadKeyByKeyIndex(descriptors, last_key_index);
987  GotoIf(WordNotEqual(key, p->name), miss);
988  } else {
989  CSA_ASSERT(this, WordEqual(LoadKeyByKeyIndex(descriptors, last_key_index),
990  p->name));
991  }
992  Node* details = LoadDetailsByKeyIndex(descriptors, last_key_index);
993  if (flags & kValidateTransitionHandler) {
994  // Follow transitions only in the following cases:
995  // 1) name is a non-private symbol and attributes equal to NONE,
996  // 2) name is a private symbol and attributes equal to DONT_ENUM.
997  Label attributes_ok(this);
998  const int kKindAndAttributesDontDeleteReadOnlyMask =
999  PropertyDetails::KindField::kMask |
1000  PropertyDetails::kAttributesDontDeleteMask |
1001  PropertyDetails::kAttributesReadOnlyMask;
1002  STATIC_ASSERT(kData == 0);
1003  // Both DontDelete and ReadOnly attributes must not be set and it has to be
1004  // a kData property.
1005  GotoIf(IsSetWord32(details, kKindAndAttributesDontDeleteReadOnlyMask),
1006  miss);
1007 
1008  // DontEnum attribute is allowed only for private symbols and vice versa.
1009  Branch(Word32Equal(
1010  IsSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
1011  IsPrivateSymbol(p->name)),
1012  &attributes_ok, miss);
1013 
1014  BIND(&attributes_ok);
1015  }
1016 
1017  OverwriteExistingFastDataProperty(p->receiver, transition_map, descriptors,
1018  last_key_index, details, p->value, miss,
1019  true);
1020 }
1021 
1022 void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
1023  Node* name_index, Node* representation,
1024  Node* value, Label* bailout) {
1025  Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this);
1026  // Ignore FLAG_track_fields etc. and always emit code for all checks,
1027  // because this builtin is part of the snapshot and therefore should
1028  // be flag independent.
1029  GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)),
1030  &r_smi);
1031  GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)),
1032  &r_double);
1033  GotoIf(
1034  Word32Equal(representation, Int32Constant(Representation::kHeapObject)),
1035  &r_heapobject);
1036  GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)),
1037  bailout);
1038  CSA_ASSERT(this, Word32Equal(representation,
1039  Int32Constant(Representation::kTagged)));
1040  Goto(&all_fine);
1041 
1042  BIND(&r_smi);
1043  { Branch(TaggedIsSmi(value), &all_fine, bailout); }
1044 
1045  BIND(&r_double);
1046  {
1047  GotoIf(TaggedIsSmi(value), &all_fine);
1048  Node* value_map = LoadMap(value);
1049  // While supporting mutable HeapNumbers would be straightforward, such
1050  // objects should not end up here anyway.
1051  CSA_ASSERT(this, WordNotEqual(value_map,
1052  LoadRoot(RootIndex::kMutableHeapNumberMap)));
1053  Branch(IsHeapNumberMap(value_map), &all_fine, bailout);
1054  }
1055 
1056  BIND(&r_heapobject);
1057  {
1058  GotoIf(TaggedIsSmi(value), bailout);
1059  TNode<MaybeObject> field_type = LoadFieldTypeByKeyIndex(
1060  descriptors, UncheckedCast<IntPtrT>(name_index));
1061  const Address kNoneType = FieldType::None().ptr();
1062  const Address kAnyType = FieldType::Any().ptr();
1063  DCHECK_NE(static_cast<uint32_t>(kNoneType), kClearedWeakHeapObjectLower32);
1064  DCHECK_NE(static_cast<uint32_t>(kAnyType), kClearedWeakHeapObjectLower32);
1065  // FieldType::None can't hold any value.
1066  GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type),
1067  IntPtrConstant(kNoneType)),
1068  bailout);
1069  // FieldType::Any can hold any value.
1070  GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type),
1071  IntPtrConstant(kAnyType)),
1072  &all_fine);
1073  // Cleared weak references count as FieldType::None, which can't hold any
1074  // value.
1075  TNode<Map> field_type_map =
1076  CAST(GetHeapObjectAssumeWeak(field_type, bailout));
1077  // FieldType::Class(...) performs a map check.
1078  Branch(WordEqual(LoadMap(value), field_type_map), &all_fine, bailout);
1079  }
1080 
1081  BIND(&all_fine);
1082 }
1083 
1084 void AccessorAssembler::OverwriteExistingFastDataProperty(
1085  Node* object, Node* object_map, Node* descriptors,
1086  Node* descriptor_name_index, Node* details, Node* value, Label* slow,
1087  bool do_transitioning_store) {
1088  Label done(this), if_field(this), if_descriptor(this);
1089 
1090  CSA_ASSERT(this,
1091  Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
1092  Int32Constant(kData)));
1093 
1094  Branch(Word32Equal(DecodeWord32<PropertyDetails::LocationField>(details),
1095  Int32Constant(kField)),
1096  &if_field, &if_descriptor);
1097 
1098  BIND(&if_field);
1099  {
1100  if (FLAG_track_constant_fields && !do_transitioning_store) {
1101  // TODO(ishell): Taking the slow path is not necessary if new and old
1102  // values are identical.
1103  GotoIf(Word32Equal(
1104  DecodeWord32<PropertyDetails::ConstnessField>(details),
1105  Int32Constant(static_cast<int32_t>(VariableMode::kConst))),
1106  slow);
1107  }
1108 
1109  Node* representation =
1110  DecodeWord32<PropertyDetails::RepresentationField>(details);
1111 
1112  CheckFieldType(CAST(descriptors), descriptor_name_index, representation,
1113  value, slow);
1114 
1115  Node* field_index =
1116  DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
1117  field_index = IntPtrAdd(field_index,
1118  LoadMapInobjectPropertiesStartInWords(object_map));
1119  Node* instance_size_in_words = LoadMapInstanceSizeInWords(object_map);
1120 
1121  Label inobject(this), backing_store(this);
1122  Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
1123  &backing_store);
1124 
1125  BIND(&inobject);
1126  {
1127  Node* field_offset = TimesPointerSize(field_index);
1128  Label tagged_rep(this), double_rep(this);
1129  Branch(
1130  Word32Equal(representation, Int32Constant(Representation::kDouble)),
1131  &double_rep, &tagged_rep);
1132  BIND(&double_rep);
1133  {
1134  Node* double_value = ChangeNumberToFloat64(value);
1135  if (FLAG_unbox_double_fields) {
1136  if (do_transitioning_store) {
1137  StoreMap(object, object_map);
1138  }
1139  StoreObjectFieldNoWriteBarrier(object, field_offset, double_value,
1140  MachineRepresentation::kFloat64);
1141  } else {
1142  if (do_transitioning_store) {
1143  Node* mutable_heap_number =
1144  AllocateMutableHeapNumberWithValue(double_value);
1145  StoreMap(object, object_map);
1146  StoreObjectField(object, field_offset, mutable_heap_number);
1147  } else {
1148  Node* mutable_heap_number = LoadObjectField(object, field_offset);
1149  StoreHeapNumberValue(mutable_heap_number, double_value);
1150  }
1151  }
1152  Goto(&done);
1153  }
1154 
1155  BIND(&tagged_rep);
1156  {
1157  if (do_transitioning_store) {
1158  StoreMap(object, object_map);
1159  }
1160  StoreObjectField(object, field_offset, value);
1161  Goto(&done);
1162  }
1163  }
1164 
1165  BIND(&backing_store);
1166  {
1167  Node* backing_store_index =
1168  IntPtrSub(field_index, instance_size_in_words);
1169 
1170  if (do_transitioning_store) {
1171  // Allocate mutable heap number before extending properties backing
1172  // store to ensure that heap verifier will not see the heap in
1173  // inconsistent state.
1174  VARIABLE(var_value, MachineRepresentation::kTagged, value);
1175  {
1176  Label cont(this);
1177  GotoIf(Word32NotEqual(representation,
1178  Int32Constant(Representation::kDouble)),
1179  &cont);
1180  {
1181  Node* double_value = ChangeNumberToFloat64(value);
1182  Node* mutable_heap_number =
1183  AllocateMutableHeapNumberWithValue(double_value);
1184  var_value.Bind(mutable_heap_number);
1185  Goto(&cont);
1186  }
1187  BIND(&cont);
1188  }
1189 
1190  TNode<PropertyArray> properties =
1191  CAST(ExtendPropertiesBackingStore(object, backing_store_index));
1192  StorePropertyArrayElement(properties, backing_store_index,
1193  var_value.value());
1194  StoreMap(object, object_map);
1195  Goto(&done);
1196 
1197  } else {
1198  Label tagged_rep(this), double_rep(this);
1199  TNode<PropertyArray> properties = CAST(LoadFastProperties(object));
1200  Branch(
1201  Word32Equal(representation, Int32Constant(Representation::kDouble)),
1202  &double_rep, &tagged_rep);
1203  BIND(&double_rep);
1204  {
1205  Node* mutable_heap_number =
1206  LoadPropertyArrayElement(properties, backing_store_index);
1207  Node* double_value = ChangeNumberToFloat64(value);
1208  StoreHeapNumberValue(mutable_heap_number, double_value);
1209  Goto(&done);
1210  }
1211  BIND(&tagged_rep);
1212  {
1213  StorePropertyArrayElement(properties, backing_store_index, value);
1214  Goto(&done);
1215  }
1216  }
1217  }
1218  }
1219 
1220  BIND(&if_descriptor);
1221  {
1222  // Check that constant matches value.
1223  Node* constant = LoadValueByKeyIndex(
1224  CAST(descriptors), UncheckedCast<IntPtrT>(descriptor_name_index));
1225  GotoIf(WordNotEqual(value, constant), slow);
1226 
1227  if (do_transitioning_store) {
1228  StoreMap(object, object_map);
1229  }
1230  Goto(&done);
1231  }
1232  BIND(&done);
1233 }
1234 
1235 void AccessorAssembler::CheckPrototypeValidityCell(Node* maybe_validity_cell,
1236  Label* miss) {
1237  Label done(this);
1238  GotoIf(WordEqual(maybe_validity_cell, SmiConstant(Map::kPrototypeChainValid)),
1239  &done);
1240  CSA_ASSERT(this, TaggedIsNotSmi(maybe_validity_cell));
1241 
1242  Node* cell_value = LoadObjectField(maybe_validity_cell, Cell::kValueOffset);
1243  Branch(WordEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)), &done,
1244  miss);
1245 
1246  BIND(&done);
1247 }
1248 
1249 void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p,
1250  Node* holder, Node* handler_word) {
1251  Comment("accessor_store");
1252  TNode<IntPtrT> descriptor =
1253  Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
1254  Node* accessor_pair = LoadDescriptorValue(LoadMap(holder), descriptor);
1255  CSA_ASSERT(this, IsAccessorPair(accessor_pair));
1256  Node* setter = LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
1257  CSA_ASSERT(this, Word32BinaryNot(IsTheHole(setter)));
1258 
1259  Callable callable = CodeFactory::Call(isolate());
1260  Return(CallJS(callable, p->context, setter, p->receiver, p->value));
1261 }
1262 
1263 void AccessorAssembler::HandleStoreICProtoHandler(
1264  const StoreICParameters* p, TNode<StoreHandler> handler, Label* miss,
1265  ICMode ic_mode, ElementSupport support_elements) {
1266  Comment("HandleStoreICProtoHandler");
1267 
1268  OnCodeHandler on_code_handler;
1269  if (support_elements == kSupportElements) {
1270  // Code sub-handlers are expected only in KeyedStoreICs.
1271  on_code_handler = [=](Node* code_handler) {
1272  // This is either element store or transitioning element store.
1273  Label if_element_store(this), if_transitioning_element_store(this);
1274  Branch(IsStoreHandler0Map(LoadMap(handler)), &if_element_store,
1275  &if_transitioning_element_store);
1276  BIND(&if_element_store);
1277  {
1278  TailCallStub(StoreWithVectorDescriptor{}, code_handler, p->context,
1279  p->receiver, p->name, p->value, p->slot, p->vector);
1280  }
1281 
1282  BIND(&if_transitioning_element_store);
1283  {
1284  TNode<MaybeObject> maybe_transition_map =
1285  LoadHandlerDataField(handler, 1);
1286  TNode<Map> transition_map =
1287  CAST(GetHeapObjectAssumeWeak(maybe_transition_map, miss));
1288 
1289  GotoIf(IsDeprecatedMap(transition_map), miss);
1290 
1291  TailCallStub(StoreTransitionDescriptor{}, code_handler, p->context,
1292  p->receiver, p->name, transition_map, p->value, p->slot,
1293  p->vector);
1294  }
1295  };
1296  }
1297 
1298  Node* smi_handler = HandleProtoHandler<StoreHandler>(
1299  p, handler, on_code_handler,
1300  // on_found_on_receiver
1301  [=](Node* properties, Node* name_index) {
1302  Node* details =
1303  LoadDetailsByKeyIndex<NameDictionary>(properties, name_index);
1304  // Check that the property is a writable data property (no accessor).
1305  const int kTypeAndReadOnlyMask =
1306  PropertyDetails::KindField::kMask |
1307  PropertyDetails::kAttributesReadOnlyMask;
1308  STATIC_ASSERT(kData == 0);
1309  GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
1310 
1311  StoreValueByKeyIndex<NameDictionary>(
1312  CAST(properties), UncheckedCast<IntPtrT>(name_index), p->value);
1313  Return(p->value);
1314  },
1315  miss, ic_mode);
1316 
1317  {
1318  Label if_add_normal(this), if_store_global_proxy(this), if_api_setter(this),
1319  if_accessor(this), if_native_data_property(this);
1320 
1321  CSA_ASSERT(this, TaggedIsSmi(smi_handler));
1322  Node* handler_word = SmiUntag(smi_handler);
1323 
1324  Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
1325  GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)),
1326  &if_add_normal);
1327 
1328  TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
1329  CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
1330  TNode<Object> holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
1331 
1332  GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)),
1333  &if_store_global_proxy);
1334 
1335  GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
1336  &if_accessor);
1337 
1338  GotoIf(WordEqual(handler_kind,
1339  IntPtrConstant(StoreHandler::kNativeDataProperty)),
1340  &if_native_data_property);
1341 
1342  GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
1343  &if_api_setter);
1344 
1345  GotoIf(WordEqual(handler_kind,
1346  IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)),
1347  &if_api_setter);
1348 
1349  CSA_ASSERT(this,
1350  WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)));
1351  HandleStoreToProxy(p, holder, miss, support_elements);
1352 
1353  BIND(&if_add_normal);
1354  {
1355  // This is a case of "transitioning store" to a dictionary mode object
1356  // when the property is still does not exist. The "existing property"
1357  // case is covered above by LookupOnReceiver bit handling of the smi
1358  // handler.
1359  Label slow(this);
1360  TNode<Map> receiver_map = LoadMap(p->receiver);
1361  InvalidateValidityCellIfPrototype(receiver_map);
1362 
1363  TNode<NameDictionary> properties = CAST(LoadSlowProperties(p->receiver));
1364  Add<NameDictionary>(properties, CAST(p->name), p->value, &slow);
1365  Return(p->value);
1366 
1367  BIND(&slow);
1368  TailCallRuntime(Runtime::kAddDictionaryProperty, p->context, p->receiver,
1369  p->name, p->value);
1370  }
1371 
1372  BIND(&if_accessor);
1373  HandleStoreAccessor(p, holder, handler_word);
1374 
1375  BIND(&if_native_data_property);
1376  HandleStoreICNativeDataProperty(p, holder, handler_word);
1377 
1378  BIND(&if_api_setter);
1379  {
1380  Comment("api_setter");
1381  CSA_ASSERT(this, TaggedIsNotSmi(handler));
1382  Node* call_handler_info = holder;
1383 
1384  // Context is stored either in data2 or data3 field depending on whether
1385  // the access check is enabled for this handler or not.
1386  TNode<MaybeObject> maybe_context = Select<MaybeObject>(
1387  IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
1388  [=] { return LoadHandlerDataField(handler, 3); },
1389  [=] { return LoadHandlerDataField(handler, 2); });
1390 
1391  CSA_ASSERT(this, IsWeakOrCleared(maybe_context));
1392  TNode<Object> context = Select<Object>(
1393  IsCleared(maybe_context), [=] { return SmiConstant(0); },
1394  [=] { return GetHeapObjectAssumeWeak(maybe_context); });
1395 
1396  Node* foreign = LoadObjectField(call_handler_info,
1397  CallHandlerInfo::kJsCallbackOffset);
1398  Node* callback = LoadObjectField(foreign, Foreign::kForeignAddressOffset,
1399  MachineType::Pointer());
1400  Node* data =
1401  LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
1402 
1403  VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver);
1404  Label store(this);
1405  GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
1406  &store);
1407 
1408  CSA_ASSERT(
1409  this,
1410  WordEqual(handler_kind,
1411  IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)));
1412 
1413  api_holder.Bind(LoadMapPrototype(LoadMap(p->receiver)));
1414  Goto(&store);
1415 
1416  BIND(&store);
1417  Callable callable = CodeFactory::CallApiCallback(isolate(), 1);
1418  Return(CallStub(callable, nullptr, context, data, api_holder.value(),
1419  callback, p->receiver, p->value));
1420  }
1421 
1422  BIND(&if_store_global_proxy);
1423  {
1424  ExitPoint direct_exit(this);
1425  StoreGlobalIC_PropertyCellCase(holder, p->value, &direct_exit, miss);
1426  }
1427  }
1428 }
1429 
1430 Node* AccessorAssembler::GetLanguageMode(Node* vector, Node* slot) {
1431  VARIABLE(var_language_mode, MachineRepresentation::kTaggedSigned,
1432  SmiConstant(LanguageMode::kStrict));
1433  Label language_mode_determined(this);
1434  BranchIfStrictMode(vector, slot, &language_mode_determined);
1435  var_language_mode.Bind(SmiConstant(LanguageMode::kSloppy));
1436  Goto(&language_mode_determined);
1437  BIND(&language_mode_determined);
1438  return var_language_mode.value();
1439 }
1440 
1441 void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
1442  Node* proxy, Label* miss,
1443  ElementSupport support_elements) {
1444  VARIABLE(var_index, MachineType::PointerRepresentation());
1445  VARIABLE(var_unique, MachineRepresentation::kTagged);
1446 
1447  Label if_index(this), if_unique_name(this),
1448  to_name_failed(this, Label::kDeferred);
1449 
1450  Node* language_mode = GetLanguageMode(p->vector, p->slot);
1451 
1452  if (support_elements == kSupportElements) {
1453  TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
1454  &to_name_failed);
1455 
1456  BIND(&if_unique_name);
1457  CallBuiltin(Builtins::kProxySetProperty, p->context, proxy,
1458  var_unique.value(), p->value, p->receiver, language_mode);
1459  Return(p->value);
1460 
1461  // The index case is handled earlier by the runtime.
1462  BIND(&if_index);
1463  // TODO(mslekova): introduce TryToName that doesn't try to compute
1464  // the intptr index value
1465  Goto(&to_name_failed);
1466 
1467  BIND(&to_name_failed);
1468  TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context, proxy,
1469  p->name, p->value, p->receiver, language_mode);
1470  } else {
1471  Node* name = CallBuiltin(Builtins::kToName, p->context, p->name);
1472  TailCallBuiltin(Builtins::kProxySetProperty, p->context, proxy, name,
1473  p->value, p->receiver, language_mode);
1474  }
1475 }
1476 
1477 void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
1478  Node* holder, Node* value,
1479  Label* miss) {
1480  Comment("field store");
1481 #ifdef DEBUG
1482  Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
1483  if (FLAG_track_constant_fields) {
1484  CSA_ASSERT(
1485  this,
1486  Word32Or(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kField)),
1487  WordEqual(handler_kind,
1488  IntPtrConstant(StoreHandler::kConstField))));
1489  } else {
1490  CSA_ASSERT(this,
1491  WordEqual(handler_kind, IntPtrConstant(StoreHandler::kField)));
1492  }
1493 #endif
1494 
1495  Node* field_representation =
1496  DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
1497 
1498  Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
1499  if_tagged_field(this);
1500 
1501  GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)),
1502  &if_tagged_field);
1503  GotoIf(WordEqual(field_representation,
1504  IntPtrConstant(StoreHandler::kHeapObject)),
1505  &if_heap_object_field);
1506  GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)),
1507  &if_double_field);
1508  CSA_ASSERT(this, WordEqual(field_representation,
1509  IntPtrConstant(StoreHandler::kSmi)));
1510  Goto(&if_smi_field);
1511 
1512  BIND(&if_tagged_field);
1513  {
1514  Comment("store tagged field");
1515  HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
1516  value, miss);
1517  }
1518 
1519  BIND(&if_double_field);
1520  {
1521  Comment("store double field");
1522  HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
1523  value, miss);
1524  }
1525 
1526  BIND(&if_heap_object_field);
1527  {
1528  Comment("store heap object field");
1529  HandleStoreFieldAndReturn(handler_word, holder,
1530  Representation::HeapObject(), value, miss);
1531  }
1532 
1533  BIND(&if_smi_field);
1534  {
1535  Comment("store smi field");
1536  HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
1537  value, miss);
1538  }
1539 }
1540 
1541 void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
1542  Node* holder,
1543  Representation representation,
1544  Node* value, Label* miss) {
1545  Node* prepared_value =
1546  PrepareValueForStore(handler_word, holder, representation, value, miss);
1547 
1548  Label if_inobject(this), if_out_of_object(this);
1549  Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
1550  &if_out_of_object);
1551 
1552  BIND(&if_inobject);
1553  {
1554  StoreNamedField(handler_word, holder, true, representation, prepared_value,
1555  miss);
1556  Return(value);
1557  }
1558 
1559  BIND(&if_out_of_object);
1560  {
1561  StoreNamedField(handler_word, holder, false, representation, prepared_value,
1562  miss);
1563  Return(value);
1564  }
1565 }
1566 
1567 Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
1568  Representation representation,
1569  Node* value, Label* bailout) {
1570  if (representation.IsDouble()) {
1571  value = TryTaggedToFloat64(value, bailout);
1572 
1573  } else if (representation.IsHeapObject()) {
1574  GotoIf(TaggedIsSmi(value), bailout);
1575 
1576  Label done(this);
1577  if (FLAG_track_constant_fields) {
1578  // Skip field type check in favor of constant value check when storing
1579  // to constant field.
1580  GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
1581  IntPtrConstant(StoreHandler::kConstField)),
1582  &done);
1583  }
1584  TNode<IntPtrT> descriptor =
1585  Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
1586  TNode<MaybeObject> maybe_field_type =
1587  LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor);
1588 
1589  GotoIf(TaggedIsSmi(maybe_field_type), &done);
1590  // Check that value type matches the field type.
1591  {
1592  Node* field_type = GetHeapObjectAssumeWeak(maybe_field_type, bailout);
1593  Branch(WordEqual(LoadMap(value), field_type), &done, bailout);
1594  }
1595  BIND(&done);
1596 
1597  } else if (representation.IsSmi()) {
1598  GotoIfNot(TaggedIsSmi(value), bailout);
1599 
1600  } else {
1601  DCHECK(representation.IsTagged());
1602  }
1603  return value;
1604 }
1605 
1606 Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
1607  Node* index) {
1608  Comment("[ Extend storage");
1609 
1610  ParameterMode mode = OptimalParameterMode();
1611 
1612  // TODO(gsathya): Clean up the type conversions by creating smarter
1613  // helpers that do the correct op based on the mode.
1614  VARIABLE(var_properties, MachineRepresentation::kTaggedPointer);
1615  VARIABLE(var_encoded_hash, MachineRepresentation::kWord32);
1616  VARIABLE(var_length, ParameterRepresentation(mode));
1617 
1618  Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
1619  var_properties.Bind(properties);
1620 
1621  Label if_smi_hash(this), if_property_array(this), extend_store(this);
1622  Branch(TaggedIsSmi(properties), &if_smi_hash, &if_property_array);
1623 
1624  BIND(&if_smi_hash);
1625  {
1626  Node* hash = SmiToInt32(properties);
1627  Node* encoded_hash =
1628  Word32Shl(hash, Int32Constant(PropertyArray::HashField::kShift));
1629  var_encoded_hash.Bind(encoded_hash);
1630  var_length.Bind(IntPtrOrSmiConstant(0, mode));
1631  var_properties.Bind(EmptyFixedArrayConstant());
1632  Goto(&extend_store);
1633  }
1634 
1635  BIND(&if_property_array);
1636  {
1637  Node* length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
1638  var_properties.value(), PropertyArray::kLengthAndHashOffset);
1639  var_encoded_hash.Bind(Word32And(
1640  length_and_hash_int32, Int32Constant(PropertyArray::HashField::kMask)));
1641  Node* length_intptr = ChangeInt32ToIntPtr(
1642  Word32And(length_and_hash_int32,
1643  Int32Constant(PropertyArray::LengthField::kMask)));
1644  Node* length = IntPtrToParameter(length_intptr, mode);
1645  var_length.Bind(length);
1646  Goto(&extend_store);
1647  }
1648 
1649  BIND(&extend_store);
1650  {
1651  VARIABLE(var_new_properties, MachineRepresentation::kTaggedPointer,
1652  var_properties.value());
1653  Label done(this);
1654  // Previous property deletion could have left behind unused backing store
1655  // capacity even for a map that think it doesn't have any unused fields.
1656  // Perform a bounds check to see if we actually have to grow the array.
1657  GotoIf(UintPtrLessThan(index, ParameterToIntPtr(var_length.value(), mode)),
1658  &done);
1659 
1660  Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode);
1661  Node* new_capacity = IntPtrOrSmiAdd(var_length.value(), delta, mode);
1662 
1663  // Grow properties array.
1664  DCHECK(kMaxNumberOfDescriptors + JSObject::kFieldsAdded <
1665  FixedArrayBase::GetMaxLengthForNewSpaceAllocation(PACKED_ELEMENTS));
1666  // The size of a new properties backing store is guaranteed to be small
1667  // enough that the new backing store will be allocated in new space.
1668  CSA_ASSERT(this,
1669  UintPtrOrSmiLessThan(
1670  new_capacity,
1671  IntPtrOrSmiConstant(
1672  kMaxNumberOfDescriptors + JSObject::kFieldsAdded, mode),
1673  mode));
1674 
1675  Node* new_properties = AllocatePropertyArray(new_capacity, mode);
1676  var_new_properties.Bind(new_properties);
1677 
1678  FillPropertyArrayWithUndefined(new_properties, var_length.value(),
1679  new_capacity, mode);
1680 
1681  // |new_properties| is guaranteed to be in new space, so we can skip
1682  // the write barrier.
1683  CopyPropertyArrayValues(var_properties.value(), new_properties,
1684  var_length.value(), SKIP_WRITE_BARRIER, mode,
1685  DestroySource::kYes);
1686 
1687  // TODO(gsathya): Clean up the type conversions by creating smarter
1688  // helpers that do the correct op based on the mode.
1689  Node* new_capacity_int32 =
1690  TruncateIntPtrToInt32(ParameterToIntPtr(new_capacity, mode));
1691  Node* new_length_and_hash_int32 =
1692  Word32Or(var_encoded_hash.value(), new_capacity_int32);
1693  StoreObjectField(new_properties, PropertyArray::kLengthAndHashOffset,
1694  SmiFromInt32(new_length_and_hash_int32));
1695  StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties);
1696  Comment("] Extend storage");
1697  Goto(&done);
1698  BIND(&done);
1699  return var_new_properties.value();
1700  }
1701 }
1702 
1703 void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
1704  bool is_inobject,
1705  Representation representation,
1706  Node* value, Label* bailout) {
1707  bool store_value_as_double = representation.IsDouble();
1708  Node* property_storage = object;
1709  if (!is_inobject) {
1710  property_storage = LoadFastProperties(object);
1711  }
1712 
1713  Node* index = DecodeWord<StoreHandler::FieldIndexBits>(handler_word);
1714  Node* offset = IntPtrMul(index, IntPtrConstant(kPointerSize));
1715  if (representation.IsDouble()) {
1716  if (!FLAG_unbox_double_fields || !is_inobject) {
1717  // Load the mutable heap number.
1718  property_storage = LoadObjectField(property_storage, offset);
1719  // Store the double value into it.
1720  offset = IntPtrConstant(HeapNumber::kValueOffset);
1721  }
1722  }
1723 
1724  // Do constant value check if necessary.
1725  if (FLAG_track_constant_fields) {
1726  Label done(this);
1727  GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
1728  IntPtrConstant(StoreHandler::kConstField)),
1729  &done);
1730  {
1731  if (store_value_as_double) {
1732  Node* current_value =
1733  LoadObjectField(property_storage, offset, MachineType::Float64());
1734  GotoIfNot(Float64Equal(current_value, value), bailout);
1735  } else {
1736  Node* current_value = LoadObjectField(property_storage, offset);
1737  GotoIfNot(WordEqual(current_value, value), bailout);
1738  }
1739  Goto(&done);
1740  }
1741  BIND(&done);
1742  }
1743 
1744  // Do the store.
1745  if (store_value_as_double) {
1746  StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
1747  MachineRepresentation::kFloat64);
1748  } else if (representation.IsSmi()) {
1749  StoreObjectFieldNoWriteBarrier(property_storage, offset, value);
1750  } else {
1751  StoreObjectField(property_storage, offset, value);
1752  }
1753 }
1754 
1755 void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
1756  Node* elements,
1757  Node* intptr_index,
1758  Node* is_jsarray_condition,
1759  Label* miss) {
1760  VARIABLE(var_length, MachineType::PointerRepresentation());
1761  Comment("Fast elements bounds check");
1762  Label if_array(this), length_loaded(this, &var_length);
1763  GotoIf(is_jsarray_condition, &if_array);
1764  {
1765  var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements)));
1766  Goto(&length_loaded);
1767  }
1768  BIND(&if_array);
1769  {
1770  var_length.Bind(SmiUntag(LoadFastJSArrayLength(object)));
1771  Goto(&length_loaded);
1772  }
1773  BIND(&length_loaded);
1774  GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
1775 }
1776 
1777 void AccessorAssembler::EmitElementLoad(
1778  Node* object, Node* elements, Node* elements_kind,
1779  SloppyTNode<IntPtrT> intptr_index, Node* is_jsarray_condition,
1780  Label* if_hole, Label* rebox_double, Variable* var_double_value,
1781  Label* unimplemented_elements_kind, Label* out_of_bounds, Label* miss,
1782  ExitPoint* exit_point) {
1783  Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
1784  if_fast_double(this), if_fast_holey_double(this), if_nonfast(this),
1785  if_dictionary(this);
1786  GotoIf(
1787  Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
1788  &if_nonfast);
1789 
1790  EmitFastElementsBoundsCheck(object, elements, intptr_index,
1791  is_jsarray_condition, out_of_bounds);
1792  int32_t kinds[] = {// Handled by if_fast_packed.
1793  PACKED_SMI_ELEMENTS, PACKED_ELEMENTS,
1794  // Handled by if_fast_holey.
1795  HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS,
1796  // Handled by if_fast_double.
1797  PACKED_DOUBLE_ELEMENTS,
1798  // Handled by if_fast_holey_double.
1799  HOLEY_DOUBLE_ELEMENTS};
1800  Label* labels[] = {// FAST_{SMI,}_ELEMENTS
1801  &if_fast_packed, &if_fast_packed,
1802  // FAST_HOLEY_{SMI,}_ELEMENTS
1803  &if_fast_holey, &if_fast_holey,
1804  // PACKED_DOUBLE_ELEMENTS
1805  &if_fast_double,
1806  // HOLEY_DOUBLE_ELEMENTS
1807  &if_fast_holey_double};
1808  Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
1809  arraysize(kinds));
1810 
1811  BIND(&if_fast_packed);
1812  {
1813  Comment("fast packed elements");
1814  exit_point->Return(LoadFixedArrayElement(CAST(elements), intptr_index));
1815  }
1816 
1817  BIND(&if_fast_holey);
1818  {
1819  Comment("fast holey elements");
1820  Node* element = LoadFixedArrayElement(CAST(elements), intptr_index);
1821  GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
1822  exit_point->Return(element);
1823  }
1824 
1825  BIND(&if_fast_double);
1826  {
1827  Comment("packed double elements");
1828  var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index,
1829  MachineType::Float64()));
1830  Goto(rebox_double);
1831  }
1832 
1833  BIND(&if_fast_holey_double);
1834  {
1835  Comment("holey double elements");
1836  Node* value = LoadFixedDoubleArrayElement(elements, intptr_index,
1837  MachineType::Float64(), 0,
1838  INTPTR_PARAMETERS, if_hole);
1839  var_double_value->Bind(value);
1840  Goto(rebox_double);
1841  }
1842 
1843  BIND(&if_nonfast);
1844  {
1845  STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
1846  GotoIf(Int32GreaterThanOrEqual(
1847  elements_kind,
1848  Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
1849  &if_typed_array);
1850  GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
1851  &if_dictionary);
1852  Goto(unimplemented_elements_kind);
1853  }
1854 
1855  BIND(&if_dictionary);
1856  {
1857  Comment("dictionary elements");
1858  GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
1859 
1860  TNode<Object> value = BasicLoadNumberDictionaryElement(
1861  CAST(elements), intptr_index, miss, if_hole);
1862  exit_point->Return(value);
1863  }
1864 
1865  BIND(&if_typed_array);
1866  {
1867  Comment("typed elements");
1868  // Check if buffer has been neutered.
1869  Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset);
1870  GotoIf(IsDetachedBuffer(buffer), miss);
1871 
1872  // Bounds check.
1873  Node* length = SmiUntag(LoadJSTypedArrayLength(CAST(object)));
1874  GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
1875 
1876  Node* backing_store = LoadFixedTypedArrayBackingStore(CAST(elements));
1877 
1878  Label uint8_elements(this), int8_elements(this), uint16_elements(this),
1879  int16_elements(this), uint32_elements(this), int32_elements(this),
1880  float32_elements(this), float64_elements(this), bigint64_elements(this),
1881  biguint64_elements(this);
1882  Label* elements_kind_labels[] = {
1883  &uint8_elements, &uint8_elements, &int8_elements,
1884  &uint16_elements, &int16_elements, &uint32_elements,
1885  &int32_elements, &float32_elements, &float64_elements,
1886  &bigint64_elements, &biguint64_elements};
1887  int32_t elements_kinds[] = {
1888  UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
1889  UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS,
1890  INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS,
1891  BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS};
1892  const size_t kTypedElementsKindCount =
1893  LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
1894  FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
1895  DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
1896  DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
1897  Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
1898  kTypedElementsKindCount);
1899  BIND(&uint8_elements);
1900  {
1901  Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
1902  Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
1903  exit_point->Return(SmiFromInt32(element));
1904  }
1905  BIND(&int8_elements);
1906  {
1907  Comment("INT8_ELEMENTS");
1908  Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
1909  exit_point->Return(SmiFromInt32(element));
1910  }
1911  BIND(&uint16_elements);
1912  {
1913  Comment("UINT16_ELEMENTS");
1914  Node* index = WordShl(intptr_index, IntPtrConstant(1));
1915  Node* element = Load(MachineType::Uint16(), backing_store, index);
1916  exit_point->Return(SmiFromInt32(element));
1917  }
1918  BIND(&int16_elements);
1919  {
1920  Comment("INT16_ELEMENTS");
1921  Node* index = WordShl(intptr_index, IntPtrConstant(1));
1922  Node* element = Load(MachineType::Int16(), backing_store, index);
1923  exit_point->Return(SmiFromInt32(element));
1924  }
1925  BIND(&uint32_elements);
1926  {
1927  Comment("UINT32_ELEMENTS");
1928  Node* index = WordShl(intptr_index, IntPtrConstant(2));
1929  Node* element = Load(MachineType::Uint32(), backing_store, index);
1930  exit_point->Return(ChangeUint32ToTagged(element));
1931  }
1932  BIND(&int32_elements);
1933  {
1934  Comment("INT32_ELEMENTS");
1935  Node* index = WordShl(intptr_index, IntPtrConstant(2));
1936  Node* element = Load(MachineType::Int32(), backing_store, index);
1937  exit_point->Return(ChangeInt32ToTagged(element));
1938  }
1939  BIND(&float32_elements);
1940  {
1941  Comment("FLOAT32_ELEMENTS");
1942  Node* index = WordShl(intptr_index, IntPtrConstant(2));
1943  Node* element = Load(MachineType::Float32(), backing_store, index);
1944  var_double_value->Bind(ChangeFloat32ToFloat64(element));
1945  Goto(rebox_double);
1946  }
1947  BIND(&float64_elements);
1948  {
1949  Comment("FLOAT64_ELEMENTS");
1950  Node* index = WordShl(intptr_index, IntPtrConstant(3));
1951  Node* element = Load(MachineType::Float64(), backing_store, index);
1952  var_double_value->Bind(element);
1953  Goto(rebox_double);
1954  }
1955  BIND(&bigint64_elements);
1956  {
1957  Comment("BIGINT64_ELEMENTS");
1958  exit_point->Return(LoadFixedTypedArrayElementAsTagged(
1959  backing_store, intptr_index, BIGINT64_ELEMENTS, INTPTR_PARAMETERS));
1960  }
1961  BIND(&biguint64_elements);
1962  {
1963  Comment("BIGUINT64_ELEMENTS");
1964  exit_point->Return(LoadFixedTypedArrayElementAsTagged(
1965  backing_store, intptr_index, BIGUINT64_ELEMENTS, INTPTR_PARAMETERS));
1966  }
1967  }
1968 }
1969 
1970 void AccessorAssembler::NameDictionaryNegativeLookup(Node* object,
1971  SloppyTNode<Name> name,
1972  Label* miss) {
1973  CSA_ASSERT(this, IsDictionaryMap(LoadMap(object)));
1974  TNode<NameDictionary> properties = CAST(LoadSlowProperties(object));
1975  // Ensure the property does not exist in a dictionary-mode object.
1976  TVARIABLE(IntPtrT, var_name_index);
1977  Label done(this);
1978  NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index,
1979  &done);
1980  BIND(&done);
1981 }
1982 
1983 void AccessorAssembler::BranchIfStrictMode(Node* vector, Node* slot,
1984  Label* if_strict) {
1985  Node* sfi =
1986  LoadObjectField(vector, FeedbackVector::kSharedFunctionInfoOffset);
1987  TNode<FeedbackMetadata> metadata = CAST(LoadObjectField(
1988  sfi, SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset));
1989  Node* slot_int = SmiToInt32(slot);
1990 
1991  // See VectorICComputer::index().
1992  const int kItemsPerWord = FeedbackMetadata::VectorICComputer::kItemsPerWord;
1993  Node* word_index = Int32Div(slot_int, Int32Constant(kItemsPerWord));
1994  Node* word_offset = Int32Mod(slot_int, Int32Constant(kItemsPerWord));
1995 
1996  int32_t first_item = FeedbackMetadata::kHeaderSize - kHeapObjectTag;
1997  Node* offset =
1998  ElementOffsetFromIndex(ChangeInt32ToIntPtr(word_index), UINT32_ELEMENTS,
1999  INTPTR_PARAMETERS, first_item);
2000 
2001  Node* data = Load(MachineType::Int32(), metadata, offset);
2002 
2003  // See VectorICComputer::decode().
2004  const int kBitsPerItem = FeedbackMetadata::kFeedbackSlotKindBits;
2005  Node* shift = Int32Mul(word_offset, Int32Constant(kBitsPerItem));
2006  const int kMask = FeedbackMetadata::VectorICComputer::kMask;
2007  Node* kind = Word32And(Word32Shr(data, shift), Int32Constant(kMask));
2008 
2009  STATIC_ASSERT(FeedbackSlotKind::kStoreGlobalSloppy <=
2010  FeedbackSlotKind::kLastSloppyKind);
2011  STATIC_ASSERT(FeedbackSlotKind::kStoreKeyedSloppy <=
2012  FeedbackSlotKind::kLastSloppyKind);
2013  STATIC_ASSERT(FeedbackSlotKind::kStoreNamedSloppy <=
2014  FeedbackSlotKind::kLastSloppyKind);
2015  GotoIfNot(Int32LessThanOrEqual(kind, Int32Constant(static_cast<int>(
2016  FeedbackSlotKind::kLastSloppyKind))),
2017  if_strict);
2018 }
2019 
2020 void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map,
2021  Node* bitfield2) {
2022  Label is_prototype(this), cont(this);
2023  if (bitfield2 == nullptr) {
2024  bitfield2 = LoadMapBitField2(map);
2025  }
2026 
2027  Branch(IsSetWord32(bitfield2, Map::IsPrototypeMapBit::kMask), &is_prototype,
2028  &cont);
2029 
2030  BIND(&is_prototype);
2031  {
2032  Node* maybe_prototype_info =
2033  LoadObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
2034  // If there's no prototype info then there's nothing to invalidate.
2035  GotoIf(TaggedIsSmi(maybe_prototype_info), &cont);
2036 
2037  Node* function = ExternalConstant(
2038  ExternalReference::invalidate_prototype_chains_function());
2039  CallCFunction1(MachineType::AnyTagged(), MachineType::AnyTagged(), function,
2040  map);
2041  Goto(&cont);
2042  }
2043  BIND(&cont);
2044 }
2045 
2046 void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
2047  SloppyTNode<Int32T> instance_type,
2048  Node* index, Label* slow) {
2049  Comment("integer index");
2050 
2051  ExitPoint direct_exit(this);
2052 
2053  Label if_custom(this), if_element_hole(this), if_oob(this);
2054  // Receivers requiring non-standard element accesses (interceptors, access
2055  // checks, strings and string wrappers, proxies) are handled in the runtime.
2056  GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &if_custom);
2057  Node* elements = LoadElements(receiver);
2058  Node* elements_kind = LoadMapElementsKind(receiver_map);
2059  Node* is_jsarray_condition = InstanceTypeEqual(instance_type, JS_ARRAY_TYPE);
2060  VARIABLE(var_double_value, MachineRepresentation::kFloat64);
2061  Label rebox_double(this, &var_double_value);
2062 
2063  // Unimplemented elements kinds fall back to a runtime call.
2064  Label* unimplemented_elements_kind = slow;
2065  IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
2066  EmitElementLoad(receiver, elements, elements_kind, index,
2067  is_jsarray_condition, &if_element_hole, &rebox_double,
2068  &var_double_value, unimplemented_elements_kind, &if_oob, slow,
2069  &direct_exit);
2070 
2071  BIND(&rebox_double);
2072  Return(AllocateHeapNumberWithValue(var_double_value.value()));
2073 
2074  BIND(&if_oob);
2075  {
2076  Comment("out of bounds");
2077  // Positive OOB indices are effectively the same as hole loads.
2078  GotoIf(IntPtrGreaterThanOrEqual(index, IntPtrConstant(0)),
2079  &if_element_hole);
2080  // Negative keys can't take the fast OOB path, except for typed arrays.
2081  GotoIfNot(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), slow);
2082  Return(UndefinedConstant());
2083  }
2084 
2085  BIND(&if_element_hole);
2086  {
2087  Comment("found the hole");
2088  Label return_undefined(this);
2089  BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow);
2090 
2091  BIND(&return_undefined);
2092  Return(UndefinedConstant());
2093  }
2094 
2095  BIND(&if_custom);
2096  {
2097  Comment("check if string");
2098  GotoIfNot(IsStringInstanceType(instance_type), slow);
2099  Comment("load string character");
2100  TNode<IntPtrT> length = LoadStringLengthAsWord(receiver);
2101  GotoIfNot(UintPtrLessThan(index, length), slow);
2102  IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
2103  TailCallBuiltin(Builtins::kStringCharAt, NoContextConstant(), receiver,
2104  index);
2105  }
2106 }
2107 
2108 void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
2109  SloppyTNode<Int32T> instance_type,
2110  const LoadICParameters* p,
2111  Label* slow,
2112  UseStubCache use_stub_cache) {
2113  ExitPoint direct_exit(this);
2114 
2115  Comment("key is unique name");
2116  Label if_found_on_receiver(this), if_property_dictionary(this),
2117  lookup_prototype_chain(this), special_receiver(this);
2118  VARIABLE(var_details, MachineRepresentation::kWord32);
2119  VARIABLE(var_value, MachineRepresentation::kTagged);
2120 
2121  // Receivers requiring non-standard accesses (interceptors, access
2122  // checks, strings and string wrappers) are handled in the runtime.
2123  GotoIf(IsSpecialReceiverInstanceType(instance_type), &special_receiver);
2124 
2125  // Check if the receiver has fast or slow properties.
2126  Node* bitfield3 = LoadMapBitField3(receiver_map);
2127  GotoIf(IsSetWord32<Map::IsDictionaryMapBit>(bitfield3),
2128  &if_property_dictionary);
2129 
2130  // Try looking up the property on the receiver; if unsuccessful, look
2131  // for a handler in the stub cache.
2132  TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
2133 
2134  Label if_descriptor_found(this), stub_cache(this);
2135  TVARIABLE(IntPtrT, var_name_index);
2136  Label* notfound =
2137  use_stub_cache == kUseStubCache ? &stub_cache : &lookup_prototype_chain;
2138  DescriptorLookup(p->name, descriptors, bitfield3, &if_descriptor_found,
2139  &var_name_index, notfound);
2140 
2141  BIND(&if_descriptor_found);
2142  {
2143  LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
2144  var_name_index.value(), &var_details,
2145  &var_value);
2146  Goto(&if_found_on_receiver);
2147  }
2148 
2149  if (use_stub_cache == kUseStubCache) {
2150  BIND(&stub_cache);
2151  Comment("stub cache probe for fast property load");
2152  TVARIABLE(MaybeObject, var_handler);
2153  Label found_handler(this, &var_handler), stub_cache_miss(this);
2154  TryProbeStubCache(isolate()->load_stub_cache(), receiver, p->name,
2155  &found_handler, &var_handler, &stub_cache_miss);
2156  BIND(&found_handler);
2157  {
2158  HandleLoadICHandlerCase(p, CAST(var_handler.value()), &stub_cache_miss,
2159  &direct_exit);
2160  }
2161 
2162  BIND(&stub_cache_miss);
2163  {
2164  // TODO(jkummerow): Check if the property exists on the prototype
2165  // chain. If it doesn't, then there's no point in missing.
2166  Comment("KeyedLoadGeneric_miss");
2167  TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
2168  p->name, p->slot, p->vector);
2169  }
2170  }
2171 
2172  BIND(&if_property_dictionary);
2173  {
2174  Comment("dictionary property load");
2175  // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
2176  // seeing global objects here (which would need special handling).
2177 
2178  TVARIABLE(IntPtrT, var_name_index);
2179  Label dictionary_found(this, &var_name_index);
2180  TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver));
2181  NameDictionaryLookup<NameDictionary>(properties, CAST(p->name),
2182  &dictionary_found, &var_name_index,
2183  &lookup_prototype_chain);
2184  BIND(&dictionary_found);
2185  {
2186  LoadPropertyFromNameDictionary(properties, var_name_index.value(),
2187  &var_details, &var_value);
2188  Goto(&if_found_on_receiver);
2189  }
2190  }
2191 
2192  BIND(&if_found_on_receiver);
2193  {
2194  Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
2195  p->context, receiver, slow);
2196  IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
2197  Return(value);
2198  }
2199 
2200  BIND(&lookup_prototype_chain);
2201  {
2202  VARIABLE(var_holder_map, MachineRepresentation::kTagged);
2203  VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32);
2204  Label return_undefined(this);
2205  Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
2206  Label loop(this, arraysize(merged_variables), merged_variables);
2207 
2208  var_holder_map.Bind(receiver_map);
2209  var_holder_instance_type.Bind(instance_type);
2210  // Private symbols must not be looked up on the prototype chain.
2211  GotoIf(IsPrivateSymbol(p->name), &return_undefined);
2212  Goto(&loop);
2213  BIND(&loop);
2214  {
2215  // Bailout if it can be an integer indexed exotic case.
2216  GotoIf(InstanceTypeEqual(var_holder_instance_type.value(),
2217  JS_TYPED_ARRAY_TYPE),
2218  slow);
2219  Node* proto = LoadMapPrototype(var_holder_map.value());
2220  GotoIf(WordEqual(proto, NullConstant()), &return_undefined);
2221  Node* proto_map = LoadMap(proto);
2222  Node* proto_instance_type = LoadMapInstanceType(proto_map);
2223  var_holder_map.Bind(proto_map);
2224  var_holder_instance_type.Bind(proto_instance_type);
2225  Label next_proto(this), return_value(this, &var_value), goto_slow(this);
2226  TryGetOwnProperty(p->context, receiver, proto, proto_map,
2227  proto_instance_type, p->name, &return_value, &var_value,
2228  &next_proto, &goto_slow);
2229 
2230  // This trampoline and the next are required to appease Turbofan's
2231  // variable merging.
2232  BIND(&next_proto);
2233  Goto(&loop);
2234 
2235  BIND(&goto_slow);
2236  Goto(slow);
2237 
2238  BIND(&return_value);
2239  Return(var_value.value());
2240  }
2241 
2242  BIND(&return_undefined);
2243  Return(UndefinedConstant());
2244  }
2245 
2246  BIND(&special_receiver);
2247  {
2248  // TODO(jkummerow): Consider supporting JSModuleNamespace.
2249  GotoIfNot(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), slow);
2250 
2251  // Private field/symbol lookup is not supported.
2252  GotoIf(IsPrivateSymbol(p->name), slow);
2253 
2254  direct_exit.ReturnCallStub(
2255  Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
2256  p->context, receiver /*holder is the same as receiver*/, p->name,
2257  receiver, SmiConstant(OnNonExistent::kReturnUndefined));
2258  }
2259 }
2260 
2262 
2263 enum AccessorAssembler::StubCacheTable : int {
2264  kPrimary = static_cast<int>(StubCache::kPrimary),
2265  kSecondary = static_cast<int>(StubCache::kSecondary)
2266 };
2267 
2268 Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
2269  // See v8::internal::StubCache::PrimaryOffset().
2270  STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
2271  // Compute the hash of the name (use entire hash field).
2272  Node* hash_field = LoadNameHashField(name);
2273  CSA_ASSERT(this,
2274  Word32Equal(Word32And(hash_field,
2275  Int32Constant(Name::kHashNotComputedMask)),
2276  Int32Constant(0)));
2277 
2278  // Using only the low bits in 64-bit mode is unlikely to increase the
2279  // risk of collision even if the heap is spread over an area larger than
2280  // 4Gb (and not at all if it isn't).
2281  Node* map32 = TruncateIntPtrToInt32(BitcastTaggedToWord(map));
2282  // Base the offset on a simple combination of name and map.
2283  Node* hash = Int32Add(hash_field, map32);
2284  uint32_t mask = (StubCache::kPrimaryTableSize - 1)
2285  << StubCache::kCacheIndexShift;
2286  return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
2287 }
2288 
2289 Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
2290  // See v8::internal::StubCache::SecondaryOffset().
2291 
2292  // Use the seed from the primary cache in the secondary cache.
2293  Node* name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name));
2294  Node* hash = Int32Sub(TruncateIntPtrToInt32(seed), name32);
2295  hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
2296  int32_t mask = (StubCache::kSecondaryTableSize - 1)
2297  << StubCache::kCacheIndexShift;
2298  return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
2299 }
2300 
2301 void AccessorAssembler::TryProbeStubCacheTable(
2302  StubCache* stub_cache, StubCacheTable table_id, Node* entry_offset,
2303  Node* name, Node* map, Label* if_handler,
2304  TVariable<MaybeObject>* var_handler, Label* if_miss) {
2305  StubCache::Table table = static_cast<StubCache::Table>(table_id);
2306 #ifdef DEBUG
2307  if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
2308  Goto(if_miss);
2309  return;
2310  } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
2311  Goto(if_miss);
2312  return;
2313  }
2314 #endif
2315  // The {table_offset} holds the entry offset times four (due to masking
2316  // and shifting optimizations).
2317  const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
2318  entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
2319 
2320  // Check that the key in the entry matches the name.
2321  Node* key_base = ExternalConstant(
2322  ExternalReference::Create(stub_cache->key_reference(table)));
2323  Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset);
2324  GotoIf(WordNotEqual(name, entry_key), if_miss);
2325 
2326  // Get the map entry from the cache.
2327  DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() -
2328  stub_cache->key_reference(table).address());
2329  Node* entry_map =
2330  Load(MachineType::Pointer(), key_base,
2331  IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize * 2)));
2332  GotoIf(WordNotEqual(map, entry_map), if_miss);
2333 
2334  DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() -
2335  stub_cache->key_reference(table).address());
2336  TNode<MaybeObject> handler = ReinterpretCast<MaybeObject>(
2337  Load(MachineType::AnyTagged(), key_base,
2338  IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize))));
2339 
2340  // We found the handler.
2341  *var_handler = handler;
2342  Goto(if_handler);
2343 }
2344 
2345 void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
2346  Node* name, Label* if_handler,
2347  TVariable<MaybeObject>* var_handler,
2348  Label* if_miss) {
2349  Label try_secondary(this), miss(this);
2350 
2351  Counters* counters = isolate()->counters();
2352  IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
2353 
2354  // Check that the {receiver} isn't a smi.
2355  GotoIf(TaggedIsSmi(receiver), &miss);
2356 
2357  Node* receiver_map = LoadMap(receiver);
2358 
2359  // Probe the primary table.
2360  Node* primary_offset = StubCachePrimaryOffset(name, receiver_map);
2361  TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
2362  receiver_map, if_handler, var_handler, &try_secondary);
2363 
2364  BIND(&try_secondary);
2365  {
2366  // Probe the secondary table.
2367  Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset);
2368  TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
2369  receiver_map, if_handler, var_handler, &miss);
2370  }
2371 
2372  BIND(&miss);
2373  {
2374  IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
2375  Goto(if_miss);
2376  }
2377 }
2378 
2380 
2381 void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
2382  ExitPoint* exit_point) {
2383  // Must be kept in sync with LoadIC.
2384 
2385  // This function is hand-tuned to omit frame construction for common cases,
2386  // e.g.: monomorphic field and constant loads through smi handlers.
2387  // Polymorphic ICs with a hit in the first two entries also omit frames.
2388  // TODO(jgruber): Frame omission is fragile and can be affected by minor
2389  // changes in control flow and logic. We currently have no way of ensuring
2390  // that no frame is constructed, so it's easy to break this optimization by
2391  // accident.
2392  Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred);
2393 
2394  // Inlined fast path.
2395  {
2396  Comment("LoadIC_BytecodeHandler_fast");
2397 
2398  Node* recv_map = LoadReceiverMap(p->receiver);
2399  GotoIf(IsDeprecatedMap(recv_map), &miss);
2400 
2401  TVARIABLE(MaybeObject, var_handler);
2402  Label try_polymorphic(this), if_handler(this, &var_handler);
2403 
2404  TNode<MaybeObject> feedback =
2405  TryMonomorphicCase(p->slot, p->vector, recv_map, &if_handler,
2406  &var_handler, &try_polymorphic);
2407 
2408  BIND(&if_handler);
2409  HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, exit_point);
2410 
2411  BIND(&try_polymorphic);
2412  {
2413  TNode<HeapObject> strong_feedback =
2414  GetHeapObjectIfStrong(feedback, &miss);
2415  GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &stub_call);
2416  HandlePolymorphicCase(recv_map, CAST(strong_feedback), &if_handler,
2417  &var_handler, &miss, 2);
2418  }
2419  }
2420 
2421  BIND(&stub_call);
2422  {
2423  Comment("LoadIC_BytecodeHandler_noninlined");
2424 
2425  // Call into the stub that implements the non-inlined parts of LoadIC.
2426  Callable ic =
2427  Builtins::CallableFor(isolate(), Builtins::kLoadIC_Noninlined);
2428  Node* code_target = HeapConstant(ic.code());
2429  exit_point->ReturnCallStub(ic.descriptor(), code_target, p->context,
2430  p->receiver, p->name, p->slot, p->vector);
2431  }
2432 
2433  BIND(&miss);
2434  {
2435  Comment("LoadIC_BytecodeHandler_miss");
2436 
2437  exit_point->ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context,
2438  p->receiver, p->name, p->slot, p->vector);
2439  }
2440 }
2441 
2442 void AccessorAssembler::LoadIC(const LoadICParameters* p) {
2443  // Must be kept in sync with LoadIC_BytecodeHandler.
2444 
2445  ExitPoint direct_exit(this);
2446 
2447  TVARIABLE(MaybeObject, var_handler);
2448  Label if_handler(this, &var_handler), non_inlined(this, Label::kDeferred),
2449  try_polymorphic(this), miss(this, Label::kDeferred);
2450 
2451  Node* receiver_map = LoadReceiverMap(p->receiver);
2452  GotoIf(IsDeprecatedMap(receiver_map), &miss);
2453 
2454  // Check monomorphic case.
2455  TNode<MaybeObject> feedback =
2456  TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
2457  &var_handler, &try_polymorphic);
2458  BIND(&if_handler);
2459  HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit);
2460 
2461  BIND(&try_polymorphic);
2462  TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
2463  {
2464  // Check polymorphic case.
2465  Comment("LoadIC_try_polymorphic");
2466  GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &non_inlined);
2467  HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
2468  &var_handler, &miss, 2);
2469  }
2470 
2471  BIND(&non_inlined);
2472  {
2473  LoadIC_Noninlined(p, receiver_map, strong_feedback, &var_handler,
2474  &if_handler, &miss, &direct_exit);
2475  }
2476 
2477  BIND(&miss);
2478  direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver,
2479  p->name, p->slot, p->vector);
2480 }
2481 
2482 void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
2483  Node* receiver_map,
2484  TNode<HeapObject> feedback,
2485  TVariable<MaybeObject>* var_handler,
2486  Label* if_handler, Label* miss,
2487  ExitPoint* exit_point) {
2488  Label try_uninitialized(this, Label::kDeferred);
2489 
2490  // Neither deprecated map nor monomorphic. These cases are handled in the
2491  // bytecode handler.
2492  CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
2493  CSA_ASSERT(this, WordNotEqual(receiver_map, feedback));
2494  CSA_ASSERT(this, Word32BinaryNot(IsWeakFixedArrayMap(LoadMap(feedback))));
2495  DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
2496 
2497  {
2498  // Check megamorphic case.
2499  GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
2500  &try_uninitialized);
2501 
2502  TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
2503  if_handler, var_handler, miss);
2504  }
2505 
2506  BIND(&try_uninitialized);
2507  {
2508  // Check uninitialized case.
2509  GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
2510  miss);
2511  exit_point->ReturnCallStub(
2512  Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized),
2513  p->context, p->receiver, p->name, p->slot, p->vector);
2514  }
2515 }
2516 
2517 void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
2518  Label miss(this, Label::kDeferred);
2519  Node* receiver = p->receiver;
2520  GotoIf(TaggedIsSmi(receiver), &miss);
2521  Node* receiver_map = LoadMap(receiver);
2522  Node* instance_type = LoadMapInstanceType(receiver_map);
2523 
2524  // Optimistically write the state transition to the vector.
2525  StoreFeedbackVectorSlot(p->vector, p->slot,
2526  LoadRoot(RootIndex::kpremonomorphic_symbol),
2527  SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
2528  StoreWeakReferenceInFeedbackVector(p->vector, p->slot, receiver_map,
2529  kPointerSize, SMI_PARAMETERS);
2530 
2531  {
2532  // Special case for Function.prototype load, because it's very common
2533  // for ICs that are only executed once (MyFunc.prototype.foo = ...).
2534  Label not_function_prototype(this, Label::kDeferred);
2535  GotoIfNot(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
2536  &not_function_prototype);
2537  GotoIfNot(IsPrototypeString(p->name), &not_function_prototype);
2538 
2539  GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), CAST(receiver_map),
2540  &not_function_prototype);
2541  Return(LoadJSFunctionPrototype(receiver, &miss));
2542  BIND(&not_function_prototype);
2543  }
2544 
2545  GenericPropertyLoad(receiver, receiver_map, instance_type, p, &miss,
2546  kDontUseStubCache);
2547 
2548  BIND(&miss);
2549  {
2550  // Undo the optimistic state transition.
2551  StoreFeedbackVectorSlot(p->vector, p->slot,
2552  LoadRoot(RootIndex::kuninitialized_symbol),
2553  SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
2554 
2555  TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
2556  p->slot, p->vector);
2557  }
2558 }
2559 
2560 void AccessorAssembler::LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot,
2561  const LazyNode<Context>& lazy_context,
2562  const LazyNode<Name>& lazy_name,
2563  TypeofMode typeof_mode,
2564  ExitPoint* exit_point,
2565  ParameterMode slot_mode) {
2566  Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred);
2567  LoadGlobalIC_TryPropertyCellCase(vector, slot, lazy_context, exit_point,
2568  &try_handler, &miss, slot_mode);
2569 
2570  BIND(&try_handler);
2571  LoadGlobalIC_TryHandlerCase(vector, slot, lazy_context, lazy_name,
2572  typeof_mode, exit_point, &miss, slot_mode);
2573 
2574  BIND(&miss);
2575  {
2576  Comment("LoadGlobalIC_MissCase");
2577  TNode<Context> context = lazy_context();
2578  TNode<Name> name = lazy_name();
2579  exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, context, name,
2580  ParameterToTagged(slot, slot_mode), vector);
2581  }
2582 }
2583 
2584 void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
2585  TNode<FeedbackVector> vector, Node* slot,
2586  const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
2587  Label* try_handler, Label* miss, ParameterMode slot_mode) {
2588  Comment("LoadGlobalIC_TryPropertyCellCase");
2589 
2590  Label if_lexical_var(this), if_property_cell(this);
2591  TNode<MaybeObject> maybe_weak_ref =
2592  LoadFeedbackVectorSlot(vector, slot, 0, slot_mode);
2593  Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
2594 
2595  BIND(&if_property_cell);
2596  {
2597  // Load value or try handler case if the weak reference is cleared.
2598  CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref));
2599  TNode<PropertyCell> property_cell =
2600  CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, try_handler));
2601  TNode<Object> value =
2602  LoadObjectField(property_cell, PropertyCell::kValueOffset);
2603  GotoIf(WordEqual(value, TheHoleConstant()), miss);
2604  exit_point->Return(value);
2605  }
2606 
2607  BIND(&if_lexical_var);
2608  {
2609  Comment("Load lexical variable");
2610  TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
2611  TNode<IntPtrT> context_index =
2612  Signed(DecodeWord<FeedbackNexus::ContextIndexBits>(lexical_handler));
2613  TNode<IntPtrT> slot_index =
2614  Signed(DecodeWord<FeedbackNexus::SlotIndexBits>(lexical_handler));
2615  TNode<Context> context = lazy_context();
2616  TNode<Context> script_context = LoadScriptContext(context, context_index);
2617  TNode<Object> result = LoadContextElement(script_context, slot_index);
2618  exit_point->Return(result);
2619  }
2620 }
2621 
2622 void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
2623  TNode<FeedbackVector> vector, Node* slot,
2624  const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name,
2625  TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss,
2626  ParameterMode slot_mode) {
2627  Comment("LoadGlobalIC_TryHandlerCase");
2628 
2629  Label call_handler(this), non_smi(this);
2630 
2631  TNode<MaybeObject> feedback_element =
2632  LoadFeedbackVectorSlot(vector, slot, kPointerSize, slot_mode);
2633  TNode<Object> handler = CAST(feedback_element);
2634  GotoIf(WordEqual(handler, LoadRoot(RootIndex::kuninitialized_symbol)), miss);
2635 
2636  OnNonExistent on_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF
2637  ? OnNonExistent::kThrowReferenceError
2638  : OnNonExistent::kReturnUndefined;
2639 
2640  TNode<Context> context = lazy_context();
2641  TNode<Context> native_context = LoadNativeContext(context);
2642  TNode<JSGlobalProxy> receiver =
2643  CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX));
2644  Node* holder = LoadContextElement(native_context, Context::EXTENSION_INDEX);
2645 
2646  LoadICParameters p(context, receiver, lazy_name(),
2647  ParameterToTagged(slot, slot_mode), vector, holder);
2648 
2649  HandleLoadICHandlerCase(&p, handler, miss, exit_point, ICMode::kGlobalIC,
2650  on_nonexistent);
2651 }
2652 
2653 void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
2654  ExitPoint direct_exit(this);
2655 
2656  TVARIABLE(MaybeObject, var_handler);
2657  Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
2658  try_megamorphic(this, Label::kDeferred),
2659  try_polymorphic_name(this, Label::kDeferred),
2660  miss(this, Label::kDeferred);
2661 
2662  Node* receiver_map = LoadReceiverMap(p->receiver);
2663  GotoIf(IsDeprecatedMap(receiver_map), &miss);
2664 
2665  // Check monomorphic case.
2666  TNode<MaybeObject> feedback =
2667  TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
2668  &var_handler, &try_polymorphic);
2669  BIND(&if_handler);
2670  {
2671  HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit,
2672  ICMode::kNonGlobalIC,
2673  OnNonExistent::kReturnUndefined, kSupportElements);
2674  }
2675 
2676  BIND(&try_polymorphic);
2677  TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
2678  {
2679  // Check polymorphic case.
2680  Comment("KeyedLoadIC_try_polymorphic");
2681  GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
2682  HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
2683  &var_handler, &miss, 2);
2684  }
2685 
2686  BIND(&try_megamorphic);
2687  {
2688  // Check megamorphic case.
2689  Comment("KeyedLoadIC_try_megamorphic");
2690  GotoIfNot(
2691  WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
2692  &try_polymorphic_name);
2693  // TODO(jkummerow): Inline this? Or some of it?
2694  TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, p->context, p->receiver,
2695  p->name, p->slot, p->vector);
2696  }
2697  BIND(&try_polymorphic_name);
2698  {
2699  // We might have a name in feedback, and a weak fixed array in the next
2700  // slot.
2701  Node* name = p->name;
2702  Comment("KeyedLoadIC_try_polymorphic_name");
2703  VARIABLE(var_name, MachineRepresentation::kTagged, name);
2704  VARIABLE(var_index, MachineType::PointerRepresentation());
2705  Label if_polymorphic_name(this, &var_name), if_internalized(this),
2706  if_notinternalized(this, Label::kDeferred);
2707 
2708  // Fast-case: The recorded {feedback} matches the {name}.
2709  GotoIf(WordEqual(strong_feedback, name), &if_polymorphic_name);
2710 
2711  // Try to internalize the {name} if it isn't already.
2712  TryToName(name, &miss, &var_index, &if_internalized, &var_name, &miss,
2713  &if_notinternalized);
2714 
2715  BIND(&if_internalized);
2716  {
2717  // The {var_name} now contains a unique name.
2718  Branch(WordEqual(strong_feedback, var_name.value()), &if_polymorphic_name,
2719  &miss);
2720  }
2721 
2722  BIND(&if_notinternalized);
2723  {
2724  // Try to internalize the {name}.
2725  Node* function = ExternalConstant(
2726  ExternalReference::try_internalize_string_function());
2727  Node* const isolate_ptr =
2728  ExternalConstant(ExternalReference::isolate_address(isolate()));
2729  var_name.Bind(CallCFunction2(
2730  MachineType::AnyTagged(), MachineType::Pointer(),
2731  MachineType::AnyTagged(), function, isolate_ptr, name));
2732  Goto(&if_internalized);
2733  }
2734 
2735  BIND(&if_polymorphic_name);
2736  {
2737  // If the name comparison succeeded, we know we have a weak fixed array
2738  // with at least one map/handler pair.
2739  Node* name = var_name.value();
2740  TailCallBuiltin(Builtins::kKeyedLoadIC_PolymorphicName, p->context,
2741  p->receiver, name, p->slot, p->vector);
2742  }
2743  }
2744 
2745  BIND(&miss);
2746  {
2747  Comment("KeyedLoadIC_miss");
2748  TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
2749  p->name, p->slot, p->vector);
2750  }
2751 }
2752 
2753 void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
2754  VARIABLE(var_index, MachineType::PointerRepresentation());
2755  VARIABLE(var_unique, MachineRepresentation::kTagged, p->name);
2756  Label if_index(this), if_unique_name(this), if_notunique(this),
2757  if_other(this, Label::kDeferred), if_runtime(this, Label::kDeferred);
2758 
2759  Node* receiver = p->receiver;
2760  GotoIf(TaggedIsSmi(receiver), &if_runtime);
2761 
2762  TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
2763  &if_other, &if_notunique);
2764 
2765  BIND(&if_other);
2766  {
2767  Node* name = CallBuiltin(Builtins::kToName, p->context, p->name);
2768  var_unique.Bind(name);
2769  TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique,
2770  &if_runtime, &if_notunique);
2771  }
2772 
2773  BIND(&if_index);
2774  {
2775  Node* receiver_map = LoadMap(receiver);
2776  Node* instance_type = LoadMapInstanceType(receiver_map);
2777  GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
2778  &if_runtime);
2779  }
2780 
2781  BIND(&if_unique_name);
2782  {
2783  LoadICParameters pp = *p;
2784  pp.name = var_unique.value();
2785  Node* receiver_map = LoadMap(receiver);
2786  Node* instance_type = LoadMapInstanceType(receiver_map);
2787  GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
2788  &if_runtime);
2789  }
2790 
2791  BIND(&if_notunique);
2792  {
2793  if (FLAG_internalize_on_the_fly) {
2794  // Ideally we could return undefined directly here if the name is not
2795  // found in the string table, i.e. it was never internalized, but that
2796  // invariant doesn't hold with named property interceptors (at this
2797  // point), so we take the {if_runtime} path instead.
2798  Label if_in_string_table(this);
2799  TryInternalizeString(var_unique.value(), &if_index, &var_index,
2800  &if_in_string_table, &var_unique, &if_runtime,
2801  &if_runtime);
2802 
2803  BIND(&if_in_string_table);
2804  {
2805  // TODO(bmeurer): We currently use a version of GenericPropertyLoad
2806  // here, where we don't try to probe the megamorphic stub cache after
2807  // successfully internalizing the incoming string. Past experiments
2808  // with this have shown that it causes too much traffic on the stub
2809  // cache. We may want to re-evaluate that in the future.
2810  LoadICParameters pp = *p;
2811  pp.name = var_unique.value();
2812  Node* receiver_map = LoadMap(receiver);
2813  Node* instance_type = LoadMapInstanceType(receiver_map);
2814  GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
2815  &if_runtime, kDontUseStubCache);
2816  }
2817  } else {
2818  Goto(&if_runtime);
2819  }
2820  }
2821 
2822  BIND(&if_runtime);
2823  {
2824  Comment("KeyedLoadGeneric_slow");
2825  IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
2826  // TODO(jkummerow): Should we use the GetProperty TF stub instead?
2827  TailCallRuntime(Runtime::kGetProperty, p->context, p->receiver,
2828  var_unique.value());
2829  }
2830 }
2831 
2832 void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p) {
2833  TVARIABLE(MaybeObject, var_handler);
2834  Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
2835 
2836  Node* receiver = p->receiver;
2837  Node* receiver_map = LoadReceiverMap(receiver);
2838  Node* name = p->name;
2839  Node* vector = p->vector;
2840  Node* slot = p->slot;
2841  Node* context = p->context;
2842 
2843  // When we get here, we know that the {name} matches the recorded
2844  // feedback name in the {vector} and can safely be used for the
2845  // LoadIC handler logic below.
2846  CSA_ASSERT(this, IsName(name));
2847  CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
2848  CSA_ASSERT(this, WordEqual(name, CAST(LoadFeedbackVectorSlot(
2849  vector, slot, 0, SMI_PARAMETERS))));
2850 
2851  // Check if we have a matching handler for the {receiver_map}.
2852  TNode<MaybeObject> feedback_element =
2853  LoadFeedbackVectorSlot(vector, slot, kPointerSize, SMI_PARAMETERS);
2854  TNode<WeakFixedArray> array = CAST(feedback_element);
2855  HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
2856  1);
2857 
2858  BIND(&if_handler);
2859  {
2860  ExitPoint direct_exit(this);
2861  HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit,
2862  ICMode::kNonGlobalIC,
2863  OnNonExistent::kReturnUndefined, kOnlyProperties);
2864  }
2865 
2866  BIND(&miss);
2867  {
2868  Comment("KeyedLoadIC_miss");
2869  TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, name, slot,
2870  vector);
2871  }
2872 }
2873 
2874 void AccessorAssembler::StoreIC(const StoreICParameters* p) {
2875  TVARIABLE(MaybeObject, var_handler,
2876  ReinterpretCast<MaybeObject>(SmiConstant(0)));
2877 
2878  Label if_handler(this, &var_handler),
2879  if_handler_from_stub_cache(this, &var_handler, Label::kDeferred),
2880  try_polymorphic(this, Label::kDeferred),
2881  try_megamorphic(this, Label::kDeferred),
2882  try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred);
2883 
2884  Node* receiver_map = LoadReceiverMap(p->receiver);
2885  GotoIf(IsDeprecatedMap(receiver_map), &miss);
2886 
2887  // Check monomorphic case.
2888  TNode<MaybeObject> feedback =
2889  TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
2890  &var_handler, &try_polymorphic);
2891  BIND(&if_handler);
2892  {
2893  Comment("StoreIC_if_handler");
2894  HandleStoreICHandlerCase(p, var_handler.value(), &miss,
2895  ICMode::kNonGlobalIC);
2896  }
2897 
2898  BIND(&try_polymorphic);
2899  TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
2900  {
2901  // Check polymorphic case.
2902  Comment("StoreIC_try_polymorphic");
2903  GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
2904  HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
2905  &var_handler, &miss, 2);
2906  }
2907 
2908  BIND(&try_megamorphic);
2909  {
2910  // Check megamorphic case.
2911  GotoIfNot(
2912  WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
2913  &try_uninitialized);
2914 
2915  TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
2916  &if_handler, &var_handler, &miss);
2917  }
2918  BIND(&try_uninitialized);
2919  {
2920  // Check uninitialized case.
2921  GotoIfNot(
2922  WordEqual(strong_feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
2923  &miss);
2924  TailCallBuiltin(Builtins::kStoreIC_Uninitialized, p->context, p->receiver,
2925  p->name, p->value, p->slot, p->vector);
2926  }
2927  BIND(&miss);
2928  {
2929  TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
2930  p->vector, p->receiver, p->name);
2931  }
2932 }
2933 
2934 void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
2935  Label if_lexical_var(this), if_property_cell(this);
2936  TNode<MaybeObject> maybe_weak_ref =
2937  LoadFeedbackVectorSlot(pp->vector, pp->slot, 0, SMI_PARAMETERS);
2938  Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
2939 
2940  BIND(&if_property_cell);
2941  {
2942  Label try_handler(this), miss(this, Label::kDeferred);
2943  CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref));
2944  TNode<PropertyCell> property_cell =
2945  CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, &try_handler));
2946 
2947  ExitPoint direct_exit(this);
2948  StoreGlobalIC_PropertyCellCase(property_cell, pp->value, &direct_exit,
2949  &miss);
2950 
2951  BIND(&try_handler);
2952  {
2953  Comment("StoreGlobalIC_try_handler");
2954  TNode<MaybeObject> handler = LoadFeedbackVectorSlot(
2955  pp->vector, pp->slot, kPointerSize, SMI_PARAMETERS);
2956 
2957  GotoIf(WordEqual(handler, LoadRoot(RootIndex::kuninitialized_symbol)),
2958  &miss);
2959 
2960  StoreICParameters p = *pp;
2961  DCHECK_NULL(p.receiver);
2962  Node* native_context = LoadNativeContext(p.context);
2963  p.receiver =
2964  LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX);
2965 
2966  HandleStoreICHandlerCase(&p, handler, &miss, ICMode::kGlobalIC);
2967  }
2968 
2969  BIND(&miss);
2970  {
2971  TailCallRuntime(Runtime::kStoreGlobalIC_Miss, pp->context, pp->value,
2972  pp->slot, pp->vector, pp->name);
2973  }
2974  }
2975 
2976  BIND(&if_lexical_var);
2977  {
2978  Comment("Store lexical variable");
2979  TNode<IntPtrT> lexical_handler = SmiUntag(CAST(maybe_weak_ref));
2980  TNode<IntPtrT> context_index =
2981  Signed(DecodeWord<FeedbackNexus::ContextIndexBits>(lexical_handler));
2982  TNode<IntPtrT> slot_index =
2983  Signed(DecodeWord<FeedbackNexus::SlotIndexBits>(lexical_handler));
2984  TNode<Context> script_context =
2985  LoadScriptContext(CAST(pp->context), context_index);
2986  StoreContextElement(script_context, slot_index, pp->value);
2987  Return(pp->value);
2988  }
2989 }
2990 
2991 void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
2992  Node* value,
2993  ExitPoint* exit_point,
2994  Label* miss) {
2995  Comment("StoreGlobalIC_TryPropertyCellCase");
2996  CSA_ASSERT(this, IsPropertyCell(property_cell));
2997 
2998  // Load the payload of the global parameter cell. A hole indicates that
2999  // the cell has been invalidated and that the store must be handled by the
3000  // runtime.
3001  Node* cell_contents =
3002  LoadObjectField(property_cell, PropertyCell::kValueOffset);
3003  Node* details = LoadAndUntagToWord32ObjectField(property_cell,
3004  PropertyCell::kDetailsOffset);
3005  GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), miss);
3006  CSA_ASSERT(this,
3007  Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
3008  Int32Constant(kData)));
3009 
3010  Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
3011 
3012  Label constant(this), store(this), not_smi(this);
3013 
3014  GotoIf(Word32Equal(type, Int32Constant(
3015  static_cast<int>(PropertyCellType::kConstant))),
3016  &constant);
3017 
3018  GotoIf(IsTheHole(cell_contents), miss);
3019 
3020  GotoIf(Word32Equal(
3021  type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))),
3022  &store);
3023  CSA_ASSERT(this,
3024  Word32Or(Word32Equal(type, Int32Constant(static_cast<int>(
3025  PropertyCellType::kConstantType))),
3026  Word32Equal(type, Int32Constant(static_cast<int>(
3027  PropertyCellType::kUndefined)))));
3028 
3029  GotoIfNot(TaggedIsSmi(cell_contents), &not_smi);
3030  GotoIfNot(TaggedIsSmi(value), miss);
3031  Goto(&store);
3032 
3033  BIND(&not_smi);
3034  {
3035  GotoIf(TaggedIsSmi(value), miss);
3036  Node* expected_map = LoadMap(cell_contents);
3037  Node* map = LoadMap(value);
3038  GotoIfNot(WordEqual(expected_map, map), miss);
3039  Goto(&store);
3040  }
3041 
3042  BIND(&store);
3043  {
3044  StoreObjectField(property_cell, PropertyCell::kValueOffset, value);
3045  exit_point->Return(value);
3046  }
3047 
3048  BIND(&constant);
3049  {
3050  GotoIfNot(WordEqual(cell_contents, value), miss);
3051  exit_point->Return(value);
3052  }
3053 }
3054 
3055 void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
3056  Label miss(this, Label::kDeferred);
3057  {
3058  TVARIABLE(MaybeObject, var_handler);
3059 
3060  Label if_handler(this, &var_handler),
3061  try_polymorphic(this, Label::kDeferred),
3062  try_megamorphic(this, Label::kDeferred),
3063  try_polymorphic_name(this, Label::kDeferred);
3064 
3065  Node* receiver_map = LoadReceiverMap(p->receiver);
3066  GotoIf(IsDeprecatedMap(receiver_map), &miss);
3067 
3068  // Check monomorphic case.
3069  TNode<MaybeObject> feedback =
3070  TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
3071  &var_handler, &try_polymorphic);
3072  BIND(&if_handler);
3073  {
3074  Comment("KeyedStoreIC_if_handler");
3075  HandleStoreICHandlerCase(p, var_handler.value(), &miss,
3076  ICMode::kNonGlobalIC, kSupportElements);
3077  }
3078 
3079  BIND(&try_polymorphic);
3080  TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3081  {
3082  // CheckPolymorphic case.
3083  Comment("KeyedStoreIC_try_polymorphic");
3084  GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
3085  &try_megamorphic);
3086  HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
3087  &var_handler, &miss, 2);
3088  }
3089 
3090  BIND(&try_megamorphic);
3091  {
3092  // Check megamorphic case.
3093  Comment("KeyedStoreIC_try_megamorphic");
3094  GotoIfNot(
3095  WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
3096  &try_polymorphic_name);
3097  TailCallBuiltin(Builtins::kKeyedStoreIC_Megamorphic, p->context,
3098  p->receiver, p->name, p->value, p->slot, p->vector);
3099  }
3100 
3101  BIND(&try_polymorphic_name);
3102  {
3103  // We might have a name in feedback, and a fixed array in the next slot.
3104  Comment("KeyedStoreIC_try_polymorphic_name");
3105  GotoIfNot(WordEqual(strong_feedback, p->name), &miss);
3106  // If the name comparison succeeded, we know we have a feedback vector
3107  // with at least one map/handler pair.
3108  TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(
3109  p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
3110  TNode<WeakFixedArray> array = CAST(feedback_element);
3111  HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
3112  &miss, 1);
3113  }
3114  }
3115  BIND(&miss);
3116  {
3117  Comment("KeyedStoreIC_miss");
3118  TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
3119  p->vector, p->receiver, p->name);
3120  }
3121 }
3122 
3123 void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
3124  Label miss(this, Label::kDeferred);
3125  {
3126  TVARIABLE(MaybeObject, var_handler);
3127 
3128  Label if_handler(this, &var_handler),
3129  try_polymorphic(this, Label::kDeferred),
3130  try_megamorphic(this, Label::kDeferred);
3131 
3132  Node* array_map = LoadReceiverMap(p->receiver);
3133  GotoIf(IsDeprecatedMap(array_map), &miss);
3134  TNode<MaybeObject> feedback =
3135  TryMonomorphicCase(p->slot, p->vector, array_map, &if_handler,
3136  &var_handler, &try_polymorphic);
3137 
3138  BIND(&if_handler);
3139  {
3140  Comment("StoreInArrayLiteralIC_if_handler");
3141  // This is a stripped-down version of HandleStoreICHandlerCase.
3142 
3143  TNode<HeapObject> handler = CAST(var_handler.value());
3144  Label if_transitioning_element_store(this);
3145  GotoIfNot(IsCode(handler), &if_transitioning_element_store);
3146  TailCallStub(StoreWithVectorDescriptor{}, CAST(handler), CAST(p->context),
3147  p->receiver, p->name, p->value, p->slot, p->vector);
3148 
3149  BIND(&if_transitioning_element_store);
3150  {
3151  TNode<MaybeObject> maybe_transition_map =
3152  LoadHandlerDataField(CAST(handler), 1);
3153  TNode<Map> transition_map =
3154  CAST(GetHeapObjectAssumeWeak(maybe_transition_map, &miss));
3155  GotoIf(IsDeprecatedMap(transition_map), &miss);
3156  Node* code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
3157  CSA_ASSERT(this, IsCode(code));
3158  TailCallStub(StoreTransitionDescriptor{}, code, p->context, p->receiver,
3159  p->name, transition_map, p->value, p->slot, p->vector);
3160  }
3161  }
3162 
3163  BIND(&try_polymorphic);
3164  TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3165  {
3166  Comment("StoreInArrayLiteralIC_try_polymorphic");
3167  GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
3168  &try_megamorphic);
3169  HandlePolymorphicCase(array_map, CAST(strong_feedback), &if_handler,
3170  &var_handler, &miss, 2);
3171  }
3172 
3173  BIND(&try_megamorphic);
3174  {
3175  Comment("StoreInArrayLiteralIC_try_megamorphic");
3176  CSA_ASSERT(this,
3177  Word32Or(WordEqual(strong_feedback,
3178  LoadRoot(RootIndex::kuninitialized_symbol)),
3179  WordEqual(strong_feedback,
3180  LoadRoot(RootIndex::kmegamorphic_symbol))));
3181  GotoIfNot(
3182  WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
3183  &miss);
3184  TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context,
3185  p->value, p->receiver, p->name);
3186  }
3187  }
3188 
3189  BIND(&miss);
3190  {
3191  Comment("StoreInArrayLiteralIC_miss");
3192  // TODO(neis): Introduce Runtime::kStoreInArrayLiteralIC_Miss.
3193  TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
3194  p->vector, p->receiver, p->name);
3195  }
3196 }
3197 
3199 
3200 void AccessorAssembler::GenerateLoadIC() {
3201  typedef LoadWithVectorDescriptor Descriptor;
3202 
3203  Node* receiver = Parameter(Descriptor::kReceiver);
3204  Node* name = Parameter(Descriptor::kName);
3205  Node* slot = Parameter(Descriptor::kSlot);
3206  Node* vector = Parameter(Descriptor::kVector);
3207  Node* context = Parameter(Descriptor::kContext);
3208 
3209  LoadICParameters p(context, receiver, name, slot, vector);
3210  LoadIC(&p);
3211 }
3212 
3213 void AccessorAssembler::GenerateLoadIC_Megamorphic() {
3214  typedef LoadWithVectorDescriptor Descriptor;
3215 
3216  Node* receiver = Parameter(Descriptor::kReceiver);
3217  Node* name = Parameter(Descriptor::kName);
3218  Node* slot = Parameter(Descriptor::kSlot);
3219  Node* vector = Parameter(Descriptor::kVector);
3220  Node* context = Parameter(Descriptor::kContext);
3221 
3222  ExitPoint direct_exit(this);
3223  TVARIABLE(MaybeObject, var_handler);
3224  Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
3225 
3226  TryProbeStubCache(isolate()->load_stub_cache(), receiver, name, &if_handler,
3227  &var_handler, &miss);
3228 
3229  BIND(&if_handler);
3230  LoadICParameters p(context, receiver, name, slot, vector);
3231  HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit);
3232 
3233  BIND(&miss);
3234  direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
3235  slot, vector);
3236 }
3237 
3238 void AccessorAssembler::GenerateLoadIC_Noninlined() {
3239  typedef LoadWithVectorDescriptor Descriptor;
3240 
3241  Node* receiver = Parameter(Descriptor::kReceiver);
3242  Node* name = Parameter(Descriptor::kName);
3243  Node* slot = Parameter(Descriptor::kSlot);
3244  Node* vector = Parameter(Descriptor::kVector);
3245  Node* context = Parameter(Descriptor::kContext);
3246 
3247  ExitPoint direct_exit(this);
3248  TVARIABLE(MaybeObject, var_handler);
3249  Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
3250 
3251  Node* receiver_map = LoadReceiverMap(receiver);
3252  TNode<MaybeObject> feedback_element =
3253  LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS);
3254  TNode<HeapObject> feedback = CAST(feedback_element);
3255 
3256  LoadICParameters p(context, receiver, name, slot, vector);
3257  LoadIC_Noninlined(&p, receiver_map, feedback, &var_handler, &if_handler,
3258  &miss, &direct_exit);
3259 
3260  BIND(&if_handler);
3261  HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit);
3262 
3263  BIND(&miss);
3264  direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
3265  slot, vector);
3266 }
3267 
3268 void AccessorAssembler::GenerateLoadIC_Uninitialized() {
3269  typedef LoadWithVectorDescriptor Descriptor;
3270 
3271  Node* receiver = Parameter(Descriptor::kReceiver);
3272  Node* name = Parameter(Descriptor::kName);
3273  Node* slot = Parameter(Descriptor::kSlot);
3274  Node* vector = Parameter(Descriptor::kVector);
3275  Node* context = Parameter(Descriptor::kContext);
3276 
3277  LoadICParameters p(context, receiver, name, slot, vector);
3278  LoadIC_Uninitialized(&p);
3279 }
3280 
3281 void AccessorAssembler::GenerateLoadICTrampoline() {
3282  typedef LoadDescriptor Descriptor;
3283 
3284  Node* receiver = Parameter(Descriptor::kReceiver);
3285  Node* name = Parameter(Descriptor::kName);
3286  Node* slot = Parameter(Descriptor::kSlot);
3287  Node* context = Parameter(Descriptor::kContext);
3288  Node* vector = LoadFeedbackVectorForStub();
3289 
3290  TailCallBuiltin(Builtins::kLoadIC, context, receiver, name, slot, vector);
3291 }
3292 
3293 void AccessorAssembler::GenerateLoadICTrampoline_Megamorphic() {
3294  typedef LoadDescriptor Descriptor;
3295 
3296  Node* receiver = Parameter(Descriptor::kReceiver);
3297  Node* name = Parameter(Descriptor::kName);
3298  Node* slot = Parameter(Descriptor::kSlot);
3299  Node* context = Parameter(Descriptor::kContext);
3300  Node* vector = LoadFeedbackVectorForStub();
3301 
3302  TailCallBuiltin(Builtins::kLoadIC_Megamorphic, context, receiver, name, slot,
3303  vector);
3304 }
3305 
3306 void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
3307  typedef LoadGlobalWithVectorDescriptor Descriptor;
3308 
3309  Node* name = Parameter(Descriptor::kName);
3310  Node* slot = Parameter(Descriptor::kSlot);
3311  Node* vector = Parameter(Descriptor::kVector);
3312  Node* context = Parameter(Descriptor::kContext);
3313 
3314  ExitPoint direct_exit(this);
3315  LoadGlobalIC(CAST(vector), slot,
3316  // lazy_context
3317  [=] { return CAST(context); },
3318  // lazy_name
3319  [=] { return CAST(name); }, typeof_mode, &direct_exit);
3320 }
3321 
3322 void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
3323  typedef LoadGlobalDescriptor Descriptor;
3324 
3325  Node* name = Parameter(Descriptor::kName);
3326  Node* slot = Parameter(Descriptor::kSlot);
3327  Node* context = Parameter(Descriptor::kContext);
3328  Node* vector = LoadFeedbackVectorForStub();
3329 
3330  Callable callable =
3331  CodeFactory::LoadGlobalICInOptimizedCode(isolate(), typeof_mode);
3332  TailCallStub(callable, context, name, slot, vector);
3333 }
3334 
3335 void AccessorAssembler::GenerateKeyedLoadIC() {
3336  typedef LoadWithVectorDescriptor Descriptor;
3337 
3338  Node* receiver = Parameter(Descriptor::kReceiver);
3339  Node* name = Parameter(Descriptor::kName);
3340  Node* slot = Parameter(Descriptor::kSlot);
3341  Node* vector = Parameter(Descriptor::kVector);
3342  Node* context = Parameter(Descriptor::kContext);
3343 
3344  LoadICParameters p(context, receiver, name, slot, vector);
3345  KeyedLoadIC(&p);
3346 }
3347 
3348 void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
3349  typedef LoadWithVectorDescriptor Descriptor;
3350 
3351  Node* receiver = Parameter(Descriptor::kReceiver);
3352  Node* name = Parameter(Descriptor::kName);
3353  Node* slot = Parameter(Descriptor::kSlot);
3354  Node* vector = Parameter(Descriptor::kVector);
3355  Node* context = Parameter(Descriptor::kContext);
3356 
3357  LoadICParameters p(context, receiver, name, slot, vector);
3358  KeyedLoadICGeneric(&p);
3359 }
3360 
3361 void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
3362  typedef LoadDescriptor Descriptor;
3363 
3364  Node* receiver = Parameter(Descriptor::kReceiver);
3365  Node* name = Parameter(Descriptor::kName);
3366  Node* slot = Parameter(Descriptor::kSlot);
3367  Node* context = Parameter(Descriptor::kContext);
3368  Node* vector = LoadFeedbackVectorForStub();
3369 
3370  TailCallBuiltin(Builtins::kKeyedLoadIC, context, receiver, name, slot,
3371  vector);
3372 }
3373 
3374 void AccessorAssembler::GenerateKeyedLoadICTrampoline_Megamorphic() {
3375  typedef LoadDescriptor Descriptor;
3376 
3377  Node* receiver = Parameter(Descriptor::kReceiver);
3378  Node* name = Parameter(Descriptor::kName);
3379  Node* slot = Parameter(Descriptor::kSlot);
3380  Node* context = Parameter(Descriptor::kContext);
3381  Node* vector = LoadFeedbackVectorForStub();
3382 
3383  TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, context, receiver, name,
3384  slot, vector);
3385 }
3386 
3387 void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
3388  typedef LoadWithVectorDescriptor Descriptor;
3389 
3390  Node* receiver = Parameter(Descriptor::kReceiver);
3391  Node* name = Parameter(Descriptor::kName);
3392  Node* slot = Parameter(Descriptor::kSlot);
3393  Node* vector = Parameter(Descriptor::kVector);
3394  Node* context = Parameter(Descriptor::kContext);
3395 
3396  LoadICParameters p(context, receiver, name, slot, vector);
3397  KeyedLoadICPolymorphicName(&p);
3398 }
3399 
3400 void AccessorAssembler::GenerateStoreGlobalIC() {
3401  typedef StoreGlobalWithVectorDescriptor Descriptor;
3402 
3403  Node* name = Parameter(Descriptor::kName);
3404  Node* value = Parameter(Descriptor::kValue);
3405  Node* slot = Parameter(Descriptor::kSlot);
3406  Node* vector = Parameter(Descriptor::kVector);
3407  Node* context = Parameter(Descriptor::kContext);
3408 
3409  StoreICParameters p(context, nullptr, name, value, slot, vector);
3410  StoreGlobalIC(&p);
3411 }
3412 
3413 void AccessorAssembler::GenerateStoreGlobalICTrampoline() {
3414  typedef StoreGlobalDescriptor Descriptor;
3415 
3416  Node* name = Parameter(Descriptor::kName);
3417  Node* value = Parameter(Descriptor::kValue);
3418  Node* slot = Parameter(Descriptor::kSlot);
3419  Node* context = Parameter(Descriptor::kContext);
3420  Node* vector = LoadFeedbackVectorForStub();
3421 
3422  TailCallBuiltin(Builtins::kStoreGlobalIC, context, name, value, slot, vector);
3423 }
3424 
3425 void AccessorAssembler::GenerateStoreIC() {
3426  typedef StoreWithVectorDescriptor Descriptor;
3427 
3428  Node* receiver = Parameter(Descriptor::kReceiver);
3429  Node* name = Parameter(Descriptor::kName);
3430  Node* value = Parameter(Descriptor::kValue);
3431  Node* slot = Parameter(Descriptor::kSlot);
3432  Node* vector = Parameter(Descriptor::kVector);
3433  Node* context = Parameter(Descriptor::kContext);
3434 
3435  StoreICParameters p(context, receiver, name, value, slot, vector);
3436  StoreIC(&p);
3437 }
3438 
3439 void AccessorAssembler::GenerateStoreICTrampoline() {
3440  typedef StoreDescriptor Descriptor;
3441 
3442  Node* receiver = Parameter(Descriptor::kReceiver);
3443  Node* name = Parameter(Descriptor::kName);
3444  Node* value = Parameter(Descriptor::kValue);
3445  Node* slot = Parameter(Descriptor::kSlot);
3446  Node* context = Parameter(Descriptor::kContext);
3447  Node* vector = LoadFeedbackVectorForStub();
3448 
3449  TailCallBuiltin(Builtins::kStoreIC, context, receiver, name, value, slot,
3450  vector);
3451 }
3452 
3453 void AccessorAssembler::GenerateKeyedStoreIC() {
3454  typedef StoreWithVectorDescriptor Descriptor;
3455 
3456  Node* receiver = Parameter(Descriptor::kReceiver);
3457  Node* name = Parameter(Descriptor::kName);
3458  Node* value = Parameter(Descriptor::kValue);
3459  Node* slot = Parameter(Descriptor::kSlot);
3460  Node* vector = Parameter(Descriptor::kVector);
3461  Node* context = Parameter(Descriptor::kContext);
3462 
3463  StoreICParameters p(context, receiver, name, value, slot, vector);
3464  KeyedStoreIC(&p);
3465 }
3466 
3467 void AccessorAssembler::GenerateKeyedStoreICTrampoline() {
3468  typedef StoreDescriptor Descriptor;
3469 
3470  Node* receiver = Parameter(Descriptor::kReceiver);
3471  Node* name = Parameter(Descriptor::kName);
3472  Node* value = Parameter(Descriptor::kValue);
3473  Node* slot = Parameter(Descriptor::kSlot);
3474  Node* context = Parameter(Descriptor::kContext);
3475  Node* vector = LoadFeedbackVectorForStub();
3476 
3477  TailCallBuiltin(Builtins::kKeyedStoreIC, context, receiver, name, value, slot,
3478  vector);
3479 }
3480 
3481 void AccessorAssembler::GenerateStoreInArrayLiteralIC() {
3482  typedef StoreWithVectorDescriptor Descriptor;
3483 
3484  Node* array = Parameter(Descriptor::kReceiver);
3485  Node* index = Parameter(Descriptor::kName);
3486  Node* value = Parameter(Descriptor::kValue);
3487  Node* slot = Parameter(Descriptor::kSlot);
3488  Node* vector = Parameter(Descriptor::kVector);
3489  Node* context = Parameter(Descriptor::kContext);
3490 
3491  StoreICParameters p(context, array, index, value, slot, vector);
3492  StoreInArrayLiteralIC(&p);
3493 }
3494 
3495 void AccessorAssembler::GenerateCloneObjectIC_Slow() {
3496  typedef CloneObjectWithVectorDescriptor Descriptor;
3497  TNode<HeapObject> source = CAST(Parameter(Descriptor::kSource));
3498  TNode<Smi> flags = CAST(Parameter(Descriptor::kFlags));
3499  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3500 
3501  // The Slow case uses the same call interface as CloneObjectIC, so that it
3502  // can be tail called from it. However, the feedback slot and vector are not
3503  // used.
3504 
3505  TNode<Context> native_context = LoadNativeContext(context);
3506  TNode<JSFunction> object_fn =
3507  CAST(LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX));
3508  TNode<Map> initial_map = CAST(
3509  LoadObjectField(object_fn, JSFunction::kPrototypeOrInitialMapOffset));
3510  CSA_ASSERT(this, IsMap(initial_map));
3511 
3512  TNode<JSObject> result = CAST(AllocateJSObjectFromMap(initial_map));
3513 
3514  {
3515  Label did_set_proto_if_needed(this);
3516  TNode<BoolT> is_null_proto = SmiNotEqual(
3517  SmiAnd(flags, SmiConstant(ObjectLiteral::kHasNullPrototype)),
3518  SmiConstant(Smi::zero()));
3519  GotoIfNot(is_null_proto, &did_set_proto_if_needed);
3520 
3521  CallRuntime(Runtime::kInternalSetPrototype, context, result,
3522  NullConstant());
3523 
3524  Goto(&did_set_proto_if_needed);
3525  BIND(&did_set_proto_if_needed);
3526  }
3527 
3528  ReturnIf(IsNullOrUndefined(source), result);
3529 
3530  CSA_ASSERT(this, IsJSReceiver(source));
3531 
3532  Label call_runtime(this, Label::kDeferred);
3533  Label done(this);
3534 
3535  TNode<Map> map = LoadMap(source);
3536  TNode<Int32T> type = LoadMapInstanceType(map);
3537  {
3538  Label cont(this);
3539  GotoIf(IsJSObjectInstanceType(type), &cont);
3540  GotoIfNot(IsStringInstanceType(type), &done);
3541  Branch(SmiEqual(LoadStringLengthAsSmi(CAST(source)), SmiConstant(0)), &done,
3542  &call_runtime);
3543  BIND(&cont);
3544  }
3545 
3546  GotoIfNot(IsEmptyFixedArray(LoadElements(CAST(source))), &call_runtime);
3547 
3548  ForEachEnumerableOwnProperty(context, map, CAST(source),
3549  [=](TNode<Name> key, TNode<Object> value) {
3550  SetPropertyInLiteral(context, result, key,
3551  value);
3552  },
3553  &call_runtime);
3554  Goto(&done);
3555 
3556  BIND(&call_runtime);
3557  CallRuntime(Runtime::kCopyDataProperties, context, result, source);
3558 
3559  Goto(&done);
3560  BIND(&done);
3561  Return(result);
3562 }
3563 
3564 void AccessorAssembler::GenerateCloneObjectIC() {
3565  typedef CloneObjectWithVectorDescriptor Descriptor;
3566  TNode<HeapObject> source = CAST(Parameter(Descriptor::kSource));
3567  Node* flags = Parameter(Descriptor::kFlags);
3568  Node* slot = Parameter(Descriptor::kSlot);
3569  Node* vector = Parameter(Descriptor::kVector);
3570  Node* context = Parameter(Descriptor::kContext);
3571  TVARIABLE(MaybeObject, var_handler);
3572  Label if_handler(this, &var_handler);
3573  Label miss(this, Label::kDeferred), try_polymorphic(this, Label::kDeferred),
3574  try_megamorphic(this, Label::kDeferred);
3575 
3576  TNode<Map> source_map = LoadMap(UncheckedCast<HeapObject>(source));
3577  GotoIf(IsDeprecatedMap(source_map), &miss);
3578  TNode<MaybeObject> feedback = TryMonomorphicCase(
3579  slot, vector, source_map, &if_handler, &var_handler, &try_polymorphic);
3580 
3581  BIND(&if_handler);
3582  {
3583  Comment("CloneObjectIC_if_handler");
3584 
3585  // Handlers for the CloneObjectIC stub are weak references to the Map of
3586  // a result object.
3587  TNode<Map> result_map = CAST(var_handler.value());
3588  TVARIABLE(Object, var_properties, EmptyFixedArrayConstant());
3589  TVARIABLE(FixedArrayBase, var_elements, EmptyFixedArrayConstant());
3590 
3591  Label allocate_object(this);
3592  GotoIf(IsNullOrUndefined(source), &allocate_object);
3593  CSA_SLOW_ASSERT(this, IsJSObjectMap(result_map));
3594 
3595  // The IC fast case should only be taken if the result map a compatible
3596  // elements kind with the source object.
3597  TNode<FixedArrayBase> source_elements = LoadElements(CAST(source));
3598 
3599  auto flags = ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW;
3600  var_elements = CAST(CloneFixedArray(source_elements, flags));
3601 
3602  // Copy the PropertyArray backing store. The source PropertyArray must be
3603  // either an Smi, or a PropertyArray.
3604  // FIXME: Make a CSA macro for this
3605  TNode<Object> source_properties =
3606  LoadObjectField(source, JSObject::kPropertiesOrHashOffset);
3607  {
3608  GotoIf(TaggedIsSmi(source_properties), &allocate_object);
3609  GotoIf(IsEmptyFixedArray(source_properties), &allocate_object);
3610 
3611  // This IC requires that the source object has fast properties
3612  CSA_SLOW_ASSERT(this, IsPropertyArray(CAST(source_properties)));
3613  TNode<IntPtrT> length = LoadPropertyArrayLength(
3614  UncheckedCast<PropertyArray>(source_properties));
3615  GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &allocate_object);
3616 
3617  auto mode = INTPTR_PARAMETERS;
3618  var_properties = CAST(AllocatePropertyArray(length, mode));
3619  FillPropertyArrayWithUndefined(var_properties.value(), IntPtrConstant(0),
3620  length, mode);
3621  CopyPropertyArrayValues(source_properties, var_properties.value(), length,
3622  SKIP_WRITE_BARRIER, mode, DestroySource::kNo);
3623  }
3624 
3625  Goto(&allocate_object);
3626  BIND(&allocate_object);
3627  TNode<JSObject> object = UncheckedCast<JSObject>(AllocateJSObjectFromMap(
3628  result_map, var_properties.value(), var_elements.value()));
3629  ReturnIf(IsNullOrUndefined(source), object);
3630 
3631  // Lastly, clone any in-object properties.
3632  // Determine the inobject property capacity of both objects, and copy the
3633  // smaller number into the resulting object.
3634  TNode<IntPtrT> source_start =
3635  LoadMapInobjectPropertiesStartInWords(source_map);
3636  TNode<IntPtrT> source_size = LoadMapInstanceSizeInWords(source_map);
3637  TNode<IntPtrT> result_start =
3638  LoadMapInobjectPropertiesStartInWords(result_map);
3639  TNode<IntPtrT> field_offset_difference =
3640  TimesPointerSize(IntPtrSub(result_start, source_start));
3641 
3642  // If MutableHeapNumbers may be present in-object, allocations may occur
3643  // within this loop, thus the write barrier is required.
3644  //
3645  // TODO(caitp): skip the write barrier until the first MutableHeapNumber
3646  // field is found
3647  const bool may_use_mutable_heap_numbers = !FLAG_unbox_double_fields;
3648 
3649  BuildFastLoop(
3650  source_start, source_size,
3651  [=](Node* field_index) {
3652  TNode<IntPtrT> field_offset =
3653  TimesPointerSize(UncheckedCast<IntPtrT>(field_index));
3654 
3655  if (may_use_mutable_heap_numbers) {
3656  TNode<Object> field = LoadObjectField(source, field_offset);
3657  field = CloneIfMutablePrimitive(field);
3658  TNode<IntPtrT> result_offset =
3659  IntPtrAdd(field_offset, field_offset_difference);
3660  StoreObjectField(object, result_offset, field);
3661  } else {
3662  // Copy fields as raw data.
3663  TNode<IntPtrT> field =
3664  LoadObjectField<IntPtrT>(source, field_offset);
3665  TNode<IntPtrT> result_offset =
3666  IntPtrAdd(field_offset, field_offset_difference);
3667  StoreObjectFieldNoWriteBarrier(object, result_offset, field);
3668  }
3669  },
3670  1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
3671  Return(object);
3672  }
3673 
3674  BIND(&try_polymorphic);
3675  TNode<HeapObject> strong_feedback = GetHeapObjectIfStrong(feedback, &miss);
3676  {
3677  Comment("CloneObjectIC_try_polymorphic");
3678  GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
3679  HandlePolymorphicCase(source_map, CAST(strong_feedback), &if_handler,
3680  &var_handler, &miss, 2);
3681  }
3682 
3683  BIND(&try_megamorphic);
3684  {
3685  Comment("CloneObjectIC_try_megamorphic");
3686  CSA_ASSERT(this,
3687  Word32Or(WordEqual(strong_feedback,
3688  LoadRoot(RootIndex::kuninitialized_symbol)),
3689  WordEqual(strong_feedback,
3690  LoadRoot(RootIndex::kmegamorphic_symbol))));
3691  GotoIfNot(
3692  WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
3693  &miss);
3694  TailCallBuiltin(Builtins::kCloneObjectIC_Slow, context, source, flags, slot,
3695  vector);
3696  }
3697 
3698  BIND(&miss);
3699  {
3700  Comment("CloneObjectIC_miss");
3701  Node* map_or_result = CallRuntime(Runtime::kCloneObjectIC_Miss, context,
3702  source, flags, slot, vector);
3703  var_handler = UncheckedCast<MaybeObject>(map_or_result);
3704  GotoIf(IsMap(map_or_result), &if_handler);
3705  CSA_ASSERT(this, IsJSObject(map_or_result));
3706  Return(map_or_result);
3707  }
3708 }
3709 
3710 } // namespace internal
3711 } // namespace v8
Definition: libplatform.h:13