~yolanda.robla/ubuntu/trusty/nodejs/add_distribution

« back to all changes in this revision

Viewing changes to deps/v8/src/x64/full-codegen-x64.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2013-08-14 00:16:46 UTC
  • mfrom: (7.1.40 sid)
  • Revision ID: package-import@ubuntu.com-20130814001646-bzlysfh8sd6mukbo
Tags: 0.10.15~dfsg1-4
* Update 2005 patch, adding a handful of tests that can fail on
  slow platforms.
* Add 1004 patch to fix test failures when writing NaN to buffer
  on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2011 the V8 project authors. All rights reserved.
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
2
2
// Redistribution and use in source and binary forms, with or without
3
3
// modification, are permitted provided that the following conditions are
4
4
// met:
34
34
#include "compiler.h"
35
35
#include "debug.h"
36
36
#include "full-codegen.h"
 
37
#include "isolate-inl.h"
37
38
#include "parser.h"
38
39
#include "scopes.h"
39
40
#include "stub-cache.h"
44
45
#define __ ACCESS_MASM(masm_)
45
46
 
46
47
 
47
 
static unsigned GetPropertyId(Property* property) {
48
 
  return property->id();
49
 
}
50
 
 
51
 
 
52
48
class JumpPatchSite BASE_EMBEDDED {
53
49
 public:
54
50
  explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
111
107
// formal parameter count expected by the function.
112
108
//
113
109
// The live registers are:
114
 
//   o rdi: the JS function object being called (ie, ourselves)
 
110
//   o rdi: the JS function object being called (i.e. ourselves)
115
111
//   o rsi: our context
116
112
//   o rbp: our caller's frame pointer
117
113
//   o rsp: stack pointer (pointing to return address)
118
114
//
119
115
// The function builds a JS frame.  Please see JavaScriptFrameConstants in
120
116
// frames-x64.h for its layout.
121
 
void FullCodeGenerator::Generate(CompilationInfo* info) {
122
 
  ASSERT(info_ == NULL);
123
 
  info_ = info;
124
 
  scope_ = info->scope();
 
117
void FullCodeGenerator::Generate() {
 
118
  CompilationInfo* info = info_;
 
119
  handler_table_ =
 
120
      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
 
121
  profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
 
122
      Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget)));
125
123
  SetFunctionPosition(function());
126
124
  Comment cmnt(masm_, "[ function compiled by full code generator");
127
125
 
 
126
  ProfileEntryHookStub::MaybeCallEntryHook(masm_);
 
127
 
128
128
#ifdef DEBUG
129
129
  if (strlen(FLAG_stop_at) > 0 &&
130
130
      info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
136
136
  // with undefined when called as functions (without an explicit
137
137
  // receiver object). rcx is zero for method calls and non-zero for
138
138
  // function calls.
139
 
  if (info->is_strict_mode() || info->is_native()) {
 
139
  if (!info->is_classic_mode() || info->is_native()) {
140
140
    Label ok;
141
141
    __ testq(rcx, rcx);
142
142
    __ j(zero, &ok, Label::kNear);
147
147
    __ bind(&ok);
148
148
  }
149
149
 
 
150
  // Open a frame scope to indicate that there is a frame on the stack.  The
 
151
  // MANUAL indicates that the scope shouldn't actually generate code to set up
 
152
  // the frame (that is done below).
 
153
  FrameScope frame_scope(masm_, StackFrame::MANUAL);
 
154
 
150
155
  __ push(rbp);  // Caller's frame pointer.
151
156
  __ movq(rbp, rsp);
152
157
  __ push(rsi);  // Callee's context.
169
174
  // Possibly allocate a local context.
170
175
  int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
171
176
  if (heap_slots > 0) {
172
 
    Comment cmnt(masm_, "[ Allocate local context");
 
177
    Comment cmnt(masm_, "[ Allocate context");
173
178
    // Argument to NewContext is the function, which is still in rdi.
174
179
    __ push(rdi);
175
 
    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
 
180
    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
 
181
      __ Push(info->scope()->GetScopeInfo());
 
182
      __ CallRuntime(Runtime::kNewGlobalContext, 2);
 
183
    } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
176
184
      FastNewContextStub stub(heap_slots);
177
185
      __ CallStub(&stub);
178
186
    } else {
195
203
        // Store it in the context.
196
204
        int context_offset = Context::SlotOffset(var->index());
197
205
        __ movq(Operand(rsi, context_offset), rax);
198
 
        // Update the write barrier. This clobbers all involved
199
 
        // registers, so we have use a third register to avoid
200
 
        // clobbering rsi.
201
 
        __ movq(rcx, rsi);
202
 
        __ RecordWrite(rcx, context_offset, rax, rbx);
 
206
        // Update the write barrier.  This clobbers rax and rbx.
 
207
        __ RecordWriteContextSlot(
 
208
            rsi, context_offset, rax, rbx, kDontSaveFPRegs);
203
209
      }
204
210
    }
205
211
  }
226
232
    //   function, receiver address, parameter count.
227
233
    // The stub will rewrite receiver and parameter count if the previous
228
234
    // stack frame was an arguments adapter frame.
229
 
    ArgumentsAccessStub stub(
230
 
        is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
231
 
                         : ArgumentsAccessStub::NEW_NON_STRICT_SLOW);
 
235
    ArgumentsAccessStub::Type type;
 
236
    if (!is_classic_mode()) {
 
237
      type = ArgumentsAccessStub::NEW_STRICT;
 
238
    } else if (function()->has_duplicate_parameters()) {
 
239
      type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
 
240
    } else {
 
241
      type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
 
242
    }
 
243
    ArgumentsAccessStub stub(type);
232
244
    __ CallStub(&stub);
233
245
 
234
246
    SetVar(arguments, rax, rbx, rdx);
245
257
    scope()->VisitIllegalRedeclaration(this);
246
258
 
247
259
  } else {
248
 
    PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
 
260
    PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
249
261
    { Comment cmnt(masm_, "[ Declarations");
250
262
      // For named function expressions, declare the function name as a
251
263
      // constant.
252
264
      if (scope()->is_function_scope() && scope()->function() != NULL) {
253
 
        int ignored = 0;
254
 
        EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
 
265
        VariableDeclaration* function = scope()->function();
 
266
        ASSERT(function->proxy()->var()->mode() == CONST ||
 
267
               function->proxy()->var()->mode() == CONST_HARMONY);
 
268
        ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
 
269
        VisitVariableDeclaration(function);
255
270
      }
256
271
      VisitDeclarations(scope()->declarations());
257
272
    }
258
273
 
259
274
    { Comment cmnt(masm_, "[ Stack check");
260
 
      PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
 
275
      PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
261
276
      Label ok;
262
277
      __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
263
278
      __ j(above_equal, &ok, Label::kNear);
287
302
}
288
303
 
289
304
 
290
 
void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
 
305
void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
 
306
  __ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
 
307
  __ SmiAddConstant(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
 
308
                    Smi::FromInt(-delta));
 
309
}
 
310
 
 
311
 
 
312
void FullCodeGenerator::EmitProfilingCounterReset() {
 
313
  int reset_value = FLAG_interrupt_budget;
 
314
  if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) {
 
315
    // Self-optimization is a one-off thing; if it fails, don't try again.
 
316
    reset_value = Smi::kMaxValue;
 
317
  }
 
318
  __ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
 
319
  __ movq(kScratchRegister,
 
320
          reinterpret_cast<uint64_t>(Smi::FromInt(reset_value)),
 
321
          RelocInfo::NONE);
 
322
  __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
 
323
          kScratchRegister);
 
324
}
 
325
 
 
326
 
 
327
void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt,
 
328
                                       Label* back_edge_target) {
291
329
  Comment cmnt(masm_, "[ Stack check");
292
330
  Label ok;
293
 
  __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
294
 
  __ j(above_equal, &ok, Label::kNear);
295
 
  StackCheckStub stub;
296
 
  __ CallStub(&stub);
 
331
 
 
332
  if (FLAG_count_based_interrupts) {
 
333
    int weight = 1;
 
334
    if (FLAG_weighted_back_edges) {
 
335
      ASSERT(back_edge_target->is_bound());
 
336
      int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
 
337
      weight = Min(kMaxBackEdgeWeight,
 
338
                   Max(1, distance / kBackEdgeDistanceUnit));
 
339
    }
 
340
    EmitProfilingCounterDecrement(weight);
 
341
    __ j(positive, &ok, Label::kNear);
 
342
    InterruptStub stub;
 
343
    __ CallStub(&stub);
 
344
  } else {
 
345
    __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
 
346
    __ j(above_equal, &ok, Label::kNear);
 
347
    StackCheckStub stub;
 
348
    __ CallStub(&stub);
 
349
  }
 
350
 
297
351
  // Record a mapping of this PC offset to the OSR id.  This is used to find
298
352
  // the AST id from the unoptimized code in order to use it as a key into
299
353
  // the deoptimization input data found in the optimized code.
306
360
  ASSERT(loop_depth() > 0);
307
361
  __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
308
362
 
 
363
  if (FLAG_count_based_interrupts) {
 
364
    EmitProfilingCounterReset();
 
365
  }
 
366
 
309
367
  __ bind(&ok);
310
368
  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
311
369
  // Record a mapping of the OSR id to this PC.  This is used if the OSR
325
383
      __ push(rax);
326
384
      __ CallRuntime(Runtime::kTraceExit, 1);
327
385
    }
 
386
    if (FLAG_interrupt_at_exit || FLAG_self_optimization) {
 
387
      // Pretend that the exit is a backwards jump to the entry.
 
388
      int weight = 1;
 
389
      if (info_->ShouldSelfOptimize()) {
 
390
        weight = FLAG_interrupt_budget / FLAG_self_opt_count;
 
391
      } else if (FLAG_weighted_back_edges) {
 
392
        int distance = masm_->pc_offset();
 
393
        weight = Min(kMaxBackEdgeWeight,
 
394
                     Max(1, distance / kBackEdgeDistanceUnit));
 
395
      }
 
396
      EmitProfilingCounterDecrement(weight);
 
397
      Label ok;
 
398
      __ j(positive, &ok, Label::kNear);
 
399
      __ push(rax);
 
400
      if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) {
 
401
        __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
 
402
        __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1);
 
403
      } else {
 
404
        InterruptStub stub;
 
405
        __ CallStub(&stub);
 
406
      }
 
407
      __ pop(rax);
 
408
      EmitProfilingCounterReset();
 
409
      __ bind(&ok);
 
410
    }
328
411
#ifdef DEBUG
329
412
    // Add a label for checking the size of the code used for returning.
330
413
    Label check_exit_codesize;
377
460
 
378
461
void FullCodeGenerator::TestContext::Plug(Variable* var) const {
379
462
  codegen()->GetVar(result_register(), var);
380
 
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
 
463
  codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
381
464
  codegen()->DoTest(this);
382
465
}
383
466
 
399
482
 
400
483
 
401
484
void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
402
 
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
 
485
  codegen()->PrepareForBailoutBeforeSplit(condition(),
403
486
                                          true,
404
487
                                          true_label_,
405
488
                                          false_label_);
422
505
 
423
506
void FullCodeGenerator::AccumulatorValueContext::Plug(
424
507
    Handle<Object> lit) const {
425
 
  __ Move(result_register(), lit);
 
508
  if (lit->IsSmi()) {
 
509
    __ SafeMove(result_register(), Smi::cast(*lit));
 
510
  } else {
 
511
    __ Move(result_register(), lit);
 
512
  }
426
513
}
427
514
 
428
515
 
429
516
void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
430
 
  __ Push(lit);
 
517
  if (lit->IsSmi()) {
 
518
    __ SafePush(Smi::cast(*lit));
 
519
  } else {
 
520
    __ Push(lit);
 
521
  }
431
522
}
432
523
 
433
524
 
434
525
void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
435
 
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
 
526
  codegen()->PrepareForBailoutBeforeSplit(condition(),
436
527
                                          true,
437
528
                                          true_label_,
438
529
                                          false_label_);
491
582
  // For simplicity we always test the accumulator register.
492
583
  __ Drop(count);
493
584
  __ Move(result_register(), reg);
494
 
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
 
585
  codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
495
586
  codegen()->DoTest(this);
496
587
}
497
588
 
555
646
 
556
647
 
557
648
void FullCodeGenerator::TestContext::Plug(bool flag) const {
558
 
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
 
649
  codegen()->PrepareForBailoutBeforeSplit(condition(),
559
650
                                          true,
560
651
                                          true_label_,
561
652
                                          false_label_);
573
664
                               Label* fall_through) {
574
665
  ToBooleanStub stub(result_register());
575
666
  __ push(result_register());
576
 
  __ CallStub(&stub);
 
667
  __ CallStub(&stub, condition->test_id());
577
668
  __ testq(result_register(), result_register());
578
669
  // The stub returns nonzero for true.
579
670
  Split(not_zero, if_true, if_false, fall_through);
638
729
  ASSERT(!scratch1.is(src));
639
730
  MemOperand location = VarOperand(var, scratch0);
640
731
  __ movq(location, src);
 
732
 
641
733
  // Emit the write barrier code if the location is in the heap.
642
734
  if (var->IsContextSlot()) {
643
735
    int offset = Context::SlotOffset(var->index());
644
 
    __ RecordWrite(scratch0, offset, src, scratch1);
 
736
    __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
645
737
  }
646
738
}
647
739
 
648
740
 
649
 
void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
 
741
void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
650
742
                                                     bool should_normalize,
651
743
                                                     Label* if_true,
652
744
                                                     Label* if_false) {
657
749
 
658
750
  Label skip;
659
751
  if (should_normalize) __ jmp(&skip, Label::kNear);
660
 
 
661
 
  ForwardBailoutStack* current = forward_bailout_stack_;
662
 
  while (current != NULL) {
663
 
    PrepareForBailout(current->expr(), state);
664
 
    current = current->parent();
665
 
  }
666
 
 
 
752
  PrepareForBailout(expr, TOS_REG);
667
753
  if (should_normalize) {
668
754
    __ CompareRoot(rax, Heap::kTrueValueRootIndex);
669
755
    Split(equal, if_true, if_false, NULL);
672
758
}
673
759
 
674
760
 
675
 
void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
676
 
                                        Variable::Mode mode,
677
 
                                        FunctionLiteral* function,
678
 
                                        int* global_count) {
 
761
void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
 
762
  // The variable in the declaration always resides in the current function
 
763
  // context.
 
764
  ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
 
765
  if (generate_debug_code_) {
 
766
    // Check that we're not inside a with or catch context.
 
767
    __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
 
768
    __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
 
769
    __ Check(not_equal, "Declaration in with context.");
 
770
    __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
 
771
    __ Check(not_equal, "Declaration in catch context.");
 
772
  }
 
773
}
 
774
 
 
775
 
 
776
void FullCodeGenerator::VisitVariableDeclaration(
 
777
    VariableDeclaration* declaration) {
679
778
  // If it was not possible to allocate the variable at compile time, we
680
779
  // need to "declare" it at runtime to make sure it actually exists in the
681
780
  // local context.
 
781
  VariableProxy* proxy = declaration->proxy();
 
782
  VariableMode mode = declaration->mode();
682
783
  Variable* variable = proxy->var();
 
784
  bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
683
785
  switch (variable->location()) {
684
786
    case Variable::UNALLOCATED:
685
 
      ++(*global_count);
 
787
      globals_->Add(variable->name(), zone());
 
788
      globals_->Add(variable->binding_needs_init()
 
789
                        ? isolate()->factory()->the_hole_value()
 
790
                    : isolate()->factory()->undefined_value(),
 
791
                    zone());
686
792
      break;
687
793
 
688
794
    case Variable::PARAMETER:
689
795
    case Variable::LOCAL:
690
 
      if (function != NULL) {
691
 
        Comment cmnt(masm_, "[ Declaration");
692
 
        VisitForAccumulatorValue(function);
693
 
        __ movq(StackOperand(variable), result_register());
694
 
      } else if (mode == Variable::CONST || mode == Variable::LET) {
695
 
        Comment cmnt(masm_, "[ Declaration");
 
796
      if (hole_init) {
 
797
        Comment cmnt(masm_, "[ VariableDeclaration");
696
798
        __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
697
799
        __ movq(StackOperand(variable), kScratchRegister);
698
800
      }
699
801
      break;
700
802
 
701
803
    case Variable::CONTEXT:
702
 
      // The variable in the decl always resides in the current function
703
 
      // context.
704
 
      ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
705
 
      if (FLAG_debug_code) {
706
 
        // Check that we're not inside a with or catch context.
707
 
        __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
708
 
        __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
709
 
        __ Check(not_equal, "Declaration in with context.");
710
 
        __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
711
 
        __ Check(not_equal, "Declaration in catch context.");
712
 
      }
713
 
      if (function != NULL) {
714
 
        Comment cmnt(masm_, "[ Declaration");
715
 
        VisitForAccumulatorValue(function);
716
 
        __ movq(ContextOperand(rsi, variable->index()), result_register());
717
 
        int offset = Context::SlotOffset(variable->index());
718
 
        __ movq(rbx, rsi);
719
 
        __ RecordWrite(rbx, offset, result_register(), rcx);
720
 
        PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
721
 
      } else if (mode == Variable::CONST || mode == Variable::LET) {
722
 
        Comment cmnt(masm_, "[ Declaration");
 
804
      if (hole_init) {
 
805
        Comment cmnt(masm_, "[ VariableDeclaration");
 
806
        EmitDebugCheckDeclarationContext(variable);
723
807
        __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
724
808
        __ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
725
809
        // No write barrier since the hole value is in old space.
728
812
      break;
729
813
 
730
814
    case Variable::LOOKUP: {
731
 
      Comment cmnt(masm_, "[ Declaration");
 
815
      Comment cmnt(masm_, "[ VariableDeclaration");
732
816
      __ push(rsi);
733
817
      __ Push(variable->name());
734
 
      // Declaration nodes are always introduced in one of three modes.
735
 
      ASSERT(mode == Variable::VAR ||
736
 
             mode == Variable::CONST ||
737
 
             mode == Variable::LET);
738
 
      PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
 
818
      // Declaration nodes are always introduced in one of four modes.
 
819
      ASSERT(IsDeclaredVariableMode(mode));
 
820
      PropertyAttributes attr =
 
821
          IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
739
822
      __ Push(Smi::FromInt(attr));
740
823
      // Push initial value, if any.
741
824
      // Note: For variables we must not push an initial value (such as
742
825
      // 'undefined') because we may have a (legal) redeclaration and we
743
826
      // must not destroy the current value.
744
 
      if (function != NULL) {
745
 
        VisitForStackValue(function);
746
 
      } else if (mode == Variable::CONST || mode == Variable::LET) {
 
827
      if (hole_init) {
747
828
        __ PushRoot(Heap::kTheHoleValueRootIndex);
748
829
      } else {
749
830
        __ Push(Smi::FromInt(0));  // Indicates no initial value.
755
836
}
756
837
 
757
838
 
758
 
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
 
839
void FullCodeGenerator::VisitFunctionDeclaration(
 
840
    FunctionDeclaration* declaration) {
 
841
  VariableProxy* proxy = declaration->proxy();
 
842
  Variable* variable = proxy->var();
 
843
  switch (variable->location()) {
 
844
    case Variable::UNALLOCATED: {
 
845
      globals_->Add(variable->name(), zone());
 
846
      Handle<SharedFunctionInfo> function =
 
847
          Compiler::BuildFunctionInfo(declaration->fun(), script());
 
848
      // Check for stack-overflow exception.
 
849
      if (function.is_null()) return SetStackOverflow();
 
850
      globals_->Add(function, zone());
 
851
      break;
 
852
    }
 
853
 
 
854
    case Variable::PARAMETER:
 
855
    case Variable::LOCAL: {
 
856
      Comment cmnt(masm_, "[ FunctionDeclaration");
 
857
      VisitForAccumulatorValue(declaration->fun());
 
858
      __ movq(StackOperand(variable), result_register());
 
859
      break;
 
860
    }
 
861
 
 
862
    case Variable::CONTEXT: {
 
863
      Comment cmnt(masm_, "[ FunctionDeclaration");
 
864
      EmitDebugCheckDeclarationContext(variable);
 
865
      VisitForAccumulatorValue(declaration->fun());
 
866
      __ movq(ContextOperand(rsi, variable->index()), result_register());
 
867
      int offset = Context::SlotOffset(variable->index());
 
868
      // We know that we have written a function, which is not a smi.
 
869
      __ RecordWriteContextSlot(rsi,
 
870
                                offset,
 
871
                                result_register(),
 
872
                                rcx,
 
873
                                kDontSaveFPRegs,
 
874
                                EMIT_REMEMBERED_SET,
 
875
                                OMIT_SMI_CHECK);
 
876
      PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
 
877
      break;
 
878
    }
 
879
 
 
880
    case Variable::LOOKUP: {
 
881
      Comment cmnt(masm_, "[ FunctionDeclaration");
 
882
      __ push(rsi);
 
883
      __ Push(variable->name());
 
884
      __ Push(Smi::FromInt(NONE));
 
885
      VisitForStackValue(declaration->fun());
 
886
      __ CallRuntime(Runtime::kDeclareContextSlot, 4);
 
887
      break;
 
888
    }
 
889
  }
 
890
}
 
891
 
 
892
 
 
893
void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
 
894
  VariableProxy* proxy = declaration->proxy();
 
895
  Variable* variable = proxy->var();
 
896
  Handle<JSModule> instance = declaration->module()->interface()->Instance();
 
897
  ASSERT(!instance.is_null());
 
898
 
 
899
  switch (variable->location()) {
 
900
    case Variable::UNALLOCATED: {
 
901
      Comment cmnt(masm_, "[ ModuleDeclaration");
 
902
      globals_->Add(variable->name(), zone());
 
903
      globals_->Add(instance, zone());
 
904
      Visit(declaration->module());
 
905
      break;
 
906
    }
 
907
 
 
908
    case Variable::CONTEXT: {
 
909
      Comment cmnt(masm_, "[ ModuleDeclaration");
 
910
      EmitDebugCheckDeclarationContext(variable);
 
911
      __ Move(ContextOperand(rsi, variable->index()), instance);
 
912
      Visit(declaration->module());
 
913
      break;
 
914
    }
 
915
 
 
916
    case Variable::PARAMETER:
 
917
    case Variable::LOCAL:
 
918
    case Variable::LOOKUP:
 
919
      UNREACHABLE();
 
920
  }
 
921
}
 
922
 
 
923
 
 
924
void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
 
925
  VariableProxy* proxy = declaration->proxy();
 
926
  Variable* variable = proxy->var();
 
927
  switch (variable->location()) {
 
928
    case Variable::UNALLOCATED:
 
929
      // TODO(rossberg)
 
930
      break;
 
931
 
 
932
    case Variable::CONTEXT: {
 
933
      Comment cmnt(masm_, "[ ImportDeclaration");
 
934
      EmitDebugCheckDeclarationContext(variable);
 
935
      // TODO(rossberg)
 
936
      break;
 
937
    }
 
938
 
 
939
    case Variable::PARAMETER:
 
940
    case Variable::LOCAL:
 
941
    case Variable::LOOKUP:
 
942
      UNREACHABLE();
 
943
  }
 
944
}
 
945
 
 
946
 
 
947
void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
 
948
  // TODO(rossberg)
 
949
}
759
950
 
760
951
 
761
952
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
819
1010
    // Record position before stub call for type feedback.
820
1011
    SetSourcePosition(clause->position());
821
1012
    Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
822
 
    __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
 
1013
    CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId());
823
1014
    patch_site.EmitPatchInfo();
824
1015
 
825
1016
    __ testq(rax, rax);
871
1062
  __ cmpq(rax, null_value);
872
1063
  __ j(equal, &exit);
873
1064
 
 
1065
  PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
 
1066
 
874
1067
  // Convert the object to a JS object.
875
1068
  Label convert, done_convert;
876
1069
  __ JumpIfSmi(rax, &convert);
882
1075
  __ bind(&done_convert);
883
1076
  __ push(rax);
884
1077
 
 
1078
  // Check for proxies.
 
1079
  Label call_runtime;
 
1080
  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
 
1081
  __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
 
1082
  __ j(below_equal, &call_runtime);
 
1083
 
885
1084
  // Check cache validity in generated code. This is a fast case for
886
1085
  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
887
1086
  // guarantee cache validity, call the runtime system to check cache
888
1087
  // validity or get the property names in a fixed array.
889
 
  Label next, call_runtime;
890
 
  Register empty_fixed_array_value = r8;
891
 
  __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
892
 
  Register empty_descriptor_array_value = r9;
893
 
  __ LoadRoot(empty_descriptor_array_value,
894
 
              Heap::kEmptyDescriptorArrayRootIndex);
895
 
  __ movq(rcx, rax);
896
 
  __ bind(&next);
897
 
 
898
 
  // Check that there are no elements.  Register rcx contains the
899
 
  // current JS object we've reached through the prototype chain.
900
 
  __ cmpq(empty_fixed_array_value,
901
 
          FieldOperand(rcx, JSObject::kElementsOffset));
902
 
  __ j(not_equal, &call_runtime);
903
 
 
904
 
  // Check that instance descriptors are not empty so that we can
905
 
  // check for an enum cache.  Leave the map in rbx for the subsequent
906
 
  // prototype load.
907
 
  __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
908
 
  __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBitField3Offset));
909
 
  __ JumpIfSmi(rdx, &call_runtime);
910
 
 
911
 
  // Check that there is an enum cache in the non-empty instance
912
 
  // descriptors (rdx).  This is the case if the next enumeration
913
 
  // index field does not contain a smi.
914
 
  __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
915
 
  __ JumpIfSmi(rdx, &call_runtime);
916
 
 
917
 
  // For all objects but the receiver, check that the cache is empty.
918
 
  Label check_prototype;
919
 
  __ cmpq(rcx, rax);
920
 
  __ j(equal, &check_prototype, Label::kNear);
921
 
  __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
922
 
  __ cmpq(rdx, empty_fixed_array_value);
923
 
  __ j(not_equal, &call_runtime);
924
 
 
925
 
  // Load the prototype from the map and loop if non-null.
926
 
  __ bind(&check_prototype);
927
 
  __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
928
 
  __ cmpq(rcx, null_value);
929
 
  __ j(not_equal, &next);
 
1088
  __ CheckEnumCache(null_value, &call_runtime);
930
1089
 
931
1090
  // The enum cache is valid.  Load the map of the object being
932
1091
  // iterated over and use the cache for the iteration.
945
1104
  Label fixed_array;
946
1105
  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
947
1106
                 Heap::kMetaMapRootIndex);
948
 
  __ j(not_equal, &fixed_array, Label::kNear);
 
1107
  __ j(not_equal, &fixed_array);
949
1108
 
950
1109
  // We got a map in register rax. Get the enumeration cache from it.
951
1110
  __ bind(&use_cache);
 
1111
 
 
1112
  Label no_descriptors;
 
1113
 
 
1114
  __ EnumLength(rdx, rax);
 
1115
  __ Cmp(rdx, Smi::FromInt(0));
 
1116
  __ j(equal, &no_descriptors);
 
1117
 
952
1118
  __ LoadInstanceDescriptors(rax, rcx);
953
 
  __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
954
 
  __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
 
1119
  __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
 
1120
  __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
955
1121
 
956
 
  // Setup the four remaining stack slots.
 
1122
  // Set up the four remaining stack slots.
957
1123
  __ push(rax);  // Map.
958
 
  __ push(rdx);  // Enumeration cache.
959
 
  __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
960
 
  __ push(rax);  // Enumeration cache length (as smi).
 
1124
  __ push(rcx);  // Enumeration cache.
 
1125
  __ push(rdx);  // Number of valid entries for the map in the enum cache.
961
1126
  __ Push(Smi::FromInt(0));  // Initial index.
962
1127
  __ jmp(&loop);
963
1128
 
 
1129
  __ bind(&no_descriptors);
 
1130
  __ addq(rsp, Immediate(kPointerSize));
 
1131
  __ jmp(&exit);
 
1132
 
964
1133
  // We got a fixed array in register rax. Iterate through that.
 
1134
  Label non_proxy;
965
1135
  __ bind(&fixed_array);
966
 
  __ Push(Smi::FromInt(0));  // Map (0) - force slow check.
967
 
  __ push(rax);
 
1136
 
 
1137
  Handle<JSGlobalPropertyCell> cell =
 
1138
      isolate()->factory()->NewJSGlobalPropertyCell(
 
1139
          Handle<Object>(
 
1140
              Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
 
1141
  RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell);
 
1142
  __ LoadHeapObject(rbx, cell);
 
1143
  __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
 
1144
          Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker));
 
1145
 
 
1146
  __ Move(rbx, Smi::FromInt(1));  // Smi indicates slow check
 
1147
  __ movq(rcx, Operand(rsp, 0 * kPointerSize));  // Get enumerated object
 
1148
  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
 
1149
  __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx);
 
1150
  __ j(above, &non_proxy);
 
1151
  __ Move(rbx, Smi::FromInt(0));  // Zero indicates proxy
 
1152
  __ bind(&non_proxy);
 
1153
  __ push(rbx);  // Smi
 
1154
  __ push(rax);  // Array
968
1155
  __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
969
1156
  __ push(rax);  // Fixed array length (as smi).
970
1157
  __ Push(Smi::FromInt(0));  // Initial index.
971
1158
 
972
1159
  // Generate code for doing the condition check.
 
1160
  PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
973
1161
  __ bind(&loop);
974
1162
  __ movq(rax, Operand(rsp, 0 * kPointerSize));  // Get the current index.
975
1163
  __ cmpq(rax, Operand(rsp, 1 * kPointerSize));  // Compare to the array length.
983
1171
                            index.scale,
984
1172
                            FixedArray::kHeaderSize));
985
1173
 
986
 
  // Get the expected map from the stack or a zero map in the
 
1174
  // Get the expected map from the stack or a smi in the
987
1175
  // permanent slow case into register rdx.
988
1176
  __ movq(rdx, Operand(rsp, 3 * kPointerSize));
989
1177
 
990
1178
  // Check if the expected map still matches that of the enumerable.
991
 
  // If not, we have to filter the key.
 
1179
  // If not, we may have to filter the key.
992
1180
  Label update_each;
993
1181
  __ movq(rcx, Operand(rsp, 4 * kPointerSize));
994
1182
  __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
995
1183
  __ j(equal, &update_each, Label::kNear);
996
1184
 
 
1185
  // For proxies, no filtering is done.
 
1186
  // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
 
1187
  __ Cmp(rdx, Smi::FromInt(0));
 
1188
  __ j(equal, &update_each, Label::kNear);
 
1189
 
997
1190
  // Convert the entry to a string or null if it isn't a property
998
1191
  // anymore. If the property has been removed while iterating, we
999
1192
  // just skip it.
1010
1203
  __ movq(result_register(), rbx);
1011
1204
  // Perform the assignment as if via '='.
1012
1205
  { EffectContext context(this);
1013
 
    EmitAssignment(stmt->each(), stmt->AssignmentId());
 
1206
    EmitAssignment(stmt->each());
1014
1207
  }
1015
1208
 
1016
1209
  // Generate code for the body of the loop.
1021
1214
  __ bind(loop_statement.continue_label());
1022
1215
  __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
1023
1216
 
1024
 
  EmitStackCheck(stmt);
 
1217
  EmitStackCheck(stmt, &loop);
1025
1218
  __ jmp(&loop);
1026
1219
 
1027
1220
  // Remove the pointers stored on the stack.
1029
1222
  __ addq(rsp, Immediate(5 * kPointerSize));
1030
1223
 
1031
1224
  // Exit and decrement the loop depth.
 
1225
  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1032
1226
  __ bind(&exit);
1033
1227
  decrement_loop_depth();
1034
1228
}
1047
1241
      !pretenure &&
1048
1242
      scope()->is_function_scope() &&
1049
1243
      info->num_literals() == 0) {
1050
 
    FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
 
1244
    FastNewClosureStub stub(info->language_mode());
1051
1245
    __ Push(info);
1052
1246
    __ CallStub(&stub);
1053
1247
  } else {
1077
1271
  Scope* s = scope();
1078
1272
  while (s != NULL) {
1079
1273
    if (s->num_heap_slots() > 0) {
1080
 
      if (s->calls_eval()) {
 
1274
      if (s->calls_non_strict_eval()) {
1081
1275
        // Check that extension is NULL.
1082
1276
        __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1083
1277
                Immediate(0));
1091
1285
    // If no outer scope calls eval, we do not need to check more
1092
1286
    // context extensions.  If we have reached an eval scope, we check
1093
1287
    // all extensions from this point.
1094
 
    if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
 
1288
    if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
1095
1289
    s = s->outer_scope();
1096
1290
  }
1097
1291
 
1103
1297
      __ movq(temp, context);
1104
1298
    }
1105
1299
    // Load map for comparison into register, outside loop.
1106
 
    __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex);
 
1300
    __ LoadRoot(kScratchRegister, Heap::kNativeContextMapRootIndex);
1107
1301
    __ bind(&next);
1108
 
    // Terminate at global context.
 
1302
    // Terminate at native context.
1109
1303
    __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset));
1110
1304
    __ j(equal, &fast, Label::kNear);
1111
1305
    // Check that extension is NULL.
1125
1319
  RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1126
1320
      ? RelocInfo::CODE_TARGET
1127
1321
      : RelocInfo::CODE_TARGET_CONTEXT;
1128
 
  __ call(ic, mode);
 
1322
  CallIC(ic, mode);
1129
1323
}
1130
1324
 
1131
1325
 
1137
1331
 
1138
1332
  for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1139
1333
    if (s->num_heap_slots() > 0) {
1140
 
      if (s->calls_eval()) {
 
1334
      if (s->calls_non_strict_eval()) {
1141
1335
        // Check that extension is NULL.
1142
1336
        __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX),
1143
1337
                Immediate(0));
1168
1362
  // introducing variables.  In those cases, we do not want to
1169
1363
  // perform a runtime call for all variables in the scope
1170
1364
  // containing the eval.
1171
 
  if (var->mode() == Variable::DYNAMIC_GLOBAL) {
 
1365
  if (var->mode() == DYNAMIC_GLOBAL) {
1172
1366
    EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
1173
1367
    __ jmp(done);
1174
 
  } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
 
1368
  } else if (var->mode() == DYNAMIC_LOCAL) {
1175
1369
    Variable* local = var->local_if_not_shadowed();
1176
1370
    __ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
1177
 
    if (local->mode() == Variable::CONST) {
 
1371
    if (local->mode() == CONST ||
 
1372
        local->mode() == CONST_HARMONY ||
 
1373
        local->mode() == LET) {
1178
1374
      __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1179
1375
      __ j(not_equal, done);
1180
 
      __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
 
1376
      if (local->mode() == CONST) {
 
1377
        __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
 
1378
      } else {  // LET || CONST_HARMONY
 
1379
        __ Push(var->name());
 
1380
        __ CallRuntime(Runtime::kThrowReferenceError, 1);
 
1381
      }
1181
1382
    }
1182
1383
    __ jmp(done);
1183
1384
  }
1199
1400
      __ Move(rcx, var->name());
1200
1401
      __ movq(rax, GlobalObjectOperand());
1201
1402
      Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
1202
 
      __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
 
1403
      CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1203
1404
      context()->Plug(rax);
1204
1405
      break;
1205
1406
    }
1208
1409
    case Variable::LOCAL:
1209
1410
    case Variable::CONTEXT: {
1210
1411
      Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
1211
 
      if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
1212
 
        context()->Plug(var);
1213
 
      } else {
1214
 
        // Let and const need a read barrier.
1215
 
        Label done;
1216
 
        GetVar(rax, var);
1217
 
        __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1218
 
        __ j(not_equal, &done, Label::kNear);
1219
 
        if (var->mode() == Variable::LET) {
1220
 
          __ Push(var->name());
1221
 
          __ CallRuntime(Runtime::kThrowReferenceError, 1);
1222
 
        } else {  // Variable::CONST
1223
 
          __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1224
 
        }
1225
 
        __ bind(&done);
1226
 
        context()->Plug(rax);
 
1412
      if (var->binding_needs_init()) {
 
1413
        // var->scope() may be NULL when the proxy is located in eval code and
 
1414
        // refers to a potential outside binding. Currently those bindings are
 
1415
        // always looked up dynamically, i.e. in that case
 
1416
        //     var->location() == LOOKUP.
 
1417
        // always holds.
 
1418
        ASSERT(var->scope() != NULL);
 
1419
 
 
1420
        // Check if the binding really needs an initialization check. The check
 
1421
        // can be skipped in the following situation: we have a LET or CONST
 
1422
        // binding in harmony mode, both the Variable and the VariableProxy have
 
1423
        // the same declaration scope (i.e. they are both in global code, in the
 
1424
        // same function or in the same eval code) and the VariableProxy is in
 
1425
        // the source physically located after the initializer of the variable.
 
1426
        //
 
1427
        // We cannot skip any initialization checks for CONST in non-harmony
 
1428
        // mode because const variables may be declared but never initialized:
 
1429
        //   if (false) { const x; }; var y = x;
 
1430
        //
 
1431
        // The condition on the declaration scopes is a conservative check for
 
1432
        // nested functions that access a binding and are called before the
 
1433
        // binding is initialized:
 
1434
        //   function() { f(); let x = 1; function f() { x = 2; } }
 
1435
        //
 
1436
        bool skip_init_check;
 
1437
        if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
 
1438
          skip_init_check = false;
 
1439
        } else {
 
1440
          // Check that we always have valid source position.
 
1441
          ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
 
1442
          ASSERT(proxy->position() != RelocInfo::kNoPosition);
 
1443
          skip_init_check = var->mode() != CONST &&
 
1444
              var->initializer_position() < proxy->position();
 
1445
        }
 
1446
 
 
1447
        if (!skip_init_check) {
 
1448
          // Let and const need a read barrier.
 
1449
          Label done;
 
1450
          GetVar(rax, var);
 
1451
          __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
 
1452
          __ j(not_equal, &done, Label::kNear);
 
1453
          if (var->mode() == LET || var->mode() == CONST_HARMONY) {
 
1454
            // Throw a reference error when using an uninitialized let/const
 
1455
            // binding in harmony mode.
 
1456
            __ Push(var->name());
 
1457
            __ CallRuntime(Runtime::kThrowReferenceError, 1);
 
1458
          } else {
 
1459
            // Uninitalized const bindings outside of harmony mode are unholed.
 
1460
            ASSERT(var->mode() == CONST);
 
1461
            __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
 
1462
          }
 
1463
          __ bind(&done);
 
1464
          context()->Plug(rax);
 
1465
          break;
 
1466
        }
1227
1467
      }
 
1468
      context()->Plug(var);
1228
1469
      break;
1229
1470
    }
1230
1471
 
1300
1541
}
1301
1542
 
1302
1543
 
 
1544
void FullCodeGenerator::EmitAccessor(Expression* expression) {
 
1545
  if (expression == NULL) {
 
1546
    __ PushRoot(Heap::kNullValueRootIndex);
 
1547
  } else {
 
1548
    VisitForStackValue(expression);
 
1549
  }
 
1550
}
 
1551
 
 
1552
 
1303
1553
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1304
1554
  Comment cmnt(masm_, "[ ObjectLiteral");
 
1555
  Handle<FixedArray> constant_properties = expr->constant_properties();
1305
1556
  __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1306
1557
  __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1307
1558
  __ Push(Smi::FromInt(expr->literal_index()));
1308
 
  __ Push(expr->constant_properties());
 
1559
  __ Push(constant_properties);
1309
1560
  int flags = expr->fast_elements()
1310
1561
      ? ObjectLiteral::kFastElements
1311
1562
      : ObjectLiteral::kNoFlags;
1313
1564
      ? ObjectLiteral::kHasFunction
1314
1565
      : ObjectLiteral::kNoFlags;
1315
1566
  __ Push(Smi::FromInt(flags));
 
1567
  int properties_count = constant_properties->length() / 2;
1316
1568
  if (expr->depth() > 1) {
1317
1569
    __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
1318
 
  } else {
 
1570
  } else if (flags != ObjectLiteral::kFastElements ||
 
1571
      properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
1319
1572
    __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
 
1573
  } else {
 
1574
    FastCloneShallowObjectStub stub(properties_count);
 
1575
    __ CallStub(&stub);
1320
1576
  }
1321
1577
 
1322
1578
  // If result_saved is true the result is on top of the stack.  If
1326
1582
  // Mark all computed expressions that are bound to a key that
1327
1583
  // is shadowed by a later occurrence of the same key. For the
1328
1584
  // marked expressions, no store code is emitted.
1329
 
  expr->CalculateEmitStore();
 
1585
  expr->CalculateEmitStore(zone());
1330
1586
 
 
1587
  AccessorTable accessor_table(zone());
1331
1588
  for (int i = 0; i < expr->properties()->length(); i++) {
1332
1589
    ObjectLiteral::Property* property = expr->properties()->at(i);
1333
1590
    if (property->IsCompileTimeValue()) continue;
1350
1607
            VisitForAccumulatorValue(value);
1351
1608
            __ Move(rcx, key->handle());
1352
1609
            __ movq(rdx, Operand(rsp, 0));
1353
 
            Handle<Code> ic = is_strict_mode()
1354
 
                ? isolate()->builtins()->StoreIC_Initialize_Strict()
1355
 
                : isolate()->builtins()->StoreIC_Initialize();
1356
 
            __ call(ic, RelocInfo::CODE_TARGET, key->id());
 
1610
            Handle<Code> ic = is_classic_mode()
 
1611
                ? isolate()->builtins()->StoreIC_Initialize()
 
1612
                : isolate()->builtins()->StoreIC_Initialize_Strict();
 
1613
            CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId());
1357
1614
            PrepareForBailoutForId(key->id(), NO_REGISTERS);
1358
1615
          } else {
1359
1616
            VisitForEffect(value);
1372
1629
          __ Drop(3);
1373
1630
        }
1374
1631
        break;
 
1632
      case ObjectLiteral::Property::GETTER:
 
1633
        accessor_table.lookup(key)->second->getter = value;
 
1634
        break;
1375
1635
      case ObjectLiteral::Property::SETTER:
1376
 
      case ObjectLiteral::Property::GETTER:
1377
 
        __ push(Operand(rsp, 0));  // Duplicate receiver.
1378
 
        VisitForStackValue(key);
1379
 
        __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
1380
 
                Smi::FromInt(1) :
1381
 
                Smi::FromInt(0));
1382
 
        VisitForStackValue(value);
1383
 
        __ CallRuntime(Runtime::kDefineAccessor, 4);
 
1636
        accessor_table.lookup(key)->second->setter = value;
1384
1637
        break;
1385
1638
    }
1386
1639
  }
1387
1640
 
 
1641
  // Emit code to define accessors, using only a single call to the runtime for
 
1642
  // each pair of corresponding getters and setters.
 
1643
  for (AccessorTable::Iterator it = accessor_table.begin();
 
1644
       it != accessor_table.end();
 
1645
       ++it) {
 
1646
    __ push(Operand(rsp, 0));  // Duplicate receiver.
 
1647
    VisitForStackValue(it->first);
 
1648
    EmitAccessor(it->second->getter);
 
1649
    EmitAccessor(it->second->setter);
 
1650
    __ Push(Smi::FromInt(NONE));
 
1651
    __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
 
1652
  }
 
1653
 
1388
1654
  if (expr->has_function()) {
1389
1655
    ASSERT(result_saved);
1390
1656
    __ push(Operand(rsp, 0));
1404
1670
 
1405
1671
  ZoneList<Expression*>* subexprs = expr->values();
1406
1672
  int length = subexprs->length();
 
1673
  Handle<FixedArray> constant_elements = expr->constant_elements();
 
1674
  ASSERT_EQ(2, constant_elements->length());
 
1675
  ElementsKind constant_elements_kind =
 
1676
      static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
 
1677
  bool has_constant_fast_elements =
 
1678
      IsFastObjectElementsKind(constant_elements_kind);
 
1679
  Handle<FixedArrayBase> constant_elements_values(
 
1680
      FixedArrayBase::cast(constant_elements->get(1)));
1407
1681
 
1408
1682
  __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1409
1683
  __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1410
1684
  __ Push(Smi::FromInt(expr->literal_index()));
1411
 
  __ Push(expr->constant_elements());
1412
 
  if (expr->constant_elements()->map() ==
1413
 
      isolate()->heap()->fixed_cow_array_map()) {
1414
 
    FastCloneShallowArrayStub stub(
1415
 
        FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1416
 
    __ CallStub(&stub);
 
1685
  __ Push(constant_elements);
 
1686
  Heap* heap = isolate()->heap();
 
1687
  if (has_constant_fast_elements &&
 
1688
      constant_elements_values->map() == heap->fixed_cow_array_map()) {
 
1689
    // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
 
1690
    // change, so it's possible to specialize the stub in advance.
1417
1691
    __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
 
1692
    FastCloneShallowArrayStub stub(
 
1693
        FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
 
1694
        length);
 
1695
    __ CallStub(&stub);
1418
1696
  } else if (expr->depth() > 1) {
1419
1697
    __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1420
1698
  } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
1421
1699
    __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
1422
1700
  } else {
1423
 
    FastCloneShallowArrayStub stub(
1424
 
        FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
 
1701
    ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
 
1702
           FLAG_smi_only_arrays);
 
1703
    // If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
 
1704
    // change, so it's possible to specialize the stub in advance.
 
1705
    FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
 
1706
        ? FastCloneShallowArrayStub::CLONE_ELEMENTS
 
1707
        : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
 
1708
    FastCloneShallowArrayStub stub(mode, length);
1425
1709
    __ CallStub(&stub);
1426
1710
  }
1427
1711
 
1444
1728
    }
1445
1729
    VisitForAccumulatorValue(subexpr);
1446
1730
 
1447
 
    // Store the subexpression value in the array's elements.
1448
 
    __ movq(rbx, Operand(rsp, 0));  // Copy of array literal.
1449
 
    __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1450
 
    int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1451
 
    __ movq(FieldOperand(rbx, offset), result_register());
1452
 
 
1453
 
    // Update the write barrier for the array store.
1454
 
    __ RecordWrite(rbx, offset, result_register(), rcx);
 
1731
    if (IsFastObjectElementsKind(constant_elements_kind)) {
 
1732
      // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
 
1733
      // cannot transition and don't need to call the runtime stub.
 
1734
      int offset = FixedArray::kHeaderSize + (i * kPointerSize);
 
1735
      __ movq(rbx, Operand(rsp, 0));  // Copy of array literal.
 
1736
      __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
 
1737
      // Store the subexpression value in the array's elements.
 
1738
      __ movq(FieldOperand(rbx, offset), result_register());
 
1739
      // Update the write barrier for the array store.
 
1740
      __ RecordWriteField(rbx, offset, result_register(), rcx,
 
1741
                          kDontSaveFPRegs,
 
1742
                          EMIT_REMEMBERED_SET,
 
1743
                          INLINE_SMI_CHECK);
 
1744
    } else {
 
1745
      // Store the subexpression value in the array's elements.
 
1746
      __ movq(rbx, Operand(rsp, 0));  // Copy of array literal.
 
1747
      __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
 
1748
      __ Move(rcx, Smi::FromInt(i));
 
1749
      __ Move(rdx, Smi::FromInt(expr->literal_index()));
 
1750
      StoreArrayLiteralElementStub stub;
 
1751
      __ CallStub(&stub);
 
1752
    }
1455
1753
 
1456
1754
    PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
1457
1755
  }
1523
1821
          break;
1524
1822
        case NAMED_PROPERTY:
1525
1823
          EmitNamedPropertyLoad(property);
1526
 
          PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
 
1824
          PrepareForBailoutForId(property->LoadId(), TOS_REG);
1527
1825
          break;
1528
1826
        case KEYED_PROPERTY:
1529
1827
          EmitKeyedPropertyLoad(property);
1530
 
          PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
 
1828
          PrepareForBailoutForId(property->LoadId(), TOS_REG);
1531
1829
          break;
1532
1830
      }
1533
1831
    }
1582
1880
  Literal* key = prop->key()->AsLiteral();
1583
1881
  __ Move(rcx, key->handle());
1584
1882
  Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
1585
 
  __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
 
1883
  CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
1586
1884
}
1587
1885
 
1588
1886
 
1589
1887
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1590
1888
  SetSourcePosition(prop->position());
1591
1889
  Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
1592
 
  __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
 
1890
  CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
1593
1891
}
1594
1892
 
1595
1893
 
1611
1909
  __ bind(&stub_call);
1612
1910
  __ movq(rax, rcx);
1613
1911
  BinaryOpStub stub(op, mode);
1614
 
  __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
 
1912
  CallIC(stub.GetCode(), RelocInfo::CODE_TARGET,
 
1913
         expr->BinaryOperationFeedbackId());
1615
1914
  patch_site.EmitPatchInfo();
1616
1915
  __ jmp(&done, Label::kNear);
1617
1916
 
1660
1959
  __ pop(rdx);
1661
1960
  BinaryOpStub stub(op, mode);
1662
1961
  JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
1663
 
  __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
 
1962
  CallIC(stub.GetCode(), RelocInfo::CODE_TARGET,
 
1963
         expr->BinaryOperationFeedbackId());
1664
1964
  patch_site.EmitPatchInfo();
1665
1965
  context()->Plug(rax);
1666
1966
}
1667
1967
 
1668
1968
 
1669
 
void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
 
1969
void FullCodeGenerator::EmitAssignment(Expression* expr) {
1670
1970
  // Invalid left-hand sides are rewritten to have a 'throw
1671
1971
  // ReferenceError' on the left-hand side.
1672
1972
  if (!expr->IsValidLeftHandSide()) {
1698
1998
      __ movq(rdx, rax);
1699
1999
      __ pop(rax);  // Restore value.
1700
2000
      __ Move(rcx, prop->key()->AsLiteral()->handle());
1701
 
      Handle<Code> ic = is_strict_mode()
1702
 
          ? isolate()->builtins()->StoreIC_Initialize_Strict()
1703
 
          : isolate()->builtins()->StoreIC_Initialize();
1704
 
      __ call(ic);
 
2001
      Handle<Code> ic = is_classic_mode()
 
2002
          ? isolate()->builtins()->StoreIC_Initialize()
 
2003
          : isolate()->builtins()->StoreIC_Initialize_Strict();
 
2004
      CallIC(ic);
1705
2005
      break;
1706
2006
    }
1707
2007
    case KEYED_PROPERTY: {
1711
2011
      __ movq(rcx, rax);
1712
2012
      __ pop(rdx);
1713
2013
      __ pop(rax);  // Restore value.
1714
 
      Handle<Code> ic = is_strict_mode()
1715
 
          ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1716
 
          : isolate()->builtins()->KeyedStoreIC_Initialize();
1717
 
      __ call(ic);
 
2014
      Handle<Code> ic = is_classic_mode()
 
2015
          ? isolate()->builtins()->KeyedStoreIC_Initialize()
 
2016
          : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
 
2017
      CallIC(ic);
1718
2018
      break;
1719
2019
    }
1720
2020
  }
1721
 
  PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1722
2021
  context()->Plug(rax);
1723
2022
}
1724
2023
 
1729
2028
    // Global var, const, or let.
1730
2029
    __ Move(rcx, var->name());
1731
2030
    __ movq(rdx, GlobalObjectOperand());
1732
 
    Handle<Code> ic = is_strict_mode()
1733
 
        ? isolate()->builtins()->StoreIC_Initialize_Strict()
1734
 
        : isolate()->builtins()->StoreIC_Initialize();
1735
 
    __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
 
2031
    Handle<Code> ic = is_classic_mode()
 
2032
        ? isolate()->builtins()->StoreIC_Initialize()
 
2033
        : isolate()->builtins()->StoreIC_Initialize_Strict();
 
2034
    CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1736
2035
  } else if (op == Token::INIT_CONST) {
1737
2036
    // Const initializers need a write barrier.
1738
2037
    ASSERT(!var->IsParameter());  // No const parameters.
1756
2055
      __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1757
2056
    }
1758
2057
 
1759
 
  } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
 
2058
  } else if (var->mode() == LET && op != Token::INIT_LET) {
1760
2059
    // Non-initializing assignment to let variable needs a write barrier.
1761
2060
    if (var->IsLookupSlot()) {
1762
2061
      __ push(rax);  // Value.
1763
2062
      __ push(rsi);  // Context.
1764
2063
      __ Push(var->name());
1765
 
      __ Push(Smi::FromInt(strict_mode_flag()));
 
2064
      __ Push(Smi::FromInt(language_mode()));
1766
2065
      __ CallRuntime(Runtime::kStoreContextSlot, 4);
1767
2066
    } else {
1768
2067
      ASSERT(var->IsStackAllocated() || var->IsContextSlot());
1777
2076
      __ movq(location, rax);
1778
2077
      if (var->IsContextSlot()) {
1779
2078
        __ movq(rdx, rax);
1780
 
        __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx);
 
2079
        __ RecordWriteContextSlot(
 
2080
            rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
1781
2081
      }
1782
2082
    }
1783
2083
 
1784
 
  } else if (var->mode() != Variable::CONST) {
1785
 
    // Assignment to var or initializing assignment to let.
 
2084
  } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
 
2085
    // Assignment to var or initializing assignment to let/const
 
2086
    // in harmony mode.
1786
2087
    if (var->IsStackAllocated() || var->IsContextSlot()) {
1787
2088
      MemOperand location = VarOperand(var, rcx);
1788
 
      if (FLAG_debug_code && op == Token::INIT_LET) {
 
2089
      if (generate_debug_code_ && op == Token::INIT_LET) {
1789
2090
        // Check for an uninitialized let binding.
1790
2091
        __ movq(rdx, location);
1791
2092
        __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1795
2096
      __ movq(location, rax);
1796
2097
      if (var->IsContextSlot()) {
1797
2098
        __ movq(rdx, rax);
1798
 
        __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx);
 
2099
        __ RecordWriteContextSlot(
 
2100
            rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
1799
2101
      }
1800
2102
    } else {
1801
2103
      ASSERT(var->IsLookupSlot());
1802
2104
      __ push(rax);  // Value.
1803
2105
      __ push(rsi);  // Context.
1804
2106
      __ Push(var->name());
1805
 
      __ Push(Smi::FromInt(strict_mode_flag()));
 
2107
      __ Push(Smi::FromInt(language_mode()));
1806
2108
      __ CallRuntime(Runtime::kStoreContextSlot, 4);
1807
2109
    }
1808
2110
  }
1816
2118
  ASSERT(prop != NULL);
1817
2119
  ASSERT(prop->key()->AsLiteral() != NULL);
1818
2120
 
1819
 
  // If the assignment starts a block of assignments to the same object,
1820
 
  // change to slow case to avoid the quadratic behavior of repeatedly
1821
 
  // adding fast properties.
1822
 
  if (expr->starts_initialization_block()) {
1823
 
    __ push(result_register());
1824
 
    __ push(Operand(rsp, kPointerSize));  // Receiver is now under value.
1825
 
    __ CallRuntime(Runtime::kToSlowProperties, 1);
1826
 
    __ pop(result_register());
1827
 
  }
1828
 
 
1829
2121
  // Record source code position before IC call.
1830
2122
  SetSourcePosition(expr->position());
1831
2123
  __ Move(rcx, prop->key()->AsLiteral()->handle());
1832
 
  if (expr->ends_initialization_block()) {
1833
 
    __ movq(rdx, Operand(rsp, 0));
1834
 
  } else {
1835
 
    __ pop(rdx);
1836
 
  }
1837
 
  Handle<Code> ic = is_strict_mode()
1838
 
      ? isolate()->builtins()->StoreIC_Initialize_Strict()
1839
 
      : isolate()->builtins()->StoreIC_Initialize();
1840
 
  __ call(ic, RelocInfo::CODE_TARGET, expr->id());
 
2124
  __ pop(rdx);
 
2125
  Handle<Code> ic = is_classic_mode()
 
2126
      ? isolate()->builtins()->StoreIC_Initialize()
 
2127
      : isolate()->builtins()->StoreIC_Initialize_Strict();
 
2128
  CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
1841
2129
 
1842
 
  // If the assignment ends an initialization block, revert to fast case.
1843
 
  if (expr->ends_initialization_block()) {
1844
 
    __ push(rax);  // Result of assignment, saved even if not needed.
1845
 
    __ push(Operand(rsp, kPointerSize));  // Receiver is under value.
1846
 
    __ CallRuntime(Runtime::kToFastProperties, 1);
1847
 
    __ pop(rax);
1848
 
    __ Drop(1);
1849
 
  }
1850
2130
  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1851
2131
  context()->Plug(rax);
1852
2132
}
1855
2135
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1856
2136
  // Assignment to a property, using a keyed store IC.
1857
2137
 
1858
 
  // If the assignment starts a block of assignments to the same object,
1859
 
  // change to slow case to avoid the quadratic behavior of repeatedly
1860
 
  // adding fast properties.
1861
 
  if (expr->starts_initialization_block()) {
1862
 
    __ push(result_register());
1863
 
    // Receiver is now under the key and value.
1864
 
    __ push(Operand(rsp, 2 * kPointerSize));
1865
 
    __ CallRuntime(Runtime::kToSlowProperties, 1);
1866
 
    __ pop(result_register());
1867
 
  }
1868
 
 
1869
2138
  __ pop(rcx);
1870
 
  if (expr->ends_initialization_block()) {
1871
 
    __ movq(rdx, Operand(rsp, 0));  // Leave receiver on the stack for later.
1872
 
  } else {
1873
 
    __ pop(rdx);
1874
 
  }
 
2139
  __ pop(rdx);
1875
2140
  // Record source code position before IC call.
1876
2141
  SetSourcePosition(expr->position());
1877
 
  Handle<Code> ic = is_strict_mode()
1878
 
      ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1879
 
      : isolate()->builtins()->KeyedStoreIC_Initialize();
1880
 
  __ call(ic, RelocInfo::CODE_TARGET, expr->id());
1881
 
 
1882
 
  // If the assignment ends an initialization block, revert to fast case.
1883
 
  if (expr->ends_initialization_block()) {
1884
 
    __ pop(rdx);
1885
 
    __ push(rax);  // Result of assignment, saved even if not needed.
1886
 
    __ push(rdx);
1887
 
    __ CallRuntime(Runtime::kToFastProperties, 1);
1888
 
    __ pop(rax);
1889
 
  }
 
2142
  Handle<Code> ic = is_classic_mode()
 
2143
      ? isolate()->builtins()->KeyedStoreIC_Initialize()
 
2144
      : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
 
2145
  CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
1890
2146
 
1891
2147
  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1892
2148
  context()->Plug(rax);
1900
2156
  if (key->IsPropertyName()) {
1901
2157
    VisitForAccumulatorValue(expr->obj());
1902
2158
    EmitNamedPropertyLoad(expr);
 
2159
    PrepareForBailoutForId(expr->LoadId(), TOS_REG);
1903
2160
    context()->Plug(rax);
1904
2161
  } else {
1905
2162
    VisitForStackValue(expr->obj());
1911
2168
}
1912
2169
 
1913
2170
 
 
2171
void FullCodeGenerator::CallIC(Handle<Code> code,
 
2172
                               RelocInfo::Mode rmode,
 
2173
                               TypeFeedbackId ast_id) {
 
2174
  ic_total_count_++;
 
2175
  __ call(code, rmode, ast_id);
 
2176
}
 
2177
 
 
2178
 
1914
2179
void FullCodeGenerator::EmitCallWithIC(Call* expr,
1915
2180
                                       Handle<Object> name,
1916
2181
                                       RelocInfo::Mode mode) {
1928
2193
  // Call the IC initialization code.
1929
2194
  Handle<Code> ic =
1930
2195
      isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
1931
 
  __ call(ic, mode, expr->id());
 
2196
  CallIC(ic, mode, expr->CallFeedbackId());
1932
2197
  RecordJSReturnSite(expr);
1933
2198
  // Restore context register.
1934
2199
  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1961
2226
  Handle<Code> ic =
1962
2227
      isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
1963
2228
  __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize));  // Key.
1964
 
  __ call(ic, RelocInfo::CODE_TARGET, expr->id());
 
2229
  CallIC(ic, RelocInfo::CODE_TARGET, expr->CallFeedbackId());
1965
2230
  RecordJSReturnSite(expr);
1966
2231
  // Restore context register.
1967
2232
  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1980
2245
  }
1981
2246
  // Record source position for debugger.
1982
2247
  SetSourcePosition(expr->position());
 
2248
 
 
2249
  // Record call targets in unoptimized code.
 
2250
  flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
 
2251
  Handle<Object> uninitialized =
 
2252
      TypeFeedbackCells::UninitializedSentinel(isolate());
 
2253
  Handle<JSGlobalPropertyCell> cell =
 
2254
      isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
 
2255
  RecordTypeFeedbackCell(expr->CallFeedbackId(), cell);
 
2256
  __ Move(rbx, cell);
 
2257
 
1983
2258
  CallFunctionStub stub(arg_count, flags);
1984
 
  __ CallStub(&stub);
 
2259
  __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
 
2260
  __ CallStub(&stub, expr->CallFeedbackId());
1985
2261
  RecordJSReturnSite(expr);
1986
2262
  // Restore context register.
1987
2263
  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1990
2266
}
1991
2267
 
1992
2268
 
1993
 
void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
1994
 
                                                      int arg_count) {
 
2269
void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
1995
2270
  // Push copy of the first argument or undefined if it doesn't exist.
1996
2271
  if (arg_count > 0) {
1997
2272
    __ push(Operand(rsp, arg_count * kPointerSize));
2002
2277
  // Push the receiver of the enclosing function and do runtime call.
2003
2278
  __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
2004
2279
 
2005
 
  // Push the strict mode flag. In harmony mode every eval call
2006
 
  // is a strict mode eval call.
2007
 
  StrictModeFlag strict_mode = strict_mode_flag();
2008
 
  if (FLAG_harmony_block_scoping) {
2009
 
    strict_mode = kStrictMode;
2010
 
  }
2011
 
  __ Push(Smi::FromInt(strict_mode));
2012
 
 
2013
 
  __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2014
 
                 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2015
 
                 : Runtime::kResolvePossiblyDirectEval, 4);
 
2280
  // Push the language mode.
 
2281
  __ Push(Smi::FromInt(language_mode()));
 
2282
 
 
2283
  // Push the start position of the scope the calls resides in.
 
2284
  __ Push(Smi::FromInt(scope()->start_position()));
 
2285
 
 
2286
  // Do the runtime call.
 
2287
  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
2016
2288
}
2017
2289
 
2018
2290
 
2043
2315
        VisitForStackValue(args->at(i));
2044
2316
      }
2045
2317
 
2046
 
      // If we know that eval can only be shadowed by eval-introduced
2047
 
      // variables we attempt to load the global eval function directly in
2048
 
      // generated code. If we succeed, there is no need to perform a
2049
 
      // context lookup in the runtime system.
2050
 
      Label done;
2051
 
      Variable* var = proxy->var();
2052
 
      if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
2053
 
        Label slow;
2054
 
        EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
2055
 
        // Push the function and resolve eval.
2056
 
        __ push(rax);
2057
 
        EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2058
 
        __ jmp(&done);
2059
 
        __ bind(&slow);
2060
 
      }
2061
 
 
2062
2318
      // Push a copy of the function (found below the arguments) and resolve
2063
2319
      // eval.
2064
2320
      __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
2065
 
      EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2066
 
      __ bind(&done);
 
2321
      EmitResolvePossiblyDirectEval(arg_count);
2067
2322
 
2068
2323
      // The runtime call returns a pair of values in rax (function) and
2069
2324
      // rdx (receiver). Touch up the stack with the right values.
2073
2328
    // Record source position for debugger.
2074
2329
    SetSourcePosition(expr->position());
2075
2330
    CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
 
2331
    __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
2076
2332
    __ CallStub(&stub);
2077
2333
    RecordJSReturnSite(expr);
2078
2334
    // Restore context register.
2175
2431
  __ Set(rax, arg_count);
2176
2432
  __ movq(rdi, Operand(rsp, arg_count * kPointerSize));
2177
2433
 
2178
 
  Handle<Code> construct_builtin =
2179
 
      isolate()->builtins()->JSConstructCall();
2180
 
  __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
 
2434
  // Record call targets in unoptimized code, but not in the snapshot.
 
2435
  Handle<Object> uninitialized =
 
2436
      TypeFeedbackCells::UninitializedSentinel(isolate());
 
2437
  Handle<JSGlobalPropertyCell> cell =
 
2438
      isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
 
2439
  RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell);
 
2440
  __ Move(rbx, cell);
 
2441
 
 
2442
  CallConstructStub stub(RECORD_CALL_TARGET);
 
2443
  __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
2444
  PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
2181
2445
  context()->Plug(rax);
2182
2446
}
2183
2447
 
2184
2448
 
2185
 
void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
 
2449
void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
 
2450
  ZoneList<Expression*>* args = expr->arguments();
2186
2451
  ASSERT(args->length() == 1);
2187
2452
 
2188
2453
  VisitForAccumulatorValue(args->at(0));
2194
2459
  context()->PrepareTest(&materialize_true, &materialize_false,
2195
2460
                         &if_true, &if_false, &fall_through);
2196
2461
 
2197
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2462
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2198
2463
  __ JumpIfSmi(rax, if_true);
2199
2464
  __ jmp(if_false);
2200
2465
 
2202
2467
}
2203
2468
 
2204
2469
 
2205
 
void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
 
2470
void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
 
2471
  ZoneList<Expression*>* args = expr->arguments();
2206
2472
  ASSERT(args->length() == 1);
2207
2473
 
2208
2474
  VisitForAccumulatorValue(args->at(0));
2214
2480
  context()->PrepareTest(&materialize_true, &materialize_false,
2215
2481
                         &if_true, &if_false, &fall_through);
2216
2482
 
2217
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2483
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2218
2484
  Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
2219
2485
  Split(non_negative_smi, if_true, if_false, fall_through);
2220
2486
 
2222
2488
}
2223
2489
 
2224
2490
 
2225
 
void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
 
2491
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
 
2492
  ZoneList<Expression*>* args = expr->arguments();
2226
2493
  ASSERT(args->length() == 1);
2227
2494
 
2228
2495
  VisitForAccumulatorValue(args->at(0));
2246
2513
  __ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2247
2514
  __ j(below, if_false);
2248
2515
  __ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
2249
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2516
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2250
2517
  Split(below_equal, if_true, if_false, fall_through);
2251
2518
 
2252
2519
  context()->Plug(if_true, if_false);
2253
2520
}
2254
2521
 
2255
2522
 
2256
 
void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
 
2523
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
 
2524
  ZoneList<Expression*>* args = expr->arguments();
2257
2525
  ASSERT(args->length() == 1);
2258
2526
 
2259
2527
  VisitForAccumulatorValue(args->at(0));
2267
2535
 
2268
2536
  __ JumpIfSmi(rax, if_false);
2269
2537
  __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
2270
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2538
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2271
2539
  Split(above_equal, if_true, if_false, fall_through);
2272
2540
 
2273
2541
  context()->Plug(if_true, if_false);
2274
2542
}
2275
2543
 
2276
2544
 
2277
 
void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
 
2545
void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
 
2546
  ZoneList<Expression*>* args = expr->arguments();
2278
2547
  ASSERT(args->length() == 1);
2279
2548
 
2280
2549
  VisitForAccumulatorValue(args->at(0));
2290
2559
  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2291
2560
  __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2292
2561
           Immediate(1 << Map::kIsUndetectable));
2293
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2562
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2294
2563
  Split(not_zero, if_true, if_false, fall_through);
2295
2564
 
2296
2565
  context()->Plug(if_true, if_false);
2298
2567
 
2299
2568
 
2300
2569
void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2301
 
    ZoneList<Expression*>* args) {
 
2570
    CallRuntime* expr) {
 
2571
  ZoneList<Expression*>* args = expr->arguments();
2302
2572
  ASSERT(args->length() == 1);
2303
2573
 
2304
2574
  VisitForAccumulatorValue(args->at(0));
2310
2580
  context()->PrepareTest(&materialize_true, &materialize_false,
2311
2581
                         &if_true, &if_false, &fall_through);
2312
2582
 
2313
 
  if (FLAG_debug_code) __ AbortIfSmi(rax);
 
2583
  __ AssertNotSmi(rax);
2314
2584
 
2315
2585
  // Check whether this map has already been checked to be safe for default
2316
2586
  // valueOf.
2326
2596
  __ j(equal, if_false);
2327
2597
 
2328
2598
  // Look for valueOf symbol in the descriptor array, and indicate false if
2329
 
  // found. The type is not checked, so if it is a transition it is a false
2330
 
  // negative.
 
2599
  // found. Since we omit an enumeration index check, if it is added via a
 
2600
  // transition that shares its descriptor array, this is a false positive.
 
2601
  Label entry, loop, done;
 
2602
 
 
2603
  // Skip loop if no descriptors are valid.
 
2604
  __ NumberOfOwnDescriptors(rcx, rbx);
 
2605
  __ cmpq(rcx, Immediate(0));
 
2606
  __ j(equal, &done);
 
2607
 
2331
2608
  __ LoadInstanceDescriptors(rbx, rbx);
2332
 
  __ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
2333
 
  // rbx: descriptor array
2334
 
  // rcx: length of descriptor array
 
2609
  // rbx: descriptor array.
 
2610
  // rcx: valid entries in the descriptor array.
2335
2611
  // Calculate the end of the descriptor array.
 
2612
  __ imul(rcx, rcx, Immediate(DescriptorArray::kDescriptorSize));
2336
2613
  SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
2337
2614
  __ lea(rcx,
2338
2615
         Operand(
2339
 
             rbx, index.reg, index.scale, FixedArray::kHeaderSize));
 
2616
             rbx, index.reg, index.scale, DescriptorArray::kFirstOffset));
2340
2617
  // Calculate location of the first key name.
2341
 
  __ addq(rbx,
2342
 
          Immediate(FixedArray::kHeaderSize +
2343
 
                    DescriptorArray::kFirstIndex * kPointerSize));
 
2618
  __ addq(rbx, Immediate(DescriptorArray::kFirstOffset));
2344
2619
  // Loop through all the keys in the descriptor array. If one of these is the
2345
2620
  // symbol valueOf the result is false.
2346
 
  Label entry, loop;
2347
2621
  __ jmp(&entry);
2348
2622
  __ bind(&loop);
2349
2623
  __ movq(rdx, FieldOperand(rbx, 0));
2350
2624
  __ Cmp(rdx, FACTORY->value_of_symbol());
2351
2625
  __ j(equal, if_false);
2352
 
  __ addq(rbx, Immediate(kPointerSize));
 
2626
  __ addq(rbx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
2353
2627
  __ bind(&entry);
2354
2628
  __ cmpq(rbx, rcx);
2355
2629
  __ j(not_equal, &loop);
2356
2630
 
 
2631
  __ bind(&done);
2357
2632
  // Reload map as register rbx was used as temporary above.
2358
2633
  __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2359
2634
 
2360
 
  // If a valueOf property is not found on the object check that it's
 
2635
  // If a valueOf property is not found on the object check that its
2361
2636
  // prototype is the un-modified String prototype. If not result is false.
2362
2637
  __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
2363
2638
  __ testq(rcx, Immediate(kSmiTagMask));
2364
2639
  __ j(zero, if_false);
2365
2640
  __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2366
 
  __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2367
 
  __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
 
2641
  __ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
 
2642
  __ movq(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset));
2368
2643
  __ cmpq(rcx,
2369
2644
          ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2370
2645
  __ j(not_equal, if_false);
2374
2649
         Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2375
2650
  __ jmp(if_true);
2376
2651
 
2377
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2652
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2378
2653
  context()->Plug(if_true, if_false);
2379
2654
}
2380
2655
 
2381
2656
 
2382
 
void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
 
2657
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
 
2658
  ZoneList<Expression*>* args = expr->arguments();
2383
2659
  ASSERT(args->length() == 1);
2384
2660
 
2385
2661
  VisitForAccumulatorValue(args->at(0));
2393
2669
 
2394
2670
  __ JumpIfSmi(rax, if_false);
2395
2671
  __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2396
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2672
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2397
2673
  Split(equal, if_true, if_false, fall_through);
2398
2674
 
2399
2675
  context()->Plug(if_true, if_false);
2400
2676
}
2401
2677
 
2402
2678
 
2403
 
void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
 
2679
void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
 
2680
  ZoneList<Expression*>* args = expr->arguments();
2404
2681
  ASSERT(args->length() == 1);
2405
2682
 
2406
2683
  VisitForAccumulatorValue(args->at(0));
2414
2691
 
2415
2692
  __ JumpIfSmi(rax, if_false);
2416
2693
  __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
2417
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2694
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2418
2695
  Split(equal, if_true, if_false, fall_through);
2419
2696
 
2420
2697
  context()->Plug(if_true, if_false);
2421
2698
}
2422
2699
 
2423
2700
 
2424
 
void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
 
2701
void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
 
2702
  ZoneList<Expression*>* args = expr->arguments();
2425
2703
  ASSERT(args->length() == 1);
2426
2704
 
2427
2705
  VisitForAccumulatorValue(args->at(0));
2435
2713
 
2436
2714
  __ JumpIfSmi(rax, if_false);
2437
2715
  __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
2438
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2716
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2439
2717
  Split(equal, if_true, if_false, fall_through);
2440
2718
 
2441
2719
  context()->Plug(if_true, if_false);
2443
2721
 
2444
2722
 
2445
2723
 
2446
 
void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2447
 
  ASSERT(args->length() == 0);
 
2724
void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
 
2725
  ASSERT(expr->arguments()->length() == 0);
2448
2726
 
2449
2727
  Label materialize_true, materialize_false;
2450
2728
  Label* if_true = NULL;
2467
2745
  __ bind(&check_frame_marker);
2468
2746
  __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2469
2747
         Smi::FromInt(StackFrame::CONSTRUCT));
2470
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2748
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2471
2749
  Split(equal, if_true, if_false, fall_through);
2472
2750
 
2473
2751
  context()->Plug(if_true, if_false);
2474
2752
}
2475
2753
 
2476
2754
 
2477
 
void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
 
2755
void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
 
2756
  ZoneList<Expression*>* args = expr->arguments();
2478
2757
  ASSERT(args->length() == 2);
2479
2758
 
2480
2759
  // Load the two objects into registers and perform the comparison.
2490
2769
 
2491
2770
  __ pop(rbx);
2492
2771
  __ cmpq(rax, rbx);
2493
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2772
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2494
2773
  Split(equal, if_true, if_false, fall_through);
2495
2774
 
2496
2775
  context()->Plug(if_true, if_false);
2497
2776
}
2498
2777
 
2499
2778
 
2500
 
void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
 
2779
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
 
2780
  ZoneList<Expression*>* args = expr->arguments();
2501
2781
  ASSERT(args->length() == 1);
2502
2782
 
2503
2783
  // ArgumentsAccessStub expects the key in rdx and the formal
2511
2791
}
2512
2792
 
2513
2793
 
2514
 
void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2515
 
  ASSERT(args->length() == 0);
 
2794
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
 
2795
  ASSERT(expr->arguments()->length() == 0);
2516
2796
 
2517
2797
  Label exit;
2518
2798
  // Get the number of formal parameters.
2529
2809
  __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2530
2810
 
2531
2811
  __ bind(&exit);
2532
 
  if (FLAG_debug_code) __ AbortIfNotSmi(rax);
 
2812
  __ AssertSmi(rax);
2533
2813
  context()->Plug(rax);
2534
2814
}
2535
2815
 
2536
2816
 
2537
 
void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
 
2817
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
 
2818
  ZoneList<Expression*>* args = expr->arguments();
2538
2819
  ASSERT(args->length() == 1);
2539
2820
  Label done, null, function, non_function_constructor;
2540
2821
 
2545
2826
 
2546
2827
  // Check that the object is a JS object but take special care of JS
2547
2828
  // functions to make sure they have 'Function' as their class.
 
2829
  // Assume that there are only two callable types, and one of them is at
 
2830
  // either end of the type range for JS object types. Saves extra comparisons.
 
2831
  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2548
2832
  __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
2549
2833
  // Map is now in rax.
2550
2834
  __ j(below, &null);
2551
 
 
2552
 
  // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2553
 
  // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2554
 
  // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2555
 
  STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2556
 
  STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2557
 
                LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2558
 
  __ CmpInstanceType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
2559
 
  __ j(above_equal, &function);
2560
 
 
2561
 
  // Check if the constructor in the map is a function.
 
2835
  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
 
2836
                FIRST_SPEC_OBJECT_TYPE + 1);
 
2837
  __ j(equal, &function);
 
2838
 
 
2839
  __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
 
2840
  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
 
2841
                LAST_SPEC_OBJECT_TYPE - 1);
 
2842
  __ j(equal, &function);
 
2843
  // Assume that there is no larger type.
 
2844
  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
 
2845
 
 
2846
  // Check if the constructor in the map is a JS function.
2562
2847
  __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2563
2848
  __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2564
2849
  __ j(not_equal, &non_function_constructor);
2590
2875
}
2591
2876
 
2592
2877
 
2593
 
void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
 
2878
void FullCodeGenerator::EmitLog(CallRuntime* expr) {
2594
2879
  // Conditionally generate a log call.
2595
2880
  // Args:
2596
2881
  //   0 (literal string): The type of logging (corresponds to the flags).
2598
2883
  //   1 (string): Format string.  Access the string at argument index 2
2599
2884
  //     with '%2s' (see Logger::LogRuntime for all the formats).
2600
2885
  //   2 (array): Arguments to the format string.
 
2886
  ZoneList<Expression*>* args = expr->arguments();
2601
2887
  ASSERT_EQ(args->length(), 3);
2602
2888
  if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2603
2889
    VisitForStackValue(args->at(1));
2610
2896
}
2611
2897
 
2612
2898
 
2613
 
void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2614
 
  ASSERT(args->length() == 0);
 
2899
void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
 
2900
  ASSERT(expr->arguments()->length() == 0);
2615
2901
 
2616
2902
  Label slow_allocate_heapnumber;
2617
2903
  Label heapnumber_allocated;
2630
2916
  // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
2631
2917
  __ PrepareCallCFunction(1);
2632
2918
#ifdef _WIN64
2633
 
  __ LoadAddress(rcx, ExternalReference::isolate_address());
 
2919
  __ movq(rcx,
 
2920
          ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
 
2921
  __ movq(rcx, FieldOperand(rcx, GlobalObject::kNativeContextOffset));
 
2922
 
2634
2923
#else
2635
 
  __ LoadAddress(rdi, ExternalReference::isolate_address());
 
2924
  __ movq(rdi,
 
2925
          ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
 
2926
  __ movq(rdi, FieldOperand(rdi, GlobalObject::kNativeContextOffset));
2636
2927
#endif
2637
2928
  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
2638
2929
 
2652
2943
}
2653
2944
 
2654
2945
 
2655
 
void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
 
2946
void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
2656
2947
  // Load the arguments on the stack and call the stub.
2657
2948
  SubStringStub stub;
 
2949
  ZoneList<Expression*>* args = expr->arguments();
2658
2950
  ASSERT(args->length() == 3);
2659
2951
  VisitForStackValue(args->at(0));
2660
2952
  VisitForStackValue(args->at(1));
2664
2956
}
2665
2957
 
2666
2958
 
2667
 
void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
 
2959
void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
2668
2960
  // Load the arguments on the stack and call the stub.
2669
2961
  RegExpExecStub stub;
 
2962
  ZoneList<Expression*>* args = expr->arguments();
2670
2963
  ASSERT(args->length() == 4);
2671
2964
  VisitForStackValue(args->at(0));
2672
2965
  VisitForStackValue(args->at(1));
2677
2970
}
2678
2971
 
2679
2972
 
2680
 
void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
 
2973
void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
 
2974
  ZoneList<Expression*>* args = expr->arguments();
2681
2975
  ASSERT(args->length() == 1);
2682
2976
 
2683
2977
  VisitForAccumulatorValue(args->at(0));  // Load the object.
2695
2989
}
2696
2990
 
2697
2991
 
2698
 
void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
 
2992
void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
 
2993
  ZoneList<Expression*>* args = expr->arguments();
 
2994
  ASSERT(args->length() == 2);
 
2995
  ASSERT_NE(NULL, args->at(1)->AsLiteral());
 
2996
  Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
 
2997
 
 
2998
  VisitForAccumulatorValue(args->at(0));  // Load the object.
 
2999
 
 
3000
  Label runtime, done, not_date_object;
 
3001
  Register object = rax;
 
3002
  Register result = rax;
 
3003
  Register scratch = rcx;
 
3004
 
 
3005
  __ JumpIfSmi(object, &not_date_object);
 
3006
  __ CmpObjectType(object, JS_DATE_TYPE, scratch);
 
3007
  __ j(not_equal, &not_date_object);
 
3008
 
 
3009
  if (index->value() == 0) {
 
3010
    __ movq(result, FieldOperand(object, JSDate::kValueOffset));
 
3011
    __ jmp(&done);
 
3012
  } else {
 
3013
    if (index->value() < JSDate::kFirstUncachedField) {
 
3014
      ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
 
3015
      __ movq(scratch, stamp);
 
3016
      __ cmpq(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
 
3017
      __ j(not_equal, &runtime, Label::kNear);
 
3018
      __ movq(result, FieldOperand(object, JSDate::kValueOffset +
 
3019
                                           kPointerSize * index->value()));
 
3020
      __ jmp(&done);
 
3021
    }
 
3022
    __ bind(&runtime);
 
3023
    __ PrepareCallCFunction(2);
 
3024
#ifdef _WIN64
 
3025
  __ movq(rcx, object);
 
3026
  __ movq(rdx, index, RelocInfo::NONE);
 
3027
#else
 
3028
  __ movq(rdi, object);
 
3029
  __ movq(rsi, index, RelocInfo::NONE);
 
3030
#endif
 
3031
    __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
 
3032
    __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
 
3033
    __ jmp(&done);
 
3034
  }
 
3035
 
 
3036
  __ bind(&not_date_object);
 
3037
  __ CallRuntime(Runtime::kThrowNotDateError, 0);
 
3038
  __ bind(&done);
 
3039
  context()->Plug(rax);
 
3040
}
 
3041
 
 
3042
 
 
3043
void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
2699
3044
  // Load the arguments on the stack and call the runtime function.
 
3045
  ZoneList<Expression*>* args = expr->arguments();
2700
3046
  ASSERT(args->length() == 2);
2701
3047
  VisitForStackValue(args->at(0));
2702
3048
  VisitForStackValue(args->at(1));
2703
 
  MathPowStub stub;
 
3049
  MathPowStub stub(MathPowStub::ON_STACK);
2704
3050
  __ CallStub(&stub);
2705
3051
  context()->Plug(rax);
2706
3052
}
2707
3053
 
2708
3054
 
2709
 
void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
 
3055
void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
 
3056
  ZoneList<Expression*>* args = expr->arguments();
2710
3057
  ASSERT(args->length() == 2);
2711
3058
 
2712
3059
  VisitForStackValue(args->at(0));  // Load the object.
2726
3073
  // Update the write barrier.  Save the value as it will be
2727
3074
  // overwritten by the write barrier code and is needed afterward.
2728
3075
  __ movq(rdx, rax);
2729
 
  __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx);
 
3076
  __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs);
2730
3077
 
2731
3078
  __ bind(&done);
2732
3079
  context()->Plug(rax);
2733
3080
}
2734
3081
 
2735
3082
 
2736
 
void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
 
3083
void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
 
3084
  ZoneList<Expression*>* args = expr->arguments();
2737
3085
  ASSERT_EQ(args->length(), 1);
2738
3086
 
2739
3087
  // Load the argument on the stack and call the stub.
2745
3093
}
2746
3094
 
2747
3095
 
2748
 
void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
 
3096
void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
 
3097
  ZoneList<Expression*>* args = expr->arguments();
2749
3098
  ASSERT(args->length() == 1);
2750
3099
 
2751
3100
  VisitForAccumulatorValue(args->at(0));
2763
3112
}
2764
3113
 
2765
3114
 
2766
 
void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
 
3115
void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
 
3116
  ZoneList<Expression*>* args = expr->arguments();
2767
3117
  ASSERT(args->length() == 2);
2768
3118
 
2769
3119
  VisitForStackValue(args->at(0));
2771
3121
 
2772
3122
  Register object = rbx;
2773
3123
  Register index = rax;
2774
 
  Register scratch = rcx;
2775
3124
  Register result = rdx;
2776
3125
 
2777
3126
  __ pop(object);
2781
3130
  Label done;
2782
3131
  StringCharCodeAtGenerator generator(object,
2783
3132
                                      index,
2784
 
                                      scratch,
2785
3133
                                      result,
2786
3134
                                      &need_conversion,
2787
3135
                                      &need_conversion,
2810
3158
}
2811
3159
 
2812
3160
 
2813
 
void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
 
3161
void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
 
3162
  ZoneList<Expression*>* args = expr->arguments();
2814
3163
  ASSERT(args->length() == 2);
2815
3164
 
2816
3165
  VisitForStackValue(args->at(0));
2818
3167
 
2819
3168
  Register object = rbx;
2820
3169
  Register index = rax;
2821
 
  Register scratch1 = rcx;
2822
 
  Register scratch2 = rdx;
 
3170
  Register scratch = rdx;
2823
3171
  Register result = rax;
2824
3172
 
2825
3173
  __ pop(object);
2829
3177
  Label done;
2830
3178
  StringCharAtGenerator generator(object,
2831
3179
                                  index,
2832
 
                                  scratch1,
2833
 
                                  scratch2,
 
3180
                                  scratch,
2834
3181
                                  result,
2835
3182
                                  &need_conversion,
2836
3183
                                  &need_conversion,
2859
3206
}
2860
3207
 
2861
3208
 
2862
 
void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
 
3209
void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
 
3210
  ZoneList<Expression*>* args = expr->arguments();
2863
3211
  ASSERT_EQ(2, args->length());
2864
3212
 
2865
3213
  VisitForStackValue(args->at(0));
2871
3219
}
2872
3220
 
2873
3221
 
2874
 
void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
 
3222
void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
 
3223
  ZoneList<Expression*>* args = expr->arguments();
2875
3224
  ASSERT_EQ(2, args->length());
2876
3225
 
2877
3226
  VisitForStackValue(args->at(0));
2883
3232
}
2884
3233
 
2885
3234
 
2886
 
void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
 
3235
void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
2887
3236
  // Load the argument on the stack and call the stub.
2888
3237
  TranscendentalCacheStub stub(TranscendentalCache::SIN,
2889
3238
                               TranscendentalCacheStub::TAGGED);
 
3239
  ZoneList<Expression*>* args = expr->arguments();
2890
3240
  ASSERT(args->length() == 1);
2891
3241
  VisitForStackValue(args->at(0));
2892
3242
  __ CallStub(&stub);
2894
3244
}
2895
3245
 
2896
3246
 
2897
 
void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
 
3247
void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
2898
3248
  // Load the argument on the stack and call the stub.
2899
3249
  TranscendentalCacheStub stub(TranscendentalCache::COS,
2900
3250
                               TranscendentalCacheStub::TAGGED);
2901
 
  ASSERT(args->length() == 1);
2902
 
  VisitForStackValue(args->at(0));
2903
 
  __ CallStub(&stub);
2904
 
  context()->Plug(rax);
2905
 
}
2906
 
 
2907
 
 
2908
 
void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
 
3251
  ZoneList<Expression*>* args = expr->arguments();
 
3252
  ASSERT(args->length() == 1);
 
3253
  VisitForStackValue(args->at(0));
 
3254
  __ CallStub(&stub);
 
3255
  context()->Plug(rax);
 
3256
}
 
3257
 
 
3258
 
 
3259
void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
 
3260
  // Load the argument on the stack and call the stub.
 
3261
  TranscendentalCacheStub stub(TranscendentalCache::TAN,
 
3262
                               TranscendentalCacheStub::TAGGED);
 
3263
  ZoneList<Expression*>* args = expr->arguments();
 
3264
  ASSERT(args->length() == 1);
 
3265
  VisitForStackValue(args->at(0));
 
3266
  __ CallStub(&stub);
 
3267
  context()->Plug(rax);
 
3268
}
 
3269
 
 
3270
 
 
3271
void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
2909
3272
  // Load the argument on the stack and call the stub.
2910
3273
  TranscendentalCacheStub stub(TranscendentalCache::LOG,
2911
3274
                               TranscendentalCacheStub::TAGGED);
 
3275
  ZoneList<Expression*>* args = expr->arguments();
2912
3276
  ASSERT(args->length() == 1);
2913
3277
  VisitForStackValue(args->at(0));
2914
3278
  __ CallStub(&stub);
2916
3280
}
2917
3281
 
2918
3282
 
2919
 
void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
 
3283
void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
2920
3284
  // Load the argument on the stack and call the runtime function.
 
3285
  ZoneList<Expression*>* args = expr->arguments();
2921
3286
  ASSERT(args->length() == 1);
2922
3287
  VisitForStackValue(args->at(0));
2923
3288
  __ CallRuntime(Runtime::kMath_sqrt, 1);
2925
3290
}
2926
3291
 
2927
3292
 
2928
 
void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
 
3293
void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
 
3294
  ZoneList<Expression*>* args = expr->arguments();
2929
3295
  ASSERT(args->length() >= 2);
2930
3296
 
2931
3297
  int arg_count = args->length() - 2;  // 2 ~ receiver and function.
2934
3300
  }
2935
3301
  VisitForAccumulatorValue(args->last());  // Function.
2936
3302
 
 
3303
  Label runtime, done;
 
3304
  // Check for non-function argument (including proxy).
 
3305
  __ JumpIfSmi(rax, &runtime);
 
3306
  __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
 
3307
  __ j(not_equal, &runtime);
 
3308
 
2937
3309
  // InvokeFunction requires the function in rdi. Move it in there.
2938
3310
  __ movq(rdi, result_register());
2939
3311
  ParameterCount count(arg_count);
2940
3312
  __ InvokeFunction(rdi, count, CALL_FUNCTION,
2941
3313
                    NullCallWrapper(), CALL_AS_METHOD);
2942
3314
  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
 
3315
  __ jmp(&done);
 
3316
 
 
3317
  __ bind(&runtime);
 
3318
  __ push(rax);
 
3319
  __ CallRuntime(Runtime::kCall, args->length());
 
3320
  __ bind(&done);
 
3321
 
2943
3322
  context()->Plug(rax);
2944
3323
}
2945
3324
 
2946
3325
 
2947
 
void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
 
3326
void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
2948
3327
  RegExpConstructResultStub stub;
 
3328
  ZoneList<Expression*>* args = expr->arguments();
2949
3329
  ASSERT(args->length() == 3);
2950
3330
  VisitForStackValue(args->at(0));
2951
3331
  VisitForStackValue(args->at(1));
2955
3335
}
2956
3336
 
2957
3337
 
2958
 
void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2959
 
  ASSERT(args->length() == 3);
2960
 
  VisitForStackValue(args->at(0));
2961
 
  VisitForStackValue(args->at(1));
2962
 
  VisitForStackValue(args->at(2));
2963
 
  Label done;
2964
 
  Label slow_case;
2965
 
  Register object = rax;
2966
 
  Register index_1 = rbx;
2967
 
  Register index_2 = rcx;
2968
 
  Register elements = rdi;
2969
 
  Register temp = rdx;
2970
 
  __ movq(object, Operand(rsp, 2 * kPointerSize));
2971
 
  // Fetch the map and check if array is in fast case.
2972
 
  // Check that object doesn't require security checks and
2973
 
  // has no indexed interceptor.
2974
 
  __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
2975
 
  __ j(not_equal, &slow_case);
2976
 
  __ testb(FieldOperand(temp, Map::kBitFieldOffset),
2977
 
           Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
2978
 
  __ j(not_zero, &slow_case);
2979
 
 
2980
 
  // Check the object's elements are in fast case and writable.
2981
 
  __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
2982
 
  __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
2983
 
                 Heap::kFixedArrayMapRootIndex);
2984
 
  __ j(not_equal, &slow_case);
2985
 
 
2986
 
  // Check that both indices are smis.
2987
 
  __ movq(index_1, Operand(rsp, 1 * kPointerSize));
2988
 
  __ movq(index_2, Operand(rsp, 0 * kPointerSize));
2989
 
  __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
2990
 
 
2991
 
  // Check that both indices are valid.
2992
 
  // The JSArray length field is a smi since the array is in fast case mode.
2993
 
  __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
2994
 
  __ SmiCompare(temp, index_1);
2995
 
  __ j(below_equal, &slow_case);
2996
 
  __ SmiCompare(temp, index_2);
2997
 
  __ j(below_equal, &slow_case);
2998
 
 
2999
 
  __ SmiToInteger32(index_1, index_1);
3000
 
  __ SmiToInteger32(index_2, index_2);
3001
 
  // Bring addresses into index1 and index2.
3002
 
  __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3003
 
                               FixedArray::kHeaderSize));
3004
 
  __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3005
 
                               FixedArray::kHeaderSize));
3006
 
 
3007
 
  // Swap elements.  Use object and temp as scratch registers.
3008
 
  __ movq(object, Operand(index_1, 0));
3009
 
  __ movq(temp,   Operand(index_2, 0));
3010
 
  __ movq(Operand(index_2, 0), object);
3011
 
  __ movq(Operand(index_1, 0), temp);
3012
 
 
3013
 
  Label new_space;
3014
 
  __ InNewSpace(elements, temp, equal, &new_space);
3015
 
 
3016
 
  __ movq(object, elements);
3017
 
  __ RecordWriteHelper(object, index_1, temp);
3018
 
  __ RecordWriteHelper(elements, index_2, temp);
3019
 
 
3020
 
  __ bind(&new_space);
3021
 
  // We are done. Drop elements from the stack, and return undefined.
3022
 
  __ addq(rsp, Immediate(3 * kPointerSize));
3023
 
  __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3024
 
  __ jmp(&done);
3025
 
 
3026
 
  __ bind(&slow_case);
3027
 
  __ CallRuntime(Runtime::kSwapElements, 3);
3028
 
 
3029
 
  __ bind(&done);
3030
 
  context()->Plug(rax);
3031
 
}
3032
 
 
3033
 
 
3034
 
void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
 
3338
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
 
3339
  ZoneList<Expression*>* args = expr->arguments();
3035
3340
  ASSERT_EQ(2, args->length());
3036
3341
 
3037
3342
  ASSERT_NE(NULL, args->at(0)->AsLiteral());
3038
3343
  int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3039
3344
 
3040
3345
  Handle<FixedArray> jsfunction_result_caches(
3041
 
      isolate()->global_context()->jsfunction_result_caches());
 
3346
      isolate()->native_context()->jsfunction_result_caches());
3042
3347
  if (jsfunction_result_caches->length() <= cache_id) {
3043
3348
    __ Abort("Attempt to use undefined cache.");
3044
3349
    __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3051
3356
  Register key = rax;
3052
3357
  Register cache = rbx;
3053
3358
  Register tmp = rcx;
3054
 
  __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX));
 
3359
  __ movq(cache, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX));
3055
3360
  __ movq(cache,
3056
 
          FieldOperand(cache, GlobalObject::kGlobalContextOffset));
 
3361
          FieldOperand(cache, GlobalObject::kNativeContextOffset));
3057
3362
  __ movq(cache,
3058
3363
          ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
3059
3364
  __ movq(cache,
3087
3392
}
3088
3393
 
3089
3394
 
3090
 
void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
 
3395
void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
 
3396
  ZoneList<Expression*>* args = expr->arguments();
3091
3397
  ASSERT_EQ(2, args->length());
3092
3398
 
3093
3399
  Register right = rax;
3125
3431
}
3126
3432
 
3127
3433
 
3128
 
void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
 
3434
void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
 
3435
  ZoneList<Expression*>* args = expr->arguments();
3129
3436
  ASSERT(args->length() == 1);
3130
3437
 
3131
3438
  VisitForAccumulatorValue(args->at(0));
3139
3446
 
3140
3447
  __ testl(FieldOperand(rax, String::kHashFieldOffset),
3141
3448
           Immediate(String::kContainsCachedArrayIndexMask));
3142
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
3449
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3143
3450
  __ j(zero, if_true);
3144
3451
  __ jmp(if_false);
3145
3452
 
3147
3454
}
3148
3455
 
3149
3456
 
3150
 
void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
 
3457
void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
 
3458
  ZoneList<Expression*>* args = expr->arguments();
3151
3459
  ASSERT(args->length() == 1);
3152
3460
  VisitForAccumulatorValue(args->at(0));
3153
3461
 
3154
 
  if (FLAG_debug_code) {
3155
 
    __ AbortIfNotString(rax);
3156
 
  }
 
3462
  __ AssertString(rax);
3157
3463
 
3158
3464
  __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3159
3465
  ASSERT(String::kHashShift >= kSmiTagSize);
3163
3469
}
3164
3470
 
3165
3471
 
3166
 
void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
 
3472
void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
3167
3473
  Label bailout, return_result, done, one_char_separator, long_separator,
3168
3474
      non_trivial_array, not_size_one_array, loop,
3169
3475
      loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
 
3476
  ZoneList<Expression*>* args = expr->arguments();
3170
3477
  ASSERT(args->length() == 2);
3171
3478
  // We will leave the separator on the stack until the end of the function.
3172
3479
  VisitForStackValue(args->at(1));
3230
3537
  // Loop condition: while (index < array_length).
3231
3538
  // Live loop registers: index(int32), array_length(int32), string(String*),
3232
3539
  //                      scratch, string_length(int32), elements(FixedArray*).
3233
 
  if (FLAG_debug_code) {
 
3540
  if (generate_debug_code_) {
3234
3541
    __ cmpq(index, array_length);
3235
3542
    __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin");
3236
3543
  }
3352
3659
 
3353
3660
  // One-character separator case
3354
3661
  __ bind(&one_char_separator);
3355
 
  // Get the separator ascii character value.
 
3662
  // Get the separator ASCII character value.
3356
3663
  // Register "string" holds the separator.
3357
3664
  __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize));
3358
3665
  __ Set(index, 0);
3476
3783
    RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3477
3784
    Handle<Code> ic =
3478
3785
        isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
3479
 
    __ call(ic, mode, expr->id());
 
3786
    CallIC(ic, mode, expr->CallRuntimeFeedbackId());
3480
3787
    // Restore context register.
3481
3788
    __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3482
3789
  } else {
3496
3803
      if (property != NULL) {
3497
3804
        VisitForStackValue(property->obj());
3498
3805
        VisitForStackValue(property->key());
3499
 
        __ Push(Smi::FromInt(strict_mode_flag()));
 
3806
        StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
 
3807
            ? kNonStrictMode : kStrictMode;
 
3808
        __ Push(Smi::FromInt(strict_mode_flag));
3500
3809
        __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3501
3810
        context()->Plug(rax);
3502
3811
      } else if (proxy != NULL) {
3503
3812
        Variable* var = proxy->var();
3504
3813
        // Delete of an unqualified identifier is disallowed in strict mode
3505
3814
        // but "delete this" is allowed.
3506
 
        ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
 
3815
        ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
3507
3816
        if (var->IsUnallocated()) {
3508
3817
          __ push(GlobalObjectOperand());
3509
3818
          __ Push(var->name());
3545
3854
        // Unary NOT has no side effects so it's only necessary to visit the
3546
3855
        // subexpression.  Match the optimizing compiler by not branching.
3547
3856
        VisitForEffect(expr->expression());
 
3857
      } else if (context()->IsTest()) {
 
3858
        const TestContext* test = TestContext::cast(context());
 
3859
        // The labels are swapped for the recursive call.
 
3860
        VisitForControl(expr->expression(),
 
3861
                        test->false_label(),
 
3862
                        test->true_label(),
 
3863
                        test->fall_through());
 
3864
        context()->Plug(test->true_label(), test->false_label());
3548
3865
      } else {
3549
 
        Label materialize_true, materialize_false;
3550
 
        Label* if_true = NULL;
3551
 
        Label* if_false = NULL;
3552
 
        Label* fall_through = NULL;
3553
 
        // Notice that the labels are swapped.
3554
 
        context()->PrepareTest(&materialize_true, &materialize_false,
3555
 
                               &if_false, &if_true, &fall_through);
3556
 
        if (context()->IsTest()) ForwardBailoutToChild(expr);
3557
 
        VisitForControl(expr->expression(), if_true, if_false, fall_through);
3558
 
        context()->Plug(if_false, if_true);  // Labels swapped.
 
3866
        // We handle value contexts explicitly rather than simply visiting
 
3867
        // for control and plugging the control flow into the context,
 
3868
        // because we need to prepare a pair of extra administrative AST ids
 
3869
        // for the optimizing compiler.
 
3870
        ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
 
3871
        Label materialize_true, materialize_false, done;
 
3872
        VisitForControl(expr->expression(),
 
3873
                        &materialize_false,
 
3874
                        &materialize_true,
 
3875
                        &materialize_true);
 
3876
        __ bind(&materialize_true);
 
3877
        PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
 
3878
        if (context()->IsAccumulatorValue()) {
 
3879
          __ LoadRoot(rax, Heap::kTrueValueRootIndex);
 
3880
        } else {
 
3881
          __ PushRoot(Heap::kTrueValueRootIndex);
 
3882
        }
 
3883
        __ jmp(&done, Label::kNear);
 
3884
        __ bind(&materialize_false);
 
3885
        PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
 
3886
        if (context()->IsAccumulatorValue()) {
 
3887
          __ LoadRoot(rax, Heap::kFalseValueRootIndex);
 
3888
        } else {
 
3889
          __ PushRoot(Heap::kFalseValueRootIndex);
 
3890
        }
 
3891
        __ bind(&done);
3559
3892
      }
3560
3893
      break;
3561
3894
    }
3608
3941
  // accumulator register rax.
3609
3942
  VisitForAccumulatorValue(expr->expression());
3610
3943
  SetSourcePosition(expr->position());
3611
 
  __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
 
3944
  CallIC(stub.GetCode(), RelocInfo::CODE_TARGET,
 
3945
         expr->UnaryOperationFeedbackId());
3612
3946
  context()->Plug(rax);
3613
3947
}
3614
3948
 
3664
3998
  if (assign_type == VARIABLE) {
3665
3999
    PrepareForBailout(expr->expression(), TOS_REG);
3666
4000
  } else {
3667
 
    PrepareForBailoutForId(expr->CountId(), TOS_REG);
 
4001
    PrepareForBailoutForId(prop->LoadId(), TOS_REG);
3668
4002
  }
3669
4003
 
3670
4004
  // Call ToNumber only if operand is not a smi.
3729
4063
    __ movq(rdx, rax);
3730
4064
    __ Move(rax, Smi::FromInt(1));
3731
4065
  }
3732
 
  __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
 
4066
  CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountBinOpFeedbackId());
3733
4067
  patch_site.EmitPatchInfo();
3734
4068
  __ bind(&done);
3735
4069
 
3760
4094
    case NAMED_PROPERTY: {
3761
4095
      __ Move(rcx, prop->key()->AsLiteral()->handle());
3762
4096
      __ pop(rdx);
3763
 
      Handle<Code> ic = is_strict_mode()
3764
 
          ? isolate()->builtins()->StoreIC_Initialize_Strict()
3765
 
          : isolate()->builtins()->StoreIC_Initialize();
3766
 
      __ call(ic, RelocInfo::CODE_TARGET, expr->id());
 
4097
      Handle<Code> ic = is_classic_mode()
 
4098
          ? isolate()->builtins()->StoreIC_Initialize()
 
4099
          : isolate()->builtins()->StoreIC_Initialize_Strict();
 
4100
      CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
3767
4101
      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3768
4102
      if (expr->is_postfix()) {
3769
4103
        if (!context()->IsEffect()) {
3777
4111
    case KEYED_PROPERTY: {
3778
4112
      __ pop(rcx);
3779
4113
      __ pop(rdx);
3780
 
      Handle<Code> ic = is_strict_mode()
3781
 
          ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3782
 
          : isolate()->builtins()->KeyedStoreIC_Initialize();
3783
 
      __ call(ic, RelocInfo::CODE_TARGET, expr->id());
 
4114
      Handle<Code> ic = is_classic_mode()
 
4115
          ? isolate()->builtins()->KeyedStoreIC_Initialize()
 
4116
          : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
 
4117
      CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
3784
4118
      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3785
4119
      if (expr->is_postfix()) {
3786
4120
        if (!context()->IsEffect()) {
3807
4141
    Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
3808
4142
    // Use a regular load, not a contextual load, to avoid a reference
3809
4143
    // error.
3810
 
    __ call(ic);
 
4144
    CallIC(ic);
3811
4145
    PrepareForBailout(expr, TOS_REG);
3812
4146
    context()->Plug(rax);
3813
4147
  } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
3827
4161
    context()->Plug(rax);
3828
4162
  } else {
3829
4163
    // This expression cannot throw a reference error at the top level.
3830
 
    VisitInCurrentContext(expr);
 
4164
    VisitInDuplicateContext(expr);
3831
4165
  }
3832
4166
}
3833
4167
 
3834
4168
 
3835
4169
void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3836
 
                                                 Handle<String> check,
3837
 
                                                 Label* if_true,
3838
 
                                                 Label* if_false,
3839
 
                                                 Label* fall_through) {
 
4170
                                                 Expression* sub_expr,
 
4171
                                                 Handle<String> check) {
 
4172
  Label materialize_true, materialize_false;
 
4173
  Label* if_true = NULL;
 
4174
  Label* if_false = NULL;
 
4175
  Label* fall_through = NULL;
 
4176
  context()->PrepareTest(&materialize_true, &materialize_false,
 
4177
                         &if_true, &if_false, &fall_through);
 
4178
 
3840
4179
  { AccumulatorValueContext context(this);
3841
 
    VisitForTypeofValue(expr);
 
4180
    VisitForTypeofValue(sub_expr);
3842
4181
  }
3843
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
4182
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3844
4183
 
3845
4184
  if (check->Equals(isolate()->heap()->number_symbol())) {
3846
4185
    __ JumpIfSmi(rax, if_true);
3875
4214
    Split(not_zero, if_true, if_false, fall_through);
3876
4215
  } else if (check->Equals(isolate()->heap()->function_symbol())) {
3877
4216
    __ JumpIfSmi(rax, if_false);
3878
 
    STATIC_ASSERT(LAST_CALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE);
3879
 
    __ CmpObjectType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, rdx);
3880
 
    Split(above_equal, if_true, if_false, fall_through);
 
4217
    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
 
4218
    __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
 
4219
    __ j(equal, if_true);
 
4220
    __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
 
4221
    Split(equal, if_true, if_false, fall_through);
3881
4222
  } else if (check->Equals(isolate()->heap()->object_symbol())) {
3882
4223
    __ JumpIfSmi(rax, if_false);
3883
4224
    if (!FLAG_harmony_typeof) {
3895
4236
  } else {
3896
4237
    if (if_false != fall_through) __ jmp(if_false);
3897
4238
  }
3898
 
}
3899
 
 
3900
 
 
3901
 
void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
3902
 
                                                    Label* if_true,
3903
 
                                                    Label* if_false,
3904
 
                                                    Label* fall_through) {
3905
 
  VisitForAccumulatorValue(expr);
3906
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3907
 
 
3908
 
  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
3909
 
  Split(equal, if_true, if_false, fall_through);
 
4239
  context()->Plug(if_true, if_false);
3910
4240
}
3911
4241
 
3912
4242
 
3914
4244
  Comment cmnt(masm_, "[ CompareOperation");
3915
4245
  SetSourcePosition(expr->position());
3916
4246
 
 
4247
  // First we try a fast inlined version of the compare when one of
 
4248
  // the operands is a literal.
 
4249
  if (TryLiteralCompare(expr)) return;
 
4250
 
3917
4251
  // Always perform the comparison for its control flow.  Pack the result
3918
4252
  // into the expression's context after the comparison is performed.
3919
4253
  Label materialize_true, materialize_false;
3923
4257
  context()->PrepareTest(&materialize_true, &materialize_false,
3924
4258
                         &if_true, &if_false, &fall_through);
3925
4259
 
3926
 
  // First we try a fast inlined version of the compare when one of
3927
 
  // the operands is a literal.
3928
 
  if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
3929
 
    context()->Plug(if_true, if_false);
3930
 
    return;
3931
 
  }
3932
 
 
3933
4260
  Token::Value op = expr->op();
3934
4261
  VisitForStackValue(expr->left());
3935
4262
  switch (op) {
3936
4263
    case Token::IN:
3937
4264
      VisitForStackValue(expr->right());
3938
4265
      __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
3939
 
      PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
 
4266
      PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3940
4267
      __ CompareRoot(rax, Heap::kTrueValueRootIndex);
3941
4268
      Split(equal, if_true, if_false, fall_through);
3942
4269
      break;
3945
4272
      VisitForStackValue(expr->right());
3946
4273
      InstanceofStub stub(InstanceofStub::kNoFlags);
3947
4274
      __ CallStub(&stub);
3948
 
      PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
4275
      PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3949
4276
      __ testq(rax, rax);
3950
4277
       // The stub returns 0 for true.
3951
4278
      Split(zero, if_true, if_false, fall_through);
3959
4286
        case Token::EQ_STRICT:
3960
4287
        case Token::EQ:
3961
4288
          cc = equal;
3962
 
          __ pop(rdx);
3963
4289
          break;
3964
4290
        case Token::LT:
3965
4291
          cc = less;
3966
 
          __ pop(rdx);
3967
4292
          break;
3968
4293
        case Token::GT:
3969
 
          // Reverse left and right sizes to obtain ECMA-262 conversion order.
3970
 
          cc = less;
3971
 
          __ movq(rdx, result_register());
3972
 
          __ pop(rax);
 
4294
          cc = greater;
3973
4295
         break;
3974
4296
        case Token::LTE:
3975
 
          // Reverse left and right sizes to obtain ECMA-262 conversion order.
3976
 
          cc = greater_equal;
3977
 
          __ movq(rdx, result_register());
3978
 
          __ pop(rax);
 
4297
          cc = less_equal;
3979
4298
          break;
3980
4299
        case Token::GTE:
3981
4300
          cc = greater_equal;
3982
 
          __ pop(rdx);
3983
4301
          break;
3984
4302
        case Token::IN:
3985
4303
        case Token::INSTANCEOF:
3986
4304
        default:
3987
4305
          UNREACHABLE();
3988
4306
      }
 
4307
      __ pop(rdx);
3989
4308
 
3990
4309
      bool inline_smi_code = ShouldInlineSmiCase(op);
3991
4310
      JumpPatchSite patch_site(masm_);
4002
4321
      // Record position and call the compare IC.
4003
4322
      SetSourcePosition(expr->position());
4004
4323
      Handle<Code> ic = CompareIC::GetUninitialized(op);
4005
 
      __ call(ic, RelocInfo::CODE_TARGET, expr->id());
 
4324
      CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
4006
4325
      patch_site.EmitPatchInfo();
4007
4326
 
4008
 
      PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
4327
      PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4009
4328
      __ testq(rax, rax);
4010
4329
      Split(cc, if_true, if_false, fall_through);
4011
4330
    }
4017
4336
}
4018
4337
 
4019
4338
 
4020
 
void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4021
 
  Comment cmnt(masm_, "[ CompareToNull");
 
4339
void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
 
4340
                                              Expression* sub_expr,
 
4341
                                              NilValue nil) {
4022
4342
  Label materialize_true, materialize_false;
4023
4343
  Label* if_true = NULL;
4024
4344
  Label* if_false = NULL;
4026
4346
  context()->PrepareTest(&materialize_true, &materialize_false,
4027
4347
                         &if_true, &if_false, &fall_through);
4028
4348
 
4029
 
  VisitForAccumulatorValue(expr->expression());
4030
 
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4031
 
  __ CompareRoot(rax, Heap::kNullValueRootIndex);
4032
 
  if (expr->is_strict()) {
 
4349
  VisitForAccumulatorValue(sub_expr);
 
4350
  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
 
4351
  Heap::RootListIndex nil_value = nil == kNullValue ?
 
4352
      Heap::kNullValueRootIndex :
 
4353
      Heap::kUndefinedValueRootIndex;
 
4354
  __ CompareRoot(rax, nil_value);
 
4355
  if (expr->op() == Token::EQ_STRICT) {
4033
4356
    Split(equal, if_true, if_false, fall_through);
4034
4357
  } else {
 
4358
    Heap::RootListIndex other_nil_value = nil == kNullValue ?
 
4359
        Heap::kUndefinedValueRootIndex :
 
4360
        Heap::kNullValueRootIndex;
4035
4361
    __ j(equal, if_true);
4036
 
    __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
 
4362
    __ CompareRoot(rax, other_nil_value);
4037
4363
    __ j(equal, if_true);
4038
4364
    __ JumpIfSmi(rax, if_false);
4039
4365
    // It can be an undetectable object.
4075
4401
 
4076
4402
void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4077
4403
  Scope* declaration_scope = scope()->DeclarationScope();
4078
 
  if (declaration_scope->is_global_scope()) {
4079
 
    // Contexts nested in the global context have a canonical empty function
 
4404
  if (declaration_scope->is_global_scope() ||
 
4405
      declaration_scope->is_module_scope()) {
 
4406
    // Contexts nested in the native context have a canonical empty function
4080
4407
    // as their closure, not the anonymous closure containing the global
4081
4408
    // code.  Pass a smi sentinel and let the runtime look up the empty
4082
4409
    // function.
4106
4433
  __ subq(rdx, rcx);
4107
4434
  __ Integer32ToSmi(rdx, rdx);
4108
4435
  __ push(rdx);
 
4436
 
4109
4437
  // Store result register while executing finally block.
4110
4438
  __ push(result_register());
 
4439
 
 
4440
  // Store pending message while executing finally block.
 
4441
  ExternalReference pending_message_obj =
 
4442
      ExternalReference::address_of_pending_message_obj(isolate());
 
4443
  __ Load(rdx, pending_message_obj);
 
4444
  __ push(rdx);
 
4445
 
 
4446
  ExternalReference has_pending_message =
 
4447
      ExternalReference::address_of_has_pending_message(isolate());
 
4448
  __ Load(rdx, has_pending_message);
 
4449
  __ Integer32ToSmi(rdx, rdx);
 
4450
  __ push(rdx);
 
4451
 
 
4452
  ExternalReference pending_message_script =
 
4453
      ExternalReference::address_of_pending_message_script(isolate());
 
4454
  __ Load(rdx, pending_message_script);
 
4455
  __ push(rdx);
4111
4456
}
4112
4457
 
4113
4458
 
4114
4459
void FullCodeGenerator::ExitFinallyBlock() {
4115
4460
  ASSERT(!result_register().is(rdx));
4116
4461
  ASSERT(!result_register().is(rcx));
 
4462
  // Restore pending message from stack.
 
4463
  __ pop(rdx);
 
4464
  ExternalReference pending_message_script =
 
4465
      ExternalReference::address_of_pending_message_script(isolate());
 
4466
  __ Store(pending_message_script, rdx);
 
4467
 
 
4468
  __ pop(rdx);
 
4469
  __ SmiToInteger32(rdx, rdx);
 
4470
  ExternalReference has_pending_message =
 
4471
      ExternalReference::address_of_has_pending_message(isolate());
 
4472
  __ Store(has_pending_message, rdx);
 
4473
 
 
4474
  __ pop(rdx);
 
4475
  ExternalReference pending_message_obj =
 
4476
      ExternalReference::address_of_pending_message_obj(isolate());
 
4477
  __ Store(pending_message_obj, rdx);
 
4478
 
 
4479
  // Restore result register from stack.
4117
4480
  __ pop(result_register());
 
4481
 
4118
4482
  // Uncook return address.
4119
4483
  __ pop(rdx);
4120
4484
  __ SmiToInteger32(rdx, rdx);