• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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/api.h"
6 #include "src/builtins/builtins-utils-gen.h"
7 #include "src/builtins/builtins.h"
8 #include "src/code-stub-assembler.h"
9 #include "src/heap/heap-inl.h"
10 #include "src/ic/accessor-assembler.h"
11 #include "src/ic/keyed-store-generic.h"
12 #include "src/macro-assembler.h"
13 #include "src/objects/debug-objects.h"
14 #include "src/objects/shared-function-info.h"
15 #include "src/runtime/runtime.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 template <typename T>
21 using TNode = compiler::TNode<T>;
22 
23 // -----------------------------------------------------------------------------
24 // Interrupt and stack checks.
25 
Generate_InterruptCheck(MacroAssembler * masm)26 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
27   masm->TailCallRuntime(Runtime::kInterrupt);
28 }
29 
Generate_StackCheck(MacroAssembler * masm)30 void Builtins::Generate_StackCheck(MacroAssembler* masm) {
31   masm->TailCallRuntime(Runtime::kStackGuard);
32 }
33 
34 // -----------------------------------------------------------------------------
35 // TurboFan support builtins.
36 
TF_BUILTIN(CopyFastSmiOrObjectElements,CodeStubAssembler)37 TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
38   Node* object = Parameter(Descriptor::kObject);
39 
40   // Load the {object}s elements.
41   Node* source = LoadObjectField(object, JSObject::kElementsOffset);
42   Node* target = CloneFixedArray(source, ExtractFixedArrayFlag::kFixedArrays);
43   StoreObjectField(object, JSObject::kElementsOffset, target);
44   Return(target);
45 }
46 
TF_BUILTIN(GrowFastDoubleElements,CodeStubAssembler)47 TF_BUILTIN(GrowFastDoubleElements, CodeStubAssembler) {
48   Node* object = Parameter(Descriptor::kObject);
49   Node* key = Parameter(Descriptor::kKey);
50   Node* context = Parameter(Descriptor::kContext);
51 
52   Label runtime(this, Label::kDeferred);
53   Node* elements = LoadElements(object);
54   elements = TryGrowElementsCapacity(object, elements, PACKED_DOUBLE_ELEMENTS,
55                                      key, &runtime);
56   Return(elements);
57 
58   BIND(&runtime);
59   TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
60 }
61 
TF_BUILTIN(GrowFastSmiOrObjectElements,CodeStubAssembler)62 TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
63   Node* object = Parameter(Descriptor::kObject);
64   Node* key = Parameter(Descriptor::kKey);
65   Node* context = Parameter(Descriptor::kContext);
66 
67   Label runtime(this, Label::kDeferred);
68   Node* elements = LoadElements(object);
69   elements =
70       TryGrowElementsCapacity(object, elements, PACKED_ELEMENTS, key, &runtime);
71   Return(elements);
72 
73   BIND(&runtime);
74   TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
75 }
76 
TF_BUILTIN(NewArgumentsElements,CodeStubAssembler)77 TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) {
78   Node* frame = Parameter(Descriptor::kFrame);
79   TNode<IntPtrT> length = SmiToIntPtr(Parameter(Descriptor::kLength));
80   TNode<IntPtrT> mapped_count =
81       SmiToIntPtr(Parameter(Descriptor::kMappedCount));
82 
83   // Check if we can allocate in new space.
84   ElementsKind kind = PACKED_ELEMENTS;
85   int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
86   Label if_newspace(this), if_oldspace(this, Label::kDeferred);
87   Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
88          &if_oldspace);
89 
90   BIND(&if_newspace);
91   {
92     // Prefer EmptyFixedArray in case of non-positive {length} (the {length}
93     // can be negative here for rest parameters).
94     Label if_empty(this), if_notempty(this);
95     Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
96            &if_notempty);
97 
98     BIND(&if_empty);
99     Return(EmptyFixedArrayConstant());
100 
101     BIND(&if_notempty);
102     {
103       // Allocate a FixedArray in new space.
104       TNode<FixedArray> result = CAST(AllocateFixedArray(kind, length));
105 
106       // The elements might be used to back mapped arguments. In that case fill
107       // the mapped elements (i.e. the first {mapped_count}) with the hole, but
108       // make sure not to overshoot the {length} if some arguments are missing.
109       TNode<IntPtrT> number_of_holes = IntPtrMin(mapped_count, length);
110       Node* the_hole = TheHoleConstant();
111 
112       // Fill the first elements up to {number_of_holes} with the hole.
113       TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
114       Label loop1(this, &var_index), done_loop1(this);
115       Goto(&loop1);
116       BIND(&loop1);
117       {
118         // Load the current {index}.
119         TNode<IntPtrT> index = var_index.value();
120 
121         // Check if we are done.
122         GotoIf(WordEqual(index, number_of_holes), &done_loop1);
123 
124         // Store the hole into the {result}.
125         StoreFixedArrayElement(result, index, the_hole, SKIP_WRITE_BARRIER);
126 
127         // Continue with next {index}.
128         var_index = IntPtrAdd(index, IntPtrConstant(1));
129         Goto(&loop1);
130       }
131       BIND(&done_loop1);
132 
133       // Compute the effective {offset} into the {frame}.
134       TNode<IntPtrT> offset = IntPtrAdd(length, IntPtrConstant(1));
135 
136       // Copy the parameters from {frame} (starting at {offset}) to {result}.
137       Label loop2(this, &var_index), done_loop2(this);
138       Goto(&loop2);
139       BIND(&loop2);
140       {
141         // Load the current {index}.
142         TNode<IntPtrT> index = var_index.value();
143 
144         // Check if we are done.
145         GotoIf(WordEqual(index, length), &done_loop2);
146 
147         // Load the parameter at the given {index}.
148         TNode<Object> value =
149             CAST(Load(MachineType::AnyTagged(), frame,
150                       TimesPointerSize(IntPtrSub(offset, index))));
151 
152         // Store the {value} into the {result}.
153         StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
154 
155         // Continue with next {index}.
156         var_index = IntPtrAdd(index, IntPtrConstant(1));
157         Goto(&loop2);
158       }
159       BIND(&done_loop2);
160 
161       Return(result);
162     }
163   }
164 
165   BIND(&if_oldspace);
166   {
167     // Allocate in old space (or large object space).
168     TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
169                     BitcastWordToTagged(frame), SmiFromIntPtr(length),
170                     SmiFromIntPtr(mapped_count));
171   }
172 }
173 
TF_BUILTIN(ReturnReceiver,CodeStubAssembler)174 TF_BUILTIN(ReturnReceiver, CodeStubAssembler) {
175   Return(Parameter(Descriptor::kReceiver));
176 }
177 
TF_BUILTIN(DebugBreakTrampoline,CodeStubAssembler)178 TF_BUILTIN(DebugBreakTrampoline, CodeStubAssembler) {
179   Label tailcall_to_shared(this);
180   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
181   TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
182   TNode<Int32T> arg_count =
183       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
184   TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
185 
186   // Check break-at-entry flag on the debug info.
187   TNode<SharedFunctionInfo> shared =
188       CAST(LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset));
189   TNode<Object> maybe_heap_object_or_smi =
190       LoadObjectField(shared, SharedFunctionInfo::kScriptOrDebugInfoOffset);
191   TNode<HeapObject> maybe_debug_info =
192       TaggedToHeapObject(maybe_heap_object_or_smi, &tailcall_to_shared);
193   GotoIfNot(HasInstanceType(maybe_debug_info, InstanceType::DEBUG_INFO_TYPE),
194             &tailcall_to_shared);
195 
196   {
197     TNode<DebugInfo> debug_info = CAST(maybe_debug_info);
198     TNode<Smi> flags =
199         CAST(LoadObjectField(debug_info, DebugInfo::kFlagsOffset));
200     GotoIfNot(SmiToInt32(SmiAnd(flags, SmiConstant(DebugInfo::kBreakAtEntry))),
201               &tailcall_to_shared);
202 
203     CallRuntime(Runtime::kDebugBreakAtEntry, context, function);
204     Goto(&tailcall_to_shared);
205   }
206 
207   BIND(&tailcall_to_shared);
208   // Tail call into code object on the SharedFunctionInfo.
209   TNode<Code> code = GetSharedFunctionInfoCode(shared);
210   TailCallJSCode(code, context, function, new_target, arg_count);
211 }
212 
213 class RecordWriteCodeStubAssembler : public CodeStubAssembler {
214  public:
RecordWriteCodeStubAssembler(compiler::CodeAssemblerState * state)215   explicit RecordWriteCodeStubAssembler(compiler::CodeAssemblerState* state)
216       : CodeStubAssembler(state) {}
217 
IsMarking()218   Node* IsMarking() {
219     Node* is_marking_addr = ExternalConstant(
220         ExternalReference::heap_is_marking_flag_address(this->isolate()));
221     return Load(MachineType::Uint8(), is_marking_addr);
222   }
223 
IsPageFlagSet(Node * object,int mask)224   Node* IsPageFlagSet(Node* object, int mask) {
225     Node* page = WordAnd(object, IntPtrConstant(~kPageAlignmentMask));
226     Node* flags = Load(MachineType::Pointer(), page,
227                        IntPtrConstant(MemoryChunk::kFlagsOffset));
228     return WordNotEqual(WordAnd(flags, IntPtrConstant(mask)),
229                         IntPtrConstant(0));
230   }
231 
IsWhite(Node * object)232   Node* IsWhite(Node* object) {
233     DCHECK_EQ(strcmp(Marking::kWhiteBitPattern, "00"), 0);
234     Node* cell;
235     Node* mask;
236     GetMarkBit(object, &cell, &mask);
237     mask = TruncateIntPtrToInt32(mask);
238     // Non-white has 1 for the first bit, so we only need to check for the first
239     // bit.
240     return Word32Equal(Word32And(Load(MachineType::Int32(), cell), mask),
241                        Int32Constant(0));
242   }
243 
GetMarkBit(Node * object,Node ** cell,Node ** mask)244   void GetMarkBit(Node* object, Node** cell, Node** mask) {
245     Node* page = WordAnd(object, IntPtrConstant(~kPageAlignmentMask));
246 
247     {
248       // Temp variable to calculate cell offset in bitmap.
249       Node* r0;
250       int shift = Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 -
251                   Bitmap::kBytesPerCellLog2;
252       r0 = WordShr(object, IntPtrConstant(shift));
253       r0 = WordAnd(r0, IntPtrConstant((kPageAlignmentMask >> shift) &
254                                       ~(Bitmap::kBytesPerCell - 1)));
255       *cell = IntPtrAdd(IntPtrAdd(page, r0),
256                         IntPtrConstant(MemoryChunk::kHeaderSize));
257     }
258     {
259       // Temp variable to calculate bit offset in cell.
260       Node* r1;
261       r1 = WordShr(object, IntPtrConstant(kPointerSizeLog2));
262       r1 = WordAnd(r1, IntPtrConstant((1 << Bitmap::kBitsPerCellLog2) - 1));
263       // It seems that LSB(e.g. cl) is automatically used, so no manual masking
264       // is needed. Uncomment the following line otherwise.
265       // WordAnd(r1, IntPtrConstant((1 << kBitsPerByte) - 1)));
266       *mask = WordShl(IntPtrConstant(1), r1);
267     }
268   }
269 
ShouldSkipFPRegs(Node * mode)270   Node* ShouldSkipFPRegs(Node* mode) {
271     return WordEqual(mode, SmiConstant(kDontSaveFPRegs));
272   }
273 
ShouldEmitRememberSet(Node * remembered_set)274   Node* ShouldEmitRememberSet(Node* remembered_set) {
275     return WordEqual(remembered_set, SmiConstant(EMIT_REMEMBERED_SET));
276   }
277 
CallCFunction1WithCallerSavedRegistersMode(MachineType return_type,MachineType arg0_type,Node * function,Node * arg0,Node * mode,Label * next)278   void CallCFunction1WithCallerSavedRegistersMode(MachineType return_type,
279                                                   MachineType arg0_type,
280                                                   Node* function, Node* arg0,
281                                                   Node* mode, Label* next) {
282     Label dont_save_fp(this), save_fp(this);
283     Branch(ShouldSkipFPRegs(mode), &dont_save_fp, &save_fp);
284     BIND(&dont_save_fp);
285     {
286       CallCFunction1WithCallerSavedRegisters(return_type, arg0_type, function,
287                                              arg0, kDontSaveFPRegs);
288       Goto(next);
289     }
290 
291     BIND(&save_fp);
292     {
293       CallCFunction1WithCallerSavedRegisters(return_type, arg0_type, function,
294                                              arg0, kSaveFPRegs);
295       Goto(next);
296     }
297   }
298 
CallCFunction3WithCallerSavedRegistersMode(MachineType return_type,MachineType arg0_type,MachineType arg1_type,MachineType arg2_type,Node * function,Node * arg0,Node * arg1,Node * arg2,Node * mode,Label * next)299   void CallCFunction3WithCallerSavedRegistersMode(
300       MachineType return_type, MachineType arg0_type, MachineType arg1_type,
301       MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
302       Node* mode, Label* next) {
303     Label dont_save_fp(this), save_fp(this);
304     Branch(ShouldSkipFPRegs(mode), &dont_save_fp, &save_fp);
305     BIND(&dont_save_fp);
306     {
307       CallCFunction3WithCallerSavedRegisters(return_type, arg0_type, arg1_type,
308                                              arg2_type, function, arg0, arg1,
309                                              arg2, kDontSaveFPRegs);
310       Goto(next);
311     }
312 
313     BIND(&save_fp);
314     {
315       CallCFunction3WithCallerSavedRegisters(return_type, arg0_type, arg1_type,
316                                              arg2_type, function, arg0, arg1,
317                                              arg2, kSaveFPRegs);
318       Goto(next);
319     }
320   }
321 
InsertToStoreBufferAndGoto(Node * isolate,Node * slot,Node * mode,Label * next)322   void InsertToStoreBufferAndGoto(Node* isolate, Node* slot, Node* mode,
323                                   Label* next) {
324     Node* store_buffer_top_addr =
325         ExternalConstant(ExternalReference::store_buffer_top(this->isolate()));
326     Node* store_buffer_top =
327         Load(MachineType::Pointer(), store_buffer_top_addr);
328     StoreNoWriteBarrier(MachineType::PointerRepresentation(), store_buffer_top,
329                         slot);
330     Node* new_store_buffer_top =
331         IntPtrAdd(store_buffer_top, IntPtrConstant(kPointerSize));
332     StoreNoWriteBarrier(MachineType::PointerRepresentation(),
333                         store_buffer_top_addr, new_store_buffer_top);
334 
335     Node* test = WordAnd(new_store_buffer_top,
336                          IntPtrConstant(Heap::store_buffer_mask_constant()));
337 
338     Label overflow(this);
339     Branch(WordEqual(test, IntPtrConstant(0)), &overflow, next);
340 
341     BIND(&overflow);
342     {
343       Node* function =
344           ExternalConstant(ExternalReference::store_buffer_overflow_function());
345       CallCFunction1WithCallerSavedRegistersMode(MachineType::Int32(),
346                                                  MachineType::Pointer(),
347                                                  function, isolate, mode, next);
348     }
349   }
350 };
351 
TF_BUILTIN(RecordWrite,RecordWriteCodeStubAssembler)352 TF_BUILTIN(RecordWrite, RecordWriteCodeStubAssembler) {
353   Node* object = BitcastTaggedToWord(Parameter(Descriptor::kObject));
354   Node* slot = Parameter(Descriptor::kSlot);
355   Node* isolate = Parameter(Descriptor::kIsolate);
356   Node* remembered_set = Parameter(Descriptor::kRememberedSet);
357   Node* fp_mode = Parameter(Descriptor::kFPMode);
358 
359   Node* value = Load(MachineType::Pointer(), slot);
360 
361   Label generational_wb(this);
362   Label incremental_wb(this);
363   Label exit(this);
364 
365   Branch(ShouldEmitRememberSet(remembered_set), &generational_wb,
366          &incremental_wb);
367 
368   BIND(&generational_wb);
369   {
370     Label test_old_to_new_flags(this);
371     Label store_buffer_exit(this), store_buffer_incremental_wb(this);
372     // When incremental marking is not on, we skip cross generation pointer
373     // checking here, because there are checks for
374     // `kPointersFromHereAreInterestingMask` and
375     // `kPointersToHereAreInterestingMask` in
376     // `src/compiler/<arch>/code-generator-<arch>.cc` before calling this stub,
377     // which serves as the cross generation checking.
378     Branch(IsMarking(), &test_old_to_new_flags, &store_buffer_exit);
379 
380     BIND(&test_old_to_new_flags);
381     {
382       // TODO(albertnetymk): Try to cache the page flag for value and object,
383       // instead of calling IsPageFlagSet each time.
384       Node* value_in_new_space =
385           IsPageFlagSet(value, MemoryChunk::kIsInNewSpaceMask);
386       GotoIfNot(value_in_new_space, &incremental_wb);
387 
388       Node* object_in_new_space =
389           IsPageFlagSet(object, MemoryChunk::kIsInNewSpaceMask);
390       GotoIf(object_in_new_space, &incremental_wb);
391 
392       Goto(&store_buffer_incremental_wb);
393     }
394 
395     BIND(&store_buffer_exit);
396     { InsertToStoreBufferAndGoto(isolate, slot, fp_mode, &exit); }
397 
398     BIND(&store_buffer_incremental_wb);
399     { InsertToStoreBufferAndGoto(isolate, slot, fp_mode, &incremental_wb); }
400   }
401 
402   BIND(&incremental_wb);
403   {
404     Label call_incremental_wb(this);
405 
406     // There are two cases we need to call incremental write barrier.
407     // 1) value_is_white
408     GotoIf(IsWhite(value), &call_incremental_wb);
409 
410     // 2) is_compacting && value_in_EC && obj_isnt_skip
411     // is_compacting = true when is_marking = true
412     GotoIfNot(IsPageFlagSet(value, MemoryChunk::kEvacuationCandidateMask),
413               &exit);
414     GotoIf(
415         IsPageFlagSet(object, MemoryChunk::kSkipEvacuationSlotsRecordingMask),
416         &exit);
417 
418     Goto(&call_incremental_wb);
419 
420     BIND(&call_incremental_wb);
421     {
422       Node* function = ExternalConstant(
423           ExternalReference::incremental_marking_record_write_function());
424       CallCFunction3WithCallerSavedRegistersMode(
425           MachineType::Int32(), MachineType::Pointer(), MachineType::Pointer(),
426           MachineType::Pointer(), function, object, slot, isolate, fp_mode,
427           &exit);
428     }
429   }
430 
431   BIND(&exit);
432   Return(TrueConstant());
433 }
434 
435 class DeletePropertyBaseAssembler : public AccessorAssembler {
436  public:
DeletePropertyBaseAssembler(compiler::CodeAssemblerState * state)437   explicit DeletePropertyBaseAssembler(compiler::CodeAssemblerState* state)
438       : AccessorAssembler(state) {}
439 
DeleteDictionaryProperty(TNode<Object> receiver,TNode<NameDictionary> properties,TNode<Name> name,TNode<Context> context,Label * dont_delete,Label * notfound)440   void DeleteDictionaryProperty(TNode<Object> receiver,
441                                 TNode<NameDictionary> properties,
442                                 TNode<Name> name, TNode<Context> context,
443                                 Label* dont_delete, Label* notfound) {
444     TVARIABLE(IntPtrT, var_name_index);
445     Label dictionary_found(this, &var_name_index);
446     NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
447                                          &var_name_index, notfound);
448 
449     BIND(&dictionary_found);
450     TNode<IntPtrT> key_index = var_name_index.value();
451     TNode<Uint32T> details =
452         LoadDetailsByKeyIndex<NameDictionary>(properties, key_index);
453     GotoIf(IsSetWord32(details, PropertyDetails::kAttributesDontDeleteMask),
454            dont_delete);
455     // Overwrite the entry itself (see NameDictionary::SetEntry).
456     TNode<HeapObject> filler = TheHoleConstant();
457     DCHECK(Heap::RootIsImmortalImmovable(Heap::kTheHoleValueRootIndex));
458     StoreFixedArrayElement(properties, key_index, filler, SKIP_WRITE_BARRIER);
459     StoreValueByKeyIndex<NameDictionary>(properties, key_index, filler,
460                                          SKIP_WRITE_BARRIER);
461     StoreDetailsByKeyIndex<NameDictionary>(properties, key_index,
462                                            SmiConstant(0));
463 
464     // Update bookkeeping information (see NameDictionary::ElementRemoved).
465     TNode<Smi> nof = GetNumberOfElements<NameDictionary>(properties);
466     TNode<Smi> new_nof = SmiSub(nof, SmiConstant(1));
467     SetNumberOfElements<NameDictionary>(properties, new_nof);
468     TNode<Smi> num_deleted =
469         GetNumberOfDeletedElements<NameDictionary>(properties);
470     TNode<Smi> new_deleted = SmiAdd(num_deleted, SmiConstant(1));
471     SetNumberOfDeletedElements<NameDictionary>(properties, new_deleted);
472 
473     // Shrink the dictionary if necessary (see NameDictionary::Shrink).
474     Label shrinking_done(this);
475     TNode<Smi> capacity = GetCapacity<NameDictionary>(properties);
476     GotoIf(SmiGreaterThan(new_nof, SmiShr(capacity, 2)), &shrinking_done);
477     GotoIf(SmiLessThan(new_nof, SmiConstant(16)), &shrinking_done);
478     CallRuntime(Runtime::kShrinkPropertyDictionary, context, receiver);
479     Goto(&shrinking_done);
480     BIND(&shrinking_done);
481 
482     Return(TrueConstant());
483   }
484 };
485 
TF_BUILTIN(DeleteProperty,DeletePropertyBaseAssembler)486 TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) {
487   TNode<Object> receiver = CAST(Parameter(Descriptor::kObject));
488   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
489   TNode<Smi> language_mode = CAST(Parameter(Descriptor::kLanguageMode));
490   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
491 
492   VARIABLE(var_index, MachineType::PointerRepresentation());
493   VARIABLE(var_unique, MachineRepresentation::kTagged, key);
494   Label if_index(this), if_unique_name(this), if_notunique(this),
495       if_notfound(this), slow(this);
496 
497   GotoIf(TaggedIsSmi(receiver), &slow);
498   TNode<Map> receiver_map = LoadMap(CAST(receiver));
499   TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
500   GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &slow);
501   TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
502             &if_notunique);
503 
504   BIND(&if_index);
505   {
506     Comment("integer index");
507     Goto(&slow);  // TODO(jkummerow): Implement more smarts here.
508   }
509 
510   BIND(&if_unique_name);
511   {
512     Comment("key is unique name");
513     TNode<Name> unique = CAST(var_unique.value());
514     CheckForAssociatedProtector(unique, &slow);
515 
516     Label dictionary(this), dont_delete(this);
517     GotoIf(IsDictionaryMap(receiver_map), &dictionary);
518 
519     // Fast properties need to clear recorded slots, which can only be done
520     // in C++.
521     Goto(&slow);
522 
523     BIND(&dictionary);
524     {
525       InvalidateValidityCellIfPrototype(receiver_map);
526 
527       TNode<NameDictionary> properties =
528           CAST(LoadSlowProperties(CAST(receiver)));
529       DeleteDictionaryProperty(receiver, properties, unique, context,
530                                &dont_delete, &if_notfound);
531     }
532 
533     BIND(&dont_delete);
534     {
535       STATIC_ASSERT(LanguageModeSize == 2);
536       GotoIf(SmiNotEqual(language_mode, SmiConstant(LanguageMode::kSloppy)),
537              &slow);
538       Return(FalseConstant());
539     }
540   }
541 
542   BIND(&if_notunique);
543   {
544     // If the string was not found in the string table, then no object can
545     // have a property with that name.
546     TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
547                          &var_unique, &if_notfound, &slow);
548   }
549 
550   BIND(&if_notfound);
551   Return(TrueConstant());
552 
553   BIND(&slow);
554   {
555     TailCallRuntime(Runtime::kDeleteProperty, context, receiver, key,
556                     language_mode);
557   }
558 }
559 
TF_BUILTIN(ForInEnumerate,CodeStubAssembler)560 TF_BUILTIN(ForInEnumerate, CodeStubAssembler) {
561   Node* receiver = Parameter(Descriptor::kReceiver);
562   Node* context = Parameter(Descriptor::kContext);
563 
564   Label if_empty(this), if_runtime(this, Label::kDeferred);
565   Node* receiver_map = CheckEnumCache(receiver, &if_empty, &if_runtime);
566   Return(receiver_map);
567 
568   BIND(&if_empty);
569   Return(EmptyFixedArrayConstant());
570 
571   BIND(&if_runtime);
572   TailCallRuntime(Runtime::kForInEnumerate, context, receiver);
573 }
574 
TF_BUILTIN(ForInFilter,CodeStubAssembler)575 TF_BUILTIN(ForInFilter, CodeStubAssembler) {
576   Node* key = Parameter(Descriptor::kKey);
577   Node* object = Parameter(Descriptor::kObject);
578   Node* context = Parameter(Descriptor::kContext);
579 
580   CSA_ASSERT(this, IsString(key));
581 
582   Label if_true(this), if_false(this);
583   TNode<Oddball> result = HasProperty(context, object, key, kForInHasProperty);
584   Branch(IsTrue(result), &if_true, &if_false);
585 
586   BIND(&if_true);
587   Return(key);
588 
589   BIND(&if_false);
590   Return(UndefinedConstant());
591 }
592 
TF_BUILTIN(SameValue,CodeStubAssembler)593 TF_BUILTIN(SameValue, CodeStubAssembler) {
594   Node* lhs = Parameter(Descriptor::kLeft);
595   Node* rhs = Parameter(Descriptor::kRight);
596 
597   Label if_true(this), if_false(this);
598   BranchIfSameValue(lhs, rhs, &if_true, &if_false);
599 
600   BIND(&if_true);
601   Return(TrueConstant());
602 
603   BIND(&if_false);
604   Return(FalseConstant());
605 }
606 
607 class InternalBuiltinsAssembler : public CodeStubAssembler {
608  public:
InternalBuiltinsAssembler(compiler::CodeAssemblerState * state)609   explicit InternalBuiltinsAssembler(compiler::CodeAssemblerState* state)
610       : CodeStubAssembler(state) {}
611 
612   TNode<IntPtrT> GetPendingMicrotaskCount();
613   void SetPendingMicrotaskCount(TNode<IntPtrT> count);
614 
615   TNode<FixedArray> GetMicrotaskQueue();
616   void SetMicrotaskQueue(TNode<FixedArray> queue);
617 
618   TNode<Context> GetCurrentContext();
619   void SetCurrentContext(TNode<Context> context);
620 
621   void EnterMicrotaskContext(TNode<Context> context);
622   void LeaveMicrotaskContext();
623 
624   void RunPromiseHook(Runtime::FunctionId id, TNode<Context> context,
625                       SloppyTNode<HeapObject> promise_or_capability);
626 
GetPendingException()627   TNode<Object> GetPendingException() {
628     auto ref = ExternalReference::Create(kPendingExceptionAddress, isolate());
629     return TNode<Object>::UncheckedCast(
630         Load(MachineType::AnyTagged(), ExternalConstant(ref)));
631   }
ClearPendingException()632   void ClearPendingException() {
633     auto ref = ExternalReference::Create(kPendingExceptionAddress, isolate());
634     StoreNoWriteBarrier(MachineRepresentation::kTagged, ExternalConstant(ref),
635                         TheHoleConstant());
636   }
637 
GetScheduledException()638   TNode<Object> GetScheduledException() {
639     auto ref = ExternalReference::scheduled_exception_address(isolate());
640     return TNode<Object>::UncheckedCast(
641         Load(MachineType::AnyTagged(), ExternalConstant(ref)));
642   }
ClearScheduledException()643   void ClearScheduledException() {
644     auto ref = ExternalReference::scheduled_exception_address(isolate());
645     StoreNoWriteBarrier(MachineRepresentation::kTagged, ExternalConstant(ref),
646                         TheHoleConstant());
647   }
648 
649   template <typename Descriptor>
650   void GenerateAdaptorWithExitFrameType(
651       Builtins::ExitFrameType exit_frame_type);
652 };
653 
654 template <typename Descriptor>
GenerateAdaptorWithExitFrameType(Builtins::ExitFrameType exit_frame_type)655 void InternalBuiltinsAssembler::GenerateAdaptorWithExitFrameType(
656     Builtins::ExitFrameType exit_frame_type) {
657   TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
658   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
659   TNode<WordT> c_function =
660       UncheckedCast<WordT>(Parameter(Descriptor::kCFunction));
661 
662   // The logic contained here is mirrored for TurboFan inlining in
663   // JSTypedLowering::ReduceJSCall{Function,Construct}. Keep these in sync.
664 
665   // Make sure we operate in the context of the called function (for example
666   // ConstructStubs implemented in C++ will be run in the context of the caller
667   // instead of the callee, due to the way that [[Construct]] is defined for
668   // ordinary functions).
669   TNode<Context> context =
670       CAST(LoadObjectField(target, JSFunction::kContextOffset));
671 
672   // Update arguments count for CEntry to contain the number of arguments
673   // including the receiver and the extra arguments.
674   TNode<Int32T> argc =
675       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
676   argc = Int32Add(
677       argc,
678       Int32Constant(BuiltinExitFrameConstants::kNumExtraArgsWithReceiver));
679 
680   TNode<Code> code = HeapConstant(
681       CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
682                           exit_frame_type == Builtins::BUILTIN_EXIT));
683 
684   // Unconditionally push argc, target and new target as extra stack arguments.
685   // They will be used by stack frame iterators when constructing stack trace.
686   TailCallStub(CEntry1ArgvOnStackDescriptor{},  // descriptor
687                code, context,       // standard arguments for TailCallStub
688                argc, c_function,    // register arguments
689                TheHoleConstant(),   // additional stack argument 1 (padding)
690                SmiFromInt32(argc),  // additional stack argument 2
691                target,              // additional stack argument 3
692                new_target);         // additional stack argument 4
693 }
694 
TF_BUILTIN(AdaptorWithExitFrame,InternalBuiltinsAssembler)695 TF_BUILTIN(AdaptorWithExitFrame, InternalBuiltinsAssembler) {
696   GenerateAdaptorWithExitFrameType<Descriptor>(Builtins::EXIT);
697 }
698 
TF_BUILTIN(AdaptorWithBuiltinExitFrame,InternalBuiltinsAssembler)699 TF_BUILTIN(AdaptorWithBuiltinExitFrame, InternalBuiltinsAssembler) {
700   GenerateAdaptorWithExitFrameType<Descriptor>(Builtins::BUILTIN_EXIT);
701 }
702 
GetPendingMicrotaskCount()703 TNode<IntPtrT> InternalBuiltinsAssembler::GetPendingMicrotaskCount() {
704   auto ref = ExternalReference::pending_microtask_count_address(isolate());
705   if (kIntSize == 8) {
706     return TNode<IntPtrT>::UncheckedCast(
707         Load(MachineType::Int64(), ExternalConstant(ref)));
708   } else {
709     Node* const value = Load(MachineType::Int32(), ExternalConstant(ref));
710     return ChangeInt32ToIntPtr(value);
711   }
712 }
713 
SetPendingMicrotaskCount(TNode<IntPtrT> count)714 void InternalBuiltinsAssembler::SetPendingMicrotaskCount(TNode<IntPtrT> count) {
715   auto ref = ExternalReference::pending_microtask_count_address(isolate());
716   auto rep = kIntSize == 8 ? MachineRepresentation::kWord64
717                            : MachineRepresentation::kWord32;
718   if (kIntSize == 4 && kPointerSize == 8) {
719     Node* const truncated_count =
720         TruncateInt64ToInt32(TNode<Int64T>::UncheckedCast(count));
721     StoreNoWriteBarrier(rep, ExternalConstant(ref), truncated_count);
722   } else {
723     StoreNoWriteBarrier(rep, ExternalConstant(ref), count);
724   }
725 }
726 
GetMicrotaskQueue()727 TNode<FixedArray> InternalBuiltinsAssembler::GetMicrotaskQueue() {
728   return TNode<FixedArray>::UncheckedCast(
729       LoadRoot(Heap::kMicrotaskQueueRootIndex));
730 }
731 
SetMicrotaskQueue(TNode<FixedArray> queue)732 void InternalBuiltinsAssembler::SetMicrotaskQueue(TNode<FixedArray> queue) {
733   StoreRoot(Heap::kMicrotaskQueueRootIndex, queue);
734 }
735 
GetCurrentContext()736 TNode<Context> InternalBuiltinsAssembler::GetCurrentContext() {
737   auto ref = ExternalReference::Create(kContextAddress, isolate());
738   return TNode<Context>::UncheckedCast(
739       Load(MachineType::AnyTagged(), ExternalConstant(ref)));
740 }
741 
SetCurrentContext(TNode<Context> context)742 void InternalBuiltinsAssembler::SetCurrentContext(TNode<Context> context) {
743   auto ref = ExternalReference::Create(kContextAddress, isolate());
744   StoreNoWriteBarrier(MachineRepresentation::kTagged, ExternalConstant(ref),
745                       context);
746 }
747 
EnterMicrotaskContext(TNode<Context> microtask_context)748 void InternalBuiltinsAssembler::EnterMicrotaskContext(
749     TNode<Context> microtask_context) {
750   auto ref = ExternalReference::handle_scope_implementer_address(isolate());
751   Node* const hsi = Load(MachineType::Pointer(), ExternalConstant(ref));
752   StoreNoWriteBarrier(
753       MachineType::PointerRepresentation(), hsi,
754       IntPtrConstant(HandleScopeImplementerOffsets::kMicrotaskContext),
755       BitcastTaggedToWord(microtask_context));
756 
757   // Load mirrored std::vector length from
758   // HandleScopeImplementer::entered_contexts_count_
759   auto type = kSizetSize == 8 ? MachineType::Uint64() : MachineType::Uint32();
760   Node* entered_contexts_length = Load(
761       type, hsi,
762       IntPtrConstant(HandleScopeImplementerOffsets::kEnteredContextsCount));
763 
764   auto rep = kSizetSize == 8 ? MachineRepresentation::kWord64
765                              : MachineRepresentation::kWord32;
766 
767   StoreNoWriteBarrier(
768       rep, hsi,
769       IntPtrConstant(
770           HandleScopeImplementerOffsets::kEnteredContextCountDuringMicrotasks),
771       entered_contexts_length);
772 }
773 
LeaveMicrotaskContext()774 void InternalBuiltinsAssembler::LeaveMicrotaskContext() {
775   auto ref = ExternalReference::handle_scope_implementer_address(isolate());
776 
777   Node* const hsi = Load(MachineType::Pointer(), ExternalConstant(ref));
778   StoreNoWriteBarrier(
779       MachineType::PointerRepresentation(), hsi,
780       IntPtrConstant(HandleScopeImplementerOffsets::kMicrotaskContext),
781       IntPtrConstant(0));
782   if (kSizetSize == 4) {
783     StoreNoWriteBarrier(
784         MachineRepresentation::kWord32, hsi,
785         IntPtrConstant(HandleScopeImplementerOffsets::
786                            kEnteredContextCountDuringMicrotasks),
787         Int32Constant(0));
788   } else {
789     StoreNoWriteBarrier(
790         MachineRepresentation::kWord64, hsi,
791         IntPtrConstant(HandleScopeImplementerOffsets::
792                            kEnteredContextCountDuringMicrotasks),
793         Int64Constant(0));
794   }
795 }
796 
RunPromiseHook(Runtime::FunctionId id,TNode<Context> context,SloppyTNode<HeapObject> promise_or_capability)797 void InternalBuiltinsAssembler::RunPromiseHook(
798     Runtime::FunctionId id, TNode<Context> context,
799     SloppyTNode<HeapObject> promise_or_capability) {
800   Label hook(this, Label::kDeferred), done_hook(this);
801   GotoIf(IsDebugActive(), &hook);
802   Branch(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &hook, &done_hook);
803   BIND(&hook);
804   {
805     // Get to the underlying JSPromise instance.
806     Node* const promise = Select<HeapObject>(
807         IsJSPromise(promise_or_capability),
808         [=] { return promise_or_capability; },
809         [=] {
810           return CAST(LoadObjectField(promise_or_capability,
811                                       PromiseCapability::kPromiseOffset));
812         });
813     CallRuntime(id, context, promise);
814     Goto(&done_hook);
815   }
816   BIND(&done_hook);
817 }
818 
TF_BUILTIN(EnqueueMicrotask,InternalBuiltinsAssembler)819 TF_BUILTIN(EnqueueMicrotask, InternalBuiltinsAssembler) {
820   Node* microtask = Parameter(Descriptor::kMicrotask);
821 
822   TNode<IntPtrT> num_tasks = GetPendingMicrotaskCount();
823   TNode<IntPtrT> new_num_tasks = IntPtrAdd(num_tasks, IntPtrConstant(1));
824   TNode<FixedArray> queue = GetMicrotaskQueue();
825   TNode<IntPtrT> queue_length = LoadAndUntagFixedArrayBaseLength(queue);
826 
827   Label if_append(this), if_grow(this), done(this);
828   Branch(WordEqual(num_tasks, queue_length), &if_grow, &if_append);
829 
830   BIND(&if_grow);
831   {
832     // Determine the new queue length and check if we need to allocate
833     // in large object space (instead of just going to new space, where
834     // we also know that we don't need any write barriers for setting
835     // up the new queue object).
836     Label if_newspace(this), if_lospace(this, Label::kDeferred);
837     TNode<IntPtrT> new_queue_length =
838         IntPtrMax(IntPtrConstant(8), IntPtrAdd(num_tasks, num_tasks));
839     Branch(IntPtrLessThanOrEqual(new_queue_length,
840                                  IntPtrConstant(FixedArray::kMaxRegularLength)),
841            &if_newspace, &if_lospace);
842 
843     BIND(&if_newspace);
844     {
845       // This is the likely case where the new queue fits into new space,
846       // and thus we don't need any write barriers for initializing it.
847       TNode<FixedArray> new_queue =
848           CAST(AllocateFixedArray(PACKED_ELEMENTS, new_queue_length));
849       CopyFixedArrayElements(PACKED_ELEMENTS, queue, new_queue, num_tasks,
850                              SKIP_WRITE_BARRIER);
851       StoreFixedArrayElement(new_queue, num_tasks, microtask,
852                              SKIP_WRITE_BARRIER);
853       FillFixedArrayWithValue(PACKED_ELEMENTS, new_queue, new_num_tasks,
854                               new_queue_length, Heap::kUndefinedValueRootIndex);
855       SetMicrotaskQueue(new_queue);
856       Goto(&done);
857     }
858 
859     BIND(&if_lospace);
860     {
861       // The fallback case where the new queue ends up in large object space.
862       TNode<FixedArray> new_queue = CAST(AllocateFixedArray(
863           PACKED_ELEMENTS, new_queue_length, INTPTR_PARAMETERS,
864           AllocationFlag::kAllowLargeObjectAllocation));
865       CopyFixedArrayElements(PACKED_ELEMENTS, queue, new_queue, num_tasks);
866       StoreFixedArrayElement(new_queue, num_tasks, microtask);
867       FillFixedArrayWithValue(PACKED_ELEMENTS, new_queue, new_num_tasks,
868                               new_queue_length, Heap::kUndefinedValueRootIndex);
869       SetMicrotaskQueue(new_queue);
870       Goto(&done);
871     }
872   }
873 
874   BIND(&if_append);
875   {
876     StoreFixedArrayElement(queue, num_tasks, microtask);
877     Goto(&done);
878   }
879 
880   BIND(&done);
881   SetPendingMicrotaskCount(new_num_tasks);
882   Return(UndefinedConstant());
883 }
884 
TF_BUILTIN(RunMicrotasks,InternalBuiltinsAssembler)885 TF_BUILTIN(RunMicrotasks, InternalBuiltinsAssembler) {
886   // Load the current context from the isolate.
887   TNode<Context> current_context = GetCurrentContext();
888 
889   Label init_queue_loop(this);
890   Goto(&init_queue_loop);
891   BIND(&init_queue_loop);
892   {
893     TVARIABLE(IntPtrT, index, IntPtrConstant(0));
894     Label loop(this, &index), loop_next(this);
895 
896     TNode<IntPtrT> num_tasks = GetPendingMicrotaskCount();
897     ReturnIf(IntPtrEqual(num_tasks, IntPtrConstant(0)), UndefinedConstant());
898 
899     TNode<FixedArray> queue = GetMicrotaskQueue();
900 
901     CSA_ASSERT(this, IntPtrGreaterThanOrEqual(
902                          LoadAndUntagFixedArrayBaseLength(queue), num_tasks));
903     CSA_ASSERT(this, IntPtrGreaterThan(num_tasks, IntPtrConstant(0)));
904 
905     SetPendingMicrotaskCount(IntPtrConstant(0));
906     SetMicrotaskQueue(EmptyFixedArrayConstant());
907 
908     Goto(&loop);
909     BIND(&loop);
910     {
911       TNode<HeapObject> microtask =
912           CAST(LoadFixedArrayElement(queue, index.value()));
913       index = IntPtrAdd(index.value(), IntPtrConstant(1));
914 
915       CSA_ASSERT(this, TaggedIsNotSmi(microtask));
916 
917       TNode<Map> microtask_map = LoadMap(microtask);
918       TNode<Int32T> microtask_type = LoadMapInstanceType(microtask_map);
919 
920       VARIABLE(var_exception, MachineRepresentation::kTagged,
921                TheHoleConstant());
922       Label if_exception(this, Label::kDeferred);
923       Label is_callable(this), is_callback(this),
924           is_promise_fulfill_reaction_job(this),
925           is_promise_reject_reaction_job(this),
926           is_promise_resolve_thenable_job(this),
927           is_unreachable(this, Label::kDeferred);
928 
929       int32_t case_values[] = {CALLABLE_TASK_TYPE, CALLBACK_TASK_TYPE,
930                                PROMISE_FULFILL_REACTION_JOB_TASK_TYPE,
931                                PROMISE_REJECT_REACTION_JOB_TASK_TYPE,
932                                PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE};
933       Label* case_labels[] = {
934           &is_callable, &is_callback, &is_promise_fulfill_reaction_job,
935           &is_promise_reject_reaction_job, &is_promise_resolve_thenable_job};
936       static_assert(arraysize(case_values) == arraysize(case_labels), "");
937       Switch(microtask_type, &is_unreachable, case_values, case_labels,
938              arraysize(case_labels));
939 
940       BIND(&is_callable);
941       {
942         // Enter the context of the {microtask}.
943         TNode<Context> microtask_context =
944             LoadObjectField<Context>(microtask, CallableTask::kContextOffset);
945         TNode<Context> native_context = LoadNativeContext(microtask_context);
946 
947         CSA_ASSERT(this, IsNativeContext(native_context));
948         EnterMicrotaskContext(microtask_context);
949         SetCurrentContext(native_context);
950 
951         TNode<JSReceiver> callable = LoadObjectField<JSReceiver>(
952             microtask, CallableTask::kCallableOffset);
953         Node* const result = CallJS(
954             CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
955             microtask_context, callable, UndefinedConstant());
956         GotoIfException(result, &if_exception, &var_exception);
957         LeaveMicrotaskContext();
958         SetCurrentContext(current_context);
959         Goto(&loop_next);
960       }
961 
962       BIND(&is_callback);
963       {
964         Node* const microtask_callback =
965             LoadObjectField(microtask, CallbackTask::kCallbackOffset);
966         Node* const microtask_data =
967             LoadObjectField(microtask, CallbackTask::kDataOffset);
968 
969         // If this turns out to become a bottleneck because of the calls
970         // to C++ via CEntry, we can choose to speed them up using a
971         // similar mechanism that we use for the CallApiFunction stub,
972         // except that calling the MicrotaskCallback is even easier, since
973         // it doesn't accept any tagged parameters, doesn't return a value
974         // and ignores exceptions.
975         //
976         // But from our current measurements it doesn't seem to be a
977         // serious performance problem, even if the microtask is full
978         // of CallHandlerTasks (which is not a realistic use case anyways).
979         Node* const result =
980             CallRuntime(Runtime::kRunMicrotaskCallback, current_context,
981                         microtask_callback, microtask_data);
982         GotoIfException(result, &if_exception, &var_exception);
983         Goto(&loop_next);
984       }
985 
986       BIND(&is_promise_resolve_thenable_job);
987       {
988         // Enter the context of the {microtask}.
989         TNode<Context> microtask_context = LoadObjectField<Context>(
990             microtask, PromiseResolveThenableJobTask::kContextOffset);
991         TNode<Context> native_context = LoadNativeContext(microtask_context);
992         CSA_ASSERT(this, IsNativeContext(native_context));
993         EnterMicrotaskContext(microtask_context);
994         SetCurrentContext(native_context);
995 
996         Node* const promise_to_resolve = LoadObjectField(
997             microtask, PromiseResolveThenableJobTask::kPromiseToResolveOffset);
998         Node* const then = LoadObjectField(
999             microtask, PromiseResolveThenableJobTask::kThenOffset);
1000         Node* const thenable = LoadObjectField(
1001             microtask, PromiseResolveThenableJobTask::kThenableOffset);
1002 
1003         Node* const result =
1004             CallBuiltin(Builtins::kPromiseResolveThenableJob, native_context,
1005                         promise_to_resolve, thenable, then);
1006         GotoIfException(result, &if_exception, &var_exception);
1007         LeaveMicrotaskContext();
1008         SetCurrentContext(current_context);
1009         Goto(&loop_next);
1010       }
1011 
1012       BIND(&is_promise_fulfill_reaction_job);
1013       {
1014         // Enter the context of the {microtask}.
1015         TNode<Context> microtask_context = LoadObjectField<Context>(
1016             microtask, PromiseReactionJobTask::kContextOffset);
1017         TNode<Context> native_context = LoadNativeContext(microtask_context);
1018         CSA_ASSERT(this, IsNativeContext(native_context));
1019         EnterMicrotaskContext(microtask_context);
1020         SetCurrentContext(native_context);
1021 
1022         Node* const argument =
1023             LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
1024         Node* const handler =
1025             LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
1026         Node* const promise_or_capability = LoadObjectField(
1027             microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset);
1028 
1029         // Run the promise before/debug hook if enabled.
1030         RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
1031                        promise_or_capability);
1032 
1033         Node* const result =
1034             CallBuiltin(Builtins::kPromiseFulfillReactionJob, microtask_context,
1035                         argument, handler, promise_or_capability);
1036         GotoIfException(result, &if_exception, &var_exception);
1037 
1038         // Run the promise after/debug hook if enabled.
1039         RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
1040                        promise_or_capability);
1041 
1042         LeaveMicrotaskContext();
1043         SetCurrentContext(current_context);
1044         Goto(&loop_next);
1045       }
1046 
1047       BIND(&is_promise_reject_reaction_job);
1048       {
1049         // Enter the context of the {microtask}.
1050         TNode<Context> microtask_context = LoadObjectField<Context>(
1051             microtask, PromiseReactionJobTask::kContextOffset);
1052         TNode<Context> native_context = LoadNativeContext(microtask_context);
1053         CSA_ASSERT(this, IsNativeContext(native_context));
1054         EnterMicrotaskContext(microtask_context);
1055         SetCurrentContext(native_context);
1056 
1057         Node* const argument =
1058             LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
1059         Node* const handler =
1060             LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
1061         Node* const promise_or_capability = LoadObjectField(
1062             microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset);
1063 
1064         // Run the promise before/debug hook if enabled.
1065         RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
1066                        promise_or_capability);
1067 
1068         Node* const result =
1069             CallBuiltin(Builtins::kPromiseRejectReactionJob, microtask_context,
1070                         argument, handler, promise_or_capability);
1071         GotoIfException(result, &if_exception, &var_exception);
1072 
1073         // Run the promise after/debug hook if enabled.
1074         RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
1075                        promise_or_capability);
1076 
1077         LeaveMicrotaskContext();
1078         SetCurrentContext(current_context);
1079         Goto(&loop_next);
1080       }
1081 
1082       BIND(&is_unreachable);
1083       Unreachable();
1084 
1085       BIND(&if_exception);
1086       {
1087         // Report unhandled exceptions from microtasks.
1088         CallRuntime(Runtime::kReportMessage, current_context,
1089                     var_exception.value());
1090         LeaveMicrotaskContext();
1091         SetCurrentContext(current_context);
1092         Goto(&loop_next);
1093       }
1094 
1095       BIND(&loop_next);
1096       Branch(IntPtrLessThan(index.value(), num_tasks), &loop, &init_queue_loop);
1097     }
1098   }
1099 }
1100 
TF_BUILTIN(AllocateInNewSpace,CodeStubAssembler)1101 TF_BUILTIN(AllocateInNewSpace, CodeStubAssembler) {
1102   TNode<Int32T> requested_size =
1103       UncheckedCast<Int32T>(Parameter(Descriptor::kRequestedSize));
1104 
1105   TailCallRuntime(Runtime::kAllocateInNewSpace, NoContextConstant(),
1106                   SmiFromInt32(requested_size));
1107 }
1108 
TF_BUILTIN(AllocateInOldSpace,CodeStubAssembler)1109 TF_BUILTIN(AllocateInOldSpace, CodeStubAssembler) {
1110   TNode<Int32T> requested_size =
1111       UncheckedCast<Int32T>(Parameter(Descriptor::kRequestedSize));
1112 
1113   int flags = AllocateTargetSpace::encode(OLD_SPACE);
1114   TailCallRuntime(Runtime::kAllocateInTargetSpace, NoContextConstant(),
1115                   SmiFromInt32(requested_size), SmiConstant(flags));
1116 }
1117 
TF_BUILTIN(Abort,CodeStubAssembler)1118 TF_BUILTIN(Abort, CodeStubAssembler) {
1119   TNode<Smi> message_id = CAST(Parameter(Descriptor::kMessageOrMessageId));
1120   TailCallRuntime(Runtime::kAbort, NoContextConstant(), message_id);
1121 }
1122 
TF_BUILTIN(AbortJS,CodeStubAssembler)1123 TF_BUILTIN(AbortJS, CodeStubAssembler) {
1124   TNode<String> message = CAST(Parameter(Descriptor::kMessageOrMessageId));
1125   TailCallRuntime(Runtime::kAbortJS, NoContextConstant(), message);
1126 }
1127 
Generate_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit(MacroAssembler * masm)1128 void Builtins::Generate_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit(
1129     MacroAssembler* masm) {
1130   Generate_CEntry(masm, 1, kDontSaveFPRegs, kArgvOnStack, false);
1131 }
1132 
Generate_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit(MacroAssembler * masm)1133 void Builtins::Generate_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit(
1134     MacroAssembler* masm) {
1135   Generate_CEntry(masm, 1, kDontSaveFPRegs, kArgvOnStack, true);
1136 }
1137 
1138 void Builtins::
Generate_CEntry_Return1_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit(MacroAssembler * masm)1139     Generate_CEntry_Return1_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit(
1140         MacroAssembler* masm) {
1141   Generate_CEntry(masm, 1, kDontSaveFPRegs, kArgvInRegister, false);
1142 }
1143 
Generate_CEntry_Return1_SaveFPRegs_ArgvOnStack_NoBuiltinExit(MacroAssembler * masm)1144 void Builtins::Generate_CEntry_Return1_SaveFPRegs_ArgvOnStack_NoBuiltinExit(
1145     MacroAssembler* masm) {
1146   Generate_CEntry(masm, 1, kSaveFPRegs, kArgvOnStack, false);
1147 }
1148 
Generate_CEntry_Return1_SaveFPRegs_ArgvOnStack_BuiltinExit(MacroAssembler * masm)1149 void Builtins::Generate_CEntry_Return1_SaveFPRegs_ArgvOnStack_BuiltinExit(
1150     MacroAssembler* masm) {
1151   Generate_CEntry(masm, 1, kSaveFPRegs, kArgvOnStack, true);
1152 }
1153 
Generate_CEntry_Return2_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit(MacroAssembler * masm)1154 void Builtins::Generate_CEntry_Return2_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit(
1155     MacroAssembler* masm) {
1156   Generate_CEntry(masm, 2, kDontSaveFPRegs, kArgvOnStack, false);
1157 }
1158 
Generate_CEntry_Return2_DontSaveFPRegs_ArgvOnStack_BuiltinExit(MacroAssembler * masm)1159 void Builtins::Generate_CEntry_Return2_DontSaveFPRegs_ArgvOnStack_BuiltinExit(
1160     MacroAssembler* masm) {
1161   Generate_CEntry(masm, 2, kDontSaveFPRegs, kArgvOnStack, true);
1162 }
1163 
1164 void Builtins::
Generate_CEntry_Return2_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit(MacroAssembler * masm)1165     Generate_CEntry_Return2_DontSaveFPRegs_ArgvInRegister_NoBuiltinExit(
1166         MacroAssembler* masm) {
1167   Generate_CEntry(masm, 2, kDontSaveFPRegs, kArgvInRegister, false);
1168 }
1169 
Generate_CEntry_Return2_SaveFPRegs_ArgvOnStack_NoBuiltinExit(MacroAssembler * masm)1170 void Builtins::Generate_CEntry_Return2_SaveFPRegs_ArgvOnStack_NoBuiltinExit(
1171     MacroAssembler* masm) {
1172   Generate_CEntry(masm, 2, kSaveFPRegs, kArgvOnStack, false);
1173 }
1174 
Generate_CEntry_Return2_SaveFPRegs_ArgvOnStack_BuiltinExit(MacroAssembler * masm)1175 void Builtins::Generate_CEntry_Return2_SaveFPRegs_ArgvOnStack_BuiltinExit(
1176     MacroAssembler* masm) {
1177   Generate_CEntry(masm, 2, kSaveFPRegs, kArgvOnStack, true);
1178 }
1179 
Generate_CallApiGetter(MacroAssembler * masm)1180 void Builtins::Generate_CallApiGetter(MacroAssembler* masm) {
1181   // CallApiGetterStub only exists as a stub to avoid duplicating code between
1182   // here and code-stubs-<arch>.cc. For example, see CallApiFunctionAndReturn.
1183   // Here we abuse the instantiated stub to generate code.
1184   CallApiGetterStub stub(masm->isolate());
1185   stub.Generate(masm);
1186 }
1187 
Generate_CallApiCallback_Argc0(MacroAssembler * masm)1188 void Builtins::Generate_CallApiCallback_Argc0(MacroAssembler* masm) {
1189   // The common variants of CallApiCallbackStub (i.e. all that are embedded into
1190   // the snapshot) are generated as builtins. The rest remain available as code
1191   // stubs. Here we abuse the instantiated stub to generate code and avoid
1192   // duplication.
1193   const int kArgc = 0;
1194   CallApiCallbackStub stub(masm->isolate(), kArgc);
1195   stub.Generate(masm);
1196 }
1197 
Generate_CallApiCallback_Argc1(MacroAssembler * masm)1198 void Builtins::Generate_CallApiCallback_Argc1(MacroAssembler* masm) {
1199   // The common variants of CallApiCallbackStub (i.e. all that are embedded into
1200   // the snapshot) are generated as builtins. The rest remain available as code
1201   // stubs. Here we abuse the instantiated stub to generate code and avoid
1202   // duplication.
1203   const int kArgc = 1;
1204   CallApiCallbackStub stub(masm->isolate(), kArgc);
1205   stub.Generate(masm);
1206 }
1207 
1208 // ES6 [[Get]] operation.
TF_BUILTIN(GetProperty,CodeStubAssembler)1209 TF_BUILTIN(GetProperty, CodeStubAssembler) {
1210   Label call_runtime(this, Label::kDeferred), return_undefined(this), end(this);
1211 
1212   Node* object = Parameter(Descriptor::kObject);
1213   Node* key = Parameter(Descriptor::kKey);
1214   Node* context = Parameter(Descriptor::kContext);
1215   VARIABLE(var_result, MachineRepresentation::kTagged);
1216 
1217   CodeStubAssembler::LookupInHolder lookup_property_in_holder =
1218       [=, &var_result, &end](Node* receiver, Node* holder, Node* holder_map,
1219                              Node* holder_instance_type, Node* unique_name,
1220                              Label* next_holder, Label* if_bailout) {
1221         VARIABLE(var_value, MachineRepresentation::kTagged);
1222         Label if_found(this);
1223         TryGetOwnProperty(context, receiver, holder, holder_map,
1224                           holder_instance_type, unique_name, &if_found,
1225                           &var_value, next_holder, if_bailout);
1226         BIND(&if_found);
1227         {
1228           var_result.Bind(var_value.value());
1229           Goto(&end);
1230         }
1231       };
1232 
1233   CodeStubAssembler::LookupInHolder lookup_element_in_holder =
1234       [=](Node* receiver, Node* holder, Node* holder_map,
1235           Node* holder_instance_type, Node* index, Label* next_holder,
1236           Label* if_bailout) {
1237         // Not supported yet.
1238         Use(next_holder);
1239         Goto(if_bailout);
1240       };
1241 
1242   TryPrototypeChainLookup(object, key, lookup_property_in_holder,
1243                           lookup_element_in_holder, &return_undefined,
1244                           &call_runtime);
1245 
1246   BIND(&return_undefined);
1247   {
1248     var_result.Bind(UndefinedConstant());
1249     Goto(&end);
1250   }
1251 
1252   BIND(&call_runtime);
1253   {
1254     var_result.Bind(CallRuntime(Runtime::kGetProperty, context, object, key));
1255     Goto(&end);
1256   }
1257 
1258   BIND(&end);
1259   Return(var_result.value());
1260 }
1261 
1262 // ES6 [[Set]] operation.
TF_BUILTIN(SetProperty,CodeStubAssembler)1263 TF_BUILTIN(SetProperty, CodeStubAssembler) {
1264   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1265   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1266   TNode<Object> key = CAST(Parameter(Descriptor::kKey));
1267   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
1268 
1269   KeyedStoreGenericGenerator::SetProperty(state(), context, receiver, key,
1270                                           value, LanguageMode::kStrict);
1271 }
1272 
1273 }  // namespace internal
1274 }  // namespace v8
1275