v8: upgrade to v8 3.20.9
[platform/upstream/nodejs.git] / deps / v8 / src / code-stubs-hydrogen.cc
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 "code-stubs.h"
31 #include "hydrogen.h"
32 #include "lithium.h"
33
34 namespace v8 {
35 namespace internal {
36
37
38 static LChunk* OptimizeGraph(HGraph* graph) {
39   DisallowHeapAllocation no_allocation;
40   DisallowHandleAllocation no_handles;
41   DisallowHandleDereference no_deref;
42
43   ASSERT(graph != NULL);
44   SmartArrayPointer<char> bailout_reason;
45   if (!graph->Optimize(&bailout_reason)) {
46     FATAL(bailout_reason.is_empty() ? "unknown" : *bailout_reason);
47   }
48   LChunk* chunk = LChunk::NewChunk(graph);
49   if (chunk == NULL) {
50     FATAL(graph->info()->bailout_reason());
51   }
52   return chunk;
53 }
54
55
56 class CodeStubGraphBuilderBase : public HGraphBuilder {
57  public:
58   CodeStubGraphBuilderBase(Isolate* isolate, HydrogenCodeStub* stub)
59       : HGraphBuilder(&info_),
60         arguments_length_(NULL),
61         info_(stub, isolate),
62         context_(NULL) {
63     descriptor_ = stub->GetInterfaceDescriptor(isolate);
64     parameters_.Reset(new HParameter*[descriptor_->register_param_count_]);
65   }
66   virtual bool BuildGraph();
67
68  protected:
69   virtual HValue* BuildCodeStub() = 0;
70   HParameter* GetParameter(int parameter) {
71     ASSERT(parameter < descriptor_->register_param_count_);
72     return parameters_[parameter];
73   }
74   HValue* GetArgumentsLength() {
75     // This is initialized in BuildGraph()
76     ASSERT(arguments_length_ != NULL);
77     return arguments_length_;
78   }
79   CompilationInfo* info() { return &info_; }
80   HydrogenCodeStub* stub() { return info_.code_stub(); }
81   HContext* context() { return context_; }
82   Isolate* isolate() { return info_.isolate(); }
83
84   class ArrayContextChecker {
85    public:
86     ArrayContextChecker(HGraphBuilder* builder, HValue* constructor,
87                         HValue* array_function)
88         : checker_(builder) {
89       checker_.If<HCompareObjectEqAndBranch, HValue*>(constructor,
90                                                       array_function);
91       checker_.Then();
92     }
93
94     ~ArrayContextChecker() {
95       checker_.ElseDeopt();
96       checker_.End();
97     }
98    private:
99     IfBuilder checker_;
100   };
101
102   enum ArgumentClass {
103     NONE,
104     SINGLE,
105     MULTIPLE
106   };
107
108   HValue* BuildArrayConstructor(ElementsKind kind,
109                                 ContextCheckMode context_mode,
110                                 AllocationSiteOverrideMode override_mode,
111                                 ArgumentClass argument_class);
112   HValue* BuildInternalArrayConstructor(ElementsKind kind,
113                                         ArgumentClass argument_class);
114
115  private:
116   HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder);
117   HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder,
118                                           ElementsKind kind);
119
120   SmartArrayPointer<HParameter*> parameters_;
121   HValue* arguments_length_;
122   CompilationInfoWithZone info_;
123   CodeStubInterfaceDescriptor* descriptor_;
124   HContext* context_;
125 };
126
127
128 bool CodeStubGraphBuilderBase::BuildGraph() {
129   // Update the static counter each time a new code stub is generated.
130   isolate()->counters()->code_stubs()->Increment();
131
132   if (FLAG_trace_hydrogen_stubs) {
133     const char* name = CodeStub::MajorName(stub()->MajorKey(), false);
134     PrintF("-----------------------------------------------------------\n");
135     PrintF("Compiling stub %s using hydrogen\n", name);
136     isolate()->GetHTracer()->TraceCompilation(&info_);
137   }
138
139   Zone* zone = this->zone();
140   int param_count = descriptor_->register_param_count_;
141   HEnvironment* start_environment = graph()->start_environment();
142   HBasicBlock* next_block = CreateBasicBlock(start_environment);
143   current_block()->Goto(next_block);
144   next_block->SetJoinId(BailoutId::StubEntry());
145   set_current_block(next_block);
146
147   HConstant* undefined_constant = new(zone) HConstant(
148       isolate()->factory()->undefined_value());
149   AddInstruction(undefined_constant);
150   graph()->set_undefined_constant(undefined_constant);
151
152   for (int i = 0; i < param_count; ++i) {
153     HParameter* param =
154         new(zone) HParameter(i, HParameter::REGISTER_PARAMETER);
155     AddInstruction(param);
156     start_environment->Bind(i, param);
157     parameters_[i] = param;
158   }
159
160   HInstruction* stack_parameter_count;
161   if (descriptor_->stack_parameter_count_ != NULL) {
162     ASSERT(descriptor_->environment_length() == (param_count + 1));
163     stack_parameter_count = new(zone) HParameter(param_count,
164                                                  HParameter::REGISTER_PARAMETER,
165                                                  Representation::Integer32());
166     stack_parameter_count->set_type(HType::Smi());
167     // It's essential to bind this value to the environment in case of deopt.
168     AddInstruction(stack_parameter_count);
169     start_environment->Bind(param_count, stack_parameter_count);
170     arguments_length_ = stack_parameter_count;
171   } else {
172     ASSERT(descriptor_->environment_length() == param_count);
173     stack_parameter_count = graph()->GetConstantMinus1();
174     arguments_length_ = graph()->GetConstant0();
175   }
176
177   context_ = new(zone) HContext();
178   AddInstruction(context_);
179   start_environment->BindContext(context_);
180
181   Add<HSimulate>(BailoutId::StubEntry());
182
183   NoObservableSideEffectsScope no_effects(this);
184
185   HValue* return_value = BuildCodeStub();
186
187   // We might have extra expressions to pop from the stack in addition to the
188   // arguments above.
189   HInstruction* stack_pop_count = stack_parameter_count;
190   if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) {
191     if (!stack_parameter_count->IsConstant() &&
192         descriptor_->hint_stack_parameter_count_ < 0) {
193       HInstruction* amount = graph()->GetConstant1();
194       stack_pop_count = AddInstruction(
195           HAdd::New(zone, context_, stack_parameter_count, amount));
196       stack_pop_count->ChangeRepresentation(Representation::Integer32());
197       stack_pop_count->ClearFlag(HValue::kCanOverflow);
198     } else {
199       int count = descriptor_->hint_stack_parameter_count_;
200       stack_pop_count = AddInstruction(new(zone) HConstant(count));
201     }
202   }
203
204   if (current_block() != NULL) {
205     HReturn* hreturn_instruction = new(zone) HReturn(return_value,
206                                                      context_,
207                                                      stack_pop_count);
208     current_block()->Finish(hreturn_instruction);
209     set_current_block(NULL);
210   }
211   return true;
212 }
213
214
215 template <class Stub>
216 class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
217  public:
218   explicit CodeStubGraphBuilder(Stub* stub)
219       : CodeStubGraphBuilderBase(Isolate::Current(), stub) {}
220
221  protected:
222   virtual HValue* BuildCodeStub() {
223     if (casted_stub()->IsUninitialized()) {
224       return BuildCodeUninitializedStub();
225     } else {
226       return BuildCodeInitializedStub();
227     }
228   }
229
230   virtual HValue* BuildCodeInitializedStub() {
231     UNIMPLEMENTED();
232     return NULL;
233   }
234
235   virtual HValue* BuildCodeUninitializedStub() {
236     // Force a deopt that falls back to the runtime.
237     HValue* undefined = graph()->GetConstantUndefined();
238     IfBuilder builder(this);
239     builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined);
240     builder.Then();
241     builder.ElseDeopt();
242     return undefined;
243   }
244
245   Stub* casted_stub() { return static_cast<Stub*>(stub()); }
246 };
247
248
249 Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(Isolate* isolate) {
250   Factory* factory = isolate->factory();
251
252   // Generate the new code.
253   MacroAssembler masm(isolate, NULL, 256);
254
255   {
256     // Update the static counter each time a new code stub is generated.
257     isolate->counters()->code_stubs()->Increment();
258
259     // Nested stubs are not allowed for leaves.
260     AllowStubCallsScope allow_scope(&masm, false);
261
262     // Generate the code for the stub.
263     masm.set_generating_stub(true);
264     NoCurrentFrameScope scope(&masm);
265     GenerateLightweightMiss(&masm);
266   }
267
268   // Create the code object.
269   CodeDesc desc;
270   masm.GetCode(&desc);
271
272   // Copy the generated code into a heap object.
273   Code::Flags flags = Code::ComputeFlags(
274       GetCodeKind(),
275       GetICState(),
276       GetExtraICState(),
277       GetStubType(),
278       GetStubFlags());
279   Handle<Code> new_object = factory->NewCode(
280       desc, flags, masm.CodeObject(), NeedsImmovableCode());
281   return new_object;
282 }
283
284
285 template <class Stub>
286 static Handle<Code> DoGenerateCode(Stub* stub) {
287   Isolate* isolate = Isolate::Current();
288   CodeStub::Major  major_key =
289       static_cast<HydrogenCodeStub*>(stub)->MajorKey();
290   CodeStubInterfaceDescriptor* descriptor =
291       isolate->code_stub_interface_descriptor(major_key);
292   if (descriptor->register_param_count_ < 0) {
293     stub->InitializeInterfaceDescriptor(isolate, descriptor);
294   }
295
296   // If we are uninitialized we can use a light-weight stub to enter
297   // the runtime that is significantly faster than using the standard
298   // stub-failure deopt mechanism.
299   if (stub->IsUninitialized() && descriptor->has_miss_handler()) {
300     ASSERT(descriptor->stack_parameter_count_ == NULL);
301     return stub->GenerateLightweightMissCode(isolate);
302   }
303   CodeStubGraphBuilder<Stub> builder(stub);
304   LChunk* chunk = OptimizeGraph(builder.CreateGraph());
305   return chunk->Codegen();
306 }
307
308
309 template <>
310 HValue* CodeStubGraphBuilder<ToNumberStub>::BuildCodeStub() {
311   HValue* value = GetParameter(0);
312
313   // Check if the parameter is already a SMI or heap number.
314   IfBuilder if_number(this);
315   if_number.If<HIsSmiAndBranch>(value);
316   if_number.OrIf<HCompareMap>(value, isolate()->factory()->heap_number_map());
317   if_number.Then();
318
319   // Return the number.
320   Push(value);
321
322   if_number.Else();
323
324   // Convert the parameter to number using the builtin.
325   HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER, context());
326   Add<HPushArgument>(value);
327   Push(Add<HInvokeFunction>(context(), function, 1));
328
329   if_number.End();
330
331   return Pop();
332 }
333
334
335 Handle<Code> ToNumberStub::GenerateCode() {
336   return DoGenerateCode(this);
337 }
338
339
340 template <>
341 HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
342   Zone* zone = this->zone();
343   Factory* factory = isolate()->factory();
344   HValue* undefined = graph()->GetConstantUndefined();
345   AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
346   FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
347   int length = casted_stub()->length();
348
349   HInstruction* allocation_site =
350       AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
351                                           GetParameter(1),
352                                           NULL,
353                                           FAST_ELEMENTS));
354   IfBuilder checker(this);
355   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, undefined);
356   checker.Then();
357
358   HObjectAccess access = HObjectAccess::ForAllocationSiteTransitionInfo();
359   HInstruction* boilerplate = AddLoad(allocation_site, access);
360   if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
361     HValue* elements = AddLoadElements(boilerplate);
362
363     IfBuilder if_fixed_cow(this);
364     if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map());
365     if_fixed_cow.Then();
366     environment()->Push(BuildCloneShallowArray(context(),
367                                                boilerplate,
368                                                allocation_site,
369                                                alloc_site_mode,
370                                                FAST_ELEMENTS,
371                                                0/*copy-on-write*/));
372     if_fixed_cow.Else();
373
374     IfBuilder if_fixed(this);
375     if_fixed.If<HCompareMap>(elements, factory->fixed_array_map());
376     if_fixed.Then();
377     environment()->Push(BuildCloneShallowArray(context(),
378                                                boilerplate,
379                                                allocation_site,
380                                                alloc_site_mode,
381                                                FAST_ELEMENTS,
382                                                length));
383     if_fixed.Else();
384     environment()->Push(BuildCloneShallowArray(context(),
385                                                boilerplate,
386                                                allocation_site,
387                                                alloc_site_mode,
388                                                FAST_DOUBLE_ELEMENTS,
389                                                length));
390   } else {
391     ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
392     environment()->Push(BuildCloneShallowArray(context(),
393                                                boilerplate,
394                                                allocation_site,
395                                                alloc_site_mode,
396                                                elements_kind,
397                                                length));
398   }
399
400   checker.ElseDeopt();
401   checker.End();
402
403   return environment()->Pop();
404 }
405
406
407 Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
408   return DoGenerateCode(this);
409 }
410
411
412 template <>
413 HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
414   Zone* zone = this->zone();
415   HValue* undefined = graph()->GetConstantUndefined();
416
417   HInstruction* boilerplate =
418       AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
419                                           GetParameter(1),
420                                           NULL,
421                                           FAST_ELEMENTS));
422
423   IfBuilder checker(this);
424   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(boilerplate, undefined);
425   checker.And();
426
427   int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
428   HValue* boilerplate_size =
429       AddInstruction(new(zone) HInstanceSize(boilerplate));
430   HValue* size_in_words =
431       AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2));
432   checker.If<HCompareNumericAndBranch>(boilerplate_size,
433                                        size_in_words, Token::EQ);
434   checker.Then();
435
436   HValue* size_in_bytes = AddInstruction(new(zone) HConstant(size));
437   HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
438   if (isolate()->heap()->ShouldGloballyPretenure()) {
439     flags = static_cast<HAllocate::Flags>(
440        flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
441   }
442
443   HInstruction* object = AddInstruction(new(zone)
444       HAllocate(context(), size_in_bytes, HType::JSObject(), flags));
445
446   for (int i = 0; i < size; i += kPointerSize) {
447     HObjectAccess access = HObjectAccess::ForJSObjectOffset(i);
448     AddStore(object, access, AddLoad(boilerplate, access));
449   }
450
451   environment()->Push(object);
452   checker.ElseDeopt();
453   checker.End();
454
455   return environment()->Pop();
456 }
457
458
459 Handle<Code> FastCloneShallowObjectStub::GenerateCode() {
460   return DoGenerateCode(this);
461 }
462
463
464 template <>
465 HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
466   Zone* zone = this->zone();
467
468   HValue* size = AddInstruction(new(zone) HConstant(AllocationSite::kSize));
469   HAllocate::Flags flags = HAllocate::DefaultFlags();
470   flags = static_cast<HAllocate::Flags>(
471       flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
472   HInstruction* object = AddInstruction(new(zone)
473       HAllocate(context(), size, HType::JSObject(), flags));
474
475   // Store the map
476   Handle<Map> allocation_site_map(isolate()->heap()->allocation_site_map(),
477                                   isolate());
478   AddStoreMapConstant(object, allocation_site_map);
479
480   // Store the payload (smi elements kind)
481   HValue* initial_elements_kind = AddInstruction(new(zone) HConstant(
482       GetInitialFastElementsKind()));
483   Add<HStoreNamedField>(object,
484                         HObjectAccess::ForAllocationSiteTransitionInfo(),
485                         initial_elements_kind);
486
487   Add<HLinkObjectInList>(object, HObjectAccess::ForAllocationSiteWeakNext(),
488                          HLinkObjectInList::ALLOCATION_SITE_LIST);
489
490   // We use a hammer (SkipWriteBarrier()) to indicate that we know the input
491   // cell is really a Cell, and so no write barrier is needed.
492   // TODO(mvstanton): Add a debug_code check to verify the input cell is really
493   // a cell. (perhaps with a new instruction, HAssert).
494   HInstruction* cell = GetParameter(0);
495   HObjectAccess access = HObjectAccess::ForCellValue();
496   HStoreNamedField* store = AddStore(cell, access, object);
497   store->SkipWriteBarrier();
498   return cell;
499 }
500
501
502 Handle<Code> CreateAllocationSiteStub::GenerateCode() {
503   return DoGenerateCode(this);
504 }
505
506
507 template <>
508 HValue* CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
509   HInstruction* load = BuildUncheckedMonomorphicElementAccess(
510       GetParameter(0), GetParameter(1), NULL, NULL,
511       casted_stub()->is_js_array(), casted_stub()->elements_kind(),
512       false, NEVER_RETURN_HOLE, STANDARD_STORE);
513   return load;
514 }
515
516
517 Handle<Code> KeyedLoadFastElementStub::GenerateCode() {
518   return DoGenerateCode(this);
519 }
520
521
522 template<>
523 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
524   Representation rep = casted_stub()->representation();
525   HObjectAccess access = casted_stub()->is_inobject() ?
526       HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) :
527       HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep);
528   return AddInstruction(BuildLoadNamedField(GetParameter(0), access));
529 }
530
531
532 Handle<Code> LoadFieldStub::GenerateCode() {
533   return DoGenerateCode(this);
534 }
535
536
537 template<>
538 HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
539   Representation rep = casted_stub()->representation();
540   HObjectAccess access = casted_stub()->is_inobject() ?
541       HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) :
542       HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep);
543   return AddInstruction(BuildLoadNamedField(GetParameter(0), access));
544 }
545
546
547 Handle<Code> KeyedLoadFieldStub::GenerateCode() {
548   return DoGenerateCode(this);
549 }
550
551
552 template <>
553 HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
554   BuildUncheckedMonomorphicElementAccess(
555       GetParameter(0), GetParameter(1), GetParameter(2), NULL,
556       casted_stub()->is_js_array(), casted_stub()->elements_kind(),
557       true, NEVER_RETURN_HOLE, casted_stub()->store_mode());
558
559   return GetParameter(2);
560 }
561
562
563 Handle<Code> KeyedStoreFastElementStub::GenerateCode() {
564   return DoGenerateCode(this);
565 }
566
567
568 template <>
569 HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
570   info()->MarkAsSavesCallerDoubles();
571
572   BuildTransitionElementsKind(GetParameter(0),
573                               GetParameter(1),
574                               casted_stub()->from_kind(),
575                               casted_stub()->to_kind(),
576                               true);
577
578   return GetParameter(0);
579 }
580
581
582 Handle<Code> TransitionElementsKindStub::GenerateCode() {
583   return DoGenerateCode(this);
584 }
585
586 HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
587     ElementsKind kind,
588     ContextCheckMode context_mode,
589     AllocationSiteOverrideMode override_mode,
590     ArgumentClass argument_class) {
591   HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor);
592   if (context_mode == CONTEXT_CHECK_REQUIRED) {
593     HInstruction* array_function = BuildGetArrayFunction(context());
594     ArrayContextChecker checker(this, constructor, array_function);
595   }
596
597   HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
598   // Walk through the property cell to the AllocationSite
599   HValue* alloc_site = AddInstruction(new(zone()) HLoadNamedField(property_cell,
600       HObjectAccess::ForCellValue()));
601   JSArrayBuilder array_builder(this, kind, alloc_site, constructor,
602                                override_mode);
603   HValue* result = NULL;
604   switch (argument_class) {
605     case NONE:
606       result = array_builder.AllocateEmptyArray();
607       break;
608     case SINGLE:
609       result = BuildArraySingleArgumentConstructor(&array_builder);
610       break;
611     case MULTIPLE:
612       result = BuildArrayNArgumentsConstructor(&array_builder, kind);
613       break;
614   }
615
616   return result;
617 }
618
619
620 HValue* CodeStubGraphBuilderBase::BuildInternalArrayConstructor(
621     ElementsKind kind, ArgumentClass argument_class) {
622   HValue* constructor = GetParameter(
623       InternalArrayConstructorStubBase::kConstructor);
624   JSArrayBuilder array_builder(this, kind, constructor);
625
626   HValue* result = NULL;
627   switch (argument_class) {
628     case NONE:
629       result = array_builder.AllocateEmptyArray();
630       break;
631     case SINGLE:
632       result = BuildArraySingleArgumentConstructor(&array_builder);
633       break;
634     case MULTIPLE:
635       result = BuildArrayNArgumentsConstructor(&array_builder, kind);
636       break;
637   }
638   return result;
639 }
640
641
642 HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor(
643     JSArrayBuilder* array_builder) {
644   // Smi check and range check on the input arg.
645   HValue* constant_one = graph()->GetConstant1();
646   HValue* constant_zero = graph()->GetConstant0();
647
648   HInstruction* elements = AddInstruction(
649       new(zone()) HArgumentsElements(false));
650   HInstruction* argument = AddInstruction(
651       new(zone()) HAccessArgumentsAt(elements, constant_one, constant_zero));
652
653   HConstant* max_alloc_length =
654       new(zone()) HConstant(JSObject::kInitialMaxFastElementArray);
655   AddInstruction(max_alloc_length);
656   const int initial_capacity = JSArray::kPreallocatedArrayElements;
657   HConstant* initial_capacity_node = new(zone()) HConstant(initial_capacity);
658   AddInstruction(initial_capacity_node);
659
660   HBoundsCheck* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
661   IfBuilder if_builder(this);
662   if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero,
663                                           Token::EQ);
664   if_builder.Then();
665   Push(initial_capacity_node);  // capacity
666   Push(constant_zero);  // length
667   if_builder.Else();
668   Push(checked_arg);  // capacity
669   Push(checked_arg);  // length
670   if_builder.End();
671
672   // Figure out total size
673   HValue* length = Pop();
674   HValue* capacity = Pop();
675   return array_builder->AllocateArray(capacity, length, true);
676 }
677
678
679 HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor(
680     JSArrayBuilder* array_builder, ElementsKind kind) {
681   // We need to fill with the hole if it's a smi array in the multi-argument
682   // case because we might have to bail out while copying arguments into
683   // the array because they aren't compatible with a smi array.
684   // If it's a double array, no problem, and if it's fast then no
685   // problem either because doubles are boxed.
686   HValue* length = GetArgumentsLength();
687   bool fill_with_hole = IsFastSmiElementsKind(kind);
688   HValue* new_object = array_builder->AllocateArray(length,
689                                                     length,
690                                                     fill_with_hole);
691   HValue* elements = array_builder->GetElementsLocation();
692   ASSERT(elements != NULL);
693
694   // Now populate the elements correctly.
695   LoopBuilder builder(this,
696                       context(),
697                       LoopBuilder::kPostIncrement);
698   HValue* start = graph()->GetConstant0();
699   HValue* key = builder.BeginBody(start, length, Token::LT);
700   HInstruction* argument_elements = AddInstruction(
701       new(zone()) HArgumentsElements(false));
702   HInstruction* argument = AddInstruction(new(zone()) HAccessArgumentsAt(
703       argument_elements, length, key));
704
705   AddInstruction(new(zone()) HStoreKeyed(elements, key, argument, kind));
706   builder.EndBody();
707   return new_object;
708 }
709
710
711 template <>
712 HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() {
713   ElementsKind kind = casted_stub()->elements_kind();
714   ContextCheckMode context_mode = casted_stub()->context_mode();
715   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
716   return BuildArrayConstructor(kind, context_mode, override_mode, NONE);
717 }
718
719
720 Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode() {
721   return DoGenerateCode(this);
722 }
723
724
725 template <>
726 HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>::
727     BuildCodeStub() {
728   ElementsKind kind = casted_stub()->elements_kind();
729   ContextCheckMode context_mode = casted_stub()->context_mode();
730   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
731   return BuildArrayConstructor(kind, context_mode, override_mode, SINGLE);
732 }
733
734
735 Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() {
736   return DoGenerateCode(this);
737 }
738
739
740 template <>
741 HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() {
742   ElementsKind kind = casted_stub()->elements_kind();
743   ContextCheckMode context_mode = casted_stub()->context_mode();
744   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
745   return BuildArrayConstructor(kind, context_mode, override_mode, MULTIPLE);
746 }
747
748
749 Handle<Code> ArrayNArgumentsConstructorStub::GenerateCode() {
750   return DoGenerateCode(this);
751 }
752
753
754 template <>
755 HValue* CodeStubGraphBuilder<InternalArrayNoArgumentConstructorStub>::
756     BuildCodeStub() {
757   ElementsKind kind = casted_stub()->elements_kind();
758   return BuildInternalArrayConstructor(kind, NONE);
759 }
760
761
762 Handle<Code> InternalArrayNoArgumentConstructorStub::GenerateCode() {
763   return DoGenerateCode(this);
764 }
765
766
767 template <>
768 HValue* CodeStubGraphBuilder<InternalArraySingleArgumentConstructorStub>::
769     BuildCodeStub() {
770   ElementsKind kind = casted_stub()->elements_kind();
771   return BuildInternalArrayConstructor(kind, SINGLE);
772 }
773
774
775 Handle<Code> InternalArraySingleArgumentConstructorStub::GenerateCode() {
776   return DoGenerateCode(this);
777 }
778
779
780 template <>
781 HValue* CodeStubGraphBuilder<InternalArrayNArgumentsConstructorStub>::
782     BuildCodeStub() {
783   ElementsKind kind = casted_stub()->elements_kind();
784   return BuildInternalArrayConstructor(kind, MULTIPLE);
785 }
786
787
788 Handle<Code> InternalArrayNArgumentsConstructorStub::GenerateCode() {
789   return DoGenerateCode(this);
790 }
791
792
793 template <>
794 HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() {
795   Isolate* isolate = graph()->isolate();
796   CompareNilICStub* stub = casted_stub();
797   HIfContinuation continuation;
798   Handle<Map> sentinel_map(isolate->heap()->meta_map());
799   Handle<Type> type = stub->GetType(isolate, sentinel_map);
800   BuildCompareNil(GetParameter(0), type, RelocInfo::kNoPosition, &continuation);
801   IfBuilder if_nil(this, &continuation);
802   if_nil.Then();
803   if (continuation.IsFalseReachable()) {
804     if_nil.Else();
805     if_nil.Return(graph()->GetConstant0());
806   }
807   if_nil.End();
808   return continuation.IsTrueReachable()
809       ? graph()->GetConstant1()
810       : graph()->GetConstantUndefined();
811 }
812
813
814 Handle<Code> CompareNilICStub::GenerateCode() {
815   return DoGenerateCode(this);
816 }
817
818
819 template <>
820 HValue* CodeStubGraphBuilder<UnaryOpStub>::BuildCodeInitializedStub() {
821   UnaryOpStub* stub = casted_stub();
822   Handle<Type> type = stub->GetType(graph()->isolate());
823   HValue* input = GetParameter(0);
824
825   // Prevent unwanted HChange being inserted to ensure that the stub
826   // deopts on newly encountered types.
827   if (!type->Maybe(Type::Double())) {
828     input = AddInstruction(new(zone())
829         HForceRepresentation(input, Representation::Smi()));
830   }
831
832   if (!type->Is(Type::Number())) {
833     // If we expect to see other things than Numbers, we will create a generic
834     // stub, which handles all numbers and calls into the runtime for the rest.
835     IfBuilder if_number(this);
836     if_number.If<HIsNumberAndBranch>(input);
837     if_number.Then();
838     HInstruction* res = BuildUnaryMathOp(input, type, stub->operation());
839     if_number.Return(AddInstruction(res));
840     if_number.Else();
841     HValue* function = AddLoadJSBuiltin(stub->ToJSBuiltin(), context());
842     Add<HPushArgument>(GetParameter(0));
843     HValue* result = Add<HInvokeFunction>(context(), function, 1);
844     if_number.Return(result);
845     if_number.End();
846     return graph()->GetConstantUndefined();
847   }
848
849   return AddInstruction(BuildUnaryMathOp(input, type, stub->operation()));
850 }
851
852
853 Handle<Code> UnaryOpStub::GenerateCode() {
854   return DoGenerateCode(this);
855 }
856
857
858 template <>
859 HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
860   ToBooleanStub* stub = casted_stub();
861
862   IfBuilder if_true(this);
863   if_true.If<HBranch>(GetParameter(0), stub->GetTypes());
864   if_true.Then();
865   if_true.Return(graph()->GetConstant1());
866   if_true.Else();
867   if_true.End();
868   return graph()->GetConstant0();
869 }
870
871
872 Handle<Code> ToBooleanStub::GenerateCode() {
873   return DoGenerateCode(this);
874 }
875
876
877 template <>
878 HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
879   StoreGlobalStub* stub = casted_stub();
880   Handle<Object> hole(isolate()->heap()->the_hole_value(), isolate());
881   Handle<Object> placeholer_value(Smi::FromInt(0), isolate());
882   Handle<PropertyCell> placeholder_cell =
883       isolate()->factory()->NewPropertyCell(placeholer_value);
884
885   HParameter* receiver = GetParameter(0);
886   HParameter* value = GetParameter(2);
887
888   // Check that the map of the global has not changed: use a placeholder map
889   // that will be replaced later with the global object's map.
890   Handle<Map> placeholder_map = isolate()->factory()->meta_map();
891   AddInstruction(HCheckMaps::New(
892       receiver, placeholder_map, zone(), top_info()));
893
894   HValue* cell = Add<HConstant>(placeholder_cell, Representation::Tagged());
895   HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
896   HValue* cell_contents = Add<HLoadNamedField>(cell, access);
897
898   if (stub->is_constant()) {
899     IfBuilder builder(this);
900     builder.If<HCompareObjectEqAndBranch>(cell_contents, value);
901     builder.Then();
902     builder.ElseDeopt();
903     builder.End();
904   } else {
905     // Load the payload of the global parameter cell. A hole indicates that the
906     // property has been deleted and that the store must be handled by the
907     // runtime.
908     IfBuilder builder(this);
909     HValue* hole_value = Add<HConstant>(hole, Representation::Tagged());
910     builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
911     builder.Then();
912     builder.Deopt();
913     builder.Else();
914     Add<HStoreNamedField>(cell, access, value);
915     builder.End();
916   }
917
918   return value;
919 }
920
921
922 Handle<Code> StoreGlobalStub::GenerateCode() {
923   return DoGenerateCode(this);
924 }
925
926
927 template<>
928 HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
929   HValue* value = GetParameter(0);
930   HValue* map = GetParameter(1);
931   HValue* key = GetParameter(2);
932   HValue* object = GetParameter(3);
933
934   if (FLAG_trace_elements_transitions) {
935     // Tracing elements transitions is the job of the runtime.
936     Add<HDeoptimize>(Deoptimizer::EAGER);
937   } else {
938     info()->MarkAsSavesCallerDoubles();
939
940     BuildTransitionElementsKind(object, map,
941                                 casted_stub()->from_kind(),
942                                 casted_stub()->to_kind(),
943                                 casted_stub()->is_jsarray());
944
945     BuildUncheckedMonomorphicElementAccess(object, key, value, NULL,
946                                           casted_stub()->is_jsarray(),
947                                           casted_stub()->to_kind(),
948                                           true, ALLOW_RETURN_HOLE,
949                                           casted_stub()->store_mode());
950   }
951
952   return value;
953 }
954
955
956 Handle<Code> ElementsTransitionAndStoreStub::GenerateCode() {
957   return DoGenerateCode(this);
958 }
959
960
961 } }  // namespace v8::internal