v8: upgrade to v8 3.20.7
[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) {
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   AddSimulate(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<FastCloneShallowArrayStub>::BuildCodeStub() {
311   Zone* zone = this->zone();
312   Factory* factory = isolate()->factory();
313   HValue* undefined = graph()->GetConstantUndefined();
314   AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
315   FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
316   int length = casted_stub()->length();
317
318   HInstruction* allocation_site =
319       AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
320                                           GetParameter(1),
321                                           NULL,
322                                           FAST_ELEMENTS));
323   IfBuilder checker(this);
324   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, undefined);
325   checker.Then();
326
327   HObjectAccess access = HObjectAccess::ForAllocationSiteTransitionInfo();
328   HInstruction* boilerplate = AddLoad(allocation_site, access);
329   if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
330     HValue* elements = AddLoadElements(boilerplate);
331
332     IfBuilder if_fixed_cow(this);
333     if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map());
334     if_fixed_cow.Then();
335     environment()->Push(BuildCloneShallowArray(context(),
336                                                boilerplate,
337                                                allocation_site,
338                                                alloc_site_mode,
339                                                FAST_ELEMENTS,
340                                                0/*copy-on-write*/));
341     if_fixed_cow.Else();
342
343     IfBuilder if_fixed(this);
344     if_fixed.If<HCompareMap>(elements, factory->fixed_array_map());
345     if_fixed.Then();
346     environment()->Push(BuildCloneShallowArray(context(),
347                                                boilerplate,
348                                                allocation_site,
349                                                alloc_site_mode,
350                                                FAST_ELEMENTS,
351                                                length));
352     if_fixed.Else();
353     environment()->Push(BuildCloneShallowArray(context(),
354                                                boilerplate,
355                                                allocation_site,
356                                                alloc_site_mode,
357                                                FAST_DOUBLE_ELEMENTS,
358                                                length));
359   } else {
360     ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
361     environment()->Push(BuildCloneShallowArray(context(),
362                                                boilerplate,
363                                                allocation_site,
364                                                alloc_site_mode,
365                                                elements_kind,
366                                                length));
367   }
368
369   HValue* result = environment()->Pop();
370   checker.ElseDeopt();
371   return result;
372 }
373
374
375 Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
376   return DoGenerateCode(this);
377 }
378
379
380 template <>
381 HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
382   Zone* zone = this->zone();
383   HValue* undefined = graph()->GetConstantUndefined();
384
385   HInstruction* boilerplate =
386       AddInstruction(new(zone) HLoadKeyed(GetParameter(0),
387                                           GetParameter(1),
388                                           NULL,
389                                           FAST_ELEMENTS));
390
391   IfBuilder checker(this);
392   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(boilerplate, undefined);
393   checker.And();
394
395   int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
396   HValue* boilerplate_size =
397       AddInstruction(new(zone) HInstanceSize(boilerplate));
398   HValue* size_in_words =
399       AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2));
400   checker.If<HCompareNumericAndBranch>(boilerplate_size,
401                                        size_in_words, Token::EQ);
402   checker.Then();
403
404   HValue* size_in_bytes = AddInstruction(new(zone) HConstant(size));
405   HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE;
406   if (isolate()->heap()->ShouldGloballyPretenure()) {
407     flags = static_cast<HAllocate::Flags>(
408        flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
409   }
410
411   HInstruction* object = AddInstruction(new(zone)
412       HAllocate(context(), size_in_bytes, HType::JSObject(), flags));
413
414   for (int i = 0; i < size; i += kPointerSize) {
415     HObjectAccess access = HObjectAccess::ForJSObjectOffset(i);
416     AddStore(object, access, AddLoad(boilerplate, access));
417   }
418
419   checker.ElseDeopt();
420   return object;
421 }
422
423
424 Handle<Code> FastCloneShallowObjectStub::GenerateCode() {
425   return DoGenerateCode(this);
426 }
427
428
429 template <>
430 HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
431   Zone* zone = this->zone();
432
433   HValue* size = AddInstruction(new(zone) HConstant(AllocationSite::kSize));
434   HAllocate::Flags flags = HAllocate::DefaultFlags();
435   flags = static_cast<HAllocate::Flags>(
436       flags | HAllocate::CAN_ALLOCATE_IN_OLD_POINTER_SPACE);
437   HInstruction* object = AddInstruction(new(zone)
438       HAllocate(context(), size, HType::JSObject(), flags));
439
440   // Store the map
441   Handle<Map> allocation_site_map(isolate()->heap()->allocation_site_map(),
442                                   isolate());
443   AddStoreMapConstant(object, allocation_site_map);
444
445   // Store the payload (smi elements kind)
446   HValue* initial_elements_kind = AddInstruction(new(zone) HConstant(
447       GetInitialFastElementsKind()));
448   Add<HStoreNamedField>(object,
449                         HObjectAccess::ForAllocationSiteTransitionInfo(),
450                         initial_elements_kind);
451
452   Add<HLinkObjectInList>(object, HObjectAccess::ForAllocationSiteWeakNext(),
453                          HLinkObjectInList::ALLOCATION_SITE_LIST);
454
455   // We use a hammer (SkipWriteBarrier()) to indicate that we know the input
456   // cell is really a Cell, and so no write barrier is needed.
457   // TODO(mvstanton): Add a debug_code check to verify the input cell is really
458   // a cell. (perhaps with a new instruction, HAssert).
459   HInstruction* cell = GetParameter(0);
460   HObjectAccess access = HObjectAccess::ForCellValue();
461   HStoreNamedField* store = AddStore(cell, access, object);
462   store->SkipWriteBarrier();
463   return cell;
464 }
465
466
467 Handle<Code> CreateAllocationSiteStub::GenerateCode() {
468   return DoGenerateCode(this);
469 }
470
471
472 template <>
473 HValue* CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
474   HInstruction* load = BuildUncheckedMonomorphicElementAccess(
475       GetParameter(0), GetParameter(1), NULL, NULL,
476       casted_stub()->is_js_array(), casted_stub()->elements_kind(),
477       false, NEVER_RETURN_HOLE, STANDARD_STORE);
478   return load;
479 }
480
481
482 Handle<Code> KeyedLoadFastElementStub::GenerateCode() {
483   return DoGenerateCode(this);
484 }
485
486
487 template<>
488 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
489   HObjectAccess access = casted_stub()->is_inobject() ?
490       HObjectAccess::ForJSObjectOffset(casted_stub()->offset()) :
491       HObjectAccess::ForBackingStoreOffset(casted_stub()->offset());
492   return AddInstruction(BuildLoadNamedField(GetParameter(0), access,
493       casted_stub()->representation()));
494 }
495
496
497 Handle<Code> LoadFieldStub::GenerateCode() {
498   return DoGenerateCode(this);
499 }
500
501
502 template<>
503 HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
504   HObjectAccess access = casted_stub()->is_inobject() ?
505       HObjectAccess::ForJSObjectOffset(casted_stub()->offset()) :
506       HObjectAccess::ForBackingStoreOffset(casted_stub()->offset());
507   return AddInstruction(BuildLoadNamedField(GetParameter(0), access,
508       casted_stub()->representation()));
509 }
510
511
512 Handle<Code> KeyedLoadFieldStub::GenerateCode() {
513   return DoGenerateCode(this);
514 }
515
516
517 template <>
518 HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
519   BuildUncheckedMonomorphicElementAccess(
520       GetParameter(0), GetParameter(1), GetParameter(2), NULL,
521       casted_stub()->is_js_array(), casted_stub()->elements_kind(),
522       true, NEVER_RETURN_HOLE, casted_stub()->store_mode());
523
524   return GetParameter(2);
525 }
526
527
528 Handle<Code> KeyedStoreFastElementStub::GenerateCode() {
529   return DoGenerateCode(this);
530 }
531
532
533 template <>
534 HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
535   info()->MarkAsSavesCallerDoubles();
536
537   BuildTransitionElementsKind(GetParameter(0),
538                               GetParameter(1),
539                               casted_stub()->from_kind(),
540                               casted_stub()->to_kind(),
541                               true);
542
543   return GetParameter(0);
544 }
545
546
547 Handle<Code> TransitionElementsKindStub::GenerateCode() {
548   return DoGenerateCode(this);
549 }
550
551 HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
552     ElementsKind kind,
553     ContextCheckMode context_mode,
554     AllocationSiteOverrideMode override_mode,
555     ArgumentClass argument_class) {
556   HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor);
557   if (context_mode == CONTEXT_CHECK_REQUIRED) {
558     HInstruction* array_function = BuildGetArrayFunction(context());
559     ArrayContextChecker checker(this, constructor, array_function);
560   }
561
562   HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
563   // Walk through the property cell to the AllocationSite
564   HValue* alloc_site = AddInstruction(new(zone()) HLoadNamedField(property_cell,
565       HObjectAccess::ForCellValue()));
566   JSArrayBuilder array_builder(this, kind, alloc_site, constructor,
567                                override_mode);
568   HValue* result = NULL;
569   switch (argument_class) {
570     case NONE:
571       result = array_builder.AllocateEmptyArray();
572       break;
573     case SINGLE:
574       result = BuildArraySingleArgumentConstructor(&array_builder);
575       break;
576     case MULTIPLE:
577       result = BuildArrayNArgumentsConstructor(&array_builder, kind);
578       break;
579   }
580
581   return result;
582 }
583
584
585 HValue* CodeStubGraphBuilderBase::BuildInternalArrayConstructor(
586     ElementsKind kind, ArgumentClass argument_class) {
587   HValue* constructor = GetParameter(
588       InternalArrayConstructorStubBase::kConstructor);
589   JSArrayBuilder array_builder(this, kind, constructor);
590
591   HValue* result = NULL;
592   switch (argument_class) {
593     case NONE:
594       result = array_builder.AllocateEmptyArray();
595       break;
596     case SINGLE:
597       result = BuildArraySingleArgumentConstructor(&array_builder);
598       break;
599     case MULTIPLE:
600       result = BuildArrayNArgumentsConstructor(&array_builder, kind);
601       break;
602   }
603   return result;
604 }
605
606
607 HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor(
608     JSArrayBuilder* array_builder) {
609   // Smi check and range check on the input arg.
610   HValue* constant_one = graph()->GetConstant1();
611   HValue* constant_zero = graph()->GetConstant0();
612
613   HInstruction* elements = AddInstruction(
614       new(zone()) HArgumentsElements(false));
615   HInstruction* argument = AddInstruction(
616       new(zone()) HAccessArgumentsAt(elements, constant_one, constant_zero));
617
618   HConstant* max_alloc_length =
619       new(zone()) HConstant(JSObject::kInitialMaxFastElementArray);
620   AddInstruction(max_alloc_length);
621   const int initial_capacity = JSArray::kPreallocatedArrayElements;
622   HConstant* initial_capacity_node = new(zone()) HConstant(initial_capacity);
623   AddInstruction(initial_capacity_node);
624
625   HBoundsCheck* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
626   IfBuilder if_builder(this);
627   if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero,
628                                           Token::EQ);
629   if_builder.Then();
630   Push(initial_capacity_node);  // capacity
631   Push(constant_zero);  // length
632   if_builder.Else();
633   Push(checked_arg);  // capacity
634   Push(checked_arg);  // length
635   if_builder.End();
636
637   // Figure out total size
638   HValue* length = Pop();
639   HValue* capacity = Pop();
640   return array_builder->AllocateArray(capacity, length, true);
641 }
642
643
644 HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor(
645     JSArrayBuilder* array_builder, ElementsKind kind) {
646   // We need to fill with the hole if it's a smi array in the multi-argument
647   // case because we might have to bail out while copying arguments into
648   // the array because they aren't compatible with a smi array.
649   // If it's a double array, no problem, and if it's fast then no
650   // problem either because doubles are boxed.
651   HValue* length = GetArgumentsLength();
652   bool fill_with_hole = IsFastSmiElementsKind(kind);
653   HValue* new_object = array_builder->AllocateArray(length,
654                                                     length,
655                                                     fill_with_hole);
656   HValue* elements = array_builder->GetElementsLocation();
657   ASSERT(elements != NULL);
658
659   // Now populate the elements correctly.
660   LoopBuilder builder(this,
661                       context(),
662                       LoopBuilder::kPostIncrement);
663   HValue* start = graph()->GetConstant0();
664   HValue* key = builder.BeginBody(start, length, Token::LT);
665   HInstruction* argument_elements = AddInstruction(
666       new(zone()) HArgumentsElements(false));
667   HInstruction* argument = AddInstruction(new(zone()) HAccessArgumentsAt(
668       argument_elements, length, key));
669
670   AddInstruction(new(zone()) HStoreKeyed(elements, key, argument, kind));
671   builder.EndBody();
672   return new_object;
673 }
674
675
676 template <>
677 HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() {
678   ElementsKind kind = casted_stub()->elements_kind();
679   ContextCheckMode context_mode = casted_stub()->context_mode();
680   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
681   return BuildArrayConstructor(kind, context_mode, override_mode, NONE);
682 }
683
684
685 Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode() {
686   return DoGenerateCode(this);
687 }
688
689
690 template <>
691 HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>::
692     BuildCodeStub() {
693   ElementsKind kind = casted_stub()->elements_kind();
694   ContextCheckMode context_mode = casted_stub()->context_mode();
695   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
696   return BuildArrayConstructor(kind, context_mode, override_mode, SINGLE);
697 }
698
699
700 Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() {
701   return DoGenerateCode(this);
702 }
703
704
705 template <>
706 HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() {
707   ElementsKind kind = casted_stub()->elements_kind();
708   ContextCheckMode context_mode = casted_stub()->context_mode();
709   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
710   return BuildArrayConstructor(kind, context_mode, override_mode, MULTIPLE);
711 }
712
713
714 Handle<Code> ArrayNArgumentsConstructorStub::GenerateCode() {
715   return DoGenerateCode(this);
716 }
717
718
719 template <>
720 HValue* CodeStubGraphBuilder<InternalArrayNoArgumentConstructorStub>::
721     BuildCodeStub() {
722   ElementsKind kind = casted_stub()->elements_kind();
723   return BuildInternalArrayConstructor(kind, NONE);
724 }
725
726
727 Handle<Code> InternalArrayNoArgumentConstructorStub::GenerateCode() {
728   return DoGenerateCode(this);
729 }
730
731
732 template <>
733 HValue* CodeStubGraphBuilder<InternalArraySingleArgumentConstructorStub>::
734     BuildCodeStub() {
735   ElementsKind kind = casted_stub()->elements_kind();
736   return BuildInternalArrayConstructor(kind, SINGLE);
737 }
738
739
740 Handle<Code> InternalArraySingleArgumentConstructorStub::GenerateCode() {
741   return DoGenerateCode(this);
742 }
743
744
745 template <>
746 HValue* CodeStubGraphBuilder<InternalArrayNArgumentsConstructorStub>::
747     BuildCodeStub() {
748   ElementsKind kind = casted_stub()->elements_kind();
749   return BuildInternalArrayConstructor(kind, MULTIPLE);
750 }
751
752
753 Handle<Code> InternalArrayNArgumentsConstructorStub::GenerateCode() {
754   return DoGenerateCode(this);
755 }
756
757
758 template <>
759 HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() {
760   Isolate* isolate = graph()->isolate();
761   CompareNilICStub* stub = casted_stub();
762   HIfContinuation continuation;
763   Handle<Map> sentinel_map(isolate->heap()->meta_map());
764   Handle<Type> type = stub->GetType(isolate, sentinel_map);
765   BuildCompareNil(GetParameter(0), type, RelocInfo::kNoPosition, &continuation);
766   IfBuilder if_nil(this, &continuation);
767   if_nil.Then();
768   if (continuation.IsFalseReachable()) {
769     if_nil.Else();
770     if_nil.Return(graph()->GetConstant0());
771   }
772   if_nil.End();
773   return continuation.IsTrueReachable()
774       ? graph()->GetConstant1()
775       : graph()->GetConstantUndefined();
776 }
777
778
779 Handle<Code> CompareNilICStub::GenerateCode() {
780   return DoGenerateCode(this);
781 }
782
783
784 template <>
785 HValue* CodeStubGraphBuilder<UnaryOpStub>::BuildCodeInitializedStub() {
786   UnaryOpStub* stub = casted_stub();
787   Handle<Type> type = stub->GetType(graph()->isolate());
788   HValue* input = GetParameter(0);
789
790   // Prevent unwanted HChange being inserted to ensure that the stub
791   // deopts on newly encountered types.
792   if (!type->Maybe(Type::Double())) {
793     input = AddInstruction(new(zone())
794         HForceRepresentation(input, Representation::Smi()));
795   }
796
797   if (!type->Is(Type::Number())) {
798     // If we expect to see other things than Numbers, we will create a generic
799     // stub, which handles all numbers and calls into the runtime for the rest.
800     IfBuilder if_number(this);
801     if_number.If<HIsNumberAndBranch>(input);
802     if_number.Then();
803     HInstruction* res = BuildUnaryMathOp(input, type, stub->operation());
804     if_number.Return(AddInstruction(res));
805     if_number.Else();
806     HValue* function = AddLoadJSBuiltin(stub->ToJSBuiltin(), context());
807     Add<HPushArgument>(GetParameter(0));
808     HValue* result = Add<HInvokeFunction>(context(), function, 1);
809     if_number.Return(result);
810     if_number.End();
811     return graph()->GetConstantUndefined();
812   }
813
814   return AddInstruction(BuildUnaryMathOp(input, type, stub->operation()));
815 }
816
817
818 Handle<Code> UnaryOpStub::GenerateCode() {
819   return DoGenerateCode(this);
820 }
821
822
823 template <>
824 HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
825   ToBooleanStub* stub = casted_stub();
826
827   IfBuilder if_true(this);
828   if_true.If<HBranch>(GetParameter(0), stub->GetTypes());
829   if_true.Then();
830   if_true.Return(graph()->GetConstant1());
831   if_true.Else();
832   if_true.End();
833   return graph()->GetConstant0();
834 }
835
836
837 Handle<Code> ToBooleanStub::GenerateCode() {
838   return DoGenerateCode(this);
839 }
840
841
842 template <>
843 HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
844   StoreGlobalStub* stub = casted_stub();
845   Handle<Object> hole(isolate()->heap()->the_hole_value(), isolate());
846   Handle<Object> placeholer_value(Smi::FromInt(0), isolate());
847   Handle<PropertyCell> placeholder_cell =
848       isolate()->factory()->NewPropertyCell(placeholer_value);
849
850   HParameter* receiver = GetParameter(0);
851   HParameter* value = GetParameter(2);
852
853   if (stub->is_constant()) {
854     // Assume every store to a constant value changes it.
855     current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
856     set_current_block(NULL);
857   } else {
858     HValue* cell = Add<HConstant>(placeholder_cell, Representation::Tagged());
859
860     // Check that the map of the global has not changed: use a placeholder map
861     // that will be replaced later with the global object's map.
862     Handle<Map> placeholder_map = isolate()->factory()->meta_map();
863     AddInstruction(HCheckMaps::New(receiver, placeholder_map, zone()));
864
865     // Load the payload of the global parameter cell. A hole indicates that the
866     // property has been deleted and that the store must be handled by the
867     // runtime.
868     HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
869     HValue* cell_contents = Add<HLoadNamedField>(cell, access);
870     IfBuilder builder(this);
871     HValue* hole_value = Add<HConstant>(hole, Representation::Tagged());
872     builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
873     builder.Then();
874     builder.Deopt();
875     builder.Else();
876     Add<HStoreNamedField>(cell, access, value);
877     builder.End();
878   }
879   return value;
880 }
881
882
883 Handle<Code> StoreGlobalStub::GenerateCode() {
884   return DoGenerateCode(this);
885 }
886
887
888 template<>
889 HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
890   HValue* value = GetParameter(0);
891   HValue* map = GetParameter(1);
892   HValue* key = GetParameter(2);
893   HValue* object = GetParameter(3);
894
895   if (FLAG_trace_elements_transitions) {
896     // Tracing elements transitions is the job of the runtime.
897     current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
898     set_current_block(NULL);
899   } else {
900     info()->MarkAsSavesCallerDoubles();
901
902     BuildTransitionElementsKind(object, map,
903                                 casted_stub()->from_kind(),
904                                 casted_stub()->to_kind(),
905                                 casted_stub()->is_jsarray());
906
907     BuildUncheckedMonomorphicElementAccess(object, key, value, NULL,
908                                           casted_stub()->is_jsarray(),
909                                           casted_stub()->to_kind(),
910                                           true, ALLOW_RETURN_HOLE,
911                                           casted_stub()->store_mode());
912   }
913
914   return value;
915 }
916
917
918 Handle<Code> ElementsTransitionAndStoreStub::GenerateCode() {
919   return DoGenerateCode(this);
920 }
921
922
923 } }  // namespace v8::internal