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 : CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
32 : : isolate_(stub->isolate()),
33 0 : call_descriptor_(stub->GetCallInterfaceDescriptor()),
34 : stack_parameter_count_(no_reg),
35 : hint_stack_parameter_count_(-1),
36 : function_mode_(NOT_JS_FUNCTION_STUB_MODE),
37 : deoptimization_handler_(nullptr),
38 : miss_handler_(),
39 0 : has_miss_handler_(false) {
40 0 : stub->InitializeDescriptor(this);
41 0 : }
42 :
43 0 : CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
44 : : isolate_(isolate),
45 : stack_parameter_count_(no_reg),
46 : hint_stack_parameter_count_(-1),
47 : function_mode_(NOT_JS_FUNCTION_STUB_MODE),
48 : deoptimization_handler_(nullptr),
49 : miss_handler_(),
50 0 : has_miss_handler_(false) {
51 : CodeStub::InitializeDescriptor(isolate, stub_key, this);
52 0 : }
53 :
54 :
55 0 : void CodeStubDescriptor::Initialize(Address deoptimization_handler,
56 : int hint_stack_parameter_count,
57 : StubFunctionMode function_mode) {
58 0 : deoptimization_handler_ = deoptimization_handler;
59 0 : hint_stack_parameter_count_ = hint_stack_parameter_count;
60 0 : function_mode_ = function_mode;
61 0 : }
62 :
63 :
64 0 : void CodeStubDescriptor::Initialize(Register stack_parameter_count,
65 : Address deoptimization_handler,
66 : int hint_stack_parameter_count,
67 : StubFunctionMode function_mode) {
68 : Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
69 0 : stack_parameter_count_ = stack_parameter_count;
70 0 : }
71 :
72 :
73 4980646 : bool CodeStub::FindCodeInCache(Code** code_out) {
74 2490323 : UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
75 2490323 : int index = stubs->FindEntry(isolate(), GetKey());
76 2490326 : if (index != UnseededNumberDictionary::kNotFound) {
77 2446058 : *code_out = Code::cast(stubs->ValueAt(index));
78 2446058 : return true;
79 : }
80 : return false;
81 : }
82 :
83 :
84 132804 : void CodeStub::RecordCodeGeneration(Handle<Code> code) {
85 44268 : std::ostringstream os;
86 : os << *this;
87 88536 : PROFILE(isolate(),
88 : CodeCreateEvent(CodeEventListener::STUB_TAG,
89 : AbstractCode::cast(*code), os.str().c_str()));
90 : Counters* counters = isolate()->counters();
91 44268 : counters->total_stubs_code_size()->Increment(code->instruction_size());
92 : #ifdef DEBUG
93 : code->VerifyEmbeddedObjects();
94 : #endif
95 44268 : }
96 :
97 :
98 0 : void CodeStub::DeleteStubFromCacheForTesting() {
99 0 : Heap* heap = isolate_->heap();
100 : Handle<UnseededNumberDictionary> dict(heap->code_stubs());
101 : int entry = dict->FindEntry(GetKey());
102 : DCHECK_NE(UnseededNumberDictionary::kNotFound, entry);
103 0 : dict = UnseededNumberDictionary::DeleteEntry(dict, entry);
104 0 : heap->SetRootCodeStubs(*dict);
105 0 : }
106 :
107 20225 : Handle<Code> PlatformCodeStub::GenerateCode() {
108 80900 : Factory* factory = isolate()->factory();
109 :
110 : // Generate the new code.
111 20225 : MacroAssembler masm(isolate(), nullptr, 256, CodeObjectRequired::kYes);
112 :
113 : {
114 : // Update the static counter each time a new code stub is generated.
115 20225 : isolate()->counters()->code_stubs()->Increment();
116 :
117 : // Generate the code for the stub.
118 : // TODO(yangguo): remove this once we can serialize IC stubs.
119 : masm.enable_serializer();
120 : NoCurrentFrameScope scope(&masm);
121 20225 : Generate(&masm);
122 : }
123 :
124 : // Allocate the handler table.
125 20225 : Handle<HandlerTable> table = GenerateHandlerTable();
126 :
127 : // Create the code object.
128 : CodeDesc desc;
129 20225 : masm.GetCode(isolate(), &desc);
130 : // Copy the generated code into a heap object.
131 : Handle<Code> new_object = factory->NewCode(
132 : desc, Code::STUB, masm.CodeObject(), table, MaybeHandle<ByteArray>(),
133 60675 : DeoptimizationData::Empty(isolate()), NeedsImmovableCode());
134 40450 : return new_object;
135 : }
136 :
137 :
138 2623127 : Handle<Code> CodeStub::GetCode() {
139 2534591 : Heap* heap = isolate()->heap();
140 : Code* code;
141 2490323 : if (FindCodeInCache(&code)) {
142 : DCHECK(code->is_stub());
143 2446058 : return handle(code);
144 : }
145 :
146 : {
147 : HandleScope scope(isolate());
148 : // Canonicalize handles, so that we can share constant pool entries pointing
149 : // to code targets without dereferencing their handles.
150 88536 : CanonicalHandleScope canonical(isolate());
151 :
152 44268 : Handle<Code> new_object = GenerateCode();
153 : new_object->set_stub_key(GetKey());
154 44268 : RecordCodeGeneration(new_object);
155 :
156 : #ifdef ENABLE_DISASSEMBLER
157 : if (FLAG_print_code_stubs) {
158 : CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
159 : OFStream os(trace_scope.file());
160 : std::ostringstream name;
161 : name << *this;
162 : new_object->Disassemble(name.str().c_str(), os);
163 : os << "\n";
164 : }
165 : #endif
166 :
167 : // Update the dictionary and the root in Heap.
168 : Handle<UnseededNumberDictionary> dict = UnseededNumberDictionary::Set(
169 44268 : handle(heap->code_stubs()), GetKey(), new_object);
170 44268 : heap->SetRootCodeStubs(*dict);
171 44268 : code = *new_object;
172 : }
173 :
174 44268 : Activate(code);
175 : DCHECK(!NeedsImmovableCode() || Heap::IsImmovable(code) ||
176 : heap->code_space()->FirstPage()->Contains(code->address()));
177 88536 : return Handle<Code>(code, isolate());
178 : }
179 :
180 20948 : CodeStub::Major CodeStub::GetMajorKey(Code* code_stub) {
181 20948 : return MajorKeyFromKey(code_stub->stub_key());
182 : }
183 :
184 88484 : const char* CodeStub::MajorName(CodeStub::Major major_key) {
185 88484 : switch (major_key) {
186 : #define DEF_CASE(name) case name: return #name "Stub";
187 3480 : CODE_STUB_LIST(DEF_CASE)
188 : #undef DEF_CASE
189 : case NoCache:
190 25 : return "<NoCache>Stub";
191 : case NUMBER_OF_IDS:
192 0 : UNREACHABLE();
193 : }
194 0 : return nullptr;
195 : }
196 :
197 :
198 43493 : void CodeStub::PrintBaseName(std::ostream& os) const { // NOLINT
199 43493 : os << MajorName(MajorKey());
200 43493 : }
201 :
202 :
203 43586 : void CodeStub::PrintName(std::ostream& os) const { // NOLINT
204 43586 : PrintBaseName(os);
205 43586 : PrintState(os);
206 43586 : }
207 :
208 :
209 60 : void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
210 : DispatchedCall call) {
211 60 : switch (MajorKeyFromKey(key)) {
212 : #define DEF_CASE(NAME) \
213 : case NAME: { \
214 : NAME##Stub stub(key, isolate); \
215 : CodeStub* pstub = &stub; \
216 : call(pstub, value_out); \
217 : break; \
218 : }
219 60 : CODE_STUB_LIST(DEF_CASE)
220 : #undef DEF_CASE
221 : case NUMBER_OF_IDS:
222 : case NoCache:
223 0 : UNREACHABLE();
224 : break;
225 : }
226 60 : }
227 :
228 20163 : Handle<HandlerTable> PlatformCodeStub::GenerateHandlerTable() {
229 20163 : return HandlerTable::Empty(isolate());
230 : }
231 :
232 0 : static void InitializeDescriptorDispatchedCall(CodeStub* stub,
233 : void** value_out) {
234 : CodeStubDescriptor* descriptor_out =
235 : reinterpret_cast<CodeStubDescriptor*>(value_out);
236 0 : stub->InitializeDescriptor(descriptor_out);
237 0 : descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
238 0 : }
239 :
240 :
241 0 : void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
242 : CodeStubDescriptor* desc) {
243 : void** value_out = reinterpret_cast<void**>(desc);
244 0 : Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
245 0 : }
246 :
247 :
248 60 : void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
249 : Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
250 60 : *code_out = stub->GetCode();
251 60 : }
252 :
253 :
254 60 : MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
255 : HandleScope scope(isolate);
256 : Handle<Code> code;
257 : void** value_out = reinterpret_cast<void**>(&code);
258 60 : Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
259 120 : return scope.CloseAndEscape(code);
260 : }
261 :
262 :
263 93 : void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
264 93 : os << "StringAddStub_" << flags() << "_" << pretenure_flag();
265 93 : }
266 :
267 372 : TF_STUB(StringAddStub, CodeStubAssembler) {
268 : StringAddFlags flags = stub->flags();
269 : PretenureFlag pretenure_flag = stub->pretenure_flag();
270 :
271 : Node* left = Parameter(Descriptor::kLeft);
272 : Node* right = Parameter(Descriptor::kRight);
273 : Node* context = Parameter(Descriptor::kContext);
274 :
275 93 : if ((flags & STRING_ADD_CHECK_LEFT) != 0) {
276 : DCHECK_NE(flags & STRING_ADD_CONVERT, 0);
277 : // TODO(danno): The ToString and JSReceiverToPrimitive below could be
278 : // combined to avoid duplicate smi and instance type checks.
279 93 : left = ToString(context, JSReceiverToPrimitive(context, left));
280 : }
281 93 : if ((flags & STRING_ADD_CHECK_RIGHT) != 0) {
282 : DCHECK_NE(flags & STRING_ADD_CONVERT, 0);
283 : // TODO(danno): The ToString and JSReceiverToPrimitive below could be
284 : // combined to avoid duplicate smi and instance type checks.
285 93 : right = ToString(context, JSReceiverToPrimitive(context, right));
286 : }
287 :
288 93 : if ((flags & STRING_ADD_CHECK_BOTH) == 0) {
289 : CodeStubAssembler::AllocationFlag allocation_flags =
290 : (pretenure_flag == TENURED) ? CodeStubAssembler::kPretenured
291 31 : : CodeStubAssembler::kNone;
292 62 : Return(StringAdd(context, left, right, allocation_flags));
293 : } else {
294 : Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE,
295 62 : pretenure_flag);
296 62 : TailCallStub(callable, context, left, right);
297 : }
298 93 : }
299 :
300 24043 : Handle<Code> TurboFanCodeStub::GenerateCode() {
301 48086 : const char* name = CodeStub::MajorName(MajorKey());
302 24043 : Zone zone(isolate()->allocator(), ZONE_NAME);
303 24043 : CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
304 : compiler::CodeAssemblerState state(isolate(), &zone, descriptor, Code::STUB,
305 48086 : name);
306 24043 : GenerateAssembly(&state);
307 48086 : return compiler::CodeAssembler::GenerateCode(&state);
308 : }
309 :
310 5280 : TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
311 : Node* receiver = Parameter(Descriptor::kReceiver);
312 : Node* key = Parameter(Descriptor::kName);
313 : Node* value = Parameter(Descriptor::kValue);
314 : Node* map = Parameter(Descriptor::kMap);
315 : Node* slot = Parameter(Descriptor::kSlot);
316 : Node* vector = Parameter(Descriptor::kVector);
317 : Node* context = Parameter(Descriptor::kContext);
318 :
319 : Comment(
320 : "ElementsTransitionAndStoreStub: from_kind=%s, to_kind=%s,"
321 : " is_jsarray=%d, store_mode=%d",
322 : ElementsKindToString(stub->from_kind()),
323 : ElementsKindToString(stub->to_kind()), stub->is_jsarray(),
324 3520 : stub->store_mode());
325 :
326 : Label miss(this);
327 :
328 : if (FLAG_trace_elements_transitions) {
329 : // Tracing elements transitions is the job of the runtime.
330 : Goto(&miss);
331 : } else {
332 : TransitionElementsKind(receiver, map, stub->from_kind(), stub->to_kind(),
333 1760 : stub->is_jsarray(), &miss);
334 : EmitElementStore(receiver, key, value, stub->is_jsarray(), stub->to_kind(),
335 880 : stub->store_mode(), &miss);
336 880 : Return(value);
337 : }
338 :
339 880 : BIND(&miss);
340 : {
341 880 : Comment("Miss");
342 : TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
343 880 : receiver, key, value, map, slot, vector);
344 880 : }
345 880 : }
346 :
347 93 : TF_STUB(TransitionElementsKindStub, CodeStubAssembler) {
348 : Node* context = Parameter(Descriptor::kContext);
349 : Node* object = Parameter(Descriptor::kObject);
350 : Node* new_map = Parameter(Descriptor::kMap);
351 :
352 : Label bailout(this);
353 : TransitionElementsKind(object, new_map, stub->from_kind(), stub->to_kind(),
354 62 : stub->is_jsarray(), &bailout);
355 : Return(object);
356 :
357 31 : BIND(&bailout);
358 : {
359 31 : Comment("Call runtime");
360 : TailCallRuntime(Runtime::kTransitionElementsKind, context, object, new_map);
361 31 : }
362 31 : }
363 :
364 : // TODO(ishell): move to builtins.
365 93 : TF_STUB(NumberToStringStub, CodeStubAssembler) {
366 : Node* context = Parameter(Descriptor::kContext);
367 : Node* argument = Parameter(Descriptor::kArgument);
368 62 : Return(NumberToString(context, argument));
369 31 : }
370 :
371 : // TODO(ishell): move to builtins-handler-gen.
372 885 : TF_STUB(KeyedLoadSloppyArgumentsStub, CodeStubAssembler) {
373 : Node* receiver = Parameter(Descriptor::kReceiver);
374 : Node* key = Parameter(Descriptor::kName);
375 : Node* slot = Parameter(Descriptor::kSlot);
376 : Node* vector = Parameter(Descriptor::kVector);
377 : Node* context = Parameter(Descriptor::kContext);
378 :
379 : Label miss(this);
380 :
381 295 : Node* result = LoadKeyedSloppyArguments(receiver, key, &miss);
382 295 : Return(result);
383 :
384 295 : BIND(&miss);
385 : {
386 295 : Comment("Miss");
387 : TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
388 : vector);
389 295 : }
390 295 : }
391 :
392 : // TODO(ishell): move to builtins-handler-gen.
393 0 : TF_STUB(KeyedStoreSloppyArgumentsStub, CodeStubAssembler) {
394 : Node* receiver = Parameter(Descriptor::kReceiver);
395 : Node* key = Parameter(Descriptor::kName);
396 : Node* value = Parameter(Descriptor::kValue);
397 : Node* slot = Parameter(Descriptor::kSlot);
398 : Node* vector = Parameter(Descriptor::kVector);
399 : Node* context = Parameter(Descriptor::kContext);
400 :
401 : Label miss(this);
402 :
403 0 : StoreKeyedSloppyArguments(receiver, key, value, &miss);
404 0 : Return(value);
405 :
406 0 : BIND(&miss);
407 : {
408 0 : Comment("Miss");
409 : TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
410 : receiver, key);
411 0 : }
412 0 : }
413 :
414 69732 : TF_STUB(LoadScriptContextFieldStub, CodeStubAssembler) {
415 : Comment("LoadScriptContextFieldStub: context_index=%d, slot=%d",
416 69732 : stub->context_index(), stub->slot_index());
417 :
418 : Node* context = Parameter(Descriptor::kContext);
419 :
420 17433 : Node* script_context = LoadScriptContext(context, stub->context_index());
421 17433 : Node* result = LoadFixedArrayElement(script_context, stub->slot_index());
422 17433 : Return(result);
423 17433 : }
424 :
425 116 : TF_STUB(StoreScriptContextFieldStub, CodeStubAssembler) {
426 : Comment("StoreScriptContextFieldStub: context_index=%d, slot=%d",
427 116 : stub->context_index(), stub->slot_index());
428 :
429 : Node* value = Parameter(Descriptor::kValue);
430 : Node* context = Parameter(Descriptor::kContext);
431 :
432 29 : Node* script_context = LoadScriptContext(context, stub->context_index());
433 29 : StoreFixedArrayElement(script_context, IntPtrConstant(stub->slot_index()),
434 58 : value);
435 29 : Return(value);
436 29 : }
437 :
438 : // TODO(ishell): move to builtins-handler-gen.
439 249 : TF_STUB(StoreInterceptorStub, CodeStubAssembler) {
440 : Node* receiver = Parameter(Descriptor::kReceiver);
441 : Node* name = Parameter(Descriptor::kName);
442 : Node* value = Parameter(Descriptor::kValue);
443 : Node* slot = Parameter(Descriptor::kSlot);
444 : Node* vector = Parameter(Descriptor::kVector);
445 : Node* context = Parameter(Descriptor::kContext);
446 : TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, value, slot,
447 : vector, receiver, name);
448 83 : }
449 :
450 : // TODO(ishell): move to builtins-handler-gen.
451 168 : TF_STUB(LoadIndexedInterceptorStub, CodeStubAssembler) {
452 : Node* receiver = Parameter(Descriptor::kReceiver);
453 : Node* key = Parameter(Descriptor::kName);
454 : Node* slot = Parameter(Descriptor::kSlot);
455 : Node* vector = Parameter(Descriptor::kVector);
456 : Node* context = Parameter(Descriptor::kContext);
457 :
458 56 : Label if_keyispositivesmi(this), if_keyisinvalid(this);
459 112 : Branch(TaggedIsPositiveSmi(key), &if_keyispositivesmi, &if_keyisinvalid);
460 56 : BIND(&if_keyispositivesmi);
461 : TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, receiver, key);
462 :
463 56 : BIND(&if_keyisinvalid);
464 : TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
465 56 : vector);
466 56 : }
467 :
468 62 : Handle<HandlerTable> JSEntryStub::GenerateHandlerTable() {
469 : Handle<FixedArray> handler_table =
470 62 : isolate()->factory()->NewFixedArray(1, TENURED);
471 62 : handler_table->set(0, Smi::FromInt(handler_offset_));
472 62 : return Handle<HandlerTable>::cast(handler_table);
473 : }
474 :
475 :
476 : // TODO(ishell): move to builtins.
477 124 : TF_STUB(GetPropertyStub, CodeStubAssembler) {
478 62 : Label call_runtime(this, Label::kDeferred), return_undefined(this), end(this);
479 :
480 : Node* object = Parameter(Descriptor::kObject);
481 : Node* key = Parameter(Descriptor::kKey);
482 : Node* context = Parameter(Descriptor::kContext);
483 62 : VARIABLE(var_result, MachineRepresentation::kTagged);
484 :
485 : CodeStubAssembler::LookupInHolder lookup_property_in_holder =
486 : [=, &var_result, &end](Node* receiver, Node* holder, Node* holder_map,
487 : Node* holder_instance_type, Node* unique_name,
488 31 : Label* next_holder, Label* if_bailout) {
489 31 : VARIABLE(var_value, MachineRepresentation::kTagged);
490 62 : Label if_found(this);
491 : TryGetOwnProperty(context, receiver, holder, holder_map,
492 : holder_instance_type, unique_name, &if_found,
493 31 : &var_value, next_holder, if_bailout);
494 31 : BIND(&if_found);
495 : {
496 31 : var_result.Bind(var_value.value());
497 31 : Goto(&end);
498 : }
499 31 : };
500 :
501 : CodeStubAssembler::LookupInHolder lookup_element_in_holder =
502 : [=](Node* receiver, Node* holder, Node* holder_map,
503 : Node* holder_instance_type, Node* index, Label* next_holder,
504 : Label* if_bailout) {
505 : // Not supported yet.
506 31 : Use(next_holder);
507 31 : Goto(if_bailout);
508 : };
509 :
510 : TryPrototypeChainLookup(object, key, lookup_property_in_holder,
511 : lookup_element_in_holder, &return_undefined,
512 31 : &call_runtime);
513 :
514 31 : BIND(&return_undefined);
515 : {
516 62 : var_result.Bind(UndefinedConstant());
517 31 : Goto(&end);
518 : }
519 :
520 31 : BIND(&call_runtime);
521 : {
522 31 : var_result.Bind(CallRuntime(Runtime::kGetProperty, context, object, key));
523 31 : Goto(&end);
524 : }
525 :
526 31 : BIND(&end);
527 93 : Return(var_result.value());
528 31 : }
529 :
530 : // TODO(ishell): move to builtins-handler-gen.
531 1680 : TF_STUB(StoreSlowElementStub, CodeStubAssembler) {
532 : Node* receiver = Parameter(Descriptor::kReceiver);
533 : Node* name = Parameter(Descriptor::kName);
534 : Node* value = Parameter(Descriptor::kValue);
535 : Node* slot = Parameter(Descriptor::kSlot);
536 : Node* vector = Parameter(Descriptor::kVector);
537 : Node* context = Parameter(Descriptor::kContext);
538 :
539 : TailCallRuntime(Runtime::kKeyedStoreIC_Slow, context, value, slot, vector,
540 : receiver, name);
541 560 : }
542 :
543 23406 : TF_STUB(StoreFastElementStub, CodeStubAssembler) {
544 : Comment("StoreFastElementStub: js_array=%d, elements_kind=%s, store_mode=%d",
545 : stub->is_js_array(), ElementsKindToString(stub->elements_kind()),
546 11703 : stub->store_mode());
547 :
548 : Node* receiver = Parameter(Descriptor::kReceiver);
549 : Node* key = Parameter(Descriptor::kName);
550 : Node* value = Parameter(Descriptor::kValue);
551 : Node* slot = Parameter(Descriptor::kSlot);
552 : Node* vector = Parameter(Descriptor::kVector);
553 : Node* context = Parameter(Descriptor::kContext);
554 :
555 : Label miss(this);
556 :
557 : EmitElementStore(receiver, key, value, stub->is_js_array(),
558 3901 : stub->elements_kind(), stub->store_mode(), &miss);
559 3901 : Return(value);
560 :
561 3901 : BIND(&miss);
562 : {
563 3901 : Comment("Miss");
564 : TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
565 : receiver, key);
566 3901 : }
567 3901 : }
568 :
569 : // static
570 31 : void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
571 62 : if (FLAG_minimal) return;
572 : StoreFastElementStub(isolate, false, HOLEY_ELEMENTS, STANDARD_STORE)
573 62 : .GetCode();
574 : StoreFastElementStub(isolate, false, HOLEY_ELEMENTS,
575 : STORE_AND_GROW_NO_TRANSITION)
576 62 : .GetCode();
577 217 : for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
578 186 : ElementsKind kind = static_cast<ElementsKind>(i);
579 372 : StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
580 : StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
581 372 : .GetCode();
582 : }
583 : }
584 :
585 :
586 0 : void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
587 : intptr_t stack_pointer,
588 0 : Isolate* isolate) {
589 : FunctionEntryHook entry_hook = isolate->function_entry_hook();
590 : DCHECK_NOT_NULL(entry_hook);
591 0 : entry_hook(function, stack_pointer);
592 0 : }
593 :
594 1054 : TF_STUB(ArrayNoArgumentConstructorStub, CodeStubAssembler) {
595 : ElementsKind elements_kind = stub->elements_kind();
596 : Node* native_context = LoadObjectField(Parameter(Descriptor::kFunction),
597 248 : JSFunction::kContextOffset);
598 : bool track_allocation_site =
599 372 : AllocationSite::ShouldTrack(elements_kind) &&
600 : stub->override_mode() != DISABLE_ALLOCATION_SITES;
601 : Node* allocation_site =
602 248 : track_allocation_site ? Parameter(Descriptor::kAllocationSite) : nullptr;
603 496 : Node* array_map = LoadJSArrayElementsMap(elements_kind, native_context);
604 : Node* array =
605 : AllocateJSArray(elements_kind, array_map,
606 : IntPtrConstant(JSArray::kPreallocatedArrayElements),
607 744 : SmiConstant(0), allocation_site);
608 248 : Return(array);
609 248 : }
610 :
611 186 : TF_STUB(InternalArrayNoArgumentConstructorStub, CodeStubAssembler) {
612 : Node* array_map = LoadObjectField(Parameter(Descriptor::kFunction),
613 62 : JSFunction::kPrototypeOrInitialMapOffset);
614 : Node* array = AllocateJSArray(
615 : stub->elements_kind(), array_map,
616 186 : IntPtrConstant(JSArray::kPreallocatedArrayElements), SmiConstant(0));
617 62 : Return(array);
618 62 : }
619 :
620 : class ArrayConstructorAssembler : public CodeStubAssembler {
621 : public:
622 : typedef compiler::Node Node;
623 :
624 : explicit ArrayConstructorAssembler(compiler::CodeAssemblerState* state)
625 310 : : CodeStubAssembler(state) {}
626 :
627 : void GenerateConstructor(Node* context, Node* array_function, Node* array_map,
628 : Node* array_size, Node* allocation_site,
629 : ElementsKind elements_kind, AllocationSiteMode mode);
630 : };
631 :
632 310 : void ArrayConstructorAssembler::GenerateConstructor(
633 : Node* context, Node* array_function, Node* array_map, Node* array_size,
634 : Node* allocation_site, ElementsKind elements_kind,
635 : AllocationSiteMode mode) {
636 310 : Label ok(this);
637 310 : Label smi_size(this);
638 310 : Label small_smi_size(this);
639 310 : Label call_runtime(this, Label::kDeferred);
640 :
641 620 : Branch(TaggedIsSmi(array_size), &smi_size, &call_runtime);
642 :
643 310 : BIND(&smi_size);
644 :
645 310 : if (IsFastPackedElementsKind(elements_kind)) {
646 : Label abort(this, Label::kDeferred);
647 465 : Branch(SmiEqual(array_size, SmiConstant(0)), &small_smi_size, &abort);
648 :
649 155 : BIND(&abort);
650 310 : Node* reason = SmiConstant(kAllocatingNonEmptyPackedArray);
651 155 : TailCallRuntime(Runtime::kAbort, context, reason);
652 : } else {
653 : int element_size =
654 : IsDoubleElementsKind(elements_kind) ? kDoubleSize : kPointerSize;
655 : int max_fast_elements =
656 : (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
657 : AllocationMemento::kSize) /
658 : element_size;
659 : Branch(SmiAboveOrEqual(array_size, SmiConstant(max_fast_elements)),
660 465 : &call_runtime, &small_smi_size);
661 : }
662 :
663 310 : BIND(&small_smi_size);
664 : {
665 : Node* array = AllocateJSArray(
666 : elements_kind, array_map, array_size, array_size,
667 : mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
668 310 : CodeStubAssembler::SMI_PARAMETERS);
669 310 : Return(array);
670 : }
671 :
672 310 : BIND(&call_runtime);
673 : {
674 : TailCallRuntime(Runtime::kNewArray, context, array_function, array_size,
675 : array_function, allocation_site);
676 310 : }
677 310 : }
678 :
679 1488 : TF_STUB(ArraySingleArgumentConstructorStub, ArrayConstructorAssembler) {
680 : ElementsKind elements_kind = stub->elements_kind();
681 : Node* context = Parameter(Descriptor::kContext);
682 : Node* function = Parameter(Descriptor::kFunction);
683 248 : Node* native_context = LoadObjectField(function, JSFunction::kContextOffset);
684 496 : Node* array_map = LoadJSArrayElementsMap(elements_kind, native_context);
685 : AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE;
686 248 : if (stub->override_mode() == DONT_OVERRIDE) {
687 : mode = AllocationSite::ShouldTrack(elements_kind)
688 : ? TRACK_ALLOCATION_SITE
689 186 : : DONT_TRACK_ALLOCATION_SITE;
690 : }
691 :
692 : Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
693 : Node* allocation_site = Parameter(Descriptor::kAllocationSite);
694 :
695 : GenerateConstructor(context, function, array_map, array_size, allocation_site,
696 248 : elements_kind, mode);
697 248 : }
698 :
699 310 : TF_STUB(InternalArraySingleArgumentConstructorStub, ArrayConstructorAssembler) {
700 : Node* context = Parameter(Descriptor::kContext);
701 : Node* function = Parameter(Descriptor::kFunction);
702 : Node* array_map =
703 62 : LoadObjectField(function, JSFunction::kPrototypeOrInitialMapOffset);
704 : Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
705 124 : Node* allocation_site = UndefinedConstant();
706 :
707 : GenerateConstructor(context, function, array_map, array_size, allocation_site,
708 62 : stub->elements_kind(), DONT_TRACK_ALLOCATION_SITE);
709 62 : }
710 :
711 0 : TF_STUB(GrowArrayElementsStub, CodeStubAssembler) {
712 0 : Label runtime(this, CodeStubAssembler::Label::kDeferred);
713 :
714 : Node* object = Parameter(Descriptor::kObject);
715 : Node* key = Parameter(Descriptor::kKey);
716 : Node* context = Parameter(Descriptor::kContext);
717 : ElementsKind kind = stub->elements_kind();
718 :
719 0 : Node* elements = LoadElements(object);
720 : Node* new_elements =
721 0 : TryGrowElementsCapacity(object, elements, kind, key, &runtime);
722 0 : Return(new_elements);
723 :
724 0 : BIND(&runtime);
725 : // TODO(danno): Make this a tail call when the stub is only used from TurboFan
726 : // code. This musn't be a tail call for now, since the caller site in lithium
727 : // creates a safepoint. This safepoint musn't have a different number of
728 : // arguments on the stack in the case that a GC happens from the slow-case
729 : // allocation path (zero, since all the stubs inputs are in registers) and
730 : // when the call happens (it would be two in the tail call case due to the
731 : // tail call pushing the arguments on the stack for the runtime call). By not
732 : // tail-calling, the runtime call case also has zero arguments on the stack
733 : // for the stub frame.
734 0 : Return(CallRuntime(Runtime::kGrowArrayElements, context, object, key));
735 0 : }
736 :
737 443474 : ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
738 443474 : : PlatformCodeStub(isolate) {}
739 :
740 153 : InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate)
741 153 : : PlatformCodeStub(isolate) {}
742 :
743 1304 : CommonArrayConstructorStub::CommonArrayConstructorStub(
744 : Isolate* isolate, ElementsKind kind,
745 : AllocationSiteOverrideMode override_mode)
746 1304 : : TurboFanCodeStub(isolate) {
747 : // It only makes sense to override local allocation site behavior
748 : // if there is a difference between the global allocation site policy
749 : // for an ElementsKind and the desired usage of the stub.
750 : DCHECK(override_mode != DISABLE_ALLOCATION_SITES ||
751 : AllocationSite::ShouldTrack(kind));
752 : set_sub_minor_key(ElementsKindBits::encode(kind) |
753 1304 : AllocationSiteOverrideModeBits::encode(override_mode));
754 1304 : }
755 :
756 : } // namespace internal
757 : } // namespace v8
|