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/v8.h"
6
7#include "src/bootstrapper.h"
8#include "src/code-stubs.h"
9#include "src/cpu-profiler.h"
10#include "src/factory.h"
11#include "src/gdb-jit.h"
12#include "src/ic/handler-compiler.h"
13#include "src/ic/ic.h"
14#include "src/macro-assembler.h"
15
16namespace v8 {
17namespace internal {
18
19
20CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
21    : call_descriptor_(stub->GetCallInterfaceDescriptor()),
22      stack_parameter_count_(no_reg),
23      hint_stack_parameter_count_(-1),
24      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
25      deoptimization_handler_(NULL),
26      handler_arguments_mode_(DONT_PASS_ARGUMENTS),
27      miss_handler_(),
28      has_miss_handler_(false) {
29  stub->InitializeDescriptor(this);
30}
31
32
33CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
34    : stack_parameter_count_(no_reg),
35      hint_stack_parameter_count_(-1),
36      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
37      deoptimization_handler_(NULL),
38      handler_arguments_mode_(DONT_PASS_ARGUMENTS),
39      miss_handler_(),
40      has_miss_handler_(false) {
41  CodeStub::InitializeDescriptor(isolate, stub_key, this);
42}
43
44
45void CodeStubDescriptor::Initialize(Address deoptimization_handler,
46                                    int hint_stack_parameter_count,
47                                    StubFunctionMode function_mode) {
48  deoptimization_handler_ = deoptimization_handler;
49  hint_stack_parameter_count_ = hint_stack_parameter_count;
50  function_mode_ = function_mode;
51}
52
53
54void CodeStubDescriptor::Initialize(Register stack_parameter_count,
55                                    Address deoptimization_handler,
56                                    int hint_stack_parameter_count,
57                                    StubFunctionMode function_mode,
58                                    HandlerArgumentsMode handler_mode) {
59  Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
60  stack_parameter_count_ = stack_parameter_count;
61  handler_arguments_mode_ = handler_mode;
62}
63
64
65bool CodeStub::FindCodeInCache(Code** code_out) {
66  UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
67  int index = stubs->FindEntry(GetKey());
68  if (index != UnseededNumberDictionary::kNotFound) {
69    *code_out = Code::cast(stubs->ValueAt(index));
70    return true;
71  }
72  return false;
73}
74
75
76void CodeStub::RecordCodeGeneration(Handle<Code> code) {
77  IC::RegisterWeakMapDependency(code);
78  OStringStream os;
79  os << *this;
80  PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, os.c_str()));
81  Counters* counters = isolate()->counters();
82  counters->total_stubs_code_size()->Increment(code->instruction_size());
83}
84
85
86Code::Kind CodeStub::GetCodeKind() const {
87  return Code::STUB;
88}
89
90
91Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) {
92  Handle<Code> ic = GetCode();
93  ic = isolate()->factory()->CopyCode(ic);
94  ic->FindAndReplace(pattern);
95  RecordCodeGeneration(ic);
96  return ic;
97}
98
99
100Handle<Code> PlatformCodeStub::GenerateCode() {
101  Factory* factory = isolate()->factory();
102
103  // Generate the new code.
104  MacroAssembler masm(isolate(), NULL, 256);
105
106  // TODO(yangguo) remove this once the code serializer handles code stubs.
107  if (FLAG_serialize_toplevel) masm.enable_serializer();
108
109  {
110    // Update the static counter each time a new code stub is generated.
111    isolate()->counters()->code_stubs()->Increment();
112
113    // Generate the code for the stub.
114    masm.set_generating_stub(true);
115    NoCurrentFrameScope scope(&masm);
116    Generate(&masm);
117  }
118
119  // Create the code object.
120  CodeDesc desc;
121  masm.GetCode(&desc);
122
123  // Copy the generated code into a heap object.
124  Code::Flags flags = Code::ComputeFlags(
125      GetCodeKind(),
126      GetICState(),
127      GetExtraICState(),
128      GetStubType());
129  Handle<Code> new_object = factory->NewCode(
130      desc, flags, masm.CodeObject(), NeedsImmovableCode());
131  return new_object;
132}
133
134
135Handle<Code> CodeStub::GetCode() {
136  Heap* heap = isolate()->heap();
137  Code* code;
138  if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
139                        : FindCodeInCache(&code)) {
140    DCHECK(GetCodeKind() == code->kind());
141    return Handle<Code>(code);
142  }
143
144  {
145    HandleScope scope(isolate());
146
147    Handle<Code> new_object = GenerateCode();
148    new_object->set_stub_key(GetKey());
149    FinishCode(new_object);
150    RecordCodeGeneration(new_object);
151
152#ifdef ENABLE_DISASSEMBLER
153    if (FLAG_print_code_stubs) {
154      CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
155      OFStream os(trace_scope.file());
156      OStringStream name;
157      name << *this;
158      new_object->Disassemble(name.c_str(), os);
159      os << "\n";
160    }
161#endif
162
163    if (UseSpecialCache()) {
164      AddToSpecialCache(new_object);
165    } else {
166      // Update the dictionary and the root in Heap.
167      Handle<UnseededNumberDictionary> dict =
168          UnseededNumberDictionary::AtNumberPut(
169              Handle<UnseededNumberDictionary>(heap->code_stubs()),
170              GetKey(),
171              new_object);
172      heap->public_set_code_stubs(*dict);
173    }
174    code = *new_object;
175  }
176
177  Activate(code);
178  DCHECK(!NeedsImmovableCode() ||
179         heap->lo_space()->Contains(code) ||
180         heap->code_space()->FirstPage()->Contains(code->address()));
181  return Handle<Code>(code, isolate());
182}
183
184
185const char* CodeStub::MajorName(CodeStub::Major major_key,
186                                bool allow_unknown_keys) {
187  switch (major_key) {
188#define DEF_CASE(name) case name: return #name "Stub";
189    CODE_STUB_LIST(DEF_CASE)
190#undef DEF_CASE
191    case NoCache:
192      return "<NoCache>Stub";
193    case NUMBER_OF_IDS:
194      UNREACHABLE();
195      return NULL;
196  }
197  return NULL;
198}
199
200
201void CodeStub::PrintBaseName(OStream& os) const {  // NOLINT
202  os << MajorName(MajorKey(), false);
203}
204
205
206void CodeStub::PrintName(OStream& os) const {  // NOLINT
207  PrintBaseName(os);
208  PrintState(os);
209}
210
211
212void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
213                        DispatchedCall call) {
214  switch (MajorKeyFromKey(key)) {
215#define DEF_CASE(NAME)             \
216  case NAME: {                     \
217    NAME##Stub stub(key, isolate); \
218    CodeStub* pstub = &stub;       \
219    call(pstub, value_out);        \
220    break;                         \
221  }
222    CODE_STUB_LIST(DEF_CASE)
223#undef DEF_CASE
224    case NUMBER_OF_IDS:
225      UNREACHABLE();
226    case NoCache:
227      *value_out = NULL;
228      break;
229  }
230}
231
232
233static void InitializeDescriptorDispatchedCall(CodeStub* stub,
234                                               void** value_out) {
235  CodeStubDescriptor* descriptor_out =
236      reinterpret_cast<CodeStubDescriptor*>(value_out);
237  stub->InitializeDescriptor(descriptor_out);
238  descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
239}
240
241
242void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
243                                    CodeStubDescriptor* desc) {
244  void** value_out = reinterpret_cast<void**>(desc);
245  Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
246}
247
248
249void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
250  Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
251  // Code stubs with special cache cannot be recreated from stub key.
252  *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
253}
254
255
256MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
257  HandleScope scope(isolate);
258  Handle<Code> code;
259  void** value_out = reinterpret_cast<void**>(&code);
260  Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
261  return scope.CloseAndEscape(code);
262}
263
264
265// static
266void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
267  // Generate the uninitialized versions of the stub.
268  for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
269    for (int mode = NO_OVERWRITE; mode <= OVERWRITE_RIGHT; ++mode) {
270      BinaryOpICStub stub(isolate,
271                          static_cast<Token::Value>(op),
272                          static_cast<OverwriteMode>(mode));
273      stub.GetCode();
274    }
275  }
276
277  // Generate special versions of the stub.
278  BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
279}
280
281
282void BinaryOpICStub::PrintState(OStream& os) const {  // NOLINT
283  os << state();
284}
285
286
287// static
288void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
289                                         const BinaryOpICState& state) {
290  BinaryOpICStub stub(isolate, state);
291  stub.GetCode();
292}
293
294
295// static
296void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
297  // Generate special versions of the stub.
298  BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
299}
300
301
302void BinaryOpICWithAllocationSiteStub::PrintState(
303    OStream& os) const {  // NOLINT
304  os << state();
305}
306
307
308// static
309void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
310    Isolate* isolate, const BinaryOpICState& state) {
311  if (state.CouldCreateAllocationMementos()) {
312    BinaryOpICWithAllocationSiteStub stub(isolate, state);
313    stub.GetCode();
314  }
315}
316
317
318void StringAddStub::PrintBaseName(OStream& os) const {  // NOLINT
319  os << "StringAddStub";
320  if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
321    os << "_CheckBoth";
322  } else if ((flags() & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
323    os << "_CheckLeft";
324  } else if ((flags() & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
325    os << "_CheckRight";
326  }
327  if (pretenure_flag() == TENURED) {
328    os << "_Tenured";
329  }
330}
331
332
333InlineCacheState CompareICStub::GetICState() const {
334  CompareICState::State state = Max(left(), right());
335  switch (state) {
336    case CompareICState::UNINITIALIZED:
337      return ::v8::internal::UNINITIALIZED;
338    case CompareICState::SMI:
339    case CompareICState::NUMBER:
340    case CompareICState::INTERNALIZED_STRING:
341    case CompareICState::STRING:
342    case CompareICState::UNIQUE_NAME:
343    case CompareICState::OBJECT:
344    case CompareICState::KNOWN_OBJECT:
345      return MONOMORPHIC;
346    case CompareICState::GENERIC:
347      return ::v8::internal::GENERIC;
348  }
349  UNREACHABLE();
350  return ::v8::internal::UNINITIALIZED;
351}
352
353
354Condition CompareICStub::GetCondition() const {
355  return CompareIC::ComputeCondition(op());
356}
357
358
359void CompareICStub::AddToSpecialCache(Handle<Code> new_object) {
360  DCHECK(*known_map_ != NULL);
361  Isolate* isolate = new_object->GetIsolate();
362  Factory* factory = isolate->factory();
363  return Map::UpdateCodeCache(known_map_,
364                              strict() ?
365                                  factory->strict_compare_ic_string() :
366                                  factory->compare_ic_string(),
367                              new_object);
368}
369
370
371bool CompareICStub::FindCodeInSpecialCache(Code** code_out) {
372  Factory* factory = isolate()->factory();
373  Code::Flags flags = Code::ComputeFlags(
374      GetCodeKind(),
375      UNINITIALIZED);
376  DCHECK(op() == Token::EQ || op() == Token::EQ_STRICT);
377  Handle<Object> probe(
378      known_map_->FindInCodeCache(
379        strict() ?
380            *factory->strict_compare_ic_string() :
381            *factory->compare_ic_string(),
382        flags),
383      isolate());
384  if (probe->IsCode()) {
385    *code_out = Code::cast(*probe);
386#ifdef DEBUG
387    CompareICStub decode((*code_out)->stub_key(), isolate());
388    DCHECK(op() == decode.op());
389    DCHECK(left() == decode.left());
390    DCHECK(right() == decode.right());
391    DCHECK(state() == decode.state());
392#endif
393    return true;
394  }
395  return false;
396}
397
398
399void CompareICStub::Generate(MacroAssembler* masm) {
400  switch (state()) {
401    case CompareICState::UNINITIALIZED:
402      GenerateMiss(masm);
403      break;
404    case CompareICState::SMI:
405      GenerateSmis(masm);
406      break;
407    case CompareICState::NUMBER:
408      GenerateNumbers(masm);
409      break;
410    case CompareICState::STRING:
411      GenerateStrings(masm);
412      break;
413    case CompareICState::INTERNALIZED_STRING:
414      GenerateInternalizedStrings(masm);
415      break;
416    case CompareICState::UNIQUE_NAME:
417      GenerateUniqueNames(masm);
418      break;
419    case CompareICState::OBJECT:
420      GenerateObjects(masm);
421      break;
422    case CompareICState::KNOWN_OBJECT:
423      DCHECK(*known_map_ != NULL);
424      GenerateKnownObjects(masm);
425      break;
426    case CompareICState::GENERIC:
427      GenerateGeneric(masm);
428      break;
429  }
430}
431
432
433void CompareNilICStub::UpdateStatus(Handle<Object> object) {
434  State state = this->state();
435  DCHECK(!state.Contains(GENERIC));
436  State old_state = state;
437  if (object->IsNull()) {
438    state.Add(NULL_TYPE);
439  } else if (object->IsUndefined()) {
440    state.Add(UNDEFINED);
441  } else if (object->IsUndetectableObject() ||
442             object->IsOddball() ||
443             !object->IsHeapObject()) {
444    state.RemoveAll();
445    state.Add(GENERIC);
446  } else if (IsMonomorphic()) {
447    state.RemoveAll();
448    state.Add(GENERIC);
449  } else {
450    state.Add(MONOMORPHIC_MAP);
451  }
452  TraceTransition(old_state, state);
453  set_sub_minor_key(TypesBits::update(sub_minor_key(), state.ToIntegral()));
454}
455
456
457template<class StateType>
458void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
459  // Note: Although a no-op transition is semantically OK, it is hinting at a
460  // bug somewhere in our state transition machinery.
461  DCHECK(from != to);
462  if (!FLAG_trace_ic) return;
463  OFStream os(stdout);
464  os << "[";
465  PrintBaseName(os);
466  os << ": " << from << "=>" << to << "]" << endl;
467}
468
469
470void CompareNilICStub::PrintBaseName(OStream& os) const {  // NOLINT
471  CodeStub::PrintBaseName(os);
472  os << ((nil_value() == kNullValue) ? "(NullValue)" : "(UndefinedValue)");
473}
474
475
476void CompareNilICStub::PrintState(OStream& os) const {  // NOLINT
477  os << state();
478}
479
480
481// TODO(svenpanne) Make this a real infix_ostream_iterator.
482class SimpleListPrinter {
483 public:
484  explicit SimpleListPrinter(OStream& os) : os_(os), first_(true) {}
485
486  void Add(const char* s) {
487    if (first_) {
488      first_ = false;
489    } else {
490      os_ << ",";
491    }
492    os_ << s;
493  }
494
495 private:
496  OStream& os_;
497  bool first_;
498};
499
500
501OStream& operator<<(OStream& os, const CompareNilICStub::State& s) {
502  os << "(";
503  SimpleListPrinter p(os);
504  if (s.IsEmpty()) p.Add("None");
505  if (s.Contains(CompareNilICStub::UNDEFINED)) p.Add("Undefined");
506  if (s.Contains(CompareNilICStub::NULL_TYPE)) p.Add("Null");
507  if (s.Contains(CompareNilICStub::MONOMORPHIC_MAP)) p.Add("MonomorphicMap");
508  if (s.Contains(CompareNilICStub::GENERIC)) p.Add("Generic");
509  return os << ")";
510}
511
512
513Type* CompareNilICStub::GetType(Zone* zone, Handle<Map> map) {
514  State state = this->state();
515  if (state.Contains(CompareNilICStub::GENERIC)) return Type::Any(zone);
516
517  Type* result = Type::None(zone);
518  if (state.Contains(CompareNilICStub::UNDEFINED)) {
519    result = Type::Union(result, Type::Undefined(zone), zone);
520  }
521  if (state.Contains(CompareNilICStub::NULL_TYPE)) {
522    result = Type::Union(result, Type::Null(zone), zone);
523  }
524  if (state.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
525    Type* type =
526        map.is_null() ? Type::Detectable(zone) : Type::Class(map, zone);
527    result = Type::Union(result, type, zone);
528  }
529
530  return result;
531}
532
533
534Type* CompareNilICStub::GetInputType(Zone* zone, Handle<Map> map) {
535  Type* output_type = GetType(zone, map);
536  Type* nil_type =
537      nil_value() == kNullValue ? Type::Null(zone) : Type::Undefined(zone);
538  return Type::Union(output_type, nil_type, zone);
539}
540
541
542void CallIC_ArrayStub::PrintState(OStream& os) const {  // NOLINT
543  os << state() << " (Array)";
544}
545
546
547void CallICStub::PrintState(OStream& os) const {  // NOLINT
548  os << state();
549}
550
551
552void InstanceofStub::PrintName(OStream& os) const {  // NOLINT
553  os << "InstanceofStub";
554  if (HasArgsInRegisters()) os << "_REGS";
555  if (HasCallSiteInlineCheck()) os << "_INLINE";
556  if (ReturnTrueFalseObject()) os << "_TRUEFALSE";
557}
558
559
560void JSEntryStub::FinishCode(Handle<Code> code) {
561  Handle<FixedArray> handler_table =
562      code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
563  handler_table->set(0, Smi::FromInt(handler_offset_));
564  code->set_handler_table(*handler_table);
565}
566
567
568void LoadFastElementStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
569  descriptor->Initialize(FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
570}
571
572
573void LoadDictionaryElementStub::InitializeDescriptor(
574    CodeStubDescriptor* descriptor) {
575  descriptor->Initialize(FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
576}
577
578
579void KeyedLoadGenericStub::InitializeDescriptor(
580    CodeStubDescriptor* descriptor) {
581  descriptor->Initialize(
582      Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry);
583}
584
585
586void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
587  if (kind() == Code::STORE_IC) {
588    descriptor->Initialize(FUNCTION_ADDR(StoreIC_MissFromStubFailure));
589  } else if (kind() == Code::KEYED_LOAD_IC) {
590    descriptor->Initialize(FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
591  }
592}
593
594
595CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() {
596  if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
597    return LoadDescriptor(isolate());
598  } else {
599    DCHECK_EQ(Code::STORE_IC, kind());
600    return StoreDescriptor(isolate());
601  }
602}
603
604
605void StoreFastElementStub::InitializeDescriptor(
606    CodeStubDescriptor* descriptor) {
607  descriptor->Initialize(FUNCTION_ADDR(KeyedStoreIC_MissFromStubFailure));
608}
609
610
611void ElementsTransitionAndStoreStub::InitializeDescriptor(
612    CodeStubDescriptor* descriptor) {
613  descriptor->Initialize(FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss));
614}
615
616
617static void InitializeVectorLoadStub(Isolate* isolate,
618                                     CodeStubDescriptor* descriptor,
619                                     Address deoptimization_handler) {
620  DCHECK(FLAG_vector_ics);
621  descriptor->Initialize(deoptimization_handler);
622}
623
624
625void VectorLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
626  InitializeVectorLoadStub(isolate(), descriptor,
627                           FUNCTION_ADDR(VectorLoadIC_MissFromStubFailure));
628}
629
630
631void VectorKeyedLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
632  InitializeVectorLoadStub(
633      isolate(), descriptor,
634      FUNCTION_ADDR(VectorKeyedLoadIC_MissFromStubFailure));
635}
636
637
638void MegamorphicLoadStub::InitializeDescriptor(CodeStubDescriptor* d) {}
639
640
641void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
642  descriptor->Initialize(
643      Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry);
644}
645
646
647void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
648
649
650void ToNumberStub::InitializeDescriptor(CodeStubDescriptor* d) {}
651
652
653void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
654  NumberToStringDescriptor call_descriptor(isolate());
655  descriptor->Initialize(
656      Runtime::FunctionForId(Runtime::kNumberToStringRT)->entry);
657}
658
659
660void FastCloneShallowArrayStub::InitializeDescriptor(
661    CodeStubDescriptor* descriptor) {
662  FastCloneShallowArrayDescriptor call_descriptor(isolate());
663  descriptor->Initialize(
664      Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry);
665}
666
667
668void FastCloneShallowObjectStub::InitializeDescriptor(
669    CodeStubDescriptor* descriptor) {
670  FastCloneShallowObjectDescriptor call_descriptor(isolate());
671  descriptor->Initialize(
672      Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry);
673}
674
675
676void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {}
677
678
679void RegExpConstructResultStub::InitializeDescriptor(
680    CodeStubDescriptor* descriptor) {
681  descriptor->Initialize(
682      Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry);
683}
684
685
686void TransitionElementsKindStub::InitializeDescriptor(
687    CodeStubDescriptor* descriptor) {
688  descriptor->Initialize(
689      Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
690}
691
692
693void CompareNilICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
694  descriptor->Initialize(FUNCTION_ADDR(CompareNilIC_Miss));
695  descriptor->SetMissHandler(
696      ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate()));
697}
698
699
700void ToBooleanStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
701  descriptor->Initialize(FUNCTION_ADDR(ToBooleanIC_Miss));
702  descriptor->SetMissHandler(
703      ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate()));
704}
705
706
707void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
708  descriptor->Initialize(FUNCTION_ADDR(BinaryOpIC_Miss));
709  descriptor->SetMissHandler(
710      ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate()));
711}
712
713
714void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
715    CodeStubDescriptor* descriptor) {
716  descriptor->Initialize(FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite));
717}
718
719
720void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
721  descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry);
722}
723
724
725void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
726  CreateAllocationSiteStub stub(isolate);
727  stub.GetCode();
728}
729
730
731void StoreElementStub::Generate(MacroAssembler* masm) {
732  switch (elements_kind()) {
733    case FAST_ELEMENTS:
734    case FAST_HOLEY_ELEMENTS:
735    case FAST_SMI_ELEMENTS:
736    case FAST_HOLEY_SMI_ELEMENTS:
737    case FAST_DOUBLE_ELEMENTS:
738    case FAST_HOLEY_DOUBLE_ELEMENTS:
739#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
740    case EXTERNAL_##TYPE##_ELEMENTS:                    \
741    case TYPE##_ELEMENTS:
742
743    TYPED_ARRAYS(TYPED_ARRAY_CASE)
744#undef TYPED_ARRAY_CASE
745      UNREACHABLE();
746      break;
747    case DICTIONARY_ELEMENTS:
748      ElementHandlerCompiler::GenerateStoreSlow(masm);
749      break;
750    case SLOPPY_ARGUMENTS_ELEMENTS:
751      UNREACHABLE();
752      break;
753  }
754}
755
756
757void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
758  switch (type()) {
759    case READ_ELEMENT:
760      GenerateReadElement(masm);
761      break;
762    case NEW_SLOPPY_FAST:
763      GenerateNewSloppyFast(masm);
764      break;
765    case NEW_SLOPPY_SLOW:
766      GenerateNewSloppySlow(masm);
767      break;
768    case NEW_STRICT:
769      GenerateNewStrict(masm);
770      break;
771  }
772}
773
774
775void ArgumentsAccessStub::PrintName(OStream& os) const {  // NOLINT
776  os << "ArgumentsAccessStub_";
777  switch (type()) {
778    case READ_ELEMENT:
779      os << "ReadElement";
780      break;
781    case NEW_SLOPPY_FAST:
782      os << "NewSloppyFast";
783      break;
784    case NEW_SLOPPY_SLOW:
785      os << "NewSloppySlow";
786      break;
787    case NEW_STRICT:
788      os << "NewStrict";
789      break;
790  }
791  return;
792}
793
794
795void CallFunctionStub::PrintName(OStream& os) const {  // NOLINT
796  os << "CallFunctionStub_Args" << argc();
797}
798
799
800void CallConstructStub::PrintName(OStream& os) const {  // NOLINT
801  os << "CallConstructStub";
802  if (RecordCallTarget()) os << "_Recording";
803}
804
805
806void ArrayConstructorStub::PrintName(OStream& os) const {  // NOLINT
807  os << "ArrayConstructorStub";
808  switch (argument_count()) {
809    case ANY:
810      os << "_Any";
811      break;
812    case NONE:
813      os << "_None";
814      break;
815    case ONE:
816      os << "_One";
817      break;
818    case MORE_THAN_ONE:
819      os << "_More_Than_One";
820      break;
821  }
822  return;
823}
824
825
826OStream& ArrayConstructorStubBase::BasePrintName(OStream& os,  // NOLINT
827                                                 const char* name) const {
828  os << name << "_" << ElementsKindToString(elements_kind());
829  if (override_mode() == DISABLE_ALLOCATION_SITES) {
830    os << "_DISABLE_ALLOCATION_SITES";
831  }
832  return os;
833}
834
835
836bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
837  Types new_types = types();
838  Types old_types = new_types;
839  bool to_boolean_value = new_types.UpdateStatus(object);
840  TraceTransition(old_types, new_types);
841  set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToByte()));
842  return to_boolean_value;
843}
844
845
846void ToBooleanStub::PrintState(OStream& os) const {  // NOLINT
847  os << types();
848}
849
850
851OStream& operator<<(OStream& os, const ToBooleanStub::Types& s) {
852  os << "(";
853  SimpleListPrinter p(os);
854  if (s.IsEmpty()) p.Add("None");
855  if (s.Contains(ToBooleanStub::UNDEFINED)) p.Add("Undefined");
856  if (s.Contains(ToBooleanStub::BOOLEAN)) p.Add("Bool");
857  if (s.Contains(ToBooleanStub::NULL_TYPE)) p.Add("Null");
858  if (s.Contains(ToBooleanStub::SMI)) p.Add("Smi");
859  if (s.Contains(ToBooleanStub::SPEC_OBJECT)) p.Add("SpecObject");
860  if (s.Contains(ToBooleanStub::STRING)) p.Add("String");
861  if (s.Contains(ToBooleanStub::SYMBOL)) p.Add("Symbol");
862  if (s.Contains(ToBooleanStub::HEAP_NUMBER)) p.Add("HeapNumber");
863  return os << ")";
864}
865
866
867bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
868  if (object->IsUndefined()) {
869    Add(UNDEFINED);
870    return false;
871  } else if (object->IsBoolean()) {
872    Add(BOOLEAN);
873    return object->IsTrue();
874  } else if (object->IsNull()) {
875    Add(NULL_TYPE);
876    return false;
877  } else if (object->IsSmi()) {
878    Add(SMI);
879    return Smi::cast(*object)->value() != 0;
880  } else if (object->IsSpecObject()) {
881    Add(SPEC_OBJECT);
882    return !object->IsUndetectableObject();
883  } else if (object->IsString()) {
884    Add(STRING);
885    return !object->IsUndetectableObject() &&
886        String::cast(*object)->length() != 0;
887  } else if (object->IsSymbol()) {
888    Add(SYMBOL);
889    return true;
890  } else if (object->IsHeapNumber()) {
891    DCHECK(!object->IsUndetectableObject());
892    Add(HEAP_NUMBER);
893    double value = HeapNumber::cast(*object)->value();
894    return value != 0 && !std::isnan(value);
895  } else {
896    // We should never see an internal object at runtime here!
897    UNREACHABLE();
898    return true;
899  }
900}
901
902
903bool ToBooleanStub::Types::NeedsMap() const {
904  return Contains(ToBooleanStub::SPEC_OBJECT)
905      || Contains(ToBooleanStub::STRING)
906      || Contains(ToBooleanStub::SYMBOL)
907      || Contains(ToBooleanStub::HEAP_NUMBER);
908}
909
910
911bool ToBooleanStub::Types::CanBeUndetectable() const {
912  return Contains(ToBooleanStub::SPEC_OBJECT)
913      || Contains(ToBooleanStub::STRING);
914}
915
916
917void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
918  StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
919  StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
920  stub1.GetCode();
921  stub2.GetCode();
922}
923
924
925void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
926                                               intptr_t stack_pointer,
927                                               Isolate* isolate) {
928  FunctionEntryHook entry_hook = isolate->function_entry_hook();
929  DCHECK(entry_hook != NULL);
930  entry_hook(function, stack_pointer);
931}
932
933
934ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
935    : PlatformCodeStub(isolate) {
936  minor_key_ = ArgumentCountBits::encode(ANY);
937  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
938}
939
940
941ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
942                                           int argument_count)
943    : PlatformCodeStub(isolate) {
944  if (argument_count == 0) {
945    minor_key_ = ArgumentCountBits::encode(NONE);
946  } else if (argument_count == 1) {
947    minor_key_ = ArgumentCountBits::encode(ONE);
948  } else if (argument_count >= 2) {
949    minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE);
950  } else {
951    UNREACHABLE();
952  }
953  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
954}
955
956
957InternalArrayConstructorStub::InternalArrayConstructorStub(
958    Isolate* isolate) : PlatformCodeStub(isolate) {
959  InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
960}
961
962
963} }  // namespace v8::internal
964