1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "bootstrapper.h"
31#include "code-stubs.h"
32#include "cpu-profiler.h"
33#include "stub-cache.h"
34#include "factory.h"
35#include "gdb-jit.h"
36#include "macro-assembler.h"
37
38namespace v8 {
39namespace internal {
40
41
42CodeStubInterfaceDescriptor::CodeStubInterfaceDescriptor()
43    : register_param_count_(-1),
44      stack_parameter_count_(NULL),
45      hint_stack_parameter_count_(-1),
46      function_mode_(NOT_JS_FUNCTION_STUB_MODE),
47      register_params_(NULL),
48      deoptimization_handler_(NULL),
49      miss_handler_(IC_Utility(IC::kUnreachable), Isolate::Current()),
50      has_miss_handler_(false) { }
51
52
53bool CodeStub::FindCodeInCache(Code** code_out, Isolate* isolate) {
54  UnseededNumberDictionary* stubs = isolate->heap()->code_stubs();
55  int index = stubs->FindEntry(GetKey());
56  if (index != UnseededNumberDictionary::kNotFound) {
57    *code_out = Code::cast(stubs->ValueAt(index));
58    return true;
59  }
60  return false;
61}
62
63
64SmartArrayPointer<const char> CodeStub::GetName() {
65  char buffer[100];
66  NoAllocationStringAllocator allocator(buffer,
67                                        static_cast<unsigned>(sizeof(buffer)));
68  StringStream stream(&allocator);
69  PrintName(&stream);
70  return stream.ToCString();
71}
72
73
74void CodeStub::RecordCodeGeneration(Code* code, Isolate* isolate) {
75  SmartArrayPointer<const char> name = GetName();
76  PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
77  GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
78  Counters* counters = isolate->counters();
79  counters->total_stubs_code_size()->Increment(code->instruction_size());
80}
81
82
83Code::Kind CodeStub::GetCodeKind() const {
84  return Code::STUB;
85}
86
87
88Handle<Code> CodeStub::GetCodeCopyFromTemplate(Isolate* isolate) {
89  Handle<Code> ic = GetCode(isolate);
90  ic = isolate->factory()->CopyCode(ic);
91  RecordCodeGeneration(*ic, isolate);
92  return ic;
93}
94
95
96Handle<Code> PlatformCodeStub::GenerateCode() {
97  Isolate* isolate = Isolate::Current();
98  Factory* factory = isolate->factory();
99
100  // Generate the new code.
101  MacroAssembler masm(isolate, NULL, 256);
102
103  {
104    // Update the static counter each time a new code stub is generated.
105    isolate->counters()->code_stubs()->Increment();
106
107    // Nested stubs are not allowed for leaves.
108    AllowStubCallsScope allow_scope(&masm, false);
109
110    // Generate the code for the stub.
111    masm.set_generating_stub(true);
112    NoCurrentFrameScope scope(&masm);
113    Generate(&masm);
114  }
115
116  // Create the code object.
117  CodeDesc desc;
118  masm.GetCode(&desc);
119
120  // Copy the generated code into a heap object.
121  Code::Flags flags = Code::ComputeFlags(
122      GetCodeKind(),
123      GetICState(),
124      GetExtraICState(),
125      GetStubType(),
126      GetStubFlags());
127  Handle<Code> new_object = factory->NewCode(
128      desc, flags, masm.CodeObject(), NeedsImmovableCode());
129  return new_object;
130}
131
132
133Handle<Code> CodeStub::GetCode(Isolate* isolate) {
134  Factory* factory = isolate->factory();
135  Heap* heap = isolate->heap();
136  Code* code;
137  if (UseSpecialCache()
138      ? FindCodeInSpecialCache(&code, isolate)
139      : FindCodeInCache(&code, isolate)) {
140    ASSERT(IsPregenerated() == code->is_pregenerated());
141    return Handle<Code>(code);
142  }
143
144  {
145    HandleScope scope(isolate);
146
147    Handle<Code> new_object = GenerateCode();
148    new_object->set_major_key(MajorKey());
149    FinishCode(new_object);
150    RecordCodeGeneration(*new_object, isolate);
151
152#ifdef ENABLE_DISASSEMBLER
153    if (FLAG_print_code_stubs) {
154      new_object->Disassemble(*GetName());
155      PrintF("\n");
156    }
157#endif
158
159    if (UseSpecialCache()) {
160      AddToSpecialCache(new_object);
161    } else {
162      // Update the dictionary and the root in Heap.
163      Handle<UnseededNumberDictionary> dict =
164          factory->DictionaryAtNumberPut(
165              Handle<UnseededNumberDictionary>(heap->code_stubs()),
166              GetKey(),
167              new_object);
168      heap->public_set_code_stubs(*dict);
169    }
170    code = *new_object;
171  }
172
173  Activate(code);
174  ASSERT(!NeedsImmovableCode() ||
175         heap->lo_space()->Contains(code) ||
176         heap->code_space()->FirstPage()->Contains(code->address()));
177  return Handle<Code>(code, isolate);
178}
179
180
181const char* CodeStub::MajorName(CodeStub::Major major_key,
182                                bool allow_unknown_keys) {
183  switch (major_key) {
184#define DEF_CASE(name) case name: return #name "Stub";
185    CODE_STUB_LIST(DEF_CASE)
186#undef DEF_CASE
187    default:
188      if (!allow_unknown_keys) {
189        UNREACHABLE();
190      }
191      return NULL;
192  }
193}
194
195
196void CodeStub::PrintBaseName(StringStream* stream) {
197  stream->Add("%s", MajorName(MajorKey(), false));
198}
199
200
201void CodeStub::PrintName(StringStream* stream) {
202  PrintBaseName(stream);
203  PrintState(stream);
204}
205
206
207void BinaryOpStub::Generate(MacroAssembler* masm) {
208  // Explicitly allow generation of nested stubs. It is safe here because
209  // generation code does not use any raw pointers.
210  AllowStubCallsScope allow_stub_calls(masm, true);
211
212  BinaryOpIC::TypeInfo operands_type = Max(left_type_, right_type_);
213  if (left_type_ == BinaryOpIC::ODDBALL && right_type_ == BinaryOpIC::ODDBALL) {
214    // The OddballStub handles a number and an oddball, not two oddballs.
215    operands_type = BinaryOpIC::GENERIC;
216  }
217  switch (operands_type) {
218    case BinaryOpIC::UNINITIALIZED:
219      GenerateTypeTransition(masm);
220      break;
221    case BinaryOpIC::SMI:
222      GenerateSmiStub(masm);
223      break;
224    case BinaryOpIC::INT32:
225      GenerateInt32Stub(masm);
226      break;
227    case BinaryOpIC::NUMBER:
228      GenerateNumberStub(masm);
229      break;
230    case BinaryOpIC::ODDBALL:
231      GenerateOddballStub(masm);
232      break;
233    case BinaryOpIC::STRING:
234      GenerateStringStub(masm);
235      break;
236    case BinaryOpIC::GENERIC:
237      GenerateGeneric(masm);
238      break;
239    default:
240      UNREACHABLE();
241  }
242}
243
244
245#define __ ACCESS_MASM(masm)
246
247
248void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
249  switch (op_) {
250    case Token::ADD:
251      __ InvokeBuiltin(Builtins::ADD, CALL_FUNCTION);
252      break;
253    case Token::SUB:
254      __ InvokeBuiltin(Builtins::SUB, CALL_FUNCTION);
255      break;
256    case Token::MUL:
257      __ InvokeBuiltin(Builtins::MUL, CALL_FUNCTION);
258      break;
259    case Token::DIV:
260      __ InvokeBuiltin(Builtins::DIV, CALL_FUNCTION);
261      break;
262    case Token::MOD:
263      __ InvokeBuiltin(Builtins::MOD, CALL_FUNCTION);
264      break;
265    case Token::BIT_OR:
266      __ InvokeBuiltin(Builtins::BIT_OR, CALL_FUNCTION);
267      break;
268    case Token::BIT_AND:
269      __ InvokeBuiltin(Builtins::BIT_AND, CALL_FUNCTION);
270      break;
271    case Token::BIT_XOR:
272      __ InvokeBuiltin(Builtins::BIT_XOR, CALL_FUNCTION);
273      break;
274    case Token::SAR:
275      __ InvokeBuiltin(Builtins::SAR, CALL_FUNCTION);
276      break;
277    case Token::SHR:
278      __ InvokeBuiltin(Builtins::SHR, CALL_FUNCTION);
279      break;
280    case Token::SHL:
281      __ InvokeBuiltin(Builtins::SHL, CALL_FUNCTION);
282      break;
283    default:
284      UNREACHABLE();
285  }
286}
287
288
289#undef __
290
291
292void BinaryOpStub::PrintName(StringStream* stream) {
293  const char* op_name = Token::Name(op_);
294  const char* overwrite_name;
295  switch (mode_) {
296    case NO_OVERWRITE: overwrite_name = "Alloc"; break;
297    case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
298    case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
299    default: overwrite_name = "UnknownOverwrite"; break;
300  }
301  stream->Add("BinaryOpStub_%s_%s_%s+%s",
302              op_name,
303              overwrite_name,
304              BinaryOpIC::GetName(left_type_),
305              BinaryOpIC::GetName(right_type_));
306}
307
308
309void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
310  ASSERT(left_type_ == BinaryOpIC::STRING || right_type_ == BinaryOpIC::STRING);
311  ASSERT(op_ == Token::ADD);
312  if (left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING) {
313    GenerateBothStringStub(masm);
314    return;
315  }
316  // Try to add arguments as strings, otherwise, transition to the generic
317  // BinaryOpIC type.
318  GenerateAddStrings(masm);
319  GenerateTypeTransition(masm);
320}
321
322
323InlineCacheState ICCompareStub::GetICState() {
324  CompareIC::State state = Max(left_, right_);
325  switch (state) {
326    case CompareIC::UNINITIALIZED:
327      return ::v8::internal::UNINITIALIZED;
328    case CompareIC::SMI:
329    case CompareIC::NUMBER:
330    case CompareIC::INTERNALIZED_STRING:
331    case CompareIC::STRING:
332    case CompareIC::UNIQUE_NAME:
333    case CompareIC::OBJECT:
334    case CompareIC::KNOWN_OBJECT:
335      return MONOMORPHIC;
336    case CompareIC::GENERIC:
337      return ::v8::internal::GENERIC;
338  }
339  UNREACHABLE();
340  return ::v8::internal::UNINITIALIZED;
341}
342
343
344void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) {
345  ASSERT(*known_map_ != NULL);
346  Isolate* isolate = new_object->GetIsolate();
347  Factory* factory = isolate->factory();
348  return Map::UpdateCodeCache(known_map_,
349                              strict() ?
350                                  factory->strict_compare_ic_string() :
351                                  factory->compare_ic_string(),
352                              new_object);
353}
354
355
356bool ICCompareStub::FindCodeInSpecialCache(Code** code_out, Isolate* isolate) {
357  Factory* factory = isolate->factory();
358  Code::Flags flags = Code::ComputeFlags(
359      GetCodeKind(),
360      UNINITIALIZED);
361  ASSERT(op_ == Token::EQ || op_ == Token::EQ_STRICT);
362  Handle<Object> probe(
363      known_map_->FindInCodeCache(
364        strict() ?
365            *factory->strict_compare_ic_string() :
366            *factory->compare_ic_string(),
367        flags),
368      isolate);
369  if (probe->IsCode()) {
370    *code_out = Code::cast(*probe);
371#ifdef DEBUG
372    Token::Value cached_op;
373    ICCompareStub::DecodeMinorKey((*code_out)->stub_info(), NULL, NULL, NULL,
374                                  &cached_op);
375    ASSERT(op_ == cached_op);
376#endif
377    return true;
378  }
379  return false;
380}
381
382
383int ICCompareStub::MinorKey() {
384  return OpField::encode(op_ - Token::EQ) |
385         LeftStateField::encode(left_) |
386         RightStateField::encode(right_) |
387         HandlerStateField::encode(state_);
388}
389
390
391void ICCompareStub::DecodeMinorKey(int minor_key,
392                                   CompareIC::State* left_state,
393                                   CompareIC::State* right_state,
394                                   CompareIC::State* handler_state,
395                                   Token::Value* op) {
396  if (left_state) {
397    *left_state =
398        static_cast<CompareIC::State>(LeftStateField::decode(minor_key));
399  }
400  if (right_state) {
401    *right_state =
402        static_cast<CompareIC::State>(RightStateField::decode(minor_key));
403  }
404  if (handler_state) {
405    *handler_state =
406        static_cast<CompareIC::State>(HandlerStateField::decode(minor_key));
407  }
408  if (op) {
409    *op = static_cast<Token::Value>(OpField::decode(minor_key) + Token::EQ);
410  }
411}
412
413
414void ICCompareStub::Generate(MacroAssembler* masm) {
415  switch (state_) {
416    case CompareIC::UNINITIALIZED:
417      GenerateMiss(masm);
418      break;
419    case CompareIC::SMI:
420      GenerateSmis(masm);
421      break;
422    case CompareIC::NUMBER:
423      GenerateNumbers(masm);
424      break;
425    case CompareIC::STRING:
426      GenerateStrings(masm);
427      break;
428    case CompareIC::INTERNALIZED_STRING:
429      GenerateInternalizedStrings(masm);
430      break;
431    case CompareIC::UNIQUE_NAME:
432      GenerateUniqueNames(masm);
433      break;
434    case CompareIC::OBJECT:
435      GenerateObjects(masm);
436      break;
437    case CompareIC::KNOWN_OBJECT:
438      ASSERT(*known_map_ != NULL);
439      GenerateKnownObjects(masm);
440      break;
441    case CompareIC::GENERIC:
442      GenerateGeneric(masm);
443      break;
444  }
445}
446
447
448void CompareNilICStub::UpdateStatus(Handle<Object> object) {
449  ASSERT(!state_.Contains(GENERIC));
450  State old_state(state_);
451  if (object->IsNull()) {
452    state_.Add(NULL_TYPE);
453  } else if (object->IsUndefined()) {
454    state_.Add(UNDEFINED);
455  } else if (object->IsUndetectableObject() ||
456             object->IsOddball() ||
457             !object->IsHeapObject()) {
458    state_.RemoveAll();
459    state_.Add(GENERIC);
460  } else if (IsMonomorphic()) {
461    state_.RemoveAll();
462    state_.Add(GENERIC);
463  } else {
464    state_.Add(MONOMORPHIC_MAP);
465  }
466  TraceTransition(old_state, state_);
467}
468
469
470template<class StateType>
471void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
472  // Note: Although a no-op transition is semantically OK, it is hinting at a
473  // bug somewhere in our state transition machinery.
474  ASSERT(from != to);
475  #ifdef DEBUG
476  if (!FLAG_trace_ic) return;
477  char buffer[100];
478  NoAllocationStringAllocator allocator(buffer,
479                                        static_cast<unsigned>(sizeof(buffer)));
480  StringStream stream(&allocator);
481  stream.Add("[");
482  PrintBaseName(&stream);
483  stream.Add(": ");
484  from.Print(&stream);
485  stream.Add("=>");
486  to.Print(&stream);
487  stream.Add("]\n");
488  stream.OutputToStdOut();
489  #endif
490}
491
492
493void CompareNilICStub::PrintBaseName(StringStream* stream) {
494  CodeStub::PrintBaseName(stream);
495  stream->Add((nil_value_ == kNullValue) ? "(NullValue)":
496                                           "(UndefinedValue)");
497}
498
499
500void CompareNilICStub::PrintState(StringStream* stream) {
501  state_.Print(stream);
502}
503
504
505void CompareNilICStub::State::Print(StringStream* stream) const {
506  stream->Add("(");
507  SimpleListPrinter printer(stream);
508  if (IsEmpty()) printer.Add("None");
509  if (Contains(UNDEFINED)) printer.Add("Undefined");
510  if (Contains(NULL_TYPE)) printer.Add("Null");
511  if (Contains(MONOMORPHIC_MAP)) printer.Add("MonomorphicMap");
512  if (Contains(GENERIC)) printer.Add("Generic");
513  stream->Add(")");
514}
515
516
517Handle<Type> CompareNilICStub::GetType(
518    Isolate* isolate,
519    Handle<Map> map) {
520  if (state_.Contains(CompareNilICStub::GENERIC)) {
521    return handle(Type::Any(), isolate);
522  }
523
524  Handle<Type> result(Type::None(), isolate);
525  if (state_.Contains(CompareNilICStub::UNDEFINED)) {
526    result = handle(Type::Union(result, handle(Type::Undefined(), isolate)),
527                    isolate);
528  }
529  if (state_.Contains(CompareNilICStub::NULL_TYPE)) {
530    result = handle(Type::Union(result, handle(Type::Null(), isolate)),
531                    isolate);
532  }
533  if (state_.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
534    Type* type = map.is_null() ? Type::Detectable() : Type::Class(map);
535    result = handle(Type::Union(result, handle(type, isolate)), isolate);
536  }
537
538  return result;
539}
540
541
542Handle<Type> CompareNilICStub::GetInputType(
543    Isolate* isolate,
544    Handle<Map> map) {
545  Handle<Type> output_type = GetType(isolate, map);
546  Handle<Type> nil_type = handle(nil_value_ == kNullValue
547      ? Type::Null() : Type::Undefined(), isolate);
548  return handle(Type::Union(output_type, nil_type), isolate);
549}
550
551
552void InstanceofStub::PrintName(StringStream* stream) {
553  const char* args = "";
554  if (HasArgsInRegisters()) {
555    args = "_REGS";
556  }
557
558  const char* inline_check = "";
559  if (HasCallSiteInlineCheck()) {
560    inline_check = "_INLINE";
561  }
562
563  const char* return_true_false_object = "";
564  if (ReturnTrueFalseObject()) {
565    return_true_false_object = "_TRUEFALSE";
566  }
567
568  stream->Add("InstanceofStub%s%s%s",
569              args,
570              inline_check,
571              return_true_false_object);
572}
573
574
575void JSEntryStub::FinishCode(Handle<Code> code) {
576  Handle<FixedArray> handler_table =
577      code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
578  handler_table->set(0, Smi::FromInt(handler_offset_));
579  code->set_handler_table(*handler_table);
580}
581
582
583void KeyedLoadDictionaryElementStub::Generate(MacroAssembler* masm) {
584  KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
585}
586
587
588void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
589  CreateAllocationSiteStub stub;
590  stub.GetCode(isolate)->set_is_pregenerated(true);
591}
592
593
594void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
595  switch (elements_kind_) {
596    case FAST_ELEMENTS:
597    case FAST_HOLEY_ELEMENTS:
598    case FAST_SMI_ELEMENTS:
599    case FAST_HOLEY_SMI_ELEMENTS: {
600      KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
601                                                       is_js_array_,
602                                                       elements_kind_,
603                                                       store_mode_);
604    }
605      break;
606    case FAST_DOUBLE_ELEMENTS:
607    case FAST_HOLEY_DOUBLE_ELEMENTS:
608      KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
609                                                             is_js_array_,
610                                                             store_mode_);
611      break;
612    case EXTERNAL_BYTE_ELEMENTS:
613    case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
614    case EXTERNAL_SHORT_ELEMENTS:
615    case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
616    case EXTERNAL_INT_ELEMENTS:
617    case EXTERNAL_UNSIGNED_INT_ELEMENTS:
618    case EXTERNAL_FLOAT_ELEMENTS:
619    case EXTERNAL_DOUBLE_ELEMENTS:
620    case EXTERNAL_PIXEL_ELEMENTS:
621      KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
622      break;
623    case DICTIONARY_ELEMENTS:
624      KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
625      break;
626    case NON_STRICT_ARGUMENTS_ELEMENTS:
627      UNREACHABLE();
628      break;
629  }
630}
631
632
633void ArgumentsAccessStub::PrintName(StringStream* stream) {
634  stream->Add("ArgumentsAccessStub_");
635  switch (type_) {
636    case READ_ELEMENT: stream->Add("ReadElement"); break;
637    case NEW_NON_STRICT_FAST: stream->Add("NewNonStrictFast"); break;
638    case NEW_NON_STRICT_SLOW: stream->Add("NewNonStrictSlow"); break;
639    case NEW_STRICT: stream->Add("NewStrict"); break;
640  }
641}
642
643
644void CallFunctionStub::PrintName(StringStream* stream) {
645  stream->Add("CallFunctionStub_Args%d", argc_);
646  if (ReceiverMightBeImplicit()) stream->Add("_Implicit");
647  if (RecordCallTarget()) stream->Add("_Recording");
648}
649
650
651void CallConstructStub::PrintName(StringStream* stream) {
652  stream->Add("CallConstructStub");
653  if (RecordCallTarget()) stream->Add("_Recording");
654}
655
656
657bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
658  Types old_types(types_);
659  bool to_boolean_value = types_.UpdateStatus(object);
660  TraceTransition(old_types, types_);
661  return to_boolean_value;
662}
663
664
665void ToBooleanStub::PrintState(StringStream* stream) {
666  types_.Print(stream);
667}
668
669
670void ToBooleanStub::Types::Print(StringStream* stream) const {
671  stream->Add("(");
672  SimpleListPrinter printer(stream);
673  if (IsEmpty()) printer.Add("None");
674  if (Contains(UNDEFINED)) printer.Add("Undefined");
675  if (Contains(BOOLEAN)) printer.Add("Bool");
676  if (Contains(NULL_TYPE)) printer.Add("Null");
677  if (Contains(SMI)) printer.Add("Smi");
678  if (Contains(SPEC_OBJECT)) printer.Add("SpecObject");
679  if (Contains(STRING)) printer.Add("String");
680  if (Contains(SYMBOL)) printer.Add("Symbol");
681  if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber");
682  stream->Add(")");
683}
684
685
686bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
687  if (object->IsUndefined()) {
688    Add(UNDEFINED);
689    return false;
690  } else if (object->IsBoolean()) {
691    Add(BOOLEAN);
692    return object->IsTrue();
693  } else if (object->IsNull()) {
694    Add(NULL_TYPE);
695    return false;
696  } else if (object->IsSmi()) {
697    Add(SMI);
698    return Smi::cast(*object)->value() != 0;
699  } else if (object->IsSpecObject()) {
700    Add(SPEC_OBJECT);
701    return !object->IsUndetectableObject();
702  } else if (object->IsString()) {
703    Add(STRING);
704    return !object->IsUndetectableObject() &&
705        String::cast(*object)->length() != 0;
706  } else if (object->IsSymbol()) {
707    Add(SYMBOL);
708    return true;
709  } else if (object->IsHeapNumber()) {
710    ASSERT(!object->IsUndetectableObject());
711    Add(HEAP_NUMBER);
712    double value = HeapNumber::cast(*object)->value();
713    return value != 0 && !std::isnan(value);
714  } else {
715    // We should never see an internal object at runtime here!
716    UNREACHABLE();
717    return true;
718  }
719}
720
721
722bool ToBooleanStub::Types::NeedsMap() const {
723  return Contains(ToBooleanStub::SPEC_OBJECT)
724      || Contains(ToBooleanStub::STRING)
725      || Contains(ToBooleanStub::SYMBOL)
726      || Contains(ToBooleanStub::HEAP_NUMBER);
727}
728
729
730bool ToBooleanStub::Types::CanBeUndetectable() const {
731  return Contains(ToBooleanStub::SPEC_OBJECT)
732      || Contains(ToBooleanStub::STRING);
733}
734
735
736void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
737  StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE);
738  StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE);
739  stub1.GetCode(isolate)->set_is_pregenerated(true);
740  stub2.GetCode(isolate)->set_is_pregenerated(true);
741}
742
743
744void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
745                                               intptr_t stack_pointer) {
746  FunctionEntryHook entry_hook = Isolate::Current()->function_entry_hook();
747  ASSERT(entry_hook != NULL);
748  entry_hook(function, stack_pointer);
749}
750
751
752static void InstallDescriptor(Isolate* isolate, HydrogenCodeStub* stub) {
753  int major_key = stub->MajorKey();
754  CodeStubInterfaceDescriptor* descriptor =
755      isolate->code_stub_interface_descriptor(major_key);
756  if (!descriptor->initialized()) {
757    stub->InitializeInterfaceDescriptor(isolate, descriptor);
758  }
759}
760
761
762void ArrayConstructorStubBase::InstallDescriptors(Isolate* isolate) {
763  ArrayNoArgumentConstructorStub stub1(GetInitialFastElementsKind());
764  InstallDescriptor(isolate, &stub1);
765  ArraySingleArgumentConstructorStub stub2(GetInitialFastElementsKind());
766  InstallDescriptor(isolate, &stub2);
767  ArrayNArgumentsConstructorStub stub3(GetInitialFastElementsKind());
768  InstallDescriptor(isolate, &stub3);
769}
770
771
772ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
773    : argument_count_(ANY) {
774  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
775}
776
777
778ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
779                                           int argument_count) {
780  if (argument_count == 0) {
781    argument_count_ = NONE;
782  } else if (argument_count == 1) {
783    argument_count_ = ONE;
784  } else if (argument_count >= 2) {
785    argument_count_ = MORE_THAN_ONE;
786  } else {
787    UNREACHABLE();
788  }
789  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
790}
791
792
793void InternalArrayConstructorStubBase::InstallDescriptors(Isolate* isolate) {
794  InternalArrayNoArgumentConstructorStub stub1(FAST_ELEMENTS);
795  InstallDescriptor(isolate, &stub1);
796  InternalArraySingleArgumentConstructorStub stub2(FAST_ELEMENTS);
797  InstallDescriptor(isolate, &stub2);
798  InternalArrayNArgumentsConstructorStub stub3(FAST_ELEMENTS);
799  InstallDescriptor(isolate, &stub3);
800}
801
802InternalArrayConstructorStub::InternalArrayConstructorStub(
803    Isolate* isolate) {
804  InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
805}
806
807
808} }  // namespace v8::internal
809