code-stubs.cc 28.8 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/bootstrapper.h"
10
#include "src/compiler/code-stub-assembler.h"
11 12
#include "src/factory.h"
#include "src/gdb-jit.h"
13
#include "src/ic/handler-compiler.h"
14
#include "src/ic/ic.h"
15
#include "src/macro-assembler.h"
16
#include "src/parsing/parser.h"
17
#include "src/profiler/cpu-profiler.h"
18

19 20
namespace v8 {
namespace internal {
21

22

23 24 25 26 27 28
RUNTIME_FUNCTION(UnexpectedStubMiss) {
  FATAL("Unexpected deopt of a stub");
  return Smi::FromInt(0);
}


29 30 31
CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
    : call_descriptor_(stub->GetCallInterfaceDescriptor()),
      stack_parameter_count_(no_reg),
32
      hint_stack_parameter_count_(-1),
33 34
      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
      deoptimization_handler_(NULL),
35
      miss_handler_(),
36
      has_miss_handler_(false) {
37
  stub->InitializeDescriptor(this);
38 39 40
}


41
CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
42 43 44 45 46 47
    : stack_parameter_count_(no_reg),
      hint_stack_parameter_count_(-1),
      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
      deoptimization_handler_(NULL),
      miss_handler_(),
      has_miss_handler_(false) {
48
  CodeStub::InitializeDescriptor(isolate, stub_key, this);
49
}
50 51


52 53 54
void CodeStubDescriptor::Initialize(Address deoptimization_handler,
                                    int hint_stack_parameter_count,
                                    StubFunctionMode function_mode) {
55 56 57 58 59 60
  deoptimization_handler_ = deoptimization_handler;
  hint_stack_parameter_count_ = hint_stack_parameter_count;
  function_mode_ = function_mode;
}


61 62 63
void CodeStubDescriptor::Initialize(Register stack_parameter_count,
                                    Address deoptimization_handler,
                                    int hint_stack_parameter_count,
64
                                    StubFunctionMode function_mode) {
65
  Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
66 67 68 69
  stack_parameter_count_ = stack_parameter_count;
}


70 71
bool CodeStub::FindCodeInCache(Code** code_out) {
  UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
72
  int index = stubs->FindEntry(GetKey());
73
  if (index != UnseededNumberDictionary::kNotFound) {
74
    *code_out = Code::cast(stubs->ValueAt(index));
75
    return true;
76
  }
77 78
  return false;
}
79

80

81
void CodeStub::RecordCodeGeneration(Handle<Code> code) {
82
  std::ostringstream os;
83
  os << *this;
84 85
  PROFILE(isolate(),
          CodeCreateEvent(Logger::STUB_TAG, *code, os.str().c_str()));
86
  Counters* counters = isolate()->counters();
87
  counters->total_stubs_code_size()->Increment(code->instruction_size());
88 89 90
#ifdef DEBUG
  code->VerifyEmbeddedObjects();
#endif
91 92 93
}


94
Code::Kind CodeStub::GetCodeKind() const {
95 96 97 98
  return Code::STUB;
}


99 100 101 102 103 104
Code::Flags CodeStub::GetCodeFlags() const {
  return Code::ComputeFlags(GetCodeKind(), GetICState(), GetExtraICState(),
                            GetStubType());
}


105 106 107
Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) {
  Handle<Code> ic = GetCode();
  ic = isolate()->factory()->CopyCode(ic);
108
  ic->FindAndReplace(pattern);
109
  RecordCodeGeneration(ic);
110 111 112 113
  return ic;
}


114 115
Handle<Code> PlatformCodeStub::GenerateCode() {
  Factory* factory = isolate()->factory();
116 117

  // Generate the new code.
118
  MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
119 120 121

  {
    // Update the static counter each time a new code stub is generated.
122
    isolate()->counters()->code_stubs()->Increment();
123 124 125

    // Generate the code for the stub.
    masm.set_generating_stub(true);
126 127
    // TODO(yangguo): remove this once we can serialize IC stubs.
    masm.enable_serializer();
128 129 130 131 132 133 134 135 136
    NoCurrentFrameScope scope(&masm);
    Generate(&masm);
  }

  // Create the code object.
  CodeDesc desc;
  masm.GetCode(&desc);
  // Copy the generated code into a heap object.
  Code::Flags flags = Code::ComputeFlags(
137
      GetCodeKind(),
138 139
      GetICState(),
      GetExtraICState(),
140
      GetStubType());
141 142 143 144 145 146
  Handle<Code> new_object = factory->NewCode(
      desc, flags, masm.CodeObject(), NeedsImmovableCode());
  return new_object;
}


147 148
Handle<Code> CodeStub::GetCode() {
  Heap* heap = isolate()->heap();
149
  Code* code;
150 151
  if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
                        : FindCodeInCache(&code)) {
152
    DCHECK(GetCodeKind() == code->kind());
153 154 155 156
    return Handle<Code>(code);
  }

  {
157
    HandleScope scope(isolate());
158

159
    Handle<Code> new_object = GenerateCode();
160
    new_object->set_stub_key(GetKey());
161
    FinishCode(new_object);
162
    RecordCodeGeneration(new_object);
163 164 165

#ifdef ENABLE_DISASSEMBLER
    if (FLAG_print_code_stubs) {
166
      CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
167
      OFStream os(trace_scope.file());
168
      std::ostringstream name;
169
      name << *this;
170
      new_object->Disassemble(name.str().c_str(), os);
171
      os << "\n";
172 173
    }
#endif
174

175 176 177 178
    if (UseSpecialCache()) {
      AddToSpecialCache(new_object);
    } else {
      // Update the dictionary and the root in Heap.
179
      Handle<UnseededNumberDictionary> dict =
180
          UnseededNumberDictionary::AtNumberPut(
181
              Handle<UnseededNumberDictionary>(heap->code_stubs()),
182 183
              GetKey(),
              new_object);
184
      heap->SetRootCodeStubs(*dict);
185
    }
186 187 188
    code = *new_object;
  }

189
  Activate(code);
190
  DCHECK(!NeedsImmovableCode() ||
191 192
         heap->lo_space()->Contains(code) ||
         heap->code_space()->FirstPage()->Contains(code->address()));
193
  return Handle<Code>(code, isolate());
194 195 196
}


197
const char* CodeStub::MajorName(CodeStub::Major major_key) {
198
  switch (major_key) {
199
#define DEF_CASE(name) case name: return #name "Stub";
200
    CODE_STUB_LIST(DEF_CASE)
201
#undef DEF_CASE
202 203
    case NoCache:
      return "<NoCache>Stub";
204 205
    case NUMBER_OF_IDS:
      UNREACHABLE();
206 207
      return NULL;
  }
208
  return NULL;
209 210
}

211

212
void CodeStub::PrintBaseName(std::ostream& os) const {  // NOLINT
213
  os << MajorName(MajorKey());
214 215
}

216

217
void CodeStub::PrintName(std::ostream& os) const {  // NOLINT
218 219
  PrintBaseName(os);
  PrintState(os);
220 221 222
}


223 224 225 226 227 228 229 230 231 232 233 234 235 236
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:
237
      UNREACHABLE();
238 239 240 241 242
      break;
  }
}


243 244 245 246 247 248
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());
249 250 251
}


252 253
void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
                                    CodeStubDescriptor* desc) {
254
  void** value_out = reinterpret_cast<void**>(desc);
255
  Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
256 257 258
}


259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
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);
}


275 276 277 278
// static
void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
  // Generate the uninitialized versions of the stub.
  for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
279
    BinaryOpICStub stub(isolate, static_cast<Token::Value>(op), Strength::WEAK);
280
    stub.GetCode();
281 282
  }

283
  // Generate special versions of the stub.
284
  BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
285 286 287
}


288
void BinaryOpICStub::PrintState(std::ostream& os) const {  // NOLINT
289
  os << state();
290 291 292
}


293 294
// static
void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
295
                                         const BinaryOpICState& state) {
296
  BinaryOpICStub stub(isolate, state);
297
  stub.GetCode();
298 299 300
}


301 302 303
// static
void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
  // Generate special versions of the stub.
304
  BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
305 306 307
}


308
void BinaryOpICWithAllocationSiteStub::PrintState(
309
    std::ostream& os) const {  // NOLINT
310
  os << state();
311 312 313 314 315
}


// static
void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
316
    Isolate* isolate, const BinaryOpICState& state) {
317
  if (state.CouldCreateAllocationMementos()) {
318
    BinaryOpICWithAllocationSiteStub stub(isolate, state);
319
    stub.GetCode();
320 321 322 323
  }
}


324 325 326 327 328 329 330 331 332 333
std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) {
  switch (flags) {
    case STRING_ADD_CHECK_NONE:
      return os << "CheckNone";
    case STRING_ADD_CHECK_LEFT:
      return os << "CheckLeft";
    case STRING_ADD_CHECK_RIGHT:
      return os << "CheckRight";
    case STRING_ADD_CHECK_BOTH:
      return os << "CheckBoth";
334 335 336 337 338 339
    case STRING_ADD_CONVERT_LEFT:
      return os << "ConvertLeft";
    case STRING_ADD_CONVERT_RIGHT:
      return os << "ConvertRight";
    case STRING_ADD_CONVERT:
      break;
340
  }
341 342 343 344 345 346 347 348 349 350
  UNREACHABLE();
  return os;
}


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


351
InlineCacheState CompareICStub::GetICState() const {
352
  CompareICState::State state = Max(left(), right());
353
  switch (state) {
354
    case CompareICState::UNINITIALIZED:
355
      return ::v8::internal::UNINITIALIZED;
356
    case CompareICState::BOOLEAN:
357 358 359 360 361
    case CompareICState::SMI:
    case CompareICState::NUMBER:
    case CompareICState::INTERNALIZED_STRING:
    case CompareICState::STRING:
    case CompareICState::UNIQUE_NAME:
362 363
    case CompareICState::RECEIVER:
    case CompareICState::KNOWN_RECEIVER:
364
      return MONOMORPHIC;
365
    case CompareICState::GENERIC:
366 367 368 369 370 371 372
      return ::v8::internal::GENERIC;
  }
  UNREACHABLE();
  return ::v8::internal::UNINITIALIZED;
}


373 374 375 376 377
Condition CompareICStub::GetCondition() const {
  return CompareIC::ComputeCondition(op());
}


378
void CompareICStub::AddToSpecialCache(Handle<Code> new_object) {
379
  DCHECK(*known_map_ != NULL);
380 381 382
  Isolate* isolate = new_object->GetIsolate();
  Factory* factory = isolate->factory();
  return Map::UpdateCodeCache(known_map_,
383
                              strict() ?
384 385
                                  factory->strict_compare_ic_string() :
                                  factory->compare_ic_string(),
386 387 388 389
                              new_object);
}


390
bool CompareICStub::FindCodeInSpecialCache(Code** code_out) {
391
  Factory* factory = isolate()->factory();
392
  Code::Flags flags = Code::ComputeFlags(
393
      GetCodeKind(),
394
      UNINITIALIZED);
395 396 397 398 399 400
  Handle<Object> probe(
      known_map_->FindInCodeCache(
        strict() ?
            *factory->strict_compare_ic_string() :
            *factory->compare_ic_string(),
        flags),
401
      isolate());
402 403
  if (probe->IsCode()) {
    *code_out = Code::cast(*probe);
404
#ifdef DEBUG
405
    CompareICStub decode((*code_out)->stub_key(), isolate());
406 407 408 409
    DCHECK(op() == decode.op());
    DCHECK(left() == decode.left());
    DCHECK(right() == decode.right());
    DCHECK(state() == decode.state());
410
#endif
411 412 413 414 415 416
    return true;
  }
  return false;
}


417
void CompareICStub::Generate(MacroAssembler* masm) {
418
  switch (state()) {
419
    case CompareICState::UNINITIALIZED:
420 421
      GenerateMiss(masm);
      break;
422 423 424
    case CompareICState::BOOLEAN:
      GenerateBooleans(masm);
      break;
425
    case CompareICState::SMI:
426 427
      GenerateSmis(masm);
      break;
428
    case CompareICState::NUMBER:
429
      GenerateNumbers(masm);
430
      break;
431
    case CompareICState::STRING:
432 433
      GenerateStrings(masm);
      break;
434
    case CompareICState::INTERNALIZED_STRING:
435
      GenerateInternalizedStrings(masm);
436
      break;
437
    case CompareICState::UNIQUE_NAME:
438 439
      GenerateUniqueNames(masm);
      break;
440 441
    case CompareICState::RECEIVER:
      GenerateReceivers(masm);
442
      break;
443
    case CompareICState::KNOWN_RECEIVER:
444
      DCHECK(*known_map_ != NULL);
445
      GenerateKnownReceivers(masm);
446
      break;
447
    case CompareICState::GENERIC:
448 449
      GenerateGeneric(masm);
      break;
450 451 452 453
  }
}


454
void CompareNilICStub::UpdateStatus(Handle<Object> object) {
455 456 457
  State state = this->state();
  DCHECK(!state.Contains(GENERIC));
  State old_state = state;
458
  if (object->IsNull()) {
459
    state.Add(NULL_TYPE);
460
  } else if (object->IsUndefined()) {
461
    state.Add(UNDEFINED);
462 463 464
  } else if (object->IsUndetectableObject() ||
             object->IsOddball() ||
             !object->IsHeapObject()) {
465 466
    state.RemoveAll();
    state.Add(GENERIC);
467
  } else if (IsMonomorphic()) {
468 469
    state.RemoveAll();
    state.Add(GENERIC);
470
  } else {
471
    state.Add(MONOMORPHIC_MAP);
472
  }
473 474
  TraceTransition(old_state, state);
  set_sub_minor_key(TypesBits::update(sub_minor_key(), state.ToIntegral()));
475 476 477
}


478
Handle<Code> TurboFanCodeStub::GenerateCode() {
479
  const char* name = CodeStub::MajorName(MajorKey());
480 481 482
  Zone zone;
  CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
  compiler::CodeStubAssembler assembler(isolate(), &zone, descriptor,
483
                                        GetCodeFlags(), name);
484 485 486 487 488 489 490 491 492 493 494 495 496
  GenerateAssembly(&assembler);
  return assembler.GenerateCode();
}


void StringLengthStub::GenerateAssembly(
    compiler::CodeStubAssembler* assembler) const {
  compiler::Node* value = assembler->Parameter(0);
  compiler::Node* string =
      assembler->LoadObjectField(value, JSValue::kValueOffset);
  compiler::Node* result =
      assembler->LoadObjectField(string, String::kLengthOffset);
  assembler->Return(result);
497 498 499
}


500 501
template<class StateType>
void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
502 503
  // Note: Although a no-op transition is semantically OK, it is hinting at a
  // bug somewhere in our state transition machinery.
504
  DCHECK(from != to);
505
  if (!FLAG_trace_ic) return;
506 507 508
  OFStream os(stdout);
  os << "[";
  PrintBaseName(os);
509
  os << ": " << from << "=>" << to << "]" << std::endl;
510 511
}

512

513
void CompareNilICStub::PrintBaseName(std::ostream& os) const {  // NOLINT
514
  CodeStub::PrintBaseName(os);
515
  os << ((nil_value() == kNullValue) ? "(NullValue)" : "(UndefinedValue)");
516
}
517

518

519
void CompareNilICStub::PrintState(std::ostream& os) const {  // NOLINT
520
  os << state();
521 522 523
}


524 525 526
// TODO(svenpanne) Make this a real infix_ostream_iterator.
class SimpleListPrinter {
 public:
527
  explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {}
528 529 530 531 532 533 534 535 536 537 538

  void Add(const char* s) {
    if (first_) {
      first_ = false;
    } else {
      os_ << ",";
    }
    os_ << s;
  }

 private:
539
  std::ostream& os_;
540 541 542 543
  bool first_;
};


544
std::ostream& operator<<(std::ostream& os, const CompareNilICStub::State& s) {
545 546 547 548 549 550 551 552
  os << "(";
  SimpleListPrinter p(os);
  if (s.IsEmpty()) p.Add("None");
  if (s.Contains(CompareNilICStub::UNDEFINED)) p.Add("Undefined");
  if (s.Contains(CompareNilICStub::NULL_TYPE)) p.Add("Null");
  if (s.Contains(CompareNilICStub::MONOMORPHIC_MAP)) p.Add("MonomorphicMap");
  if (s.Contains(CompareNilICStub::GENERIC)) p.Add("Generic");
  return os << ")";
553 554 555
}


556
Type* CompareNilICStub::GetType(Zone* zone, Handle<Map> map) {
557
  State state = this->state();
558
  if (state.Contains(CompareNilICStub::GENERIC)) return Type::Any();
559

560
  Type* result = Type::None();
561
  if (state.Contains(CompareNilICStub::UNDEFINED)) {
562
    result = Type::Union(result, Type::Undefined(), zone);
563
  }
564
  if (state.Contains(CompareNilICStub::NULL_TYPE)) {
565
    result = Type::Union(result, Type::Null(), zone);
566
  }
567
  if (state.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
568
    Type* type = map.is_null() ? Type::Detectable() : Type::Class(map, zone);
569
    result = Type::Union(result, type, zone);
570 571 572 573 574 575
  }

  return result;
}


576 577
Type* CompareNilICStub::GetInputType(Zone* zone, Handle<Map> map) {
  Type* output_type = GetType(zone, map);
578
  Type* nil_type = nil_value() == kNullValue ? Type::Null() : Type::Undefined();
579
  return Type::Union(output_type, nil_type, zone);
580 581 582
}


583
void CallICStub::PrintState(std::ostream& os) const {  // NOLINT
584
  os << state();
585 586 587
}


588 589 590 591 592 593 594 595
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);
}


596 597
void LoadDictionaryElementStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
598 599
  descriptor->Initialize(
      FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
600 601 602
}


603 604
void KeyedLoadGenericStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
605
  descriptor->Initialize(
606 607 608
      Runtime::FunctionForId(is_strong(language_mode())
                                 ? Runtime::kKeyedGetPropertyStrong
                                 : Runtime::kKeyedGetProperty)->entry);
609 610 611
}


612 613
void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
  if (kind() == Code::STORE_IC) {
614
    descriptor->Initialize(FUNCTION_ADDR(Runtime_StoreIC_MissFromStubFailure));
615
  } else if (kind() == Code::KEYED_LOAD_IC) {
616 617
    descriptor->Initialize(
        FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
618
  } else if (kind() == Code::KEYED_STORE_IC) {
619 620
    descriptor->Initialize(
        FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
621
  }
622 623 624
}


625
CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const {
626
  if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
627
    return LoadWithVectorDescriptor(isolate());
628
  } else {
629
    DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
630
    return VectorStoreICDescriptor(isolate());
631
  }
632 633 634
}


635 636
void StoreFastElementStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
637 638
  descriptor->Initialize(
      FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
639 640 641
}


642 643
void ElementsTransitionAndStoreStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
644 645
  descriptor->Initialize(
      FUNCTION_ADDR(Runtime_ElementsTransitionAndStoreIC_Miss));
646 647 648
}


649 650 651 652 653
void ToObjectStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
  descriptor->Initialize(Runtime::FunctionForId(Runtime::kToObject)->entry);
}


654 655
CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor()
    const {
656
  return VectorStoreTransitionDescriptor(isolate());
657 658 659 660 661
}


CallInterfaceDescriptor
ElementsTransitionAndStoreStub::GetCallInterfaceDescriptor() const {
662
  return VectorStoreTransitionDescriptor(isolate());
663 664
}

665 666 667 668 669

void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
  descriptor->Initialize(Runtime::FunctionForId(Runtime::kNewClosure)->entry);
}

670

671
void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
672 673


674 675 676
void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}


677
void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
678
  NumberToStringDescriptor call_descriptor(isolate());
679
  descriptor->Initialize(
680
      Runtime::FunctionForId(Runtime::kNumberToString)->entry);
681 682 683
}


684 685 686 687 688 689 690
void FastCloneRegExpStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
  FastCloneRegExpDescriptor call_descriptor(isolate());
  descriptor->Initialize(
      Runtime::FunctionForId(Runtime::kCreateRegExpLiteral)->entry);
}


691 692
void FastCloneShallowArrayStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
693
  FastCloneShallowArrayDescriptor call_descriptor(isolate());
694 695 696 697 698
  descriptor->Initialize(
      Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry);
}


699 700
void FastCloneShallowObjectStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
701
  FastCloneShallowObjectDescriptor call_descriptor(isolate());
702 703 704 705 706
  descriptor->Initialize(
      Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry);
}


707
void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {}
708 709


710 711 712
void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {}


713 714
void RegExpConstructResultStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
715
  descriptor->Initialize(
716
      Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry);
717 718 719
}


720 721
void TransitionElementsKindStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
722 723 724 725 726
  descriptor->Initialize(
      Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
}


727 728 729 730 731 732 733
void AllocateHeapNumberStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
  descriptor->Initialize(
      Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
}


734 735 736 737 738 739
void AllocateMutableHeapNumberStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
  descriptor->Initialize();
}


740 741 742 743 744 745
void AllocateInNewSpaceStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
  descriptor->Initialize();
}


746
void CompareNilICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
747 748 749
  descriptor->Initialize(FUNCTION_ADDR(Runtime_CompareNilIC_Miss));
  descriptor->SetMissHandler(ExternalReference(
      Runtime::FunctionForId(Runtime::kCompareNilIC_Miss), isolate()));
750 751
}

752 753

void ToBooleanStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
754 755 756
  descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
  descriptor->SetMissHandler(ExternalReference(
      Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate()));
757 758 759
}


760
void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
761 762 763
  descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
  descriptor->SetMissHandler(ExternalReference(
      Runtime::FunctionForId(Runtime::kBinaryOpIC_Miss), isolate()));
764 765 766
}


767 768
void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
769 770
  descriptor->Initialize(
      FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
771 772 773
}


774
void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
775
  descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry);
776 777 778
}


779 780 781 782 783 784 785
void GrowArrayElementsStub::InitializeDescriptor(
    CodeStubDescriptor* descriptor) {
  descriptor->Initialize(
      Runtime::FunctionForId(Runtime::kGrowArrayElements)->entry);
}


786 787 788 789 790 791
void TypeofStub::GenerateAheadOfTime(Isolate* isolate) {
  TypeofStub stub(isolate);
  stub.GetCode();
}


792
void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
793
  CreateAllocationSiteStub stub(isolate);
794
  stub.GetCode();
795 796 797
}


798 799 800 801 802 803
void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
  CreateWeakCellStub stub(isolate);
  stub.GetCode();
}


804
void StoreElementStub::Generate(MacroAssembler* masm) {
805 806
  DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind());
  ElementHandlerCompiler::GenerateStoreSlow(masm);
danno@chromium.org's avatar
danno@chromium.org committed
807 808 809
}


810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
// static
void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
  StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE)
      .GetCode();
  StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS,
                       STORE_AND_GROW_NO_TRANSITION).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();
  }
}


825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
  switch (type()) {
    case READ_ELEMENT:
      GenerateReadElement(masm);
      break;
    case NEW_SLOPPY_FAST:
      GenerateNewSloppyFast(masm);
      break;
    case NEW_SLOPPY_SLOW:
      GenerateNewSloppySlow(masm);
      break;
    case NEW_STRICT:
      GenerateNewStrict(masm);
      break;
  }
}


843
void ArgumentsAccessStub::PrintName(std::ostream& os) const {  // NOLINT
844
  os << "ArgumentsAccessStub_";
845
  switch (type()) {
846 847 848 849 850 851 852 853 854 855 856 857
    case READ_ELEMENT:
      os << "ReadElement";
      break;
    case NEW_SLOPPY_FAST:
      os << "NewSloppyFast";
      break;
    case NEW_SLOPPY_SLOW:
      os << "NewSloppySlow";
      break;
    case NEW_STRICT:
      os << "NewStrict";
      break;
858
  }
859
  return;
860 861 862
}


863
void ArrayConstructorStub::PrintName(std::ostream& os) const {  // NOLINT
864
  os << "ArrayConstructorStub";
865
  switch (argument_count()) {
866 867 868 869 870 871 872 873 874 875 876 877
    case ANY:
      os << "_Any";
      break;
    case NONE:
      os << "_None";
      break;
    case ONE:
      os << "_One";
      break;
    case MORE_THAN_ONE:
      os << "_More_Than_One";
      break;
878
  }
879
  return;
880 881 882
}


883 884 885
std::ostream& ArrayConstructorStubBase::BasePrintName(
    std::ostream& os,  // NOLINT
    const char* name) const {
886
  os << name << "_" << ElementsKindToString(elements_kind());
887
  if (override_mode() == DISABLE_ALLOCATION_SITES) {
888
    os << "_DISABLE_ALLOCATION_SITES";
889
  }
890
  return os;
891 892 893
}


894
bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
895 896 897 898
  Types new_types = types();
  Types old_types = new_types;
  bool to_boolean_value = new_types.UpdateStatus(object);
  TraceTransition(old_types, new_types);
899
  set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral()));
900 901 902 903
  return to_boolean_value;
}


904
void ToBooleanStub::PrintState(std::ostream& os) const {  // NOLINT
905
  os << types();
906 907 908
}


909
std::ostream& operator<<(std::ostream& os, const ToBooleanStub::Types& s) {
910 911 912 913 914 915 916 917 918 919 920
  os << "(";
  SimpleListPrinter p(os);
  if (s.IsEmpty()) p.Add("None");
  if (s.Contains(ToBooleanStub::UNDEFINED)) p.Add("Undefined");
  if (s.Contains(ToBooleanStub::BOOLEAN)) p.Add("Bool");
  if (s.Contains(ToBooleanStub::NULL_TYPE)) p.Add("Null");
  if (s.Contains(ToBooleanStub::SMI)) p.Add("Smi");
  if (s.Contains(ToBooleanStub::SPEC_OBJECT)) p.Add("SpecObject");
  if (s.Contains(ToBooleanStub::STRING)) p.Add("String");
  if (s.Contains(ToBooleanStub::SYMBOL)) p.Add("Symbol");
  if (s.Contains(ToBooleanStub::HEAP_NUMBER)) p.Add("HeapNumber");
921
  if (s.Contains(ToBooleanStub::SIMD_VALUE)) p.Add("SimdValue");
922
  return os << ")";
923 924 925
}


926
bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
927 928 929 930 931 932 933 934 935 936 937 938
  if (object->IsUndefined()) {
    Add(UNDEFINED);
    return false;
  } else if (object->IsBoolean()) {
    Add(BOOLEAN);
    return object->IsTrue();
  } else if (object->IsNull()) {
    Add(NULL_TYPE);
    return false;
  } else if (object->IsSmi()) {
    Add(SMI);
    return Smi::cast(*object)->value() != 0;
939
  } else if (object->IsJSReceiver()) {
940
    Add(SPEC_OBJECT);
941
    return !object->IsUndetectableObject();
942 943
  } else if (object->IsString()) {
    Add(STRING);
944 945
    return !object->IsUndetectableObject() &&
        String::cast(*object)->length() != 0;
946 947 948
  } else if (object->IsSymbol()) {
    Add(SYMBOL);
    return true;
949
  } else if (object->IsHeapNumber()) {
950
    DCHECK(!object->IsUndetectableObject());
951 952
    Add(HEAP_NUMBER);
    double value = HeapNumber::cast(*object)->value();
953
    return value != 0 && !std::isnan(value);
954
  } else if (object->IsSimd128Value()) {
955 956
    Add(SIMD_VALUE);
    return true;
957
  } else {
958 959 960
    // We should never see an internal object at runtime here!
    UNREACHABLE();
    return true;
961 962 963 964
  }
}


965
bool ToBooleanStub::Types::NeedsMap() const {
966 967 968 969
  return Contains(ToBooleanStub::SPEC_OBJECT) ||
         Contains(ToBooleanStub::STRING) || Contains(ToBooleanStub::SYMBOL) ||
         Contains(ToBooleanStub::HEAP_NUMBER) ||
         Contains(ToBooleanStub::SIMD_VALUE);
970 971 972
}


973
void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
974 975
  StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
  StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
976 977
  stub1.GetCode();
  stub2.GetCode();
978 979 980
}


981
void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
982 983 984
                                               intptr_t stack_pointer,
                                               Isolate* isolate) {
  FunctionEntryHook entry_hook = isolate->function_entry_hook();
985
  DCHECK(entry_hook != NULL);
986
  entry_hook(function, stack_pointer);
987 988 989
}


990
ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
991 992
    : PlatformCodeStub(isolate) {
  minor_key_ = ArgumentCountBits::encode(ANY);
993 994 995 996 997
  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
}


ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
998 999
                                           int argument_count)
    : PlatformCodeStub(isolate) {
1000
  if (argument_count == 0) {
1001
    minor_key_ = ArgumentCountBits::encode(NONE);
1002
  } else if (argument_count == 1) {
1003
    minor_key_ = ArgumentCountBits::encode(ONE);
1004
  } else if (argument_count >= 2) {
1005
    minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE);
1006 1007 1008 1009 1010 1011 1012
  } else {
    UNREACHABLE();
  }
  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
}


1013
InternalArrayConstructorStub::InternalArrayConstructorStub(
1014
    Isolate* isolate) : PlatformCodeStub(isolate) {
1015 1016 1017 1018
  InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
}


1019
Representation RepresentationFromType(Type* type) {
1020
  if (type->Is(Type::UntaggedIntegral())) {
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
    return Representation::Integer32();
  }

  if (type->Is(Type::TaggedSigned())) {
    return Representation::Smi();
  }

  if (type->Is(Type::UntaggedPointer())) {
    return Representation::External();
  }

  DCHECK(!type->Is(Type::Untagged()));
  return Representation::Tagged();
}
1035

1036 1037
}  // namespace internal
}  // namespace v8