Line data Source code
1 : // Copyright 2012 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/code-stubs.h"
6 :
7 : #include <sstream>
8 :
9 : #include "src/arguments.h"
10 : #include "src/assembler-inl.h"
11 : #include "src/ast/ast.h"
12 : #include "src/bootstrapper.h"
13 : #include "src/code-factory.h"
14 : #include "src/code-stub-assembler.h"
15 : #include "src/code-stubs-utils.h"
16 : #include "src/counters.h"
17 : #include "src/factory.h"
18 : #include "src/gdb-jit.h"
19 : #include "src/heap/heap-inl.h"
20 : #include "src/ic/ic-stats.h"
21 : #include "src/ic/ic.h"
22 : #include "src/macro-assembler.h"
23 : #include "src/objects-inl.h"
24 : #include "src/tracing/tracing-category-observer.h"
25 :
26 : namespace v8 {
27 : namespace internal {
28 :
29 : using compiler::CodeAssemblerState;
30 :
31 0 : RUNTIME_FUNCTION(UnexpectedStubMiss) {
32 0 : FATAL("Unexpected deopt of a stub");
33 : return Smi::kZero;
34 : }
35 :
36 55168 : CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
37 : : isolate_(stub->isolate()),
38 55168 : call_descriptor_(stub->GetCallInterfaceDescriptor()),
39 : stack_parameter_count_(no_reg),
40 : hint_stack_parameter_count_(-1),
41 : function_mode_(NOT_JS_FUNCTION_STUB_MODE),
42 : deoptimization_handler_(NULL),
43 : miss_handler_(),
44 165504 : has_miss_handler_(false) {
45 55168 : stub->InitializeDescriptor(this);
46 55168 : }
47 :
48 26647 : CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
49 : : isolate_(isolate),
50 : stack_parameter_count_(no_reg),
51 : hint_stack_parameter_count_(-1),
52 : function_mode_(NOT_JS_FUNCTION_STUB_MODE),
53 : deoptimization_handler_(NULL),
54 : miss_handler_(),
55 79941 : has_miss_handler_(false) {
56 : CodeStub::InitializeDescriptor(isolate, stub_key, this);
57 26647 : }
58 :
59 :
60 0 : void CodeStubDescriptor::Initialize(Address deoptimization_handler,
61 : int hint_stack_parameter_count,
62 : StubFunctionMode function_mode) {
63 81815 : deoptimization_handler_ = deoptimization_handler;
64 81815 : hint_stack_parameter_count_ = hint_stack_parameter_count;
65 81815 : function_mode_ = function_mode;
66 0 : }
67 :
68 :
69 0 : void CodeStubDescriptor::Initialize(Register stack_parameter_count,
70 : Address deoptimization_handler,
71 : int hint_stack_parameter_count,
72 : StubFunctionMode function_mode) {
73 : Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
74 0 : stack_parameter_count_ = stack_parameter_count;
75 0 : }
76 :
77 :
78 20038633 : bool CodeStub::FindCodeInCache(Code** code_out) {
79 10019316 : UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
80 10019317 : int index = stubs->FindEntry(isolate(), GetKey());
81 10019326 : if (index != UnseededNumberDictionary::kNotFound) {
82 9781673 : *code_out = Code::cast(stubs->ValueAt(index));
83 9781673 : return true;
84 : }
85 : return false;
86 : }
87 :
88 :
89 859896 : void CodeStub::RecordCodeGeneration(Handle<Code> code) {
90 286632 : std::ostringstream os;
91 : os << *this;
92 573264 : PROFILE(isolate(),
93 : CodeCreateEvent(CodeEventListener::STUB_TAG,
94 : AbstractCode::cast(*code), os.str().c_str()));
95 286632 : Counters* counters = isolate()->counters();
96 286632 : counters->total_stubs_code_size()->Increment(code->instruction_size());
97 : #ifdef DEBUG
98 : code->VerifyEmbeddedObjects();
99 : #endif
100 286632 : }
101 :
102 :
103 115304 : Code::Kind CodeStub::GetCodeKind() const {
104 115304 : return Code::STUB;
105 : }
106 :
107 :
108 110263 : Code::Flags CodeStub::GetCodeFlags() const {
109 220526 : return Code::ComputeFlags(GetCodeKind(), GetExtraICState());
110 : }
111 :
112 93648 : Handle<Code> CodeStub::GetCodeCopy(const FindAndReplacePattern& pattern) {
113 46824 : Handle<Code> ic = GetCode();
114 46824 : ic = isolate()->factory()->CopyCode(ic);
115 46824 : ic->FindAndReplace(pattern);
116 46824 : RecordCodeGeneration(ic);
117 46824 : return ic;
118 : }
119 :
120 0 : void CodeStub::DeleteStubFromCacheForTesting() {
121 0 : Heap* heap = isolate_->heap();
122 : Handle<UnseededNumberDictionary> dict(heap->code_stubs());
123 0 : dict = UnseededNumberDictionary::DeleteKey(dict, GetKey());
124 0 : heap->SetRootCodeStubs(*dict);
125 0 : }
126 :
127 129552 : Handle<Code> PlatformCodeStub::GenerateCode() {
128 259104 : Factory* factory = isolate()->factory();
129 :
130 : // Generate the new code.
131 129552 : MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
132 :
133 : {
134 : // Update the static counter each time a new code stub is generated.
135 129552 : isolate()->counters()->code_stubs()->Increment();
136 :
137 : // Generate the code for the stub.
138 : masm.set_generating_stub(true);
139 : // TODO(yangguo): remove this once we can serialize IC stubs.
140 : masm.enable_serializer();
141 : NoCurrentFrameScope scope(&masm);
142 129552 : Generate(&masm);
143 : }
144 :
145 : // Create the code object.
146 : CodeDesc desc;
147 129552 : masm.GetCode(&desc);
148 : // Copy the generated code into a heap object.
149 129552 : Code::Flags flags = Code::ComputeFlags(GetCodeKind(), GetExtraICState());
150 : Handle<Code> new_object = factory->NewCode(
151 129552 : desc, flags, masm.CodeObject(), NeedsImmovableCode());
152 259104 : return new_object;
153 : }
154 :
155 :
156 10474437 : Handle<Code> CodeStub::GetCode() {
157 10232470 : Heap* heap = isolate()->heap();
158 : Code* code;
159 9994821 : if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
160 : : FindCodeInCache(&code)) {
161 : DCHECK(GetCodeKind() == code->kind());
162 19510048 : return Handle<Code>(code);
163 : }
164 :
165 : {
166 : HandleScope scope(isolate());
167 :
168 239808 : Handle<Code> new_object = GenerateCode();
169 : new_object->set_stub_key(GetKey());
170 239808 : FinishCode(new_object);
171 239808 : RecordCodeGeneration(new_object);
172 :
173 : #ifdef ENABLE_DISASSEMBLER
174 : if (FLAG_print_code_stubs) {
175 : CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
176 : OFStream os(trace_scope.file());
177 : std::ostringstream name;
178 : name << *this;
179 : new_object->Disassemble(name.str().c_str(), os);
180 : os << "\n";
181 : }
182 : #endif
183 :
184 239808 : if (UseSpecialCache()) {
185 2159 : AddToSpecialCache(new_object);
186 : } else {
187 : // Update the dictionary and the root in Heap.
188 : Handle<UnseededNumberDictionary> dict =
189 : UnseededNumberDictionary::AtNumberPut(
190 : Handle<UnseededNumberDictionary>(heap->code_stubs()),
191 : GetKey(),
192 237649 : new_object);
193 237649 : heap->SetRootCodeStubs(*dict);
194 : }
195 239808 : code = *new_object;
196 : }
197 :
198 239808 : Activate(code);
199 : DCHECK(!NeedsImmovableCode() || Heap::IsImmovable(code) ||
200 : heap->code_space()->FirstPage()->Contains(code->address()));
201 479616 : return Handle<Code>(code, isolate());
202 : }
203 :
204 :
205 466529 : const char* CodeStub::MajorName(CodeStub::Major major_key) {
206 466529 : switch (major_key) {
207 : #define DEF_CASE(name) case name: return #name "Stub";
208 50691 : CODE_STUB_LIST(DEF_CASE)
209 : #undef DEF_CASE
210 : case NoCache:
211 0 : return "<NoCache>Stub";
212 : case NUMBER_OF_IDS:
213 0 : UNREACHABLE();
214 : return NULL;
215 : }
216 0 : return NULL;
217 : }
218 :
219 :
220 285557 : void CodeStub::PrintBaseName(std::ostream& os) const { // NOLINT
221 285557 : os << MajorName(MajorKey());
222 285557 : }
223 :
224 :
225 285686 : void CodeStub::PrintName(std::ostream& os) const { // NOLINT
226 285686 : PrintBaseName(os);
227 285686 : PrintState(os);
228 285686 : }
229 :
230 :
231 26928 : void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
232 : DispatchedCall call) {
233 26928 : switch (MajorKeyFromKey(key)) {
234 : #define DEF_CASE(NAME) \
235 : case NAME: { \
236 : NAME##Stub stub(key, isolate); \
237 : CodeStub* pstub = &stub; \
238 : call(pstub, value_out); \
239 : break; \
240 : }
241 26928 : CODE_STUB_LIST(DEF_CASE)
242 : #undef DEF_CASE
243 : case NUMBER_OF_IDS:
244 : case NoCache:
245 0 : UNREACHABLE();
246 : break;
247 : }
248 26928 : }
249 :
250 :
251 26647 : static void InitializeDescriptorDispatchedCall(CodeStub* stub,
252 : void** value_out) {
253 : CodeStubDescriptor* descriptor_out =
254 : reinterpret_cast<CodeStubDescriptor*>(value_out);
255 26647 : stub->InitializeDescriptor(descriptor_out);
256 53294 : descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
257 26647 : }
258 :
259 :
260 0 : void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
261 : CodeStubDescriptor* desc) {
262 : void** value_out = reinterpret_cast<void**>(desc);
263 26647 : Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
264 0 : }
265 :
266 :
267 281 : void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
268 : Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
269 : // Code stubs with special cache cannot be recreated from stub key.
270 281 : *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
271 281 : }
272 :
273 :
274 281 : MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
275 : HandleScope scope(isolate);
276 : Handle<Code> code;
277 : void** value_out = reinterpret_cast<void**>(&code);
278 281 : Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
279 562 : return scope.CloseAndEscape(code);
280 : }
281 :
282 :
283 : // static
284 43 : void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
285 86 : if (FLAG_minimal) return;
286 : // Generate the uninitialized versions of the stub.
287 516 : for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
288 516 : BinaryOpICStub stub(isolate, static_cast<Token::Value>(op));
289 516 : stub.GetCode();
290 : }
291 :
292 : // Generate special versions of the stub.
293 43 : BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
294 : }
295 :
296 :
297 10239 : void BinaryOpICStub::PrintState(std::ostream& os) const { // NOLINT
298 10239 : os << state();
299 10239 : }
300 :
301 :
302 : // static
303 4214 : void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
304 : const BinaryOpICState& state) {
305 4214 : if (FLAG_minimal) return;
306 : BinaryOpICStub stub(isolate, state);
307 4214 : stub.GetCode();
308 : }
309 :
310 :
311 : // static
312 43 : void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
313 : // Generate special versions of the stub.
314 43 : BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
315 43 : }
316 :
317 :
318 50691 : void BinaryOpICWithAllocationSiteStub::PrintState(
319 : std::ostream& os) const { // NOLINT
320 50691 : os << state();
321 50691 : }
322 :
323 :
324 : // static
325 4214 : void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
326 4214 : Isolate* isolate, const BinaryOpICState& state) {
327 4214 : if (state.CouldCreateAllocationMementos()) {
328 : BinaryOpICWithAllocationSiteStub stub(isolate, state);
329 0 : stub.GetCode();
330 : }
331 4214 : }
332 :
333 129 : void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
334 129 : os << "StringAddStub_" << flags() << "_" << pretenure_flag();
335 129 : }
336 :
337 516 : TF_STUB(StringAddStub, CodeStubAssembler) {
338 : StringAddFlags flags = stub->flags();
339 : PretenureFlag pretenure_flag = stub->pretenure_flag();
340 :
341 : Node* left = Parameter(Descriptor::kLeft);
342 : Node* right = Parameter(Descriptor::kRight);
343 : Node* context = Parameter(Descriptor::kContext);
344 :
345 129 : if ((flags & STRING_ADD_CHECK_LEFT) != 0) {
346 : DCHECK((flags & STRING_ADD_CONVERT) != 0);
347 : // TODO(danno): The ToString and JSReceiverToPrimitive below could be
348 : // combined to avoid duplicate smi and instance type checks.
349 43 : left = ToString(context, JSReceiverToPrimitive(context, left));
350 : }
351 129 : if ((flags & STRING_ADD_CHECK_RIGHT) != 0) {
352 : DCHECK((flags & STRING_ADD_CONVERT) != 0);
353 : // TODO(danno): The ToString and JSReceiverToPrimitive below could be
354 : // combined to avoid duplicate smi and instance type checks.
355 43 : right = ToString(context, JSReceiverToPrimitive(context, right));
356 : }
357 :
358 129 : if ((flags & STRING_ADD_CHECK_BOTH) == 0) {
359 : CodeStubAssembler::AllocationFlag allocation_flags =
360 : (pretenure_flag == TENURED) ? CodeStubAssembler::kPretenured
361 43 : : CodeStubAssembler::kNone;
362 43 : Return(StringAdd(context, left, right, allocation_flags));
363 : } else {
364 : Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE,
365 86 : pretenure_flag);
366 86 : TailCallStub(callable, context, left, right);
367 : }
368 129 : }
369 :
370 818740 : InlineCacheState CompareICStub::GetICState() const {
371 : CompareICState::State state = Max(left(), right());
372 818740 : switch (state) {
373 : case CompareICState::UNINITIALIZED:
374 : return ::v8::internal::UNINITIALIZED;
375 : case CompareICState::BOOLEAN:
376 : case CompareICState::SMI:
377 : case CompareICState::NUMBER:
378 : case CompareICState::INTERNALIZED_STRING:
379 : case CompareICState::STRING:
380 : case CompareICState::UNIQUE_NAME:
381 : case CompareICState::RECEIVER:
382 : case CompareICState::KNOWN_RECEIVER:
383 289086 : return MONOMORPHIC;
384 : case CompareICState::GENERIC:
385 24500 : return ::v8::internal::GENERIC;
386 : }
387 0 : UNREACHABLE();
388 : return ::v8::internal::UNINITIALIZED;
389 : }
390 :
391 :
392 28590 : Condition CompareICStub::GetCondition() const {
393 28590 : return CompareIC::ComputeCondition(op());
394 : }
395 :
396 :
397 66854 : void CompareICStub::Generate(MacroAssembler* masm) {
398 66854 : switch (state()) {
399 : case CompareICState::UNINITIALIZED:
400 23121 : GenerateMiss(masm);
401 23121 : break;
402 : case CompareICState::BOOLEAN:
403 2101 : GenerateBooleans(masm);
404 2101 : break;
405 : case CompareICState::SMI:
406 15291 : GenerateSmis(masm);
407 15291 : break;
408 : case CompareICState::NUMBER:
409 3424 : GenerateNumbers(masm);
410 3424 : break;
411 : case CompareICState::STRING:
412 3545 : GenerateStrings(masm);
413 3545 : break;
414 : case CompareICState::INTERNALIZED_STRING:
415 3376 : GenerateInternalizedStrings(masm);
416 3376 : break;
417 : case CompareICState::UNIQUE_NAME:
418 42 : GenerateUniqueNames(masm);
419 42 : break;
420 : case CompareICState::RECEIVER:
421 597 : GenerateReceivers(masm);
422 597 : break;
423 : case CompareICState::KNOWN_RECEIVER:
424 : DCHECK(*known_map_ != NULL);
425 2159 : GenerateKnownReceivers(masm);
426 2159 : break;
427 : case CompareICState::GENERIC:
428 13198 : GenerateGeneric(masm);
429 13198 : break;
430 : }
431 66854 : }
432 :
433 78628 : Handle<Code> TurboFanCodeStub::GenerateCode() {
434 157256 : const char* name = CodeStub::MajorName(MajorKey());
435 78628 : Zone zone(isolate()->allocator(), ZONE_NAME);
436 78628 : CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
437 : compiler::CodeAssemblerState state(isolate(), &zone, descriptor,
438 235884 : GetCodeFlags(), name);
439 78628 : GenerateAssembly(&state);
440 157256 : return compiler::CodeAssembler::GenerateCode(&state);
441 : }
442 :
443 12828 : TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
444 : Node* receiver = Parameter(Descriptor::kReceiver);
445 : Node* key = Parameter(Descriptor::kName);
446 : Node* value = Parameter(Descriptor::kValue);
447 : Node* map = Parameter(Descriptor::kMap);
448 : Node* slot = Parameter(Descriptor::kSlot);
449 : Node* vector = Parameter(Descriptor::kVector);
450 : Node* context = Parameter(Descriptor::kContext);
451 :
452 : Comment(
453 : "ElementsTransitionAndStoreStub: from_kind=%s, to_kind=%s,"
454 : " is_jsarray=%d, store_mode=%d",
455 : ElementsKindToString(stub->from_kind()),
456 : ElementsKindToString(stub->to_kind()), stub->is_jsarray(),
457 8552 : stub->store_mode());
458 :
459 : Label miss(this);
460 :
461 : if (FLAG_trace_elements_transitions) {
462 : // Tracing elements transitions is the job of the runtime.
463 : Goto(&miss);
464 : } else {
465 : TransitionElementsKind(receiver, map, stub->from_kind(), stub->to_kind(),
466 4276 : stub->is_jsarray(), &miss);
467 : EmitElementStore(receiver, key, value, stub->is_jsarray(), stub->to_kind(),
468 2138 : stub->store_mode(), &miss);
469 2138 : Return(value);
470 : }
471 :
472 2138 : BIND(&miss);
473 : {
474 2138 : Comment("Miss");
475 : TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
476 2138 : receiver, key, value, map, slot, vector);
477 2138 : }
478 2138 : }
479 :
480 : // TODO(ishell): move to builtins.
481 1794 : TF_STUB(AllocateHeapNumberStub, CodeStubAssembler) {
482 598 : Node* result = AllocateHeapNumber();
483 598 : Return(result);
484 598 : }
485 :
486 : // TODO(ishell): move to builtins-handler-gen.
487 228 : TF_STUB(StringLengthStub, CodeStubAssembler) {
488 : Node* value = Parameter(Descriptor::kReceiver);
489 76 : Node* string = LoadJSValueValue(value);
490 76 : Node* result = LoadStringLength(string);
491 76 : Return(result);
492 76 : }
493 :
494 : // TODO(ishell): move to builtins.
495 129 : TF_STUB(NumberToStringStub, CodeStubAssembler) {
496 : Node* context = Parameter(Descriptor::kContext);
497 : Node* argument = Parameter(Descriptor::kArgument);
498 43 : Return(NumberToString(context, argument));
499 43 : }
500 :
501 : // TODO(ishell): move to builtins.
502 129 : TF_STUB(SubStringStub, CodeStubAssembler) {
503 : Node* context = Parameter(Descriptor::kContext);
504 : Node* string = Parameter(Descriptor::kString);
505 : Node* from = Parameter(Descriptor::kFrom);
506 : Node* to = Parameter(Descriptor::kTo);
507 :
508 43 : Return(SubString(context, string, from, to));
509 43 : }
510 :
511 : // TODO(ishell): move to builtins-handler-gen.
512 1050 : TF_STUB(KeyedLoadSloppyArgumentsStub, CodeStubAssembler) {
513 : Node* receiver = Parameter(Descriptor::kReceiver);
514 : Node* key = Parameter(Descriptor::kName);
515 : Node* slot = Parameter(Descriptor::kSlot);
516 : Node* vector = Parameter(Descriptor::kVector);
517 : Node* context = Parameter(Descriptor::kContext);
518 :
519 : Label miss(this);
520 :
521 350 : Node* result = LoadKeyedSloppyArguments(receiver, key, &miss);
522 350 : Return(result);
523 :
524 350 : BIND(&miss);
525 : {
526 350 : Comment("Miss");
527 : TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
528 350 : vector);
529 350 : }
530 350 : }
531 :
532 : // TODO(ishell): move to builtins-handler-gen.
533 0 : TF_STUB(KeyedStoreSloppyArgumentsStub, CodeStubAssembler) {
534 : Node* receiver = Parameter(Descriptor::kReceiver);
535 : Node* key = Parameter(Descriptor::kName);
536 : Node* value = Parameter(Descriptor::kValue);
537 : Node* slot = Parameter(Descriptor::kSlot);
538 : Node* vector = Parameter(Descriptor::kVector);
539 : Node* context = Parameter(Descriptor::kContext);
540 :
541 : Label miss(this);
542 :
543 0 : StoreKeyedSloppyArguments(receiver, key, value, &miss);
544 0 : Return(value);
545 :
546 0 : BIND(&miss);
547 : {
548 0 : Comment("Miss");
549 : TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
550 0 : receiver, key);
551 0 : }
552 0 : }
553 :
554 59844 : TF_STUB(LoadScriptContextFieldStub, CodeStubAssembler) {
555 : Comment("LoadScriptContextFieldStub: context_index=%d, slot=%d",
556 59844 : stub->context_index(), stub->slot_index());
557 :
558 : Node* context = Parameter(Descriptor::kContext);
559 :
560 14961 : Node* script_context = LoadScriptContext(context, stub->context_index());
561 14961 : Node* result = LoadFixedArrayElement(script_context, stub->slot_index());
562 14961 : Return(result);
563 14961 : }
564 :
565 124 : TF_STUB(StoreScriptContextFieldStub, CodeStubAssembler) {
566 : Comment("StoreScriptContextFieldStub: context_index=%d, slot=%d",
567 124 : stub->context_index(), stub->slot_index());
568 :
569 : Node* value = Parameter(Descriptor::kValue);
570 : Node* context = Parameter(Descriptor::kContext);
571 :
572 31 : Node* script_context = LoadScriptContext(context, stub->context_index());
573 : StoreFixedArrayElement(script_context, IntPtrConstant(stub->slot_index()),
574 31 : value);
575 31 : Return(value);
576 31 : }
577 :
578 : // TODO(ishell): move to builtins-handler-gen.
579 294 : TF_STUB(StoreInterceptorStub, CodeStubAssembler) {
580 : Node* receiver = Parameter(Descriptor::kReceiver);
581 : Node* name = Parameter(Descriptor::kName);
582 : Node* value = Parameter(Descriptor::kValue);
583 : Node* slot = Parameter(Descriptor::kSlot);
584 : Node* vector = Parameter(Descriptor::kVector);
585 : Node* context = Parameter(Descriptor::kContext);
586 : TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, value, slot,
587 98 : vector, receiver, name);
588 98 : }
589 :
590 : // TODO(ishell): move to builtins-handler-gen.
591 204 : TF_STUB(LoadIndexedInterceptorStub, CodeStubAssembler) {
592 : Node* receiver = Parameter(Descriptor::kReceiver);
593 : Node* key = Parameter(Descriptor::kName);
594 : Node* slot = Parameter(Descriptor::kSlot);
595 : Node* vector = Parameter(Descriptor::kVector);
596 : Node* context = Parameter(Descriptor::kContext);
597 :
598 68 : Label if_keyispositivesmi(this), if_keyisinvalid(this);
599 68 : Branch(TaggedIsPositiveSmi(key), &if_keyispositivesmi, &if_keyisinvalid);
600 68 : BIND(&if_keyispositivesmi);
601 68 : TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, receiver, key);
602 :
603 68 : BIND(&if_keyisinvalid);
604 : TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
605 136 : vector);
606 68 : }
607 :
608 54308 : void CallICStub::PrintState(std::ostream& os) const { // NOLINT
609 54308 : os << convert_mode() << ", " << tail_call_mode();
610 54308 : }
611 :
612 : // TODO(ishell): Move to CallICAssembler.
613 140740 : TF_STUB(CallICStub, CodeStubAssembler) {
614 : Node* context = Parameter(Descriptor::kContext);
615 : Node* target = Parameter(Descriptor::kTarget);
616 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
617 : Node* slot = Parameter(Descriptor::kSlot);
618 : Node* vector = Parameter(Descriptor::kVector);
619 :
620 : // TODO(bmeurer): The slot should actually be an IntPtr, but TurboFan's
621 : // SimplifiedLowering cannot deal with IntPtr machine type properly yet.
622 28148 : slot = ChangeInt32ToIntPtr(slot);
623 :
624 : // Static checks to assert it is safe to examine the type feedback element.
625 : // We don't know that we have a weak cell. We might have a private symbol
626 : // or an AllocationSite, but the memory is safe to examine.
627 : // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to
628 : // FixedArray.
629 : // WeakCell::kValueOffset - contains a JSFunction or Smi(0)
630 : // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not
631 : // computed, meaning that it can't appear to be a pointer. If the low bit is
632 : // 0, then hash is computed, but the 0 bit prevents the field from appearing
633 : // to be a pointer.
634 : STATIC_ASSERT(WeakCell::kSize >= kPointerSize);
635 : STATIC_ASSERT(AllocationSite::kTransitionInfoOffset ==
636 : WeakCell::kValueOffset &&
637 : WeakCell::kValueOffset == Symbol::kHashFieldSlot);
638 :
639 : // Increment the call count.
640 : // TODO(bmeurer): Would it be beneficial to use Int32Add on 64-bit?
641 28148 : Comment("increment call count");
642 28148 : Node* call_count = LoadFixedArrayElement(vector, slot, 1 * kPointerSize);
643 28148 : Node* new_count = SmiAdd(call_count, SmiConstant(1));
644 : // Count is Smi, so we don't need a write barrier.
645 : StoreFixedArrayElement(vector, slot, new_count, SKIP_WRITE_BARRIER,
646 28148 : 1 * kPointerSize);
647 :
648 28148 : Label call_function(this), extra_checks(this), call(this);
649 :
650 : // The checks. First, does function match the recorded monomorphic target?
651 28148 : Node* feedback_element = LoadFixedArrayElement(vector, slot);
652 28148 : Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element);
653 28148 : Node* is_monomorphic = WordEqual(target, feedback_value);
654 28148 : GotoIfNot(is_monomorphic, &extra_checks);
655 :
656 : // The compare above could have been a SMI/SMI comparison. Guard against
657 : // this convincing us that we have a monomorphic JSFunction.
658 28148 : Node* is_smi = TaggedIsSmi(target);
659 28148 : Branch(is_smi, &extra_checks, &call_function);
660 :
661 28148 : BIND(&call_function);
662 : {
663 : // Call using CallFunction builtin.
664 : Callable callable = CodeFactory::CallFunction(
665 28148 : isolate(), stub->convert_mode(), stub->tail_call_mode());
666 28148 : TailCallStub(callable, context, target, argc);
667 : }
668 :
669 28148 : BIND(&extra_checks);
670 : {
671 28148 : Label check_initialized(this), mark_megamorphic(this),
672 28148 : create_allocation_site(this, Label::kDeferred),
673 28148 : create_weak_cell(this, Label::kDeferred);
674 :
675 28148 : Comment("check if megamorphic");
676 : // Check if it is a megamorphic target.
677 : Node* is_megamorphic =
678 : WordEqual(feedback_element,
679 56296 : HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())));
680 28148 : GotoIf(is_megamorphic, &call);
681 :
682 28148 : Comment("check if it is an allocation site");
683 : GotoIfNot(IsAllocationSiteMap(LoadMap(feedback_element)),
684 28148 : &check_initialized);
685 :
686 : // If it is not the Array() function, mark megamorphic.
687 : Node* context_slot = LoadContextElement(LoadNativeContext(context),
688 28148 : Context::ARRAY_FUNCTION_INDEX);
689 28148 : Node* is_array_function = WordEqual(context_slot, target);
690 28148 : GotoIfNot(is_array_function, &mark_megamorphic);
691 :
692 : // Call ArrayConstructorStub.
693 28148 : Callable callable = CodeFactory::ArrayConstructor(isolate());
694 28148 : TailCallStub(callable, context, target, target, argc, feedback_element);
695 :
696 28148 : BIND(&check_initialized);
697 : {
698 28148 : Comment("check if uninitialized");
699 : // Check if it is uninitialized target first.
700 : Node* is_uninitialized = WordEqual(
701 : feedback_element,
702 56296 : HeapConstant(FeedbackVector::UninitializedSentinel(isolate())));
703 28148 : GotoIfNot(is_uninitialized, &mark_megamorphic);
704 :
705 28148 : Comment("handle unitinitialized");
706 : // If it is not a JSFunction mark it as megamorphic.
707 28148 : Node* is_smi = TaggedIsSmi(target);
708 28148 : GotoIf(is_smi, &mark_megamorphic);
709 :
710 : // Check if function is an object of JSFunction type.
711 28148 : Node* is_js_function = IsJSFunction(target);
712 28148 : GotoIfNot(is_js_function, &mark_megamorphic);
713 :
714 : // Check if it is the Array() function.
715 : Node* context_slot = LoadContextElement(LoadNativeContext(context),
716 28148 : Context::ARRAY_FUNCTION_INDEX);
717 28148 : Node* is_array_function = WordEqual(context_slot, target);
718 28148 : GotoIf(is_array_function, &create_allocation_site);
719 :
720 : // Check if the function belongs to the same native context.
721 : Node* native_context = LoadNativeContext(
722 28148 : LoadObjectField(target, JSFunction::kContextOffset));
723 : Node* is_same_native_context =
724 28148 : WordEqual(native_context, LoadNativeContext(context));
725 28148 : Branch(is_same_native_context, &create_weak_cell, &mark_megamorphic);
726 : }
727 :
728 28148 : BIND(&create_weak_cell);
729 : {
730 : // Wrap the {target} in a WeakCell and remember it.
731 28148 : Comment("create weak cell");
732 28148 : CreateWeakCellInFeedbackVector(vector, SmiTag(slot), target);
733 :
734 : // Call using CallFunction builtin.
735 28148 : Goto(&call_function);
736 : }
737 :
738 28148 : BIND(&create_allocation_site);
739 : {
740 : // Create an AllocationSite for the {target}.
741 28148 : Comment("create allocation site");
742 28148 : CreateAllocationSiteInFeedbackVector(vector, SmiTag(slot));
743 :
744 : // Call using CallFunction builtin. CallICs have a PREMONOMORPHIC state.
745 : // They start collecting feedback only when a call is executed the second
746 : // time. So, do not pass any feedback here.
747 28148 : Goto(&call_function);
748 : }
749 :
750 28148 : BIND(&mark_megamorphic);
751 : {
752 : // Mark it as a megamorphic.
753 : // MegamorphicSentinel is created as a part of Heap::InitialObjects
754 : // and will not move during a GC. So it is safe to skip write barrier.
755 : DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
756 : StoreFixedArrayElement(
757 : vector, slot,
758 : HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())),
759 56296 : SKIP_WRITE_BARRIER);
760 28148 : Goto(&call);
761 28148 : }
762 : }
763 :
764 28148 : BIND(&call);
765 : {
766 : // Call using call builtin.
767 28148 : Comment("call using Call builtin");
768 : Callable callable_call = CodeFactory::Call(isolate(), stub->convert_mode(),
769 28148 : stub->tail_call_mode());
770 28148 : TailCallStub(callable_call, context, target, argc);
771 28148 : }
772 28148 : }
773 :
774 78480 : TF_STUB(CallICTrampolineStub, CodeStubAssembler) {
775 : Node* context = Parameter(Descriptor::kContext);
776 : Node* target = Parameter(Descriptor::kTarget);
777 : Node* argc = Parameter(Descriptor::kActualArgumentsCount);
778 : Node* slot = Parameter(Descriptor::kSlot);
779 26159 : Node* vector = LoadFeedbackVectorForStub();
780 :
781 : Callable callable = CodeFactory::CallIC(isolate(), stub->convert_mode(),
782 52320 : stub->tail_call_mode());
783 26160 : TailCallStub(callable, context, target, argc, slot, vector);
784 26160 : }
785 :
786 86 : void JSEntryStub::FinishCode(Handle<Code> code) {
787 : Handle<FixedArray> handler_table =
788 86 : code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
789 86 : handler_table->set(0, Smi::FromInt(handler_offset_));
790 86 : code->set_handler_table(*handler_table);
791 86 : }
792 :
793 220 : void TransitionElementsKindStub::InitializeDescriptor(
794 : CodeStubDescriptor* descriptor) {
795 : descriptor->Initialize(
796 220 : Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
797 220 : }
798 :
799 :
800 0 : void AllocateHeapNumberStub::InitializeDescriptor(
801 : CodeStubDescriptor* descriptor) {
802 : descriptor->Initialize(
803 0 : Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
804 0 : }
805 :
806 :
807 45324 : void ToBooleanICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
808 : descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
809 45324 : descriptor->SetMissHandler(Runtime::kToBooleanIC_Miss);
810 45324 : }
811 :
812 :
813 28076 : void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
814 : descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
815 28076 : descriptor->SetMissHandler(Runtime::kBinaryOpIC_Miss);
816 28076 : }
817 :
818 :
819 8195 : void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
820 : CodeStubDescriptor* descriptor) {
821 : descriptor->Initialize(
822 : FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
823 8195 : }
824 :
825 : // TODO(ishell): move to builtins.
826 172 : TF_STUB(GetPropertyStub, CodeStubAssembler) {
827 86 : Label call_runtime(this, Label::kDeferred), return_undefined(this), end(this);
828 :
829 : Node* object = Parameter(Descriptor::kObject);
830 : Node* key = Parameter(Descriptor::kKey);
831 : Node* context = Parameter(Descriptor::kContext);
832 86 : VARIABLE(var_result, MachineRepresentation::kTagged);
833 :
834 : CodeStubAssembler::LookupInHolder lookup_property_in_holder =
835 : [=, &var_result, &end](Node* receiver, Node* holder, Node* holder_map,
836 : Node* holder_instance_type, Node* unique_name,
837 43 : Label* next_holder, Label* if_bailout) {
838 43 : VARIABLE(var_value, MachineRepresentation::kTagged);
839 86 : Label if_found(this);
840 : TryGetOwnProperty(context, receiver, holder, holder_map,
841 : holder_instance_type, unique_name, &if_found,
842 43 : &var_value, next_holder, if_bailout);
843 43 : BIND(&if_found);
844 : {
845 43 : var_result.Bind(var_value.value());
846 43 : Goto(&end);
847 : }
848 43 : };
849 :
850 : CodeStubAssembler::LookupInHolder lookup_element_in_holder =
851 : [=](Node* receiver, Node* holder, Node* holder_map,
852 : Node* holder_instance_type, Node* index, Label* next_holder,
853 : Label* if_bailout) {
854 : // Not supported yet.
855 43 : Use(next_holder);
856 43 : Goto(if_bailout);
857 : };
858 :
859 : TryPrototypeChainLookup(object, key, lookup_property_in_holder,
860 : lookup_element_in_holder, &return_undefined,
861 43 : &call_runtime);
862 :
863 43 : BIND(&return_undefined);
864 : {
865 43 : var_result.Bind(UndefinedConstant());
866 43 : Goto(&end);
867 : }
868 :
869 43 : BIND(&call_runtime);
870 : {
871 43 : var_result.Bind(CallRuntime(Runtime::kGetProperty, context, object, key));
872 43 : Goto(&end);
873 : }
874 :
875 43 : BIND(&end);
876 86 : Return(var_result.value());
877 43 : }
878 :
879 43 : void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
880 : CreateAllocationSiteStub stub(isolate);
881 43 : stub.GetCode();
882 43 : }
883 :
884 :
885 43 : void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
886 : CreateWeakCellStub stub(isolate);
887 43 : stub.GetCode();
888 43 : }
889 :
890 : // TODO(ishell): move to builtins-handler-gen.
891 1929 : TF_STUB(StoreSlowElementStub, CodeStubAssembler) {
892 : Node* receiver = Parameter(Descriptor::kReceiver);
893 : Node* name = Parameter(Descriptor::kName);
894 : Node* value = Parameter(Descriptor::kValue);
895 : Node* slot = Parameter(Descriptor::kSlot);
896 : Node* vector = Parameter(Descriptor::kVector);
897 : Node* context = Parameter(Descriptor::kContext);
898 :
899 : TailCallRuntime(Runtime::kKeyedStoreIC_Slow, context, value, slot, vector,
900 643 : receiver, name);
901 643 : }
902 :
903 23064 : TF_STUB(StoreFastElementStub, CodeStubAssembler) {
904 : Comment("StoreFastElementStub: js_array=%d, elements_kind=%s, store_mode=%d",
905 : stub->is_js_array(), ElementsKindToString(stub->elements_kind()),
906 11532 : stub->store_mode());
907 :
908 : Node* receiver = Parameter(Descriptor::kReceiver);
909 : Node* key = Parameter(Descriptor::kName);
910 : Node* value = Parameter(Descriptor::kValue);
911 : Node* slot = Parameter(Descriptor::kSlot);
912 : Node* vector = Parameter(Descriptor::kVector);
913 : Node* context = Parameter(Descriptor::kContext);
914 :
915 : Label miss(this);
916 :
917 : EmitElementStore(receiver, key, value, stub->is_js_array(),
918 3844 : stub->elements_kind(), stub->store_mode(), &miss);
919 3844 : Return(value);
920 :
921 3844 : BIND(&miss);
922 : {
923 3844 : Comment("Miss");
924 : TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
925 3844 : receiver, key);
926 3844 : }
927 3844 : }
928 :
929 : // static
930 43 : void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
931 86 : if (FLAG_minimal) return;
932 : StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE)
933 86 : .GetCode();
934 : StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS,
935 86 : STORE_AND_GROW_NO_TRANSITION).GetCode();
936 301 : for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
937 258 : ElementsKind kind = static_cast<ElementsKind>(i);
938 516 : StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
939 : StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
940 516 : .GetCode();
941 : }
942 : }
943 :
944 130693 : bool ToBooleanICStub::UpdateStatus(Handle<Object> object) {
945 : ToBooleanHints old_hints = hints();
946 : ToBooleanHints new_hints = old_hints;
947 : bool to_boolean_value = false; // Dummy initialization.
948 367680 : if (object->IsUndefined(isolate())) {
949 : new_hints |= ToBooleanHint::kUndefined;
950 : to_boolean_value = false;
951 106294 : } else if (object->IsBoolean()) {
952 : new_hints |= ToBooleanHint::kBoolean;
953 : to_boolean_value = object->IsTrue(isolate());
954 55693 : } else if (object->IsNull(isolate())) {
955 : new_hints |= ToBooleanHint::kNull;
956 : to_boolean_value = false;
957 53709 : } else if (object->IsSmi()) {
958 : new_hints |= ToBooleanHint::kSmallInteger;
959 12976 : to_boolean_value = Smi::cast(*object)->value() != 0;
960 40733 : } else if (object->IsJSReceiver()) {
961 : new_hints |= ToBooleanHint::kReceiver;
962 33883 : to_boolean_value = !object->IsUndetectable();
963 6850 : } else if (object->IsString()) {
964 : DCHECK(!object->IsUndetectable());
965 : new_hints |= ToBooleanHint::kString;
966 6737 : to_boolean_value = String::cast(*object)->length() != 0;
967 113 : } else if (object->IsSymbol()) {
968 : new_hints |= ToBooleanHint::kSymbol;
969 : to_boolean_value = true;
970 76 : } else if (object->IsHeapNumber()) {
971 : DCHECK(!object->IsUndetectable());
972 : new_hints |= ToBooleanHint::kHeapNumber;
973 : double value = HeapNumber::cast(*object)->value();
974 76 : to_boolean_value = value != 0 && !std::isnan(value);
975 : } else {
976 : // We should never see an internal object at runtime here!
977 0 : UNREACHABLE();
978 : to_boolean_value = true;
979 : }
980 :
981 130693 : set_sub_minor_key(HintsBits::update(sub_minor_key(), new_hints));
982 130693 : return to_boolean_value;
983 : }
984 :
985 21342 : void ToBooleanICStub::PrintState(std::ostream& os) const { // NOLINT
986 21342 : os << hints();
987 21342 : }
988 :
989 60686 : void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
990 : StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
991 : StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
992 60686 : stub1.GetCode();
993 60686 : stub2.GetCode();
994 60686 : }
995 :
996 :
997 0 : void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
998 : intptr_t stack_pointer,
999 0 : Isolate* isolate) {
1000 : FunctionEntryHook entry_hook = isolate->function_entry_hook();
1001 : DCHECK(entry_hook != NULL);
1002 0 : entry_hook(function, stack_pointer);
1003 0 : }
1004 :
1005 : // TODO(ishell): move to builtins.
1006 129 : TF_STUB(CreateAllocationSiteStub, CodeStubAssembler) {
1007 : Return(CreateAllocationSiteInFeedbackVector(Parameter(Descriptor::kVector),
1008 43 : Parameter(Descriptor::kSlot)));
1009 43 : }
1010 :
1011 : // TODO(ishell): move to builtins.
1012 129 : TF_STUB(CreateWeakCellStub, CodeStubAssembler) {
1013 : Return(CreateWeakCellInFeedbackVector(Parameter(Descriptor::kVector),
1014 : Parameter(Descriptor::kSlot),
1015 43 : Parameter(Descriptor::kValue)));
1016 43 : }
1017 :
1018 1462 : TF_STUB(ArrayNoArgumentConstructorStub, CodeStubAssembler) {
1019 : ElementsKind elements_kind = stub->elements_kind();
1020 : Node* native_context = LoadObjectField(Parameter(Descriptor::kFunction),
1021 344 : JSFunction::kContextOffset);
1022 : bool track_allocation_site =
1023 516 : AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE &&
1024 : stub->override_mode() != DISABLE_ALLOCATION_SITES;
1025 : Node* allocation_site =
1026 344 : track_allocation_site ? Parameter(Descriptor::kAllocationSite) : nullptr;
1027 344 : Node* array_map = LoadJSArrayElementsMap(elements_kind, native_context);
1028 : Node* array =
1029 : AllocateJSArray(elements_kind, array_map,
1030 : IntPtrConstant(JSArray::kPreallocatedArrayElements),
1031 344 : SmiConstant(Smi::kZero), allocation_site);
1032 344 : Return(array);
1033 344 : }
1034 :
1035 258 : TF_STUB(InternalArrayNoArgumentConstructorStub, CodeStubAssembler) {
1036 : Node* array_map = LoadObjectField(Parameter(Descriptor::kFunction),
1037 86 : JSFunction::kPrototypeOrInitialMapOffset);
1038 : Node* array =
1039 : AllocateJSArray(stub->elements_kind(), array_map,
1040 : IntPtrConstant(JSArray::kPreallocatedArrayElements),
1041 172 : SmiConstant(Smi::kZero));
1042 86 : Return(array);
1043 86 : }
1044 :
1045 : class ArrayConstructorAssembler : public CodeStubAssembler {
1046 : public:
1047 : typedef compiler::Node Node;
1048 :
1049 : explicit ArrayConstructorAssembler(compiler::CodeAssemblerState* state)
1050 430 : : CodeStubAssembler(state) {}
1051 :
1052 : void GenerateConstructor(Node* context, Node* array_function, Node* array_map,
1053 : Node* array_size, Node* allocation_site,
1054 : ElementsKind elements_kind, AllocationSiteMode mode);
1055 : };
1056 :
1057 430 : void ArrayConstructorAssembler::GenerateConstructor(
1058 : Node* context, Node* array_function, Node* array_map, Node* array_size,
1059 : Node* allocation_site, ElementsKind elements_kind,
1060 : AllocationSiteMode mode) {
1061 430 : Label ok(this);
1062 430 : Label smi_size(this);
1063 430 : Label small_smi_size(this);
1064 430 : Label call_runtime(this, Label::kDeferred);
1065 :
1066 430 : Branch(TaggedIsSmi(array_size), &smi_size, &call_runtime);
1067 :
1068 430 : BIND(&smi_size);
1069 :
1070 430 : if (IsFastPackedElementsKind(elements_kind)) {
1071 : Label abort(this, Label::kDeferred);
1072 : Branch(SmiEqual(array_size, SmiConstant(Smi::kZero)), &small_smi_size,
1073 215 : &abort);
1074 :
1075 215 : BIND(&abort);
1076 215 : Node* reason = SmiConstant(Smi::FromInt(kAllocatingNonEmptyPackedArray));
1077 215 : TailCallRuntime(Runtime::kAbort, context, reason);
1078 : } else {
1079 : int element_size =
1080 : IsFastDoubleElementsKind(elements_kind) ? kDoubleSize : kPointerSize;
1081 : int max_fast_elements =
1082 : (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
1083 : AllocationMemento::kSize) /
1084 : element_size;
1085 : Branch(SmiAboveOrEqual(array_size,
1086 : SmiConstant(Smi::FromInt(max_fast_elements))),
1087 215 : &call_runtime, &small_smi_size);
1088 : }
1089 :
1090 430 : BIND(&small_smi_size);
1091 : {
1092 : Node* array = AllocateJSArray(
1093 : elements_kind, array_map, array_size, array_size,
1094 : mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
1095 430 : CodeStubAssembler::SMI_PARAMETERS);
1096 430 : Return(array);
1097 : }
1098 :
1099 430 : BIND(&call_runtime);
1100 : {
1101 : TailCallRuntime(Runtime::kNewArray, context, array_function, array_size,
1102 430 : array_function, allocation_site);
1103 430 : }
1104 430 : }
1105 :
1106 2064 : TF_STUB(ArraySingleArgumentConstructorStub, ArrayConstructorAssembler) {
1107 : ElementsKind elements_kind = stub->elements_kind();
1108 : Node* context = Parameter(Descriptor::kContext);
1109 : Node* function = Parameter(Descriptor::kFunction);
1110 344 : Node* native_context = LoadObjectField(function, JSFunction::kContextOffset);
1111 344 : Node* array_map = LoadJSArrayElementsMap(elements_kind, native_context);
1112 : AllocationSiteMode mode = stub->override_mode() == DISABLE_ALLOCATION_SITES
1113 : ? DONT_TRACK_ALLOCATION_SITE
1114 344 : : AllocationSite::GetMode(elements_kind);
1115 : Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
1116 : Node* allocation_site = Parameter(Descriptor::kAllocationSite);
1117 :
1118 : GenerateConstructor(context, function, array_map, array_size, allocation_site,
1119 344 : elements_kind, mode);
1120 344 : }
1121 :
1122 430 : TF_STUB(InternalArraySingleArgumentConstructorStub, ArrayConstructorAssembler) {
1123 : Node* context = Parameter(Descriptor::kContext);
1124 : Node* function = Parameter(Descriptor::kFunction);
1125 : Node* array_map =
1126 86 : LoadObjectField(function, JSFunction::kPrototypeOrInitialMapOffset);
1127 : Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
1128 86 : Node* allocation_site = UndefinedConstant();
1129 :
1130 : GenerateConstructor(context, function, array_map, array_size, allocation_site,
1131 86 : stub->elements_kind(), DONT_TRACK_ALLOCATION_SITE);
1132 86 : }
1133 :
1134 1236 : TF_STUB(GrowArrayElementsStub, CodeStubAssembler) {
1135 309 : Label runtime(this, CodeStubAssembler::Label::kDeferred);
1136 :
1137 : Node* object = Parameter(Descriptor::kObject);
1138 : Node* key = Parameter(Descriptor::kKey);
1139 : Node* context = Parameter(Descriptor::kContext);
1140 : ElementsKind kind = stub->elements_kind();
1141 :
1142 309 : Node* elements = LoadElements(object);
1143 : Node* new_elements =
1144 309 : TryGrowElementsCapacity(object, elements, kind, key, &runtime);
1145 309 : Return(new_elements);
1146 :
1147 309 : BIND(&runtime);
1148 : // TODO(danno): Make this a tail call when the stub is only used from TurboFan
1149 : // code. This musn't be a tail call for now, since the caller site in lithium
1150 : // creates a safepoint. This safepoint musn't have a different number of
1151 : // arguments on the stack in the case that a GC happens from the slow-case
1152 : // allocation path (zero, since all the stubs inputs are in registers) and
1153 : // when the call happens (it would be two in the tail call case due to the
1154 : // tail call pushing the arguments on the stack for the runtime call). By not
1155 : // tail-calling, the runtime call case also has zero arguments on the stack
1156 : // for the stub frame.
1157 309 : Return(CallRuntime(Runtime::kGrowArrayElements, context, object, key));
1158 309 : }
1159 :
1160 28313 : ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
1161 28313 : : PlatformCodeStub(isolate) {}
1162 :
1163 280 : InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate)
1164 280 : : PlatformCodeStub(isolate) {}
1165 :
1166 : } // namespace internal
1167 : } // namespace v8
|