ee57db741e3714ef45c5fb913c17b1f5a2461126
[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 RUNTIME_FUNCTION(UnexpectedStubMiss) {
23   FATAL("Unexpected deopt of a stub");
24   return Smi::FromInt(0);
25 }
26
27
28 CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
29     : call_descriptor_(stub->GetCallInterfaceDescriptor()),
30       stack_parameter_count_(no_reg),
31       hint_stack_parameter_count_(-1),
32       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
33       deoptimization_handler_(NULL),
34       miss_handler_(),
35       has_miss_handler_(false) {
36   stub->InitializeDescriptor(this);
37 }
38
39
40 CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
41     : stack_parameter_count_(no_reg),
42       hint_stack_parameter_count_(-1),
43       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
44       deoptimization_handler_(NULL),
45       miss_handler_(),
46       has_miss_handler_(false) {
47   CodeStub::InitializeDescriptor(isolate, stub_key, this);
48 }
49
50
51 void CodeStubDescriptor::Initialize(Address deoptimization_handler,
52                                     int hint_stack_parameter_count,
53                                     StubFunctionMode function_mode) {
54   deoptimization_handler_ = deoptimization_handler;
55   hint_stack_parameter_count_ = hint_stack_parameter_count;
56   function_mode_ = function_mode;
57 }
58
59
60 void CodeStubDescriptor::Initialize(Register stack_parameter_count,
61                                     Address deoptimization_handler,
62                                     int hint_stack_parameter_count,
63                                     StubFunctionMode function_mode) {
64   Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
65   stack_parameter_count_ = stack_parameter_count;
66 }
67
68
69 bool CodeStub::FindCodeInCache(Code** code_out) {
70   UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
71   int index = stubs->FindEntry(GetKey());
72   if (index != UnseededNumberDictionary::kNotFound) {
73     *code_out = Code::cast(stubs->ValueAt(index));
74     return true;
75   }
76   return false;
77 }
78
79
80 void CodeStub::RecordCodeGeneration(Handle<Code> code) {
81   std::ostringstream os;
82   os << *this;
83   PROFILE(isolate(),
84           CodeCreateEvent(Logger::STUB_TAG, *code, os.str().c_str()));
85   Counters* counters = isolate()->counters();
86   counters->total_stubs_code_size()->Increment(code->instruction_size());
87 #ifdef DEBUG
88   code->VerifyEmbeddedObjects();
89 #endif
90 }
91
92
93 Code::Kind CodeStub::GetCodeKind() const {
94   return Code::STUB;
95 }
96
97
98 Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) {
99   Handle<Code> ic = GetCode();
100   ic = isolate()->factory()->CopyCode(ic);
101   ic->FindAndReplace(pattern);
102   RecordCodeGeneration(ic);
103   return ic;
104 }
105
106
107 Handle<Code> PlatformCodeStub::GenerateCode() {
108   Factory* factory = isolate()->factory();
109
110   // Generate the new code.
111   MacroAssembler masm(isolate(), NULL, 256);
112
113   {
114     // Update the static counter each time a new code stub is generated.
115     isolate()->counters()->code_stubs()->Increment();
116
117     // Generate the code for the stub.
118     masm.set_generating_stub(true);
119     // TODO(yangguo): remove this once we can serialize IC stubs.
120     masm.enable_serializer();
121     NoCurrentFrameScope scope(&masm);
122     Generate(&masm);
123   }
124
125   // Create the code object.
126   CodeDesc desc;
127   masm.GetCode(&desc);
128   // Copy the generated code into a heap object.
129   Code::Flags flags = Code::ComputeFlags(
130       GetCodeKind(),
131       GetICState(),
132       GetExtraICState(),
133       GetStubType());
134   Handle<Code> new_object = factory->NewCode(
135       desc, flags, masm.CodeObject(), NeedsImmovableCode());
136   return new_object;
137 }
138
139
140 Handle<Code> CodeStub::GetCode() {
141   Heap* heap = isolate()->heap();
142   Code* code;
143   if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
144                         : FindCodeInCache(&code)) {
145     DCHECK(GetCodeKind() == code->kind());
146     return Handle<Code>(code);
147   }
148
149   {
150     HandleScope scope(isolate());
151
152     Handle<Code> new_object = GenerateCode();
153     new_object->set_stub_key(GetKey());
154     FinishCode(new_object);
155     RecordCodeGeneration(new_object);
156
157 #ifdef ENABLE_DISASSEMBLER
158     if (FLAG_print_code_stubs) {
159       CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
160       OFStream os(trace_scope.file());
161       std::ostringstream name;
162       name << *this;
163       new_object->Disassemble(name.str().c_str(), os);
164       os << "\n";
165     }
166 #endif
167
168     if (UseSpecialCache()) {
169       AddToSpecialCache(new_object);
170     } else {
171       // Update the dictionary and the root in Heap.
172       Handle<UnseededNumberDictionary> dict =
173           UnseededNumberDictionary::AtNumberPut(
174               Handle<UnseededNumberDictionary>(heap->code_stubs()),
175               GetKey(),
176               new_object);
177       heap->public_set_code_stubs(*dict);
178     }
179     code = *new_object;
180   }
181
182   Activate(code);
183   DCHECK(!NeedsImmovableCode() ||
184          heap->lo_space()->Contains(code) ||
185          heap->code_space()->FirstPage()->Contains(code->address()));
186   return Handle<Code>(code, isolate());
187 }
188
189
190 const char* CodeStub::MajorName(CodeStub::Major major_key,
191                                 bool allow_unknown_keys) {
192   switch (major_key) {
193 #define DEF_CASE(name) case name: return #name "Stub";
194     CODE_STUB_LIST(DEF_CASE)
195 #undef DEF_CASE
196     case NoCache:
197       return "<NoCache>Stub";
198     case NUMBER_OF_IDS:
199       UNREACHABLE();
200       return NULL;
201   }
202   return NULL;
203 }
204
205
206 void CodeStub::PrintBaseName(std::ostream& os) const {  // NOLINT
207   os << MajorName(MajorKey(), false);
208 }
209
210
211 void CodeStub::PrintName(std::ostream& os) const {  // NOLINT
212   PrintBaseName(os);
213   PrintState(os);
214 }
215
216
217 void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
218                         DispatchedCall call) {
219   switch (MajorKeyFromKey(key)) {
220 #define DEF_CASE(NAME)             \
221   case NAME: {                     \
222     NAME##Stub stub(key, isolate); \
223     CodeStub* pstub = &stub;       \
224     call(pstub, value_out);        \
225     break;                         \
226   }
227     CODE_STUB_LIST(DEF_CASE)
228 #undef DEF_CASE
229     case NUMBER_OF_IDS:
230     case NoCache:
231       UNREACHABLE();
232       break;
233   }
234 }
235
236
237 static void InitializeDescriptorDispatchedCall(CodeStub* stub,
238                                                void** value_out) {
239   CodeStubDescriptor* descriptor_out =
240       reinterpret_cast<CodeStubDescriptor*>(value_out);
241   stub->InitializeDescriptor(descriptor_out);
242   descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
243 }
244
245
246 void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
247                                     CodeStubDescriptor* desc) {
248   void** value_out = reinterpret_cast<void**>(desc);
249   Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
250 }
251
252
253 void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
254   Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
255   // Code stubs with special cache cannot be recreated from stub key.
256   *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
257 }
258
259
260 MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
261   HandleScope scope(isolate);
262   Handle<Code> code;
263   void** value_out = reinterpret_cast<void**>(&code);
264   Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
265   return scope.CloseAndEscape(code);
266 }
267
268
269 // static
270 void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
271   // Generate the uninitialized versions of the stub.
272   for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
273     BinaryOpICStub stub(isolate, static_cast<Token::Value>(op), Strength::WEAK);
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   MaybeHandle<Object> fun = Object::GetProperty(
473       isolate, isolate->factory()->code_stub_exports_object(), name);
474   Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked());
475   DCHECK(!function->IsUndefined() &&
476          "JavaScript implementation of stub not found");
477   return function;
478 }
479 }  // namespace
480
481
482 Handle<Code> TurboFanCodeStub::GenerateCode() {
483   // Get the outer ("stub generator") function.
484   const char* name = CodeStub::MajorName(MajorKey(), false);
485   Handle<JSFunction> outer = GetFunction(isolate(), name);
486   DCHECK_EQ(2, outer->shared()->length());
487
488   // Invoke the outer function to get the stub itself.
489   Factory* factory = isolate()->factory();
490   Handle<Object> call_conv = factory->InternalizeUtf8String(name);
491   Handle<Object> minor_key = factory->NewNumber(MinorKey());
492   Handle<Object> args[] = {call_conv, minor_key};
493   MaybeHandle<Object> result = Execution::Call(
494       isolate(), outer, factory->undefined_value(), 2, args, false);
495   Handle<JSFunction> inner = Handle<JSFunction>::cast(result.ToHandleChecked());
496   // Just to make sure nobody calls this...
497   inner->set_code(isolate()->builtins()->builtin(Builtins::kIllegal));
498
499   Zone zone;
500   // Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair.
501   ParseInfo parse_info(&zone, inner);
502   CompilationInfo info(&parse_info);
503   info.SetFunctionType(GetCallInterfaceDescriptor().GetFunctionType());
504   info.MarkAsContextSpecializing();
505   info.MarkAsDeoptimizationEnabled();
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(
625       FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
626 }
627
628
629 void KeyedLoadGenericStub::InitializeDescriptor(
630     CodeStubDescriptor* descriptor) {
631   descriptor->Initialize(
632       Runtime::FunctionForId(is_strong(language_mode())
633                                  ? Runtime::kKeyedGetPropertyStrong
634                                  : Runtime::kKeyedGetProperty)->entry);
635 }
636
637
638 void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
639   if (kind() == Code::STORE_IC) {
640     descriptor->Initialize(FUNCTION_ADDR(Runtime_StoreIC_MissFromStubFailure));
641   } else if (kind() == Code::KEYED_LOAD_IC) {
642     descriptor->Initialize(
643         FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
644   } else if (kind() == Code::KEYED_STORE_IC) {
645     descriptor->Initialize(
646         FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
647   }
648 }
649
650
651 CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const {
652   if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
653     return LoadWithVectorDescriptor(isolate());
654   } else {
655     DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
656     return StoreDescriptor(isolate());
657   }
658 }
659
660
661 void StoreFastElementStub::InitializeDescriptor(
662     CodeStubDescriptor* descriptor) {
663   descriptor->Initialize(
664       FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
665 }
666
667
668 void ElementsTransitionAndStoreStub::InitializeDescriptor(
669     CodeStubDescriptor* descriptor) {
670   descriptor->Initialize(
671       FUNCTION_ADDR(Runtime_ElementsTransitionAndStoreIC_Miss));
672 }
673
674
675 CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor()
676     const {
677   return StoreTransitionDescriptor(isolate());
678 }
679
680
681 void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
682   descriptor->Initialize(
683       Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry);
684 }
685
686
687 void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
688
689
690 void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
691
692
693 void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
694   NumberToStringDescriptor call_descriptor(isolate());
695   descriptor->Initialize(
696       Runtime::FunctionForId(Runtime::kNumberToStringRT)->entry);
697 }
698
699
700 void FastCloneShallowArrayStub::InitializeDescriptor(
701     CodeStubDescriptor* descriptor) {
702   FastCloneShallowArrayDescriptor call_descriptor(isolate());
703   descriptor->Initialize(
704       Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry);
705 }
706
707
708 void FastCloneShallowObjectStub::InitializeDescriptor(
709     CodeStubDescriptor* descriptor) {
710   FastCloneShallowObjectDescriptor call_descriptor(isolate());
711   descriptor->Initialize(
712       Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry);
713 }
714
715
716 void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {}
717
718
719 void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {}
720
721
722 void RegExpConstructResultStub::InitializeDescriptor(
723     CodeStubDescriptor* descriptor) {
724   descriptor->Initialize(
725       Runtime::FunctionForId(Runtime::kRegExpConstructResultRT)->entry);
726 }
727
728
729 void TransitionElementsKindStub::InitializeDescriptor(
730     CodeStubDescriptor* descriptor) {
731   descriptor->Initialize(
732       Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
733 }
734
735
736 void AllocateHeapNumberStub::InitializeDescriptor(
737     CodeStubDescriptor* descriptor) {
738   descriptor->Initialize(
739       Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
740 }
741
742
743 void CompareNilICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
744   descriptor->Initialize(FUNCTION_ADDR(Runtime_CompareNilIC_Miss));
745   descriptor->SetMissHandler(ExternalReference(
746       Runtime::FunctionForId(Runtime::kCompareNilIC_Miss), isolate()));
747 }
748
749
750 void ToBooleanStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
751   descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
752   descriptor->SetMissHandler(ExternalReference(
753       Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate()));
754 }
755
756
757 void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
758   descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
759   descriptor->SetMissHandler(ExternalReference(
760       Runtime::FunctionForId(Runtime::kBinaryOpIC_Miss), isolate()));
761 }
762
763
764 void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
765     CodeStubDescriptor* descriptor) {
766   descriptor->Initialize(
767       FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
768 }
769
770
771 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
772   descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAddRT)->entry);
773 }
774
775
776 void GrowArrayElementsStub::InitializeDescriptor(
777     CodeStubDescriptor* descriptor) {
778   descriptor->Initialize(
779       Runtime::FunctionForId(Runtime::kGrowArrayElements)->entry);
780 }
781
782
783 void TypeofStub::GenerateAheadOfTime(Isolate* isolate) {
784   TypeofStub stub(isolate);
785   stub.GetCode();
786 }
787
788
789 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
790   CreateAllocationSiteStub stub(isolate);
791   stub.GetCode();
792 }
793
794
795 void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
796   CreateWeakCellStub stub(isolate);
797   stub.GetCode();
798 }
799
800
801 void StoreElementStub::Generate(MacroAssembler* masm) {
802   switch (elements_kind()) {
803     case FAST_ELEMENTS:
804     case FAST_HOLEY_ELEMENTS:
805     case FAST_SMI_ELEMENTS:
806     case FAST_HOLEY_SMI_ELEMENTS:
807     case FAST_DOUBLE_ELEMENTS:
808     case FAST_HOLEY_DOUBLE_ELEMENTS:
809 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
810     case TYPE##_ELEMENTS:
811
812     TYPED_ARRAYS(TYPED_ARRAY_CASE)
813 #undef TYPED_ARRAY_CASE
814       UNREACHABLE();
815       break;
816     case DICTIONARY_ELEMENTS:
817       ElementHandlerCompiler::GenerateStoreSlow(masm);
818       break;
819     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
820     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
821       UNREACHABLE();
822       break;
823   }
824 }
825
826
827 // static
828 void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
829   StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE)
830       .GetCode();
831   StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS,
832                        STORE_AND_GROW_NO_TRANSITION).GetCode();
833   for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
834     ElementsKind kind = static_cast<ElementsKind>(i);
835     StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
836     StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
837         .GetCode();
838   }
839 }
840
841
842 void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
843   switch (type()) {
844     case READ_ELEMENT:
845       GenerateReadElement(masm);
846       break;
847     case NEW_SLOPPY_FAST:
848       GenerateNewSloppyFast(masm);
849       break;
850     case NEW_SLOPPY_SLOW:
851       GenerateNewSloppySlow(masm);
852       break;
853     case NEW_STRICT:
854       GenerateNewStrict(masm);
855       break;
856   }
857 }
858
859
860 void RestParamAccessStub::Generate(MacroAssembler* masm) {
861   GenerateNew(masm);
862 }
863
864
865 void ArgumentsAccessStub::PrintName(std::ostream& os) const {  // NOLINT
866   os << "ArgumentsAccessStub_";
867   switch (type()) {
868     case READ_ELEMENT:
869       os << "ReadElement";
870       break;
871     case NEW_SLOPPY_FAST:
872       os << "NewSloppyFast";
873       break;
874     case NEW_SLOPPY_SLOW:
875       os << "NewSloppySlow";
876       break;
877     case NEW_STRICT:
878       os << "NewStrict";
879       break;
880   }
881   return;
882 }
883
884
885 void RestParamAccessStub::PrintName(std::ostream& os) const {  // NOLINT
886   os << "RestParamAccessStub_";
887 }
888
889
890 void CallFunctionStub::PrintName(std::ostream& os) const {  // NOLINT
891   os << "CallFunctionStub_Args" << argc();
892 }
893
894
895 void CallConstructStub::PrintName(std::ostream& os) const {  // NOLINT
896   os << "CallConstructStub";
897   if (RecordCallTarget()) os << "_Recording";
898 }
899
900
901 void ArrayConstructorStub::PrintName(std::ostream& os) const {  // NOLINT
902   os << "ArrayConstructorStub";
903   switch (argument_count()) {
904     case ANY:
905       os << "_Any";
906       break;
907     case NONE:
908       os << "_None";
909       break;
910     case ONE:
911       os << "_One";
912       break;
913     case MORE_THAN_ONE:
914       os << "_More_Than_One";
915       break;
916   }
917   return;
918 }
919
920
921 std::ostream& ArrayConstructorStubBase::BasePrintName(
922     std::ostream& os,  // NOLINT
923     const char* name) const {
924   os << name << "_" << ElementsKindToString(elements_kind());
925   if (override_mode() == DISABLE_ALLOCATION_SITES) {
926     os << "_DISABLE_ALLOCATION_SITES";
927   }
928   return os;
929 }
930
931
932 bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
933   Types new_types = types();
934   Types old_types = new_types;
935   bool to_boolean_value = new_types.UpdateStatus(object);
936   TraceTransition(old_types, new_types);
937   set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral()));
938   return to_boolean_value;
939 }
940
941
942 void ToBooleanStub::PrintState(std::ostream& os) const {  // NOLINT
943   os << types();
944 }
945
946
947 std::ostream& operator<<(std::ostream& os, const ToBooleanStub::Types& s) {
948   os << "(";
949   SimpleListPrinter p(os);
950   if (s.IsEmpty()) p.Add("None");
951   if (s.Contains(ToBooleanStub::UNDEFINED)) p.Add("Undefined");
952   if (s.Contains(ToBooleanStub::BOOLEAN)) p.Add("Bool");
953   if (s.Contains(ToBooleanStub::NULL_TYPE)) p.Add("Null");
954   if (s.Contains(ToBooleanStub::SMI)) p.Add("Smi");
955   if (s.Contains(ToBooleanStub::SPEC_OBJECT)) p.Add("SpecObject");
956   if (s.Contains(ToBooleanStub::STRING)) p.Add("String");
957   if (s.Contains(ToBooleanStub::SYMBOL)) p.Add("Symbol");
958   if (s.Contains(ToBooleanStub::HEAP_NUMBER)) p.Add("HeapNumber");
959   if (s.Contains(ToBooleanStub::SIMD_VALUE)) p.Add("SimdValue");
960   return os << ")";
961 }
962
963
964 bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
965   if (object->IsUndefined()) {
966     Add(UNDEFINED);
967     return false;
968   } else if (object->IsBoolean()) {
969     Add(BOOLEAN);
970     return object->IsTrue();
971   } else if (object->IsNull()) {
972     Add(NULL_TYPE);
973     return false;
974   } else if (object->IsSmi()) {
975     Add(SMI);
976     return Smi::cast(*object)->value() != 0;
977   } else if (object->IsSpecObject()) {
978     Add(SPEC_OBJECT);
979     return !object->IsUndetectableObject();
980   } else if (object->IsString()) {
981     Add(STRING);
982     return !object->IsUndetectableObject() &&
983         String::cast(*object)->length() != 0;
984   } else if (object->IsSymbol()) {
985     Add(SYMBOL);
986     return true;
987   } else if (object->IsHeapNumber()) {
988     DCHECK(!object->IsUndetectableObject());
989     Add(HEAP_NUMBER);
990     double value = HeapNumber::cast(*object)->value();
991     return value != 0 && !std::isnan(value);
992   } else if (object->IsFloat32x4()) {
993     Add(SIMD_VALUE);
994     return true;
995   } else {
996     // We should never see an internal object at runtime here!
997     UNREACHABLE();
998     return true;
999   }
1000 }
1001
1002
1003 bool ToBooleanStub::Types::NeedsMap() const {
1004   return Contains(ToBooleanStub::SPEC_OBJECT) ||
1005          Contains(ToBooleanStub::STRING) || Contains(ToBooleanStub::SYMBOL) ||
1006          Contains(ToBooleanStub::HEAP_NUMBER) ||
1007          Contains(ToBooleanStub::SIMD_VALUE);
1008 }
1009
1010
1011 bool ToBooleanStub::Types::CanBeUndetectable() const {
1012   return Contains(ToBooleanStub::SPEC_OBJECT)
1013       || Contains(ToBooleanStub::STRING);
1014 }
1015
1016
1017 void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
1018   StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
1019   StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
1020   stub1.GetCode();
1021   stub2.GetCode();
1022 }
1023
1024
1025 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
1026                                                intptr_t stack_pointer,
1027                                                Isolate* isolate) {
1028   FunctionEntryHook entry_hook = isolate->function_entry_hook();
1029   DCHECK(entry_hook != NULL);
1030   entry_hook(function, stack_pointer);
1031 }
1032
1033
1034 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
1035     : PlatformCodeStub(isolate) {
1036   minor_key_ = ArgumentCountBits::encode(ANY);
1037   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
1038 }
1039
1040
1041 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
1042                                            int argument_count)
1043     : PlatformCodeStub(isolate) {
1044   if (argument_count == 0) {
1045     minor_key_ = ArgumentCountBits::encode(NONE);
1046   } else if (argument_count == 1) {
1047     minor_key_ = ArgumentCountBits::encode(ONE);
1048   } else if (argument_count >= 2) {
1049     minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE);
1050   } else {
1051     UNREACHABLE();
1052   }
1053   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
1054 }
1055
1056
1057 InternalArrayConstructorStub::InternalArrayConstructorStub(
1058     Isolate* isolate) : PlatformCodeStub(isolate) {
1059   InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
1060 }
1061
1062
1063 Representation RepresentationFromType(Type* type) {
1064   if (type->Is(Type::UntaggedSigned()) || type->Is(Type::UntaggedUnsigned())) {
1065     return Representation::Integer32();
1066   }
1067
1068   if (type->Is(Type::TaggedSigned())) {
1069     return Representation::Smi();
1070   }
1071
1072   if (type->Is(Type::UntaggedPointer())) {
1073     return Representation::External();
1074   }
1075
1076   DCHECK(!type->Is(Type::Untagged()));
1077   return Representation::Tagged();
1078 }
1079 }  // namespace internal
1080 }  // namespace v8