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