code-stubs.cc 28.2 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6 7
#include "src/code-stubs.h"

#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 18
#include "src/factory.h"
#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 27
namespace v8 {
namespace internal {
28

29
using compiler::CodeAssemblerState;
30

31 32
RUNTIME_FUNCTION(UnexpectedStubMiss) {
  FATAL("Unexpected deopt of a stub");
33
  return Smi::kZero;
34 35
}

36
CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
37 38
    : isolate_(stub->isolate()),
      call_descriptor_(stub->GetCallInterfaceDescriptor()),
39
      stack_parameter_count_(no_reg),
40
      hint_stack_parameter_count_(-1),
41 42
      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
      deoptimization_handler_(NULL),
43
      miss_handler_(),
44
      has_miss_handler_(false) {
45
  stub->InitializeDescriptor(this);
46 47
}

48
CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
49 50
    : isolate_(isolate),
      stack_parameter_count_(no_reg),
51 52 53 54 55
      hint_stack_parameter_count_(-1),
      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
      deoptimization_handler_(NULL),
      miss_handler_(),
      has_miss_handler_(false) {
56
  CodeStub::InitializeDescriptor(isolate, stub_key, this);
57
}
58 59


60 61 62
void CodeStubDescriptor::Initialize(Address deoptimization_handler,
                                    int hint_stack_parameter_count,
                                    StubFunctionMode function_mode) {
63 64 65 66 67 68
  deoptimization_handler_ = deoptimization_handler;
  hint_stack_parameter_count_ = hint_stack_parameter_count;
  function_mode_ = function_mode;
}


69 70 71
void CodeStubDescriptor::Initialize(Register stack_parameter_count,
                                    Address deoptimization_handler,
                                    int hint_stack_parameter_count,
72
                                    StubFunctionMode function_mode) {
73
  Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
74 75 76 77
  stack_parameter_count_ = stack_parameter_count;
}


78 79
bool CodeStub::FindCodeInCache(Code** code_out) {
  UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
80
  int index = stubs->FindEntry(isolate(), GetKey());
81
  if (index != UnseededNumberDictionary::kNotFound) {
82
    *code_out = Code::cast(stubs->ValueAt(index));
83
    return true;
84
  }
85 86
  return false;
}
87

88

89
void CodeStub::RecordCodeGeneration(Handle<Code> code) {
90
  std::ostringstream os;
91
  os << *this;
92
  PROFILE(isolate(),
93 94
          CodeCreateEvent(CodeEventListener::STUB_TAG,
                          AbstractCode::cast(*code), os.str().c_str()));
95
  Counters* counters = isolate()->counters();
96
  counters->total_stubs_code_size()->Increment(code->instruction_size());
97 98 99
#ifdef DEBUG
  code->VerifyEmbeddedObjects();
#endif
100 101 102
}


103
Code::Kind CodeStub::GetCodeKind() const {
104 105 106 107
  return Code::STUB;
}


108
Code::Flags CodeStub::GetCodeFlags() const {
109
  return Code::ComputeFlags(GetCodeKind(), GetExtraICState());
110 111
}

112
Handle<Code> CodeStub::GetCodeCopy(const FindAndReplacePattern& pattern) {
113 114
  Handle<Code> ic = GetCode();
  ic = isolate()->factory()->CopyCode(ic);
115
  ic->FindAndReplace(pattern);
116
  RecordCodeGeneration(ic);
117 118 119
  return ic;
}

120 121 122
void CodeStub::DeleteStubFromCacheForTesting() {
  Heap* heap = isolate_->heap();
  Handle<UnseededNumberDictionary> dict(heap->code_stubs());
123 124 125
  int entry = dict->FindEntry(GetKey());
  DCHECK_NE(UnseededNumberDictionary::kNotFound, entry);
  dict = UnseededNumberDictionary::DeleteEntry(dict, entry);
126 127
  heap->SetRootCodeStubs(*dict);
}
128

129 130
Handle<Code> PlatformCodeStub::GenerateCode() {
  Factory* factory = isolate()->factory();
131 132

  // Generate the new code.
133
  MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
134 135 136

  {
    // Update the static counter each time a new code stub is generated.
137
    isolate()->counters()->code_stubs()->Increment();
138 139

    // Generate the code for the stub.
140 141
    // TODO(yangguo): remove this once we can serialize IC stubs.
    masm.enable_serializer();
142 143 144 145 146 147
    NoCurrentFrameScope scope(&masm);
    Generate(&masm);
  }

  // Create the code object.
  CodeDesc desc;
148
  masm.GetCode(isolate(), &desc);
149
  // Copy the generated code into a heap object.
150
  Code::Flags flags = Code::ComputeFlags(GetCodeKind(), GetExtraICState());
151 152 153 154 155 156
  Handle<Code> new_object = factory->NewCode(
      desc, flags, masm.CodeObject(), NeedsImmovableCode());
  return new_object;
}


157 158
Handle<Code> CodeStub::GetCode() {
  Heap* heap = isolate()->heap();
159
  Code* code;
160 161
  if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
                        : FindCodeInCache(&code)) {
162
    DCHECK(GetCodeKind() == code->kind());
163 164 165 166
    return Handle<Code>(code);
  }

  {
167
    HandleScope scope(isolate());
168 169 170
    // Canonicalize handles, so that we can share constant pool entries pointing
    // to code targets without dereferencing their handles.
    CanonicalHandleScope canonical(isolate());
171

172
    Handle<Code> new_object = GenerateCode();
173
    new_object->set_stub_key(GetKey());
174
    FinishCode(new_object);
175
    RecordCodeGeneration(new_object);
176 177 178

#ifdef ENABLE_DISASSEMBLER
    if (FLAG_print_code_stubs) {
179
      CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
180
      OFStream os(trace_scope.file());
181
      std::ostringstream name;
182
      name << *this;
183
      new_object->Disassemble(name.str().c_str(), os);
184
      os << "\n";
185 186
    }
#endif
187

188 189 190 191
    if (UseSpecialCache()) {
      AddToSpecialCache(new_object);
    } else {
      // Update the dictionary and the root in Heap.
192 193
      Handle<UnseededNumberDictionary> dict = UnseededNumberDictionary::Set(
          handle(heap->code_stubs()), GetKey(), new_object);
194
      heap->SetRootCodeStubs(*dict);
195
    }
196 197 198
    code = *new_object;
  }

199
  Activate(code);
200
  DCHECK(!NeedsImmovableCode() || Heap::IsImmovable(code) ||
201
         heap->code_space()->FirstPage()->Contains(code->address()));
202
  return Handle<Code>(code, isolate());
203 204 205
}


206
const char* CodeStub::MajorName(CodeStub::Major major_key) {
207
  switch (major_key) {
208
#define DEF_CASE(name) case name: return #name "Stub";
209
    CODE_STUB_LIST(DEF_CASE)
210
#undef DEF_CASE
211 212
    case NoCache:
      return "<NoCache>Stub";
213 214
    case NUMBER_OF_IDS:
      UNREACHABLE();
215
  }
216
  return NULL;
217 218
}

219

220
void CodeStub::PrintBaseName(std::ostream& os) const {  // NOLINT
221
  os << MajorName(MajorKey());
222 223
}

224

225
void CodeStub::PrintName(std::ostream& os) const {  // NOLINT
226 227
  PrintBaseName(os);
  PrintState(os);
228 229 230
}


231 232 233 234 235 236 237 238 239 240 241 242 243 244
void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
                        DispatchedCall call) {
  switch (MajorKeyFromKey(key)) {
#define DEF_CASE(NAME)             \
  case NAME: {                     \
    NAME##Stub stub(key, isolate); \
    CodeStub* pstub = &stub;       \
    call(pstub, value_out);        \
    break;                         \
  }
    CODE_STUB_LIST(DEF_CASE)
#undef DEF_CASE
    case NUMBER_OF_IDS:
    case NoCache:
245
      UNREACHABLE();
246 247 248 249 250
      break;
  }
}


251 252 253 254 255 256
static void InitializeDescriptorDispatchedCall(CodeStub* stub,
                                               void** value_out) {
  CodeStubDescriptor* descriptor_out =
      reinterpret_cast<CodeStubDescriptor*>(value_out);
  stub->InitializeDescriptor(descriptor_out);
  descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
257 258 259
}


260 261
void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
                                    CodeStubDescriptor* desc) {
262
  void** value_out = reinterpret_cast<void**>(desc);
263
  Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
264 265 266
}


267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
  Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
  // Code stubs with special cache cannot be recreated from stub key.
  *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
}


MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
  HandleScope scope(isolate);
  Handle<Code> code;
  void** value_out = reinterpret_cast<void**>(&code);
  Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
  return scope.CloseAndEscape(code);
}


283 284 285 286
void StringAddStub::PrintBaseName(std::ostream& os) const {  // NOLINT
  os << "StringAddStub_" << flags() << "_" << pretenure_flag();
}

287 288 289 290 291 292 293
TF_STUB(StringAddStub, CodeStubAssembler) {
  StringAddFlags flags = stub->flags();
  PretenureFlag pretenure_flag = stub->pretenure_flag();

  Node* left = Parameter(Descriptor::kLeft);
  Node* right = Parameter(Descriptor::kRight);
  Node* context = Parameter(Descriptor::kContext);
294

295 296
  if ((flags & STRING_ADD_CHECK_LEFT) != 0) {
    DCHECK((flags & STRING_ADD_CONVERT) != 0);
297 298
    // TODO(danno): The ToString and JSReceiverToPrimitive below could be
    // combined to avoid duplicate smi and instance type checks.
299
    left = ToString(context, JSReceiverToPrimitive(context, left));
300
  }
301 302
  if ((flags & STRING_ADD_CHECK_RIGHT) != 0) {
    DCHECK((flags & STRING_ADD_CONVERT) != 0);
303 304
    // TODO(danno): The ToString and JSReceiverToPrimitive below could be
    // combined to avoid duplicate smi and instance type checks.
305
    right = ToString(context, JSReceiverToPrimitive(context, right));
306 307
  }

308 309 310 311 312
  if ((flags & STRING_ADD_CHECK_BOTH) == 0) {
    CodeStubAssembler::AllocationFlag allocation_flags =
        (pretenure_flag == TENURED) ? CodeStubAssembler::kPretenured
                                    : CodeStubAssembler::kNone;
    Return(StringAdd(context, left, right, allocation_flags));
313 314
  } else {
    Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE,
315 316
                                               pretenure_flag);
    TailCallStub(callable, context, left, right);
317 318
  }
}
319

320
InlineCacheState CompareICStub::GetICState() const {
321
  CompareICState::State state = Max(left(), right());
322
  switch (state) {
323
    case CompareICState::UNINITIALIZED:
324
      return ::v8::internal::UNINITIALIZED;
325
    case CompareICState::BOOLEAN:
326 327 328 329 330
    case CompareICState::SMI:
    case CompareICState::NUMBER:
    case CompareICState::INTERNALIZED_STRING:
    case CompareICState::STRING:
    case CompareICState::UNIQUE_NAME:
331 332
    case CompareICState::RECEIVER:
    case CompareICState::KNOWN_RECEIVER:
333
      return MONOMORPHIC;
334
    case CompareICState::GENERIC:
335 336 337 338 339 340
      return ::v8::internal::GENERIC;
  }
  UNREACHABLE();
}


341 342 343 344 345
Condition CompareICStub::GetCondition() const {
  return CompareIC::ComputeCondition(op());
}


346
void CompareICStub::Generate(MacroAssembler* masm) {
347
  switch (state()) {
348
    case CompareICState::UNINITIALIZED:
349 350
      GenerateMiss(masm);
      break;
351 352 353
    case CompareICState::BOOLEAN:
      GenerateBooleans(masm);
      break;
354
    case CompareICState::SMI:
355 356
      GenerateSmis(masm);
      break;
357
    case CompareICState::NUMBER:
358
      GenerateNumbers(masm);
359
      break;
360
    case CompareICState::STRING:
361 362
      GenerateStrings(masm);
      break;
363
    case CompareICState::INTERNALIZED_STRING:
364
      GenerateInternalizedStrings(masm);
365
      break;
366
    case CompareICState::UNIQUE_NAME:
367 368
      GenerateUniqueNames(masm);
      break;
369 370
    case CompareICState::RECEIVER:
      GenerateReceivers(masm);
371
      break;
372
    case CompareICState::KNOWN_RECEIVER:
373
      DCHECK(*known_map_ != NULL);
374
      GenerateKnownReceivers(masm);
375
      break;
376
    case CompareICState::GENERIC:
377 378
      GenerateGeneric(masm);
      break;
379 380 381
  }
}

382
Handle<Code> TurboFanCodeStub::GenerateCode() {
383
  const char* name = CodeStub::MajorName(MajorKey());
384
  Zone zone(isolate()->allocator(), ZONE_NAME);
385
  CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
386 387 388
  compiler::CodeAssemblerState state(isolate(), &zone, descriptor,
                                     GetCodeFlags(), name);
  GenerateAssembly(&state);
389
  return compiler::CodeAssembler::GenerateCode(&state);
390 391
}

392 393 394 395 396 397 398 399
TF_STUB(ElementsTransitionAndStoreStub, CodeStubAssembler) {
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* key = Parameter(Descriptor::kName);
  Node* value = Parameter(Descriptor::kValue);
  Node* map = Parameter(Descriptor::kMap);
  Node* slot = Parameter(Descriptor::kSlot);
  Node* vector = Parameter(Descriptor::kVector);
  Node* context = Parameter(Descriptor::kContext);
400

401
  Comment(
402 403
      "ElementsTransitionAndStoreStub: from_kind=%s, to_kind=%s,"
      " is_jsarray=%d, store_mode=%d",
404 405 406
      ElementsKindToString(stub->from_kind()),
      ElementsKindToString(stub->to_kind()), stub->is_jsarray(),
      stub->store_mode());
407

408
  Label miss(this);
409 410 411

  if (FLAG_trace_elements_transitions) {
    // Tracing elements transitions is the job of the runtime.
412
    Goto(&miss);
413
  } else {
414 415 416 417 418
    TransitionElementsKind(receiver, map, stub->from_kind(), stub->to_kind(),
                           stub->is_jsarray(), &miss);
    EmitElementStore(receiver, key, value, stub->is_jsarray(), stub->to_kind(),
                     stub->store_mode(), &miss);
    Return(value);
419 420
  }

421
  BIND(&miss);
422
  {
423 424 425
    Comment("Miss");
    TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
                    receiver, key, value, map, slot, vector);
426 427 428
  }
}

429 430 431 432
// TODO(ishell): move to builtins.
TF_STUB(AllocateHeapNumberStub, CodeStubAssembler) {
  Node* result = AllocateHeapNumber();
  Return(result);
433 434
}

435 436 437 438 439 440
// TODO(ishell): move to builtins-handler-gen.
TF_STUB(StringLengthStub, CodeStubAssembler) {
  Node* value = Parameter(Descriptor::kReceiver);
  Node* string = LoadJSValueValue(value);
  Node* result = LoadStringLength(string);
  Return(result);
441 442
}

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
TF_STUB(TransitionElementsKindStub, CodeStubAssembler) {
  Node* context = Parameter(Descriptor::kContext);
  Node* object = Parameter(Descriptor::kObject);
  Node* new_map = Parameter(Descriptor::kMap);

  Label bailout(this);
  TransitionElementsKind(object, new_map, stub->from_kind(), stub->to_kind(),
                         stub->is_jsarray(), &bailout);
  Return(object);

  BIND(&bailout);
  {
    Comment("Call runtime");
    TailCallRuntime(Runtime::kTransitionElementsKind, context, object, new_map);
  }
}

460 461 462 463 464
// TODO(ishell): move to builtins.
TF_STUB(NumberToStringStub, CodeStubAssembler) {
  Node* context = Parameter(Descriptor::kContext);
  Node* argument = Parameter(Descriptor::kArgument);
  Return(NumberToString(context, argument));
465 466
}

467 468 469 470 471 472
// TODO(ishell): move to builtins.
TF_STUB(SubStringStub, CodeStubAssembler) {
  Node* context = Parameter(Descriptor::kContext);
  Node* string = Parameter(Descriptor::kString);
  Node* from = Parameter(Descriptor::kFrom);
  Node* to = Parameter(Descriptor::kTo);
473

474
  Return(SubString(context, string, from, to));
475 476
}

477 478 479 480 481 482 483
// TODO(ishell): move to builtins-handler-gen.
TF_STUB(KeyedLoadSloppyArgumentsStub, CodeStubAssembler) {
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* key = Parameter(Descriptor::kName);
  Node* slot = Parameter(Descriptor::kSlot);
  Node* vector = Parameter(Descriptor::kVector);
  Node* context = Parameter(Descriptor::kContext);
484

485
  Label miss(this);
486

487 488
  Node* result = LoadKeyedSloppyArguments(receiver, key, &miss);
  Return(result);
489

490
  BIND(&miss);
491
  {
492 493 494
    Comment("Miss");
    TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
                    vector);
495 496 497
  }
}

498 499 500 501 502 503 504 505
// TODO(ishell): move to builtins-handler-gen.
TF_STUB(KeyedStoreSloppyArgumentsStub, CodeStubAssembler) {
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* key = Parameter(Descriptor::kName);
  Node* value = Parameter(Descriptor::kValue);
  Node* slot = Parameter(Descriptor::kSlot);
  Node* vector = Parameter(Descriptor::kVector);
  Node* context = Parameter(Descriptor::kContext);
506

507
  Label miss(this);
508

509 510
  StoreKeyedSloppyArguments(receiver, key, value, &miss);
  Return(value);
511

512
  BIND(&miss);
513
  {
514 515 516
    Comment("Miss");
    TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
                    receiver, key);
517 518 519
  }
}

520 521 522
TF_STUB(LoadScriptContextFieldStub, CodeStubAssembler) {
  Comment("LoadScriptContextFieldStub: context_index=%d, slot=%d",
          stub->context_index(), stub->slot_index());
523

524
  Node* context = Parameter(Descriptor::kContext);
525

526 527 528
  Node* script_context = LoadScriptContext(context, stub->context_index());
  Node* result = LoadFixedArrayElement(script_context, stub->slot_index());
  Return(result);
529 530
}

531 532 533
TF_STUB(StoreScriptContextFieldStub, CodeStubAssembler) {
  Comment("StoreScriptContextFieldStub: context_index=%d, slot=%d",
          stub->context_index(), stub->slot_index());
534

535 536
  Node* value = Parameter(Descriptor::kValue);
  Node* context = Parameter(Descriptor::kContext);
537

538 539 540 541
  Node* script_context = LoadScriptContext(context, stub->context_index());
  StoreFixedArrayElement(script_context, IntPtrConstant(stub->slot_index()),
                         value);
  Return(value);
542 543
}

544 545 546 547 548 549 550 551 552 553
// TODO(ishell): move to builtins-handler-gen.
TF_STUB(StoreInterceptorStub, CodeStubAssembler) {
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* name = Parameter(Descriptor::kName);
  Node* value = Parameter(Descriptor::kValue);
  Node* slot = Parameter(Descriptor::kSlot);
  Node* vector = Parameter(Descriptor::kVector);
  Node* context = Parameter(Descriptor::kContext);
  TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, value, slot,
                  vector, receiver, name);
554 555
}

556 557 558 559 560 561 562
// TODO(ishell): move to builtins-handler-gen.
TF_STUB(LoadIndexedInterceptorStub, CodeStubAssembler) {
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* key = Parameter(Descriptor::kName);
  Node* slot = Parameter(Descriptor::kSlot);
  Node* vector = Parameter(Descriptor::kVector);
  Node* context = Parameter(Descriptor::kContext);
563

564 565
  Label if_keyispositivesmi(this), if_keyisinvalid(this);
  Branch(TaggedIsPositiveSmi(key), &if_keyispositivesmi, &if_keyisinvalid);
566
  BIND(&if_keyispositivesmi);
567
  TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, receiver, key);
568

569
  BIND(&if_keyisinvalid);
570 571
  TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
                  vector);
572 573
}

574 575 576 577 578 579 580
void JSEntryStub::FinishCode(Handle<Code> code) {
  Handle<FixedArray> handler_table =
      code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
  handler_table->set(0, Smi::FromInt(handler_offset_));
  code->set_handler_table(*handler_table);
}

581

582 583 584 585 586 587 588
void AllocateHeapNumberStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
  descriptor->Initialize(
      Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
}


589 590 591
// TODO(ishell): move to builtins.
TF_STUB(GetPropertyStub, CodeStubAssembler) {
  Label call_runtime(this, Label::kDeferred), return_undefined(this), end(this);
592

593 594 595
  Node* object = Parameter(Descriptor::kObject);
  Node* key = Parameter(Descriptor::kKey);
  Node* context = Parameter(Descriptor::kContext);
596
  VARIABLE(var_result, MachineRepresentation::kTagged);
597 598

  CodeStubAssembler::LookupInHolder lookup_property_in_holder =
599 600 601
      [=, &var_result, &end](Node* receiver, Node* holder, Node* holder_map,
                             Node* holder_instance_type, Node* unique_name,
                             Label* next_holder, Label* if_bailout) {
602
        VARIABLE(var_value, MachineRepresentation::kTagged);
603 604 605 606
        Label if_found(this);
        TryGetOwnProperty(context, receiver, holder, holder_map,
                          holder_instance_type, unique_name, &if_found,
                          &var_value, next_holder, if_bailout);
607
        BIND(&if_found);
608 609
        {
          var_result.Bind(var_value.value());
610
          Goto(&end);
611 612 613 614
        }
      };

  CodeStubAssembler::LookupInHolder lookup_element_in_holder =
615
      [=](Node* receiver, Node* holder, Node* holder_map,
616 617 618
          Node* holder_instance_type, Node* index, Label* next_holder,
          Label* if_bailout) {
        // Not supported yet.
619 620
        Use(next_holder);
        Goto(if_bailout);
621 622
      };

623 624 625
  TryPrototypeChainLookup(object, key, lookup_property_in_holder,
                          lookup_element_in_holder, &return_undefined,
                          &call_runtime);
626

627
  BIND(&return_undefined);
628
  {
629 630
    var_result.Bind(UndefinedConstant());
    Goto(&end);
631 632
  }

633
  BIND(&call_runtime);
634
  {
635 636
    var_result.Bind(CallRuntime(Runtime::kGetProperty, context, object, key));
    Goto(&end);
637 638
  }

639
  BIND(&end);
640
  Return(var_result.value());
641 642
}

643 644 645 646 647 648 649 650
// TODO(ishell): move to builtins-handler-gen.
TF_STUB(StoreSlowElementStub, CodeStubAssembler) {
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* name = Parameter(Descriptor::kName);
  Node* value = Parameter(Descriptor::kValue);
  Node* slot = Parameter(Descriptor::kSlot);
  Node* vector = Parameter(Descriptor::kVector);
  Node* context = Parameter(Descriptor::kContext);
651

652 653
  TailCallRuntime(Runtime::kKeyedStoreIC_Slow, context, value, slot, vector,
                  receiver, name);
danno@chromium.org's avatar
danno@chromium.org committed
654 655
}

656 657 658 659
TF_STUB(StoreFastElementStub, CodeStubAssembler) {
  Comment("StoreFastElementStub: js_array=%d, elements_kind=%s, store_mode=%d",
          stub->is_js_array(), ElementsKindToString(stub->elements_kind()),
          stub->store_mode());
660

661 662 663 664 665 666
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* key = Parameter(Descriptor::kName);
  Node* value = Parameter(Descriptor::kValue);
  Node* slot = Parameter(Descriptor::kSlot);
  Node* vector = Parameter(Descriptor::kVector);
  Node* context = Parameter(Descriptor::kContext);
667

668
  Label miss(this);
669

670 671 672
  EmitElementStore(receiver, key, value, stub->is_js_array(),
                   stub->elements_kind(), stub->store_mode(), &miss);
  Return(value);
673

674
  BIND(&miss);
675
  {
676 677 678
    Comment("Miss");
    TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
                    receiver, key);
679 680
  }
}
danno@chromium.org's avatar
danno@chromium.org committed
681

682 683
// static
void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
684
  if (FLAG_minimal) return;
685 686 687 688
  StoreFastElementStub(isolate, false, HOLEY_ELEMENTS, STANDARD_STORE)
      .GetCode();
  StoreFastElementStub(isolate, false, HOLEY_ELEMENTS,
                       STORE_AND_GROW_NO_TRANSITION)
689 690 691 692 693 694 695 696 697
      .GetCode();
  for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
    ElementsKind kind = static_cast<ElementsKind>(i);
    StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
    StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
        .GetCode();
  }
}

698

699
void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
700 701 702
                                               intptr_t stack_pointer,
                                               Isolate* isolate) {
  FunctionEntryHook entry_hook = isolate->function_entry_hook();
703
  DCHECK(entry_hook != NULL);
704
  entry_hook(function, stack_pointer);
705 706
}

707 708 709 710
TF_STUB(ArrayNoArgumentConstructorStub, CodeStubAssembler) {
  ElementsKind elements_kind = stub->elements_kind();
  Node* native_context = LoadObjectField(Parameter(Descriptor::kFunction),
                                         JSFunction::kContextOffset);
711
  bool track_allocation_site =
712
      AllocationSite::ShouldTrack(elements_kind) &&
713 714 715 716 717 718 719
      stub->override_mode() != DISABLE_ALLOCATION_SITES;
  Node* allocation_site =
      track_allocation_site ? Parameter(Descriptor::kAllocationSite) : nullptr;
  Node* array_map = LoadJSArrayElementsMap(elements_kind, native_context);
  Node* array =
      AllocateJSArray(elements_kind, array_map,
                      IntPtrConstant(JSArray::kPreallocatedArrayElements),
720
                      SmiConstant(0), allocation_site);
721 722 723 724 725 726
  Return(array);
}

TF_STUB(InternalArrayNoArgumentConstructorStub, CodeStubAssembler) {
  Node* array_map = LoadObjectField(Parameter(Descriptor::kFunction),
                                    JSFunction::kPrototypeOrInitialMapOffset);
727 728 729
  Node* array = AllocateJSArray(
      stub->elements_kind(), array_map,
      IntPtrConstant(JSArray::kPreallocatedArrayElements), SmiConstant(0));
730
  Return(array);
731 732
}

733 734
class ArrayConstructorAssembler : public CodeStubAssembler {
 public:
735 736
  typedef compiler::Node Node;

737 738 739 740 741 742 743
  explicit ArrayConstructorAssembler(compiler::CodeAssemblerState* state)
      : CodeStubAssembler(state) {}

  void GenerateConstructor(Node* context, Node* array_function, Node* array_map,
                           Node* array_size, Node* allocation_site,
                           ElementsKind elements_kind, AllocationSiteMode mode);
};
744

745 746 747 748 749 750 751 752
void ArrayConstructorAssembler::GenerateConstructor(
    Node* context, Node* array_function, Node* array_map, Node* array_size,
    Node* allocation_site, ElementsKind elements_kind,
    AllocationSiteMode mode) {
  Label ok(this);
  Label smi_size(this);
  Label small_smi_size(this);
  Label call_runtime(this, Label::kDeferred);
753

754 755
  Branch(TaggedIsSmi(array_size), &smi_size, &call_runtime);

756
  BIND(&smi_size);
757 758

  if (IsFastPackedElementsKind(elements_kind)) {
759
    Label abort(this, Label::kDeferred);
760
    Branch(SmiEqual(array_size, SmiConstant(0)), &small_smi_size, &abort);
761

762
    BIND(&abort);
763
    Node* reason = SmiConstant(kAllocatingNonEmptyPackedArray);
764
    TailCallRuntime(Runtime::kAbort, context, reason);
765 766
  } else {
    int element_size =
767
        IsDoubleElementsKind(elements_kind) ? kDoubleSize : kPointerSize;
768
    int max_fast_elements =
769 770
        (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
         AllocationMemento::kSize) /
771
        element_size;
772
    Branch(SmiAboveOrEqual(array_size, SmiConstant(max_fast_elements)),
773
           &call_runtime, &small_smi_size);
774
  }
775

776
  BIND(&small_smi_size);
777
  {
778 779
    Node* array = AllocateJSArray(
        elements_kind, array_map, array_size, array_size,
780 781
        mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
        CodeStubAssembler::SMI_PARAMETERS);
782
    Return(array);
783 784
  }

785
  BIND(&call_runtime);
786
  {
787 788
    TailCallRuntime(Runtime::kNewArray, context, array_function, array_size,
                    array_function, allocation_site);
789 790 791
  }
}

792
TF_STUB(ArraySingleArgumentConstructorStub, ArrayConstructorAssembler) {
793
  ElementsKind elements_kind = stub->elements_kind();
794
  Node* context = Parameter(Descriptor::kContext);
795 796 797
  Node* function = Parameter(Descriptor::kFunction);
  Node* native_context = LoadObjectField(function, JSFunction::kContextOffset);
  Node* array_map = LoadJSArrayElementsMap(elements_kind, native_context);
798 799 800 801 802 803 804
  AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE;
  if (stub->override_mode() == DONT_OVERRIDE) {
    mode = AllocationSite::ShouldTrack(elements_kind)
               ? TRACK_ALLOCATION_SITE
               : DONT_TRACK_ALLOCATION_SITE;
  }

805
  Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
806
  Node* allocation_site = Parameter(Descriptor::kAllocationSite);
807 808 809

  GenerateConstructor(context, function, array_map, array_size, allocation_site,
                      elements_kind, mode);
810 811
}

812 813
TF_STUB(InternalArraySingleArgumentConstructorStub, ArrayConstructorAssembler) {
  Node* context = Parameter(Descriptor::kContext);
814 815 816
  Node* function = Parameter(Descriptor::kFunction);
  Node* array_map =
      LoadObjectField(function, JSFunction::kPrototypeOrInitialMapOffset);
817 818
  Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
  Node* allocation_site = UndefinedConstant();
819

820 821
  GenerateConstructor(context, function, array_map, array_size, allocation_site,
                      stub->elements_kind(), DONT_TRACK_ALLOCATION_SITE);
822 823
}

824 825
TF_STUB(GrowArrayElementsStub, CodeStubAssembler) {
  Label runtime(this, CodeStubAssembler::Label::kDeferred);
826

827 828 829 830
  Node* object = Parameter(Descriptor::kObject);
  Node* key = Parameter(Descriptor::kKey);
  Node* context = Parameter(Descriptor::kContext);
  ElementsKind kind = stub->elements_kind();
831

832
  Node* elements = LoadElements(object);
833
  Node* new_elements =
834 835
      TryGrowElementsCapacity(object, elements, kind, key, &runtime);
  Return(new_elements);
836

837
  BIND(&runtime);
838 839 840 841 842 843 844 845 846
  // TODO(danno): Make this a tail call when the stub is only used from TurboFan
  // code. This musn't be a tail call for now, since the caller site in lithium
  // creates a safepoint. This safepoint musn't have a different number of
  // arguments on the stack in the case that a GC happens from the slow-case
  // allocation path (zero, since all the stubs inputs are in registers) and
  // when the call happens (it would be two in the tail call case due to the
  // tail call pushing the arguments on the stack for the runtime call). By not
  // tail-calling, the runtime call case also has zero arguments on the stack
  // for the stub frame.
847
  Return(CallRuntime(Runtime::kGrowArrayElements, context, object, key));
848 849
}

850
ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
851
    : PlatformCodeStub(isolate) {}
852

853 854
InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate)
    : PlatformCodeStub(isolate) {}
855

856 857
}  // namespace internal
}  // namespace v8