The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / code-stubs-hydrogen.cc @ f230a1cf

History | View | Annotate | Download (44.1 KB)

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
  BailoutReason bailout_reason = kNoReason;
45
  if (!graph->Optimize(&bailout_reason)) {
46
    FATAL(GetBailoutReason(bailout_reason));
47
  }
48
  LChunk* chunk = LChunk::NewChunk(graph);
49
  if (chunk == NULL) {
50
    FATAL(GetBailoutReason(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("Array constructor called from different context");
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
  void BuildInstallOptimizedCode(HValue* js_function, HValue* native_context,
116
                                 HValue* code_object);
117
  void BuildInstallCode(HValue* js_function, HValue* shared_info);
118
  void BuildInstallFromOptimizedCodeMap(HValue* js_function,
119
                                        HValue* shared_info,
120
                                        HValue* native_context);
121

    
122
 private:
123
  HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder);
124
  HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder,
125
                                          ElementsKind kind);
126

    
127
  SmartArrayPointer<HParameter*> parameters_;
128
  HValue* arguments_length_;
129
  CompilationInfoWithZone info_;
130
  CodeStubInterfaceDescriptor* descriptor_;
131
  HContext* context_;
132
};
133

    
134

    
135
bool CodeStubGraphBuilderBase::BuildGraph() {
136
  // Update the static counter each time a new code stub is generated.
137
  isolate()->counters()->code_stubs()->Increment();
138

    
139
  if (FLAG_trace_hydrogen_stubs) {
140
    const char* name = CodeStub::MajorName(stub()->MajorKey(), false);
141
    PrintF("-----------------------------------------------------------\n");
142
    PrintF("Compiling stub %s using hydrogen\n", name);
143
    isolate()->GetHTracer()->TraceCompilation(&info_);
144
  }
145

    
146
  int param_count = descriptor_->register_param_count_;
147
  HEnvironment* start_environment = graph()->start_environment();
148
  HBasicBlock* next_block = CreateBasicBlock(start_environment);
149
  Goto(next_block);
150
  next_block->SetJoinId(BailoutId::StubEntry());
151
  set_current_block(next_block);
152

    
153
  for (int i = 0; i < param_count; ++i) {
154
    HParameter* param =
155
        Add<HParameter>(i, HParameter::REGISTER_PARAMETER);
156
    start_environment->Bind(i, param);
157
    parameters_[i] = param;
158
  }
159

    
160
  HInstruction* stack_parameter_count;
161
  if (descriptor_->stack_parameter_count_.is_valid()) {
162
    ASSERT(descriptor_->environment_length() == (param_count + 1));
163
    stack_parameter_count = New<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_ = Add<HContext>();
178
  start_environment->BindContext(context_);
179

    
180
  Add<HSimulate>(BailoutId::StubEntry());
181

    
182
  NoObservableSideEffectsScope no_effects(this);
183

    
184
  HValue* return_value = BuildCodeStub();
185

    
186
  // We might have extra expressions to pop from the stack in addition to the
187
  // arguments above.
188
  HInstruction* stack_pop_count = stack_parameter_count;
189
  if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) {
190
    if (!stack_parameter_count->IsConstant() &&
191
        descriptor_->hint_stack_parameter_count_ < 0) {
192
      HInstruction* amount = graph()->GetConstant1();
193
      stack_pop_count = Add<HAdd>(stack_parameter_count, amount);
194
      stack_pop_count->ChangeRepresentation(Representation::Integer32());
195
      stack_pop_count->ClearFlag(HValue::kCanOverflow);
196
    } else {
197
      int count = descriptor_->hint_stack_parameter_count_;
198
      stack_pop_count = Add<HConstant>(count);
199
    }
200
  }
201

    
202
  if (current_block() != NULL) {
203
    HReturn* hreturn_instruction = New<HReturn>(return_value,
204
                                                stack_pop_count);
205
    FinishCurrentBlock(hreturn_instruction);
206
  }
207
  return true;
208
}
209

    
210

    
211
template <class Stub>
212
class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
213
 public:
214
  explicit CodeStubGraphBuilder(Isolate* isolate, Stub* stub)
215
      : CodeStubGraphBuilderBase(isolate, stub) {}
216

    
217
 protected:
218
  virtual HValue* BuildCodeStub() {
219
    if (casted_stub()->IsUninitialized()) {
220
      return BuildCodeUninitializedStub();
221
    } else {
222
      return BuildCodeInitializedStub();
223
    }
224
  }
225

    
226
  virtual HValue* BuildCodeInitializedStub() {
227
    UNIMPLEMENTED();
228
    return NULL;
229
  }
230

    
231
  virtual HValue* BuildCodeUninitializedStub() {
232
    // Force a deopt that falls back to the runtime.
233
    HValue* undefined = graph()->GetConstantUndefined();
234
    IfBuilder builder(this);
235
    builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined);
236
    builder.Then();
237
    builder.ElseDeopt("Forced deopt to runtime");
238
    return undefined;
239
  }
240

    
241
  Stub* casted_stub() { return static_cast<Stub*>(stub()); }
242
};
243

    
244

    
245
Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(Isolate* isolate) {
246
  Factory* factory = isolate->factory();
247

    
248
  // Generate the new code.
249
  MacroAssembler masm(isolate, NULL, 256);
250

    
251
  {
252
    // Update the static counter each time a new code stub is generated.
253
    isolate->counters()->code_stubs()->Increment();
254

    
255
    // Nested stubs are not allowed for leaves.
256
    AllowStubCallsScope allow_scope(&masm, false);
257

    
258
    // Generate the code for the stub.
259
    masm.set_generating_stub(true);
260
    NoCurrentFrameScope scope(&masm);
261
    GenerateLightweightMiss(&masm);
262
  }
263

    
264
  // Create the code object.
265
  CodeDesc desc;
266
  masm.GetCode(&desc);
267

    
268
  // Copy the generated code into a heap object.
269
  Code::Flags flags = Code::ComputeFlags(
270
      GetCodeKind(),
271
      GetICState(),
272
      GetExtraICState(),
273
      GetStubType(),
274
      GetStubFlags());
275
  Handle<Code> new_object = factory->NewCode(
276
      desc, flags, masm.CodeObject(), NeedsImmovableCode());
277
  return new_object;
278
}
279

    
280

    
281
template <class Stub>
282
static Handle<Code> DoGenerateCode(Isolate* isolate, Stub* stub) {
283
  CodeStub::Major  major_key =
284
      static_cast<HydrogenCodeStub*>(stub)->MajorKey();
285
  CodeStubInterfaceDescriptor* descriptor =
286
      isolate->code_stub_interface_descriptor(major_key);
287
  if (descriptor->register_param_count_ < 0) {
288
    stub->InitializeInterfaceDescriptor(isolate, descriptor);
289
  }
290

    
291
  // If we are uninitialized we can use a light-weight stub to enter
292
  // the runtime that is significantly faster than using the standard
293
  // stub-failure deopt mechanism.
294
  if (stub->IsUninitialized() && descriptor->has_miss_handler()) {
295
    ASSERT(!descriptor->stack_parameter_count_.is_valid());
296
    return stub->GenerateLightweightMissCode(isolate);
297
  }
298
  ElapsedTimer timer;
299
  if (FLAG_profile_hydrogen_code_stub_compilation) {
300
    timer.Start();
301
  }
302
  CodeStubGraphBuilder<Stub> builder(isolate, stub);
303
  LChunk* chunk = OptimizeGraph(builder.CreateGraph());
304
  Handle<Code> code = chunk->Codegen();
305
  if (FLAG_profile_hydrogen_code_stub_compilation) {
306
    double ms = timer.Elapsed().InMillisecondsF();
307
    PrintF("[Lazy compilation of %s took %0.3f ms]\n", *stub->GetName(), ms);
308
  }
309
  return code;
310
}
311

    
312

    
313
template <>
314
HValue* CodeStubGraphBuilder<ToNumberStub>::BuildCodeStub() {
315
  HValue* value = GetParameter(0);
316

    
317
  // Check if the parameter is already a SMI or heap number.
318
  IfBuilder if_number(this);
319
  if_number.If<HIsSmiAndBranch>(value);
320
  if_number.OrIf<HCompareMap>(value, isolate()->factory()->heap_number_map());
321
  if_number.Then();
322

    
323
  // Return the number.
324
  Push(value);
325

    
326
  if_number.Else();
327

    
328
  // Convert the parameter to number using the builtin.
329
  HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER);
330
  Add<HPushArgument>(value);
331
  Push(Add<HInvokeFunction>(function, 1));
332

    
333
  if_number.End();
334

    
335
  return Pop();
336
}
337

    
338

    
339
Handle<Code> ToNumberStub::GenerateCode(Isolate* isolate) {
340
  return DoGenerateCode(isolate, this);
341
}
342

    
343

    
344
template <>
345
HValue* CodeStubGraphBuilder<NumberToStringStub>::BuildCodeStub() {
346
  info()->MarkAsSavesCallerDoubles();
347
  HValue* number = GetParameter(NumberToStringStub::kNumber);
348
  return BuildNumberToString(number, handle(Type::Number(), isolate()));
349
}
350

    
351

    
352
Handle<Code> NumberToStringStub::GenerateCode(Isolate* isolate) {
353
  return DoGenerateCode(isolate, this);
354
}
355

    
356

    
357
template <>
358
HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
359
  Factory* factory = isolate()->factory();
360
  HValue* undefined = graph()->GetConstantUndefined();
361
  AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
362
  FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
363
  int length = casted_stub()->length();
364

    
365
  HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0),
366
                                                  GetParameter(1),
367
                                                  static_cast<HValue*>(NULL),
368
                                                  FAST_ELEMENTS);
369
  IfBuilder checker(this);
370
  checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site,
371
                                                    undefined);
372
  checker.Then();
373

    
374
  HObjectAccess access = HObjectAccess::ForAllocationSiteOffset(
375
      AllocationSite::kTransitionInfoOffset);
376
  HInstruction* boilerplate = Add<HLoadNamedField>(allocation_site, access);
377
  HValue* push_value;
378
  if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
379
    HValue* elements = AddLoadElements(boilerplate);
380

    
381
    IfBuilder if_fixed_cow(this);
382
    if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map());
383
    if_fixed_cow.Then();
384
    push_value = BuildCloneShallowArray(boilerplate,
385
                                        allocation_site,
386
                                        alloc_site_mode,
387
                                        FAST_ELEMENTS,
388
                                        0/*copy-on-write*/);
389
    environment()->Push(push_value);
390
    if_fixed_cow.Else();
391

    
392
    IfBuilder if_fixed(this);
393
    if_fixed.If<HCompareMap>(elements, factory->fixed_array_map());
394
    if_fixed.Then();
395
    push_value = BuildCloneShallowArray(boilerplate,
396
                                        allocation_site,
397
                                        alloc_site_mode,
398
                                        FAST_ELEMENTS,
399
                                        length);
400
    environment()->Push(push_value);
401
    if_fixed.Else();
402
    push_value = BuildCloneShallowArray(boilerplate,
403
                                        allocation_site,
404
                                        alloc_site_mode,
405
                                        FAST_DOUBLE_ELEMENTS,
406
                                        length);
407
    environment()->Push(push_value);
408
  } else {
409
    ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
410
    push_value = BuildCloneShallowArray(boilerplate,
411
                                        allocation_site,
412
                                        alloc_site_mode,
413
                                        elements_kind,
414
                                        length);
415
    environment()->Push(push_value);
416
  }
417

    
418
  checker.ElseDeopt("Uninitialized boilerplate literals");
419
  checker.End();
420

    
421
  return environment()->Pop();
422
}
423

    
424

    
425
Handle<Code> FastCloneShallowArrayStub::GenerateCode(Isolate* isolate) {
426
  return DoGenerateCode(isolate, this);
427
}
428

    
429

    
430
template <>
431
HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
432
  HValue* undefined = graph()->GetConstantUndefined();
433

    
434
  HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0),
435
                                                  GetParameter(1),
436
                                                  static_cast<HValue*>(NULL),
437
                                                  FAST_ELEMENTS);
438

    
439
  IfBuilder checker(this);
440
  checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site,
441
                                                    undefined);
442
  checker.And();
443

    
444
  HObjectAccess access = HObjectAccess::ForAllocationSiteOffset(
445
      AllocationSite::kTransitionInfoOffset);
446
  HInstruction* boilerplate = Add<HLoadNamedField>(allocation_site, access);
447

    
448
  int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
449
  int object_size = size;
450
  if (FLAG_allocation_site_pretenuring) {
451
    size += AllocationMemento::kSize;
452
  }
453

    
454
  HValue* boilerplate_map = Add<HLoadNamedField>(
455
      boilerplate, HObjectAccess::ForMap());
456
  HValue* boilerplate_size = Add<HLoadNamedField>(
457
      boilerplate_map, HObjectAccess::ForMapInstanceSize());
458
  HValue* size_in_words = Add<HConstant>(object_size >> kPointerSizeLog2);
459
  checker.If<HCompareNumericAndBranch>(boilerplate_size,
460
                                       size_in_words, Token::EQ);
461
  checker.Then();
462

    
463
  HValue* size_in_bytes = Add<HConstant>(size);
464

    
465
  HInstruction* object = Add<HAllocate>(size_in_bytes, HType::JSObject(),
466
      isolate()->heap()->GetPretenureMode(), JS_OBJECT_TYPE);
467

    
468
  for (int i = 0; i < object_size; i += kPointerSize) {
469
    HObjectAccess access = HObjectAccess::ForJSObjectOffset(i);
470
    Add<HStoreNamedField>(object, access,
471
                          Add<HLoadNamedField>(boilerplate, access));
472
  }
473

    
474
  ASSERT(FLAG_allocation_site_pretenuring || (size == object_size));
475
  if (FLAG_allocation_site_pretenuring) {
476
    BuildCreateAllocationMemento(object, object_size, allocation_site);
477
  }
478

    
479
  environment()->Push(object);
480
  checker.ElseDeopt("Uninitialized boilerplate in fast clone");
481
  checker.End();
482

    
483
  return environment()->Pop();
484
}
485

    
486

    
487
Handle<Code> FastCloneShallowObjectStub::GenerateCode(Isolate* isolate) {
488
  return DoGenerateCode(isolate, this);
489
}
490

    
491

    
492
template <>
493
HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
494
  HValue* size = Add<HConstant>(AllocationSite::kSize);
495
  HInstruction* object = Add<HAllocate>(size, HType::JSObject(), TENURED,
496
      JS_OBJECT_TYPE);
497

    
498
  // Store the map
499
  Handle<Map> allocation_site_map = isolate()->factory()->allocation_site_map();
500
  AddStoreMapConstant(object, allocation_site_map);
501

    
502
  // Store the payload (smi elements kind)
503
  HValue* initial_elements_kind = Add<HConstant>(GetInitialFastElementsKind());
504
  Add<HStoreNamedField>(object,
505
                        HObjectAccess::ForAllocationSiteOffset(
506
                            AllocationSite::kTransitionInfoOffset),
507
                        initial_elements_kind);
508

    
509
  // Unlike literals, constructed arrays don't have nested sites
510
  Add<HStoreNamedField>(object,
511
                        HObjectAccess::ForAllocationSiteOffset(
512
                            AllocationSite::kNestedSiteOffset),
513
                        graph()->GetConstant0());
514

    
515
  // Store an empty fixed array for the code dependency.
516
  HConstant* empty_fixed_array =
517
    Add<HConstant>(isolate()->factory()->empty_fixed_array());
518
  HStoreNamedField* store = Add<HStoreNamedField>(
519
      object,
520
      HObjectAccess::ForAllocationSiteOffset(
521
          AllocationSite::kDependentCodeOffset),
522
      empty_fixed_array);
523

    
524
  // Link the object to the allocation site list
525
  HValue* site_list = Add<HConstant>(
526
      ExternalReference::allocation_sites_list_address(isolate()));
527
  HValue* site = Add<HLoadNamedField>(site_list,
528
                                      HObjectAccess::ForAllocationSiteList());
529
  store = Add<HStoreNamedField>(object,
530
      HObjectAccess::ForAllocationSiteOffset(AllocationSite::kWeakNextOffset),
531
      site);
532
  store->SkipWriteBarrier();
533
  Add<HStoreNamedField>(site_list, HObjectAccess::ForAllocationSiteList(),
534
                        object);
535

    
536
  // We use a hammer (SkipWriteBarrier()) to indicate that we know the input
537
  // cell is really a Cell, and so no write barrier is needed.
538
  // TODO(mvstanton): Add a debug_code check to verify the input cell is really
539
  // a cell. (perhaps with a new instruction, HAssert).
540
  HInstruction* cell = GetParameter(0);
541
  HObjectAccess access = HObjectAccess::ForCellValue();
542
  store = Add<HStoreNamedField>(cell, access, object);
543
  store->SkipWriteBarrier();
544
  return cell;
545
}
546

    
547

    
548
Handle<Code> CreateAllocationSiteStub::GenerateCode(Isolate* isolate) {
549
  return DoGenerateCode(isolate, this);
550
}
551

    
552

    
553
template <>
554
HValue* CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
555
  HInstruction* load = BuildUncheckedMonomorphicElementAccess(
556
      GetParameter(0), GetParameter(1), NULL,
557
      casted_stub()->is_js_array(), casted_stub()->elements_kind(),
558
      false, NEVER_RETURN_HOLE, STANDARD_STORE);
559
  return load;
560
}
561

    
562

    
563
Handle<Code> KeyedLoadFastElementStub::GenerateCode(Isolate* isolate) {
564
  return DoGenerateCode(isolate, this);
565
}
566

    
567

    
568
template<>
569
HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
570
  Representation rep = casted_stub()->representation();
571
  HObjectAccess access = casted_stub()->is_inobject() ?
572
      HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) :
573
      HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep);
574
  return AddLoadNamedField(GetParameter(0), access);
575
}
576

    
577

    
578
Handle<Code> LoadFieldStub::GenerateCode(Isolate* isolate) {
579
  return DoGenerateCode(isolate, this);
580
}
581

    
582

    
583
template<>
584
HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
585
  Representation rep = casted_stub()->representation();
586
  HObjectAccess access = casted_stub()->is_inobject() ?
587
      HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) :
588
      HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep);
589
  return AddLoadNamedField(GetParameter(0), access);
590
}
591

    
592

    
593
Handle<Code> KeyedLoadFieldStub::GenerateCode(Isolate* isolate) {
594
  return DoGenerateCode(isolate, this);
595
}
596

    
597

    
598
template <>
599
HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
600
  BuildUncheckedMonomorphicElementAccess(
601
      GetParameter(0), GetParameter(1), GetParameter(2),
602
      casted_stub()->is_js_array(), casted_stub()->elements_kind(),
603
      true, NEVER_RETURN_HOLE, casted_stub()->store_mode());
604

    
605
  return GetParameter(2);
606
}
607

    
608

    
609
Handle<Code> KeyedStoreFastElementStub::GenerateCode(Isolate* isolate) {
610
  return DoGenerateCode(isolate, this);
611
}
612

    
613

    
614
template <>
615
HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
616
  info()->MarkAsSavesCallerDoubles();
617

    
618
  BuildTransitionElementsKind(GetParameter(0),
619
                              GetParameter(1),
620
                              casted_stub()->from_kind(),
621
                              casted_stub()->to_kind(),
622
                              true);
623

    
624
  return GetParameter(0);
625
}
626

    
627

    
628
Handle<Code> TransitionElementsKindStub::GenerateCode(Isolate* isolate) {
629
  return DoGenerateCode(isolate, this);
630
}
631

    
632
HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
633
    ElementsKind kind,
634
    ContextCheckMode context_mode,
635
    AllocationSiteOverrideMode override_mode,
636
    ArgumentClass argument_class) {
637
  HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor);
638
  if (context_mode == CONTEXT_CHECK_REQUIRED) {
639
    HInstruction* array_function = BuildGetArrayFunction();
640
    ArrayContextChecker checker(this, constructor, array_function);
641
  }
642

    
643
  HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
644
  // Walk through the property cell to the AllocationSite
645
  HValue* alloc_site = Add<HLoadNamedField>(property_cell,
646
                                            HObjectAccess::ForCellValue());
647
  JSArrayBuilder array_builder(this, kind, alloc_site, constructor,
648
                               override_mode);
649
  HValue* result = NULL;
650
  switch (argument_class) {
651
    case NONE:
652
      result = array_builder.AllocateEmptyArray();
653
      break;
654
    case SINGLE:
655
      result = BuildArraySingleArgumentConstructor(&array_builder);
656
      break;
657
    case MULTIPLE:
658
      result = BuildArrayNArgumentsConstructor(&array_builder, kind);
659
      break;
660
  }
661

    
662
  return result;
663
}
664

    
665

    
666
HValue* CodeStubGraphBuilderBase::BuildInternalArrayConstructor(
667
    ElementsKind kind, ArgumentClass argument_class) {
668
  HValue* constructor = GetParameter(
669
      InternalArrayConstructorStubBase::kConstructor);
670
  JSArrayBuilder array_builder(this, kind, constructor);
671

    
672
  HValue* result = NULL;
673
  switch (argument_class) {
674
    case NONE:
675
      result = array_builder.AllocateEmptyArray();
676
      break;
677
    case SINGLE:
678
      result = BuildArraySingleArgumentConstructor(&array_builder);
679
      break;
680
    case MULTIPLE:
681
      result = BuildArrayNArgumentsConstructor(&array_builder, kind);
682
      break;
683
  }
684
  return result;
685
}
686

    
687

    
688
HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor(
689
    JSArrayBuilder* array_builder) {
690
  // Smi check and range check on the input arg.
691
  HValue* constant_one = graph()->GetConstant1();
692
  HValue* constant_zero = graph()->GetConstant0();
693

    
694
  HInstruction* elements = Add<HArgumentsElements>(false);
695
  HInstruction* argument = Add<HAccessArgumentsAt>(
696
      elements, constant_one, constant_zero);
697

    
698
  HConstant* max_alloc_length =
699
      Add<HConstant>(JSObject::kInitialMaxFastElementArray);
700
  const int initial_capacity = JSArray::kPreallocatedArrayElements;
701
  HConstant* initial_capacity_node = Add<HConstant>(initial_capacity);
702

    
703
  HInstruction* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
704
  IfBuilder if_builder(this);
705
  if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero,
706
                                          Token::EQ);
707
  if_builder.Then();
708
  Push(initial_capacity_node);  // capacity
709
  Push(constant_zero);  // length
710
  if_builder.Else();
711
  Push(checked_arg);  // capacity
712
  Push(checked_arg);  // length
713
  if_builder.End();
714

    
715
  // Figure out total size
716
  HValue* length = Pop();
717
  HValue* capacity = Pop();
718
  return array_builder->AllocateArray(capacity, length, true);
719
}
720

    
721

    
722
HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor(
723
    JSArrayBuilder* array_builder, ElementsKind kind) {
724
  // We need to fill with the hole if it's a smi array in the multi-argument
725
  // case because we might have to bail out while copying arguments into
726
  // the array because they aren't compatible with a smi array.
727
  // If it's a double array, no problem, and if it's fast then no
728
  // problem either because doubles are boxed.
729
  HValue* length = GetArgumentsLength();
730
  bool fill_with_hole = IsFastSmiElementsKind(kind);
731
  HValue* new_object = array_builder->AllocateArray(length,
732
                                                    length,
733
                                                    fill_with_hole);
734
  HValue* elements = array_builder->GetElementsLocation();
735
  ASSERT(elements != NULL);
736

    
737
  // Now populate the elements correctly.
738
  LoopBuilder builder(this,
739
                      context(),
740
                      LoopBuilder::kPostIncrement);
741
  HValue* start = graph()->GetConstant0();
742
  HValue* key = builder.BeginBody(start, length, Token::LT);
743
  HInstruction* argument_elements = Add<HArgumentsElements>(false);
744
  HInstruction* argument = Add<HAccessArgumentsAt>(
745
      argument_elements, length, key);
746

    
747
  Add<HStoreKeyed>(elements, key, argument, kind);
748
  builder.EndBody();
749
  return new_object;
750
}
751

    
752

    
753
template <>
754
HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() {
755
  ElementsKind kind = casted_stub()->elements_kind();
756
  ContextCheckMode context_mode = casted_stub()->context_mode();
757
  AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
758
  return BuildArrayConstructor(kind, context_mode, override_mode, NONE);
759
}
760

    
761

    
762
Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode(Isolate* isolate) {
763
  return DoGenerateCode(isolate, this);
764
}
765

    
766

    
767
template <>
768
HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>::
769
    BuildCodeStub() {
770
  ElementsKind kind = casted_stub()->elements_kind();
771
  ContextCheckMode context_mode = casted_stub()->context_mode();
772
  AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
773
  return BuildArrayConstructor(kind, context_mode, override_mode, SINGLE);
774
}
775

    
776

    
777
Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode(
778
    Isolate* isolate) {
779
  return DoGenerateCode(isolate, this);
780
}
781

    
782

    
783
template <>
784
HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() {
785
  ElementsKind kind = casted_stub()->elements_kind();
786
  ContextCheckMode context_mode = casted_stub()->context_mode();
787
  AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
788
  return BuildArrayConstructor(kind, context_mode, override_mode, MULTIPLE);
789
}
790

    
791

    
792
Handle<Code> ArrayNArgumentsConstructorStub::GenerateCode(Isolate* isolate) {
793
  return DoGenerateCode(isolate, this);
794
}
795

    
796

    
797
template <>
798
HValue* CodeStubGraphBuilder<InternalArrayNoArgumentConstructorStub>::
799
    BuildCodeStub() {
800
  ElementsKind kind = casted_stub()->elements_kind();
801
  return BuildInternalArrayConstructor(kind, NONE);
802
}
803

    
804

    
805
Handle<Code> InternalArrayNoArgumentConstructorStub::GenerateCode(
806
    Isolate* isolate) {
807
  return DoGenerateCode(isolate, this);
808
}
809

    
810

    
811
template <>
812
HValue* CodeStubGraphBuilder<InternalArraySingleArgumentConstructorStub>::
813
    BuildCodeStub() {
814
  ElementsKind kind = casted_stub()->elements_kind();
815
  return BuildInternalArrayConstructor(kind, SINGLE);
816
}
817

    
818

    
819
Handle<Code> InternalArraySingleArgumentConstructorStub::GenerateCode(
820
    Isolate* isolate) {
821
  return DoGenerateCode(isolate, this);
822
}
823

    
824

    
825
template <>
826
HValue* CodeStubGraphBuilder<InternalArrayNArgumentsConstructorStub>::
827
    BuildCodeStub() {
828
  ElementsKind kind = casted_stub()->elements_kind();
829
  return BuildInternalArrayConstructor(kind, MULTIPLE);
830
}
831

    
832

    
833
Handle<Code> InternalArrayNArgumentsConstructorStub::GenerateCode(
834
    Isolate* isolate) {
835
  return DoGenerateCode(isolate, this);
836
}
837

    
838

    
839
template <>
840
HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() {
841
  Isolate* isolate = graph()->isolate();
842
  CompareNilICStub* stub = casted_stub();
843
  HIfContinuation continuation;
844
  Handle<Map> sentinel_map(isolate->heap()->meta_map());
845
  Handle<Type> type = stub->GetType(isolate, sentinel_map);
846
  BuildCompareNil(GetParameter(0), type, &continuation);
847
  IfBuilder if_nil(this, &continuation);
848
  if_nil.Then();
849
  if (continuation.IsFalseReachable()) {
850
    if_nil.Else();
851
    if_nil.Return(graph()->GetConstant0());
852
  }
853
  if_nil.End();
854
  return continuation.IsTrueReachable()
855
      ? graph()->GetConstant1()
856
      : graph()->GetConstantUndefined();
857
}
858

    
859

    
860
Handle<Code> CompareNilICStub::GenerateCode(Isolate* isolate) {
861
  return DoGenerateCode(isolate, this);
862
}
863

    
864

    
865
template <>
866
HValue* CodeStubGraphBuilder<BinaryOpStub>::BuildCodeInitializedStub() {
867
  BinaryOpStub* stub = casted_stub();
868
  HValue* left = GetParameter(0);
869
  HValue* right = GetParameter(1);
870

    
871
  Handle<Type> left_type = stub->GetLeftType(isolate());
872
  Handle<Type> right_type = stub->GetRightType(isolate());
873
  Handle<Type> result_type = stub->GetResultType(isolate());
874

    
875
  ASSERT(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) &&
876
         (stub->HasSideEffects(isolate()) || !result_type->Is(Type::None())));
877

    
878
  HValue* result = NULL;
879
  if (stub->operation() == Token::ADD &&
880
      (left_type->Maybe(Type::String()) || right_type->Maybe(Type::String())) &&
881
      !left_type->Is(Type::String()) && !right_type->Is(Type::String())) {
882
    // For the generic add stub a fast case for string addition is performance
883
    // critical.
884
    if (left_type->Maybe(Type::String())) {
885
      IfBuilder if_leftisstring(this);
886
      if_leftisstring.If<HIsStringAndBranch>(left);
887
      if_leftisstring.Then();
888
      {
889
        Push(AddInstruction(BuildBinaryOperation(
890
                    stub->operation(), left, right,
891
                    handle(Type::String(), isolate()), right_type,
892
                    result_type, stub->fixed_right_arg(), true)));
893
      }
894
      if_leftisstring.Else();
895
      {
896
        Push(AddInstruction(BuildBinaryOperation(
897
                    stub->operation(), left, right,
898
                    left_type, right_type, result_type,
899
                    stub->fixed_right_arg(), true)));
900
      }
901
      if_leftisstring.End();
902
      result = Pop();
903
    } else {
904
      IfBuilder if_rightisstring(this);
905
      if_rightisstring.If<HIsStringAndBranch>(right);
906
      if_rightisstring.Then();
907
      {
908
        Push(AddInstruction(BuildBinaryOperation(
909
                    stub->operation(), left, right,
910
                    left_type, handle(Type::String(), isolate()),
911
                    result_type, stub->fixed_right_arg(), true)));
912
      }
913
      if_rightisstring.Else();
914
      {
915
        Push(AddInstruction(BuildBinaryOperation(
916
                    stub->operation(), left, right,
917
                    left_type, right_type, result_type,
918
                    stub->fixed_right_arg(), true)));
919
      }
920
      if_rightisstring.End();
921
      result = Pop();
922
    }
923
  } else {
924
    result = AddInstruction(BuildBinaryOperation(
925
            stub->operation(), left, right,
926
            left_type, right_type, result_type,
927
            stub->fixed_right_arg(), true));
928
  }
929

    
930
  // If we encounter a generic argument, the number conversion is
931
  // observable, thus we cannot afford to bail out after the fact.
932
  if (!stub->HasSideEffects(isolate())) {
933
    if (result_type->Is(Type::Smi())) {
934
      if (stub->operation() == Token::SHR) {
935
        // TODO(olivf) Replace this by a SmiTagU Instruction.
936
        // 0x40000000: this number would convert to negative when interpreting
937
        // the register as signed value;
938
        IfBuilder if_of(this);
939
        if_of.IfNot<HCompareNumericAndBranch>(result,
940
            Add<HConstant>(static_cast<int>(SmiValuesAre32Bits()
941
                ? 0x80000000 : 0x40000000)), Token::EQ_STRICT);
942
        if_of.Then();
943
        if_of.ElseDeopt("UInt->Smi oveflow");
944
        if_of.End();
945
      }
946
    }
947
    result = EnforceNumberType(result, result_type);
948
  }
949

    
950
  // Reuse the double box of one of the operands if we are allowed to (i.e.
951
  // chained binops).
952
  if (stub->CanReuseDoubleBox()) {
953
    HValue* operand = (stub->mode() == OVERWRITE_LEFT) ? left : right;
954
    IfBuilder if_heap_number(this);
955
    if_heap_number.IfNot<HIsSmiAndBranch>(operand);
956
    if_heap_number.Then();
957
    Add<HStoreNamedField>(operand, HObjectAccess::ForHeapNumberValue(), result);
958
    Push(operand);
959
    if_heap_number.Else();
960
    Push(result);
961
    if_heap_number.End();
962
    result = Pop();
963
  }
964

    
965
  return result;
966
}
967

    
968

    
969
Handle<Code> BinaryOpStub::GenerateCode(Isolate* isolate) {
970
  return DoGenerateCode(isolate, this);
971
}
972

    
973

    
974
template <>
975
HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
976
  ToBooleanStub* stub = casted_stub();
977

    
978
  IfBuilder if_true(this);
979
  if_true.If<HBranch>(GetParameter(0), stub->GetTypes());
980
  if_true.Then();
981
  if_true.Return(graph()->GetConstant1());
982
  if_true.Else();
983
  if_true.End();
984
  return graph()->GetConstant0();
985
}
986

    
987

    
988
Handle<Code> ToBooleanStub::GenerateCode(Isolate* isolate) {
989
  return DoGenerateCode(isolate, this);
990
}
991

    
992

    
993
template <>
994
HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
995
  StoreGlobalStub* stub = casted_stub();
996
  Handle<Object> hole(isolate()->heap()->the_hole_value(), isolate());
997
  Handle<Object> placeholer_value(Smi::FromInt(0), isolate());
998
  Handle<PropertyCell> placeholder_cell =
999
      isolate()->factory()->NewPropertyCell(placeholer_value);
1000

    
1001
  HParameter* receiver = GetParameter(0);
1002
  HParameter* value = GetParameter(2);
1003

    
1004
  // Check that the map of the global has not changed: use a placeholder map
1005
  // that will be replaced later with the global object's map.
1006
  Handle<Map> placeholder_map = isolate()->factory()->meta_map();
1007
  Add<HCheckMaps>(receiver, placeholder_map, top_info());
1008

    
1009
  HValue* cell = Add<HConstant>(placeholder_cell);
1010
  HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
1011
  HValue* cell_contents = Add<HLoadNamedField>(cell, access);
1012

    
1013
  if (stub->is_constant()) {
1014
    IfBuilder builder(this);
1015
    builder.If<HCompareObjectEqAndBranch>(cell_contents, value);
1016
    builder.Then();
1017
    builder.ElseDeopt("Unexpected cell contents in constant global store");
1018
    builder.End();
1019
  } else {
1020
    // Load the payload of the global parameter cell. A hole indicates that the
1021
    // property has been deleted and that the store must be handled by the
1022
    // runtime.
1023
    IfBuilder builder(this);
1024
    HValue* hole_value = Add<HConstant>(hole);
1025
    builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
1026
    builder.Then();
1027
    builder.Deopt("Unexpected cell contents in global store");
1028
    builder.Else();
1029
    Add<HStoreNamedField>(cell, access, value);
1030
    builder.End();
1031
  }
1032

    
1033
  return value;
1034
}
1035

    
1036

    
1037
Handle<Code> StoreGlobalStub::GenerateCode(Isolate* isolate) {
1038
  return DoGenerateCode(isolate, this);
1039
}
1040

    
1041

    
1042
template<>
1043
HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
1044
  HValue* value = GetParameter(0);
1045
  HValue* map = GetParameter(1);
1046
  HValue* key = GetParameter(2);
1047
  HValue* object = GetParameter(3);
1048

    
1049
  if (FLAG_trace_elements_transitions) {
1050
    // Tracing elements transitions is the job of the runtime.
1051
    Add<HDeoptimize>("Tracing elements transitions", Deoptimizer::EAGER);
1052
  } else {
1053
    info()->MarkAsSavesCallerDoubles();
1054

    
1055
    BuildTransitionElementsKind(object, map,
1056
                                casted_stub()->from_kind(),
1057
                                casted_stub()->to_kind(),
1058
                                casted_stub()->is_jsarray());
1059

    
1060
    BuildUncheckedMonomorphicElementAccess(object, key, value,
1061
                                           casted_stub()->is_jsarray(),
1062
                                           casted_stub()->to_kind(),
1063
                                           true, ALLOW_RETURN_HOLE,
1064
                                           casted_stub()->store_mode());
1065
  }
1066

    
1067
  return value;
1068
}
1069

    
1070

    
1071
Handle<Code> ElementsTransitionAndStoreStub::GenerateCode(Isolate* isolate) {
1072
  return DoGenerateCode(isolate, this);
1073
}
1074

    
1075

    
1076
void CodeStubGraphBuilderBase::BuildInstallOptimizedCode(
1077
    HValue* js_function,
1078
    HValue* native_context,
1079
    HValue* code_object) {
1080
  Counters* counters = isolate()->counters();
1081
  AddIncrementCounter(counters->fast_new_closure_install_optimized());
1082

    
1083
  // TODO(fschneider): Idea: store proper code pointers in the optimized code
1084
  // map and either unmangle them on marking or do nothing as the whole map is
1085
  // discarded on major GC anyway.
1086
  Add<HStoreCodeEntry>(js_function, code_object);
1087

    
1088
  // Now link a function into a list of optimized functions.
1089
  HValue* optimized_functions_list = Add<HLoadNamedField>(native_context,
1090
      HObjectAccess::ForContextSlot(Context::OPTIMIZED_FUNCTIONS_LIST));
1091
  Add<HStoreNamedField>(js_function,
1092
                        HObjectAccess::ForNextFunctionLinkPointer(),
1093
                        optimized_functions_list);
1094

    
1095
  // This store is the only one that should have a write barrier.
1096
  Add<HStoreNamedField>(native_context,
1097
           HObjectAccess::ForContextSlot(Context::OPTIMIZED_FUNCTIONS_LIST),
1098
           js_function);
1099
}
1100

    
1101

    
1102
void CodeStubGraphBuilderBase::BuildInstallCode(HValue* js_function,
1103
                                                HValue* shared_info) {
1104
  Add<HStoreNamedField>(js_function,
1105
                        HObjectAccess::ForNextFunctionLinkPointer(),
1106
                        graph()->GetConstantUndefined());
1107
  HValue* code_object = Add<HLoadNamedField>(shared_info,
1108
                                             HObjectAccess::ForCodeOffset());
1109
  Add<HStoreCodeEntry>(js_function, code_object);
1110
}
1111

    
1112

    
1113
void CodeStubGraphBuilderBase::BuildInstallFromOptimizedCodeMap(
1114
    HValue* js_function,
1115
    HValue* shared_info,
1116
    HValue* native_context) {
1117
  Counters* counters = isolate()->counters();
1118
  IfBuilder is_optimized(this);
1119
  HInstruction* optimized_map = Add<HLoadNamedField>(shared_info,
1120
      HObjectAccess::ForOptimizedCodeMap());
1121
  HValue* null_constant = Add<HConstant>(0);
1122
  is_optimized.If<HCompareObjectEqAndBranch>(optimized_map, null_constant);
1123
  is_optimized.Then();
1124
  {
1125
    BuildInstallCode(js_function, shared_info);
1126
  }
1127
  is_optimized.Else();
1128
  {
1129
    AddIncrementCounter(counters->fast_new_closure_try_optimized());
1130
    // optimized_map points to fixed array of 3-element entries
1131
    // (native context, optimized code, literals).
1132
    // Map must never be empty, so check the first elements.
1133
    Label install_optimized;
1134
    HValue* first_context_slot = Add<HLoadNamedField>(optimized_map,
1135
        HObjectAccess::ForFirstContextSlot());
1136
    IfBuilder already_in(this);
1137
    already_in.If<HCompareObjectEqAndBranch>(native_context,
1138
                                             first_context_slot);
1139
    already_in.Then();
1140
    {
1141
      HValue* code_object = Add<HLoadNamedField>(optimized_map,
1142
        HObjectAccess::ForFirstCodeSlot());
1143
      BuildInstallOptimizedCode(js_function, native_context, code_object);
1144
    }
1145
    already_in.Else();
1146
    {
1147
      HValue* shared_function_entry_length =
1148
          Add<HConstant>(SharedFunctionInfo::kEntryLength);
1149
      LoopBuilder loop_builder(this,
1150
                               context(),
1151
                               LoopBuilder::kPostDecrement,
1152
                               shared_function_entry_length);
1153
      HValue* array_length = Add<HLoadNamedField>(optimized_map,
1154
          HObjectAccess::ForFixedArrayLength());
1155
      HValue* key = loop_builder.BeginBody(array_length,
1156
                                           graph()->GetConstant0(),
1157
                                           Token::GT);
1158
      {
1159
        // Iterate through the rest of map backwards.
1160
        // Do not double check first entry.
1161
        HValue* second_entry_index =
1162
            Add<HConstant>(SharedFunctionInfo::kSecondEntryIndex);
1163
        IfBuilder restore_check(this);
1164
        restore_check.If<HCompareNumericAndBranch>(key, second_entry_index,
1165
                                                   Token::EQ);
1166
        restore_check.Then();
1167
        {
1168
          // Store the unoptimized code
1169
          BuildInstallCode(js_function, shared_info);
1170
          loop_builder.Break();
1171
        }
1172
        restore_check.Else();
1173
        {
1174
          HValue* keyed_minus = AddUncasted<HSub>(
1175
              key, shared_function_entry_length);
1176
          HInstruction* keyed_lookup = Add<HLoadKeyed>(optimized_map,
1177
              keyed_minus, static_cast<HValue*>(NULL), FAST_ELEMENTS);
1178
          IfBuilder done_check(this);
1179
          done_check.If<HCompareObjectEqAndBranch>(native_context,
1180
                                                   keyed_lookup);
1181
          done_check.Then();
1182
          {
1183
            // Hit: fetch the optimized code.
1184
            HValue* keyed_plus = AddUncasted<HAdd>(
1185
                keyed_minus, graph()->GetConstant1());
1186
            HValue* code_object = Add<HLoadKeyed>(optimized_map,
1187
                keyed_plus, static_cast<HValue*>(NULL), FAST_ELEMENTS);
1188
            BuildInstallOptimizedCode(js_function, native_context, code_object);
1189

    
1190
            // Fall out of the loop
1191
            loop_builder.Break();
1192
          }
1193
          done_check.Else();
1194
          done_check.End();
1195
        }
1196
        restore_check.End();
1197
      }
1198
      loop_builder.EndBody();
1199
    }
1200
    already_in.End();
1201
  }
1202
  is_optimized.End();
1203
}
1204

    
1205

    
1206
template<>
1207
HValue* CodeStubGraphBuilder<FastNewClosureStub>::BuildCodeStub() {
1208
  Counters* counters = isolate()->counters();
1209
  Factory* factory = isolate()->factory();
1210
  HInstruction* empty_fixed_array =
1211
      Add<HConstant>(factory->empty_fixed_array());
1212
  HValue* shared_info = GetParameter(0);
1213

    
1214
  AddIncrementCounter(counters->fast_new_closure_total());
1215

    
1216
  // Create a new closure from the given function info in new space
1217
  HValue* size = Add<HConstant>(JSFunction::kSize);
1218
  HInstruction* js_function = Add<HAllocate>(size, HType::JSObject(),
1219
                                             NOT_TENURED, JS_FUNCTION_TYPE);
1220

    
1221
  int map_index = Context::FunctionMapIndex(casted_stub()->language_mode(),
1222
                                            casted_stub()->is_generator());
1223

    
1224
  // Compute the function map in the current native context and set that
1225
  // as the map of the allocated object.
1226
  HInstruction* native_context = BuildGetNativeContext();
1227
  HInstruction* map_slot_value = Add<HLoadNamedField>(native_context,
1228
      HObjectAccess::ForContextSlot(map_index));
1229
  Add<HStoreNamedField>(js_function, HObjectAccess::ForMap(), map_slot_value);
1230

    
1231
  // Initialize the rest of the function.
1232
  Add<HStoreNamedField>(js_function, HObjectAccess::ForPropertiesPointer(),
1233
                        empty_fixed_array);
1234
  Add<HStoreNamedField>(js_function, HObjectAccess::ForElementsPointer(),
1235
                        empty_fixed_array);
1236
  Add<HStoreNamedField>(js_function, HObjectAccess::ForLiteralsPointer(),
1237
                        empty_fixed_array);
1238
  Add<HStoreNamedField>(js_function, HObjectAccess::ForPrototypeOrInitialMap(),
1239
                        graph()->GetConstantHole());
1240
  Add<HStoreNamedField>(js_function,
1241
                        HObjectAccess::ForSharedFunctionInfoPointer(),
1242
                        shared_info);
1243
  Add<HStoreNamedField>(js_function, HObjectAccess::ForFunctionContextPointer(),
1244
                        shared_info);
1245
  Add<HStoreNamedField>(js_function, HObjectAccess::ForFunctionContextPointer(),
1246
                        context());
1247

    
1248
  // Initialize the code pointer in the function to be the one
1249
  // found in the shared function info object.
1250
  // But first check if there is an optimized version for our context.
1251
  if (FLAG_cache_optimized_code) {
1252
    BuildInstallFromOptimizedCodeMap(js_function, shared_info, native_context);
1253
  } else {
1254
    BuildInstallCode(js_function, shared_info);
1255
  }
1256

    
1257
  return js_function;
1258
}
1259

    
1260

    
1261
Handle<Code> FastNewClosureStub::GenerateCode(Isolate* isolate) {
1262
  return DoGenerateCode(isolate, this);
1263
}
1264

    
1265

    
1266
} }  // namespace v8::internal