~james-page/ubuntu/precise/nodejs/test-timeout

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Fabrice Coutadeur
  • Date: 2011-06-30 07:03:44 UTC
  • mfrom: (7.1.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110630070344-5928xvhb3ddw5adb
Tags: 0.4.9-1ubuntu1
* Merge from Debian unstable (LP: #786428). Remaining changes:
  - debian/patches/2007_remove_internet_test.patch: Remove test which requires
    internet connection

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2009 the V8 project authors. All rights reserved.
 
1
// Copyright 2011 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:
29
29
 
30
30
#if defined(V8_TARGET_ARCH_ARM)
31
31
 
 
32
#include "code-stubs.h"
32
33
#include "codegen-inl.h"
33
34
#include "compiler.h"
34
35
#include "debug.h"
35
36
#include "full-codegen.h"
36
37
#include "parser.h"
37
38
#include "scopes.h"
 
39
#include "stub-cache.h"
 
40
 
 
41
#include "arm/code-stubs-arm.h"
38
42
 
39
43
namespace v8 {
40
44
namespace internal {
41
45
 
42
46
#define __ ACCESS_MASM(masm_)
43
47
 
 
48
 
 
49
// A patch site is a location in the code which it is possible to patch. This
 
50
// class has a number of methods to emit the code which is patchable and the
 
51
// method EmitPatchInfo to record a marker back to the patchable code. This
 
52
// marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit
 
53
// immediate value is used) is the delta from the pc to the first instruction of
 
54
// the patchable code.
 
55
class JumpPatchSite BASE_EMBEDDED {
 
56
 public:
 
57
  explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
 
58
#ifdef DEBUG
 
59
    info_emitted_ = false;
 
60
#endif
 
61
  }
 
62
 
 
63
  ~JumpPatchSite() {
 
64
    ASSERT(patch_site_.is_bound() == info_emitted_);
 
65
  }
 
66
 
 
67
  // When initially emitting this ensure that a jump is always generated to skip
 
68
  // the inlined smi code.
 
69
  void EmitJumpIfNotSmi(Register reg, Label* target) {
 
70
    ASSERT(!patch_site_.is_bound() && !info_emitted_);
 
71
    __ bind(&patch_site_);
 
72
    __ cmp(reg, Operand(reg));
 
73
    // Don't use b(al, ...) as that might emit the constant pool right after the
 
74
    // branch. After patching when the branch is no longer unconditional
 
75
    // execution can continue into the constant pool.
 
76
    __ b(eq, target);  // Always taken before patched.
 
77
  }
 
78
 
 
79
  // When initially emitting this ensure that a jump is never generated to skip
 
80
  // the inlined smi code.
 
81
  void EmitJumpIfSmi(Register reg, Label* target) {
 
82
    ASSERT(!patch_site_.is_bound() && !info_emitted_);
 
83
    __ bind(&patch_site_);
 
84
    __ cmp(reg, Operand(reg));
 
85
    __ b(ne, target);  // Never taken before patched.
 
86
  }
 
87
 
 
88
  void EmitPatchInfo() {
 
89
    int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
 
90
    Register reg;
 
91
    reg.set_code(delta_to_patch_site / kOff12Mask);
 
92
    __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask);
 
93
#ifdef DEBUG
 
94
    info_emitted_ = true;
 
95
#endif
 
96
  }
 
97
 
 
98
  bool is_bound() const { return patch_site_.is_bound(); }
 
99
 
 
100
 private:
 
101
  MacroAssembler* masm_;
 
102
  Label patch_site_;
 
103
#ifdef DEBUG
 
104
  bool info_emitted_;
 
105
#endif
 
106
};
 
107
 
 
108
 
44
109
// Generate code for a JS function.  On entry to the function the receiver
45
110
// and arguments have been pushed on the stack left to right.  The actual
46
111
// argument count matches the formal parameter count expected by the
61
126
  SetFunctionPosition(function());
62
127
  Comment cmnt(masm_, "[ function compiled by full code generator");
63
128
 
 
129
#ifdef DEBUG
 
130
  if (strlen(FLAG_stop_at) > 0 &&
 
131
      info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
 
132
    __ stop("stop-at");
 
133
  }
 
134
#endif
 
135
 
64
136
  int locals_count = scope()->num_stack_slots();
65
137
 
66
138
  __ Push(lr, fp, cp, r1);
99
171
    // Copy any necessary parameters into the context.
100
172
    int num_parameters = scope()->num_parameters();
101
173
    for (int i = 0; i < num_parameters; i++) {
102
 
      Slot* slot = scope()->parameter(i)->slot();
 
174
      Slot* slot = scope()->parameter(i)->AsSlot();
103
175
      if (slot != NULL && slot->type() == Slot::CONTEXT) {
104
176
        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
105
177
            (num_parameters - 1 - i) * kPointerSize;
117
189
    }
118
190
  }
119
191
 
120
 
  Variable* arguments = scope()->arguments()->AsVariable();
 
192
  Variable* arguments = scope()->arguments();
121
193
  if (arguments != NULL) {
122
194
    // Function uses arguments object.
123
195
    Comment cmnt(masm_, "[ Allocate arguments object");
142
214
    __ CallStub(&stub);
143
215
    // Duplicate the value; move-to-slot operation might clobber registers.
144
216
    __ mov(r3, r0);
145
 
    Move(arguments->slot(), r0, r1, r2);
146
 
    Slot* dot_arguments_slot =
147
 
        scope()->arguments_shadow()->AsVariable()->slot();
 
217
    Move(arguments->AsSlot(), r0, r1, r2);
 
218
    Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
148
219
    Move(dot_arguments_slot, r3, r1, r2);
149
220
  }
150
221
 
151
 
  { Comment cmnt(masm_, "[ Declarations");
152
 
    // For named function expressions, declare the function name as a
153
 
    // constant.
154
 
    if (scope()->is_function_scope() && scope()->function() != NULL) {
155
 
      EmitDeclaration(scope()->function(), Variable::CONST, NULL);
156
 
    }
157
 
    // Visit all the explicit declarations unless there is an illegal
158
 
    // redeclaration.
159
 
    if (scope()->HasIllegalRedeclaration()) {
160
 
      scope()->VisitIllegalRedeclaration(this);
161
 
    } else {
162
 
      VisitDeclarations(scope()->declarations());
163
 
    }
164
 
  }
165
 
 
166
 
  // Check the stack for overflow or break request.
167
 
  // Put the lr setup instruction in the delay slot.  The kInstrSize is
168
 
  // added to the implicit 8 byte offset that always applies to operations
169
 
  // with pc and gives a return address 12 bytes down.
170
 
  { Comment cmnt(masm_, "[ Stack check");
171
 
    __ LoadRoot(r2, Heap::kStackLimitRootIndex);
172
 
    __ add(lr, pc, Operand(Assembler::kInstrSize));
173
 
    __ cmp(sp, Operand(r2));
174
 
    StackCheckStub stub;
175
 
    __ mov(pc,
176
 
           Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
177
 
                   RelocInfo::CODE_TARGET),
178
 
           LeaveCC,
179
 
           lo);
180
 
  }
181
 
 
182
222
  if (FLAG_trace) {
183
223
    __ CallRuntime(Runtime::kTraceEnter, 0);
184
224
  }
185
225
 
186
 
  { Comment cmnt(masm_, "[ Body");
187
 
    ASSERT(loop_depth() == 0);
188
 
    VisitStatements(function()->body());
189
 
    ASSERT(loop_depth() == 0);
 
226
  // Visit the declarations and body unless there is an illegal
 
227
  // redeclaration.
 
228
  if (scope()->HasIllegalRedeclaration()) {
 
229
    Comment cmnt(masm_, "[ Declarations");
 
230
    scope()->VisitIllegalRedeclaration(this);
 
231
 
 
232
  } else {
 
233
    { Comment cmnt(masm_, "[ Declarations");
 
234
      // For named function expressions, declare the function name as a
 
235
      // constant.
 
236
      if (scope()->is_function_scope() && scope()->function() != NULL) {
 
237
        EmitDeclaration(scope()->function(), Variable::CONST, NULL);
 
238
      }
 
239
      VisitDeclarations(scope()->declarations());
 
240
    }
 
241
 
 
242
    { Comment cmnt(masm_, "[ Stack check");
 
243
      PrepareForBailout(info->function(), NO_REGISTERS);
 
244
      Label ok;
 
245
      __ LoadRoot(ip, Heap::kStackLimitRootIndex);
 
246
      __ cmp(sp, Operand(ip));
 
247
      __ b(hs, &ok);
 
248
      StackCheckStub stub;
 
249
      __ CallStub(&stub);
 
250
      __ bind(&ok);
 
251
    }
 
252
 
 
253
    { Comment cmnt(masm_, "[ Body");
 
254
      ASSERT(loop_depth() == 0);
 
255
      VisitStatements(function()->body());
 
256
      ASSERT(loop_depth() == 0);
 
257
    }
190
258
  }
191
259
 
 
260
  // Always emit a 'return undefined' in case control fell off the end of
 
261
  // the body.
192
262
  { Comment cmnt(masm_, "[ return <undefined>;");
193
 
    // Emit a 'return undefined' in case control fell off the end of the
194
 
    // body.
195
263
    __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
196
264
  }
197
265
  EmitReturnSequence();
 
266
 
 
267
  // Force emit the constant pool, so it doesn't get emitted in the middle
 
268
  // of the stack check table.
 
269
  masm()->CheckConstPool(true, false);
 
270
}
 
271
 
 
272
 
 
273
void FullCodeGenerator::ClearAccumulator() {
 
274
  __ mov(r0, Operand(Smi::FromInt(0)));
 
275
}
 
276
 
 
277
 
 
278
void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
 
279
  Comment cmnt(masm_, "[ Stack check");
 
280
  Label ok;
 
281
  __ LoadRoot(ip, Heap::kStackLimitRootIndex);
 
282
  __ cmp(sp, Operand(ip));
 
283
  __ b(hs, &ok);
 
284
  StackCheckStub stub;
 
285
  __ CallStub(&stub);
 
286
  // Record a mapping of this PC offset to the OSR id.  This is used to find
 
287
  // the AST id from the unoptimized code in order to use it as a key into
 
288
  // the deoptimization input data found in the optimized code.
 
289
  RecordStackCheck(stmt->OsrEntryId());
 
290
 
 
291
  __ bind(&ok);
 
292
  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
 
293
  // Record a mapping of the OSR id to this PC.  This is used if the OSR
 
294
  // entry becomes the target of a bailout.  We don't expect it to be, but
 
295
  // we want it to work if it is.
 
296
  PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
198
297
}
199
298
 
200
299
 
231
330
    }
232
331
 
233
332
#ifdef DEBUG
234
 
    // Check that the size of the code used for returning matches what is
235
 
    // expected by the debugger. If the sp_delts above cannot be encoded in the
236
 
    // add instruction the add will generate two instructions.
237
 
    int return_sequence_length =
238
 
        masm_->InstructionsGeneratedSince(&check_exit_codesize);
239
 
    CHECK(return_sequence_length ==
240
 
          Assembler::kJSReturnSequenceInstructions ||
241
 
          return_sequence_length ==
242
 
          Assembler::kJSReturnSequenceInstructions + 1);
 
333
    // Check that the size of the code used for returning is large enough
 
334
    // for the debugger's requirements.
 
335
    ASSERT(Assembler::kJSReturnSequenceInstructions <=
 
336
           masm_->InstructionsGeneratedSince(&check_exit_codesize));
243
337
#endif
244
338
  }
245
339
}
246
340
 
247
341
 
248
 
void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
249
 
  switch (context) {
250
 
    case Expression::kUninitialized:
251
 
      UNREACHABLE();
252
 
 
253
 
    case Expression::kEffect:
254
 
      // Nothing to do.
255
 
      break;
256
 
 
257
 
    case Expression::kValue:
258
 
      // Move value into place.
259
 
      switch (location_) {
260
 
        case kAccumulator:
261
 
          if (!reg.is(result_register())) __ mov(result_register(), reg);
262
 
          break;
263
 
        case kStack:
264
 
          __ push(reg);
265
 
          break;
266
 
      }
267
 
      break;
268
 
 
269
 
    case Expression::kValueTest:
270
 
    case Expression::kTestValue:
271
 
      // Push an extra copy of the value in case it's needed.
272
 
      __ push(reg);
273
 
      // Fall through.
274
 
 
275
 
    case Expression::kTest:
276
 
      // We always call the runtime on ARM, so push the value as argument.
277
 
      __ push(reg);
278
 
      DoTest(context);
279
 
      break;
280
 
  }
281
 
}
282
 
 
283
 
 
284
 
void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
285
 
  switch (context) {
286
 
    case Expression::kUninitialized:
287
 
      UNREACHABLE();
288
 
    case Expression::kEffect:
289
 
      // Nothing to do.
290
 
      break;
291
 
    case Expression::kValue:
292
 
    case Expression::kTest:
293
 
    case Expression::kValueTest:
294
 
    case Expression::kTestValue:
295
 
      // On ARM we have to move the value into a register to do anything
296
 
      // with it.
297
 
      Move(result_register(), slot);
298
 
      Apply(context, result_register());
299
 
      break;
300
 
  }
301
 
}
302
 
 
303
 
 
304
 
void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
305
 
  switch (context) {
306
 
    case Expression::kUninitialized:
307
 
      UNREACHABLE();
308
 
    case Expression::kEffect:
309
 
      break;
310
 
      // Nothing to do.
311
 
    case Expression::kValue:
312
 
    case Expression::kTest:
313
 
    case Expression::kValueTest:
314
 
    case Expression::kTestValue:
315
 
      // On ARM we have to move the value into a register to do anything
316
 
      // with it.
317
 
      __ mov(result_register(), Operand(lit->handle()));
318
 
      Apply(context, result_register());
319
 
      break;
320
 
  }
321
 
}
322
 
 
323
 
 
324
 
void FullCodeGenerator::ApplyTOS(Expression::Context context) {
325
 
  switch (context) {
326
 
    case Expression::kUninitialized:
327
 
      UNREACHABLE();
328
 
 
329
 
    case Expression::kEffect:
330
 
      __ Drop(1);
331
 
      break;
332
 
 
333
 
    case Expression::kValue:
334
 
      switch (location_) {
335
 
        case kAccumulator:
336
 
          __ pop(result_register());
337
 
          break;
338
 
        case kStack:
339
 
          break;
340
 
      }
341
 
      break;
342
 
 
343
 
    case Expression::kValueTest:
344
 
    case Expression::kTestValue:
345
 
      // Duplicate the value on the stack in case it's needed.
346
 
      __ ldr(ip, MemOperand(sp));
347
 
      __ push(ip);
348
 
      // Fall through.
349
 
 
350
 
    case Expression::kTest:
351
 
      DoTest(context);
352
 
      break;
353
 
  }
354
 
}
355
 
 
356
 
 
357
 
void FullCodeGenerator::DropAndApply(int count,
358
 
                                     Expression::Context context,
359
 
                                     Register reg) {
360
 
  ASSERT(count > 0);
361
 
  ASSERT(!reg.is(sp));
362
 
  switch (context) {
363
 
    case Expression::kUninitialized:
364
 
      UNREACHABLE();
365
 
 
366
 
    case Expression::kEffect:
367
 
      __ Drop(count);
368
 
      break;
369
 
 
370
 
    case Expression::kValue:
371
 
      switch (location_) {
372
 
        case kAccumulator:
373
 
          __ Drop(count);
374
 
          if (!reg.is(result_register())) __ mov(result_register(), reg);
375
 
          break;
376
 
        case kStack:
377
 
          if (count > 1) __ Drop(count - 1);
378
 
          __ str(reg, MemOperand(sp));
379
 
          break;
380
 
      }
381
 
      break;
382
 
 
383
 
    case Expression::kTest:
384
 
      if (count > 1) __ Drop(count - 1);
385
 
      __ str(reg, MemOperand(sp));
386
 
      DoTest(context);
387
 
      break;
388
 
 
389
 
    case Expression::kValueTest:
390
 
    case Expression::kTestValue:
391
 
      if (count == 1) {
392
 
        __ str(reg, MemOperand(sp));
393
 
        __ push(reg);
394
 
      } else {  // count > 1
395
 
        __ Drop(count - 2);
396
 
        __ str(reg, MemOperand(sp, kPointerSize));
397
 
        __ str(reg, MemOperand(sp));
398
 
      }
399
 
      DoTest(context);
400
 
      break;
401
 
  }
402
 
}
403
 
 
404
 
void FullCodeGenerator::PrepareTest(Label* materialize_true,
405
 
                                    Label* materialize_false,
406
 
                                    Label** if_true,
407
 
                                    Label** if_false) {
408
 
  switch (context_) {
409
 
    case Expression::kUninitialized:
410
 
      UNREACHABLE();
411
 
      break;
412
 
    case Expression::kEffect:
413
 
      // In an effect context, the true and the false case branch to the
414
 
      // same label.
415
 
      *if_true = *if_false = materialize_true;
416
 
      break;
417
 
    case Expression::kValue:
418
 
      *if_true = materialize_true;
419
 
      *if_false = materialize_false;
420
 
      break;
421
 
    case Expression::kTest:
422
 
      *if_true = true_label_;
423
 
      *if_false = false_label_;
424
 
      break;
425
 
    case Expression::kValueTest:
426
 
      *if_true = materialize_true;
427
 
      *if_false = false_label_;
428
 
      break;
429
 
    case Expression::kTestValue:
430
 
      *if_true = true_label_;
431
 
      *if_false = materialize_false;
432
 
      break;
433
 
  }
434
 
}
435
 
 
436
 
 
437
 
void FullCodeGenerator::Apply(Expression::Context context,
438
 
                              Label* materialize_true,
439
 
                              Label* materialize_false) {
440
 
  switch (context) {
441
 
    case Expression::kUninitialized:
442
 
 
443
 
    case Expression::kEffect:
444
 
      ASSERT_EQ(materialize_true, materialize_false);
445
 
      __ bind(materialize_true);
446
 
      break;
447
 
 
448
 
    case Expression::kValue: {
449
 
      Label done;
450
 
      switch (location_) {
451
 
        case kAccumulator:
452
 
          __ bind(materialize_true);
453
 
          __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
454
 
          __ jmp(&done);
455
 
          __ bind(materialize_false);
456
 
          __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
457
 
          break;
458
 
        case kStack:
459
 
          __ bind(materialize_true);
460
 
          __ LoadRoot(ip, Heap::kTrueValueRootIndex);
461
 
          __ push(ip);
462
 
          __ jmp(&done);
463
 
          __ bind(materialize_false);
464
 
          __ LoadRoot(ip, Heap::kFalseValueRootIndex);
465
 
          __ push(ip);
466
 
          break;
467
 
      }
468
 
      __ bind(&done);
469
 
      break;
470
 
    }
471
 
 
472
 
    case Expression::kTest:
473
 
      break;
474
 
 
475
 
    case Expression::kValueTest:
476
 
      __ bind(materialize_true);
477
 
      switch (location_) {
478
 
        case kAccumulator:
479
 
          __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
480
 
          break;
481
 
        case kStack:
482
 
          __ LoadRoot(ip, Heap::kTrueValueRootIndex);
483
 
          __ push(ip);
484
 
          break;
485
 
      }
486
 
      __ jmp(true_label_);
487
 
      break;
488
 
 
489
 
    case Expression::kTestValue:
490
 
      __ bind(materialize_false);
491
 
      switch (location_) {
492
 
        case kAccumulator:
493
 
          __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
494
 
          break;
495
 
        case kStack:
496
 
          __ LoadRoot(ip, Heap::kFalseValueRootIndex);
497
 
          __ push(ip);
498
 
          break;
499
 
      }
500
 
      __ jmp(false_label_);
501
 
      break;
502
 
  }
503
 
}
504
 
 
505
 
 
506
 
// Convert constant control flow (true or false) to the result expected for
507
 
// a given expression context.
508
 
void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
509
 
  switch (context) {
510
 
    case Expression::kUninitialized:
511
 
      UNREACHABLE();
512
 
      break;
513
 
    case Expression::kEffect:
514
 
      break;
515
 
    case Expression::kValue: {
516
 
      Heap::RootListIndex value_root_index =
517
 
          flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
518
 
      switch (location_) {
519
 
        case kAccumulator:
520
 
          __ LoadRoot(result_register(), value_root_index);
521
 
          break;
522
 
        case kStack:
523
 
          __ LoadRoot(ip, value_root_index);
524
 
          __ push(ip);
525
 
          break;
526
 
      }
527
 
      break;
528
 
    }
529
 
    case Expression::kTest:
530
 
      __ b(flag ? true_label_ : false_label_);
531
 
      break;
532
 
    case Expression::kTestValue:
533
 
      switch (location_) {
534
 
        case kAccumulator:
535
 
          // If value is false it's needed.
536
 
          if (!flag) __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
537
 
          break;
538
 
        case kStack:
539
 
          // If value is false it's needed.
540
 
          if (!flag) {
541
 
            __ LoadRoot(ip, Heap::kFalseValueRootIndex);
542
 
            __ push(ip);
543
 
          }
544
 
          break;
545
 
      }
546
 
      __ b(flag ? true_label_ : false_label_);
547
 
      break;
548
 
    case Expression::kValueTest:
549
 
      switch (location_) {
550
 
        case kAccumulator:
551
 
          // If value is true it's needed.
552
 
          if (flag) __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
553
 
          break;
554
 
        case kStack:
555
 
          // If value is true it's needed.
556
 
          if (flag) {
557
 
            __ LoadRoot(ip, Heap::kTrueValueRootIndex);
558
 
            __ push(ip);
559
 
          }
560
 
          break;
561
 
      }
562
 
      __ b(flag ? true_label_ : false_label_);
563
 
      break;
564
 
  }
565
 
}
566
 
 
567
 
 
568
 
void FullCodeGenerator::DoTest(Expression::Context context) {
569
 
  // The value to test is pushed on the stack, and duplicated on the stack
570
 
  // if necessary (for value/test and test/value contexts).
571
 
  ASSERT_NE(NULL, true_label_);
572
 
  ASSERT_NE(NULL, false_label_);
573
 
 
574
 
  // Call the runtime to find the boolean value of the source and then
575
 
  // translate it into control flow to the pair of labels.
576
 
  __ CallRuntime(Runtime::kToBool, 1);
 
342
void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
 
343
}
 
344
 
 
345
 
 
346
void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
 
347
  codegen()->Move(result_register(), slot);
 
348
}
 
349
 
 
350
 
 
351
void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
 
352
  codegen()->Move(result_register(), slot);
 
353
  __ push(result_register());
 
354
}
 
355
 
 
356
 
 
357
void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
 
358
  // For simplicity we always test the accumulator register.
 
359
  codegen()->Move(result_register(), slot);
 
360
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
 
361
  codegen()->DoTest(true_label_, false_label_, fall_through_);
 
362
}
 
363
 
 
364
 
 
365
void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
 
366
}
 
367
 
 
368
 
 
369
void FullCodeGenerator::AccumulatorValueContext::Plug(
 
370
    Heap::RootListIndex index) const {
 
371
  __ LoadRoot(result_register(), index);
 
372
}
 
373
 
 
374
 
 
375
void FullCodeGenerator::StackValueContext::Plug(
 
376
    Heap::RootListIndex index) const {
 
377
  __ LoadRoot(result_register(), index);
 
378
  __ push(result_register());
 
379
}
 
380
 
 
381
 
 
382
void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
 
383
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
 
384
                                          true,
 
385
                                          true_label_,
 
386
                                          false_label_);
 
387
  if (index == Heap::kUndefinedValueRootIndex ||
 
388
      index == Heap::kNullValueRootIndex ||
 
389
      index == Heap::kFalseValueRootIndex) {
 
390
    if (false_label_ != fall_through_) __ b(false_label_);
 
391
  } else if (index == Heap::kTrueValueRootIndex) {
 
392
    if (true_label_ != fall_through_) __ b(true_label_);
 
393
  } else {
 
394
    __ LoadRoot(result_register(), index);
 
395
    codegen()->DoTest(true_label_, false_label_, fall_through_);
 
396
  }
 
397
}
 
398
 
 
399
 
 
400
void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
 
401
}
 
402
 
 
403
 
 
404
void FullCodeGenerator::AccumulatorValueContext::Plug(
 
405
    Handle<Object> lit) const {
 
406
  __ mov(result_register(), Operand(lit));
 
407
}
 
408
 
 
409
 
 
410
void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
 
411
  // Immediates cannot be pushed directly.
 
412
  __ mov(result_register(), Operand(lit));
 
413
  __ push(result_register());
 
414
}
 
415
 
 
416
 
 
417
void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
 
418
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
 
419
                                          true,
 
420
                                          true_label_,
 
421
                                          false_label_);
 
422
  ASSERT(!lit->IsUndetectableObject());  // There are no undetectable literals.
 
423
  if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
 
424
    if (false_label_ != fall_through_) __ b(false_label_);
 
425
  } else if (lit->IsTrue() || lit->IsJSObject()) {
 
426
    if (true_label_ != fall_through_) __ b(true_label_);
 
427
  } else if (lit->IsString()) {
 
428
    if (String::cast(*lit)->length() == 0) {
 
429
    if (false_label_ != fall_through_) __ b(false_label_);
 
430
      __ b(false_label_);
 
431
    } else {
 
432
      if (true_label_ != fall_through_) __ b(true_label_);
 
433
    }
 
434
  } else if (lit->IsSmi()) {
 
435
    if (Smi::cast(*lit)->value() == 0) {
 
436
      if (false_label_ != fall_through_) __ b(false_label_);
 
437
    } else {
 
438
      if (true_label_ != fall_through_) __ b(true_label_);
 
439
    }
 
440
  } else {
 
441
    // For simplicity we always test the accumulator register.
 
442
    __ mov(result_register(), Operand(lit));
 
443
    codegen()->DoTest(true_label_, false_label_, fall_through_);
 
444
  }
 
445
}
 
446
 
 
447
 
 
448
void FullCodeGenerator::EffectContext::DropAndPlug(int count,
 
449
                                                   Register reg) const {
 
450
  ASSERT(count > 0);
 
451
  __ Drop(count);
 
452
}
 
453
 
 
454
 
 
455
void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
 
456
    int count,
 
457
    Register reg) const {
 
458
  ASSERT(count > 0);
 
459
  __ Drop(count);
 
460
  __ Move(result_register(), reg);
 
461
}
 
462
 
 
463
 
 
464
void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
 
465
                                                       Register reg) const {
 
466
  ASSERT(count > 0);
 
467
  if (count > 1) __ Drop(count - 1);
 
468
  __ str(reg, MemOperand(sp, 0));
 
469
}
 
470
 
 
471
 
 
472
void FullCodeGenerator::TestContext::DropAndPlug(int count,
 
473
                                                 Register reg) const {
 
474
  ASSERT(count > 0);
 
475
  // For simplicity we always test the accumulator register.
 
476
  __ Drop(count);
 
477
  __ Move(result_register(), reg);
 
478
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
 
479
  codegen()->DoTest(true_label_, false_label_, fall_through_);
 
480
}
 
481
 
 
482
 
 
483
void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
 
484
                                            Label* materialize_false) const {
 
485
  ASSERT(materialize_true == materialize_false);
 
486
  __ bind(materialize_true);
 
487
}
 
488
 
 
489
 
 
490
void FullCodeGenerator::AccumulatorValueContext::Plug(
 
491
    Label* materialize_true,
 
492
    Label* materialize_false) const {
 
493
  Label done;
 
494
  __ bind(materialize_true);
 
495
  __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
 
496
  __ jmp(&done);
 
497
  __ bind(materialize_false);
 
498
  __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
 
499
  __ bind(&done);
 
500
}
 
501
 
 
502
 
 
503
void FullCodeGenerator::StackValueContext::Plug(
 
504
    Label* materialize_true,
 
505
    Label* materialize_false) const {
 
506
  Label done;
 
507
  __ bind(materialize_true);
577
508
  __ LoadRoot(ip, Heap::kTrueValueRootIndex);
578
 
  __ cmp(r0, ip);
579
 
 
580
 
  // Complete based on the context.
581
 
  switch (context) {
582
 
    case Expression::kUninitialized:
583
 
    case Expression::kEffect:
584
 
    case Expression::kValue:
585
 
      UNREACHABLE();
586
 
 
587
 
    case Expression::kTest:
588
 
      __ b(eq, true_label_);
589
 
      __ jmp(false_label_);
590
 
      break;
591
 
 
592
 
    case Expression::kValueTest: {
593
 
      Label discard;
594
 
      switch (location_) {
595
 
        case kAccumulator:
596
 
          __ b(ne, &discard);
597
 
          __ pop(result_register());
598
 
          __ jmp(true_label_);
599
 
          break;
600
 
        case kStack:
601
 
          __ b(eq, true_label_);
602
 
          break;
603
 
      }
604
 
      __ bind(&discard);
605
 
      __ Drop(1);
606
 
      __ jmp(false_label_);
607
 
      break;
608
 
    }
609
 
 
610
 
    case Expression::kTestValue: {
611
 
      Label discard;
612
 
      switch (location_) {
613
 
        case kAccumulator:
614
 
          __ b(eq, &discard);
615
 
          __ pop(result_register());
616
 
          __ jmp(false_label_);
617
 
          break;
618
 
        case kStack:
619
 
          __ b(ne, false_label_);
620
 
          break;
621
 
      }
622
 
      __ bind(&discard);
623
 
      __ Drop(1);
624
 
      __ jmp(true_label_);
625
 
      break;
626
 
    }
 
509
  __ push(ip);
 
510
  __ jmp(&done);
 
511
  __ bind(materialize_false);
 
512
  __ LoadRoot(ip, Heap::kFalseValueRootIndex);
 
513
  __ push(ip);
 
514
  __ bind(&done);
 
515
}
 
516
 
 
517
 
 
518
void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
 
519
                                          Label* materialize_false) const {
 
520
  ASSERT(materialize_true == true_label_);
 
521
  ASSERT(materialize_false == false_label_);
 
522
}
 
523
 
 
524
 
 
525
void FullCodeGenerator::EffectContext::Plug(bool flag) const {
 
526
}
 
527
 
 
528
 
 
529
void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
 
530
  Heap::RootListIndex value_root_index =
 
531
      flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
 
532
  __ LoadRoot(result_register(), value_root_index);
 
533
}
 
534
 
 
535
 
 
536
void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
 
537
  Heap::RootListIndex value_root_index =
 
538
      flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
 
539
  __ LoadRoot(ip, value_root_index);
 
540
  __ push(ip);
 
541
}
 
542
 
 
543
 
 
544
void FullCodeGenerator::TestContext::Plug(bool flag) const {
 
545
  codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
 
546
                                          true,
 
547
                                          true_label_,
 
548
                                          false_label_);
 
549
  if (flag) {
 
550
    if (true_label_ != fall_through_) __ b(true_label_);
 
551
  } else {
 
552
    if (false_label_ != fall_through_) __ b(false_label_);
 
553
  }
 
554
}
 
555
 
 
556
 
 
557
void FullCodeGenerator::DoTest(Label* if_true,
 
558
                               Label* if_false,
 
559
                               Label* fall_through) {
 
560
  if (CpuFeatures::IsSupported(VFP3)) {
 
561
    CpuFeatures::Scope scope(VFP3);
 
562
    // Emit the inlined tests assumed by the stub.
 
563
    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
 
564
    __ cmp(result_register(), ip);
 
565
    __ b(eq, if_false);
 
566
    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
 
567
    __ cmp(result_register(), ip);
 
568
    __ b(eq, if_true);
 
569
    __ LoadRoot(ip, Heap::kFalseValueRootIndex);
 
570
    __ cmp(result_register(), ip);
 
571
    __ b(eq, if_false);
 
572
    STATIC_ASSERT(kSmiTag == 0);
 
573
    __ tst(result_register(), result_register());
 
574
    __ b(eq, if_false);
 
575
    __ JumpIfSmi(result_register(), if_true);
 
576
 
 
577
    // Call the ToBoolean stub for all other cases.
 
578
    ToBooleanStub stub(result_register());
 
579
    __ CallStub(&stub);
 
580
    __ tst(result_register(), result_register());
 
581
  } else {
 
582
    // Call the runtime to find the boolean value of the source and then
 
583
    // translate it into control flow to the pair of labels.
 
584
    __ push(result_register());
 
585
    __ CallRuntime(Runtime::kToBool, 1);
 
586
    __ LoadRoot(ip, Heap::kFalseValueRootIndex);
 
587
    __ cmp(r0, ip);
 
588
  }
 
589
 
 
590
  // The stub returns nonzero for true.
 
591
  Split(ne, if_true, if_false, fall_through);
 
592
}
 
593
 
 
594
 
 
595
void FullCodeGenerator::Split(Condition cond,
 
596
                              Label* if_true,
 
597
                              Label* if_false,
 
598
                              Label* fall_through) {
 
599
  if (if_false == fall_through) {
 
600
    __ b(cond, if_true);
 
601
  } else if (if_true == fall_through) {
 
602
    __ b(NegateCondition(cond), if_false);
 
603
  } else {
 
604
    __ b(cond, if_true);
 
605
    __ b(if_false);
627
606
  }
628
607
}
629
608
 
637
616
      int context_chain_length =
638
617
          scope()->ContextChainLength(slot->var()->scope());
639
618
      __ LoadContext(scratch, context_chain_length);
640
 
      return CodeGenerator::ContextOperand(scratch, slot->index());
 
619
      return ContextOperand(scratch, slot->index());
641
620
    }
642
621
    case Slot::LOOKUP:
643
622
      UNREACHABLE();
672
651
}
673
652
 
674
653
 
 
654
void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
 
655
                                                     bool should_normalize,
 
656
                                                     Label* if_true,
 
657
                                                     Label* if_false) {
 
658
  // Only prepare for bailouts before splits if we're in a test
 
659
  // context. Otherwise, we let the Visit function deal with the
 
660
  // preparation to avoid preparing with the same AST id twice.
 
661
  if (!context()->IsTest() || !info_->IsOptimizable()) return;
 
662
 
 
663
  Label skip;
 
664
  if (should_normalize) __ b(&skip);
 
665
 
 
666
  ForwardBailoutStack* current = forward_bailout_stack_;
 
667
  while (current != NULL) {
 
668
    PrepareForBailout(current->expr(), state);
 
669
    current = current->parent();
 
670
  }
 
671
 
 
672
  if (should_normalize) {
 
673
    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
 
674
    __ cmp(r0, ip);
 
675
    Split(eq, if_true, if_false, NULL);
 
676
    __ bind(&skip);
 
677
  }
 
678
}
 
679
 
 
680
 
675
681
void FullCodeGenerator::EmitDeclaration(Variable* variable,
676
682
                                        Variable::Mode mode,
677
683
                                        FunctionLiteral* function) {
678
684
  Comment cmnt(masm_, "[ Declaration");
679
685
  ASSERT(variable != NULL);  // Must have been resolved.
680
 
  Slot* slot = variable->slot();
 
686
  Slot* slot = variable->AsSlot();
681
687
  Property* prop = variable->AsProperty();
682
688
 
683
689
  if (slot != NULL) {
688
694
          __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
689
695
          __ str(ip, MemOperand(fp, SlotOffset(slot)));
690
696
        } else if (function != NULL) {
691
 
          VisitForValue(function, kAccumulator);
 
697
          VisitForAccumulatorValue(function);
692
698
          __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
693
699
        }
694
700
        break;
697
703
        // We bypass the general EmitSlotSearch because we know more about
698
704
        // this specific context.
699
705
 
700
 
        // The variable in the decl always resides in the current context.
 
706
        // The variable in the decl always resides in the current function
 
707
        // context.
701
708
        ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
702
709
        if (FLAG_debug_code) {
703
 
          // Check if we have the correct context pointer.
704
 
          __ ldr(r1,
705
 
                 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX));
 
710
          // Check that we're not inside a 'with'.
 
711
          __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
706
712
          __ cmp(r1, cp);
707
713
          __ Check(eq, "Unexpected declaration in current context.");
708
714
        }
709
715
        if (mode == Variable::CONST) {
710
716
          __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
711
 
          __ str(ip, CodeGenerator::ContextOperand(cp, slot->index()));
 
717
          __ str(ip, ContextOperand(cp, slot->index()));
712
718
          // No write barrier since the_hole_value is in old space.
713
719
        } else if (function != NULL) {
714
 
          VisitForValue(function, kAccumulator);
715
 
          __ str(result_register(),
716
 
                 CodeGenerator::ContextOperand(cp, slot->index()));
 
720
          VisitForAccumulatorValue(function);
 
721
          __ str(result_register(), ContextOperand(cp, slot->index()));
717
722
          int offset = Context::SlotOffset(slot->index());
718
723
          // We know that we have written a function, which is not a smi.
719
724
          __ mov(r1, Operand(cp));
739
744
        } else if (function != NULL) {
740
745
          __ Push(cp, r2, r1);
741
746
          // Push initial value for function declaration.
742
 
          VisitForValue(function, kStack);
 
747
          VisitForStackValue(function);
743
748
        } else {
744
749
          __ mov(r0, Operand(Smi::FromInt(0)));  // No initial value!
745
750
          __ Push(cp, r2, r1, r0);
752
757
  } else if (prop != NULL) {
753
758
    if (function != NULL || mode == Variable::CONST) {
754
759
      // We are declaring a function or constant that rewrites to a
755
 
      // property.  Use (keyed) IC to set the initial value.
756
 
      VisitForValue(prop->obj(), kStack);
 
760
      // property.  Use (keyed) IC to set the initial value.  We
 
761
      // cannot visit the rewrite because it's shared and we risk
 
762
      // recording duplicate AST IDs for bailouts from optimized code.
 
763
      ASSERT(prop->obj()->AsVariableProxy() != NULL);
 
764
      { AccumulatorValueContext for_object(this);
 
765
        EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
 
766
      }
757
767
      if (function != NULL) {
758
 
        VisitForValue(prop->key(), kStack);
759
 
        VisitForValue(function, kAccumulator);
760
 
        __ pop(r1);  // Key.
 
768
        __ push(r0);
 
769
        VisitForAccumulatorValue(function);
 
770
        __ pop(r2);
761
771
      } else {
762
 
        VisitForValue(prop->key(), kAccumulator);
763
 
        __ mov(r1, result_register());  // Key.
764
 
        __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
 
772
        __ mov(r2, r0);
 
773
        __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
765
774
      }
766
 
      __ pop(r2);  // Receiver.
 
775
      ASSERT(prop->key()->AsLiteral() != NULL &&
 
776
             prop->key()->AsLiteral()->handle()->IsSmi());
 
777
      __ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
767
778
 
768
 
      Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
769
 
      __ Call(ic, RelocInfo::CODE_TARGET);
 
779
      Handle<Code> ic(Builtins::builtin(is_strict()
 
780
          ? Builtins::KeyedStoreIC_Initialize_Strict
 
781
          : Builtins::KeyedStoreIC_Initialize));
 
782
      EmitCallIC(ic, RelocInfo::CODE_TARGET);
770
783
      // Value in r0 is ignored (declarations are statements).
771
784
    }
772
785
  }
781
794
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
782
795
  // Call the runtime to declare the globals.
783
796
  // The context is the first argument.
784
 
  __ mov(r1, Operand(pairs));
785
 
  __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
786
 
  __ Push(cp, r1, r0);
787
 
  __ CallRuntime(Runtime::kDeclareGlobals, 3);
 
797
  __ mov(r2, Operand(pairs));
 
798
  __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
 
799
  __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
 
800
  __ Push(cp, r2, r1, r0);
 
801
  __ CallRuntime(Runtime::kDeclareGlobals, 4);
788
802
  // Return value is ignored.
789
803
}
790
804
 
793
807
  Comment cmnt(masm_, "[ SwitchStatement");
794
808
  Breakable nested_statement(this, stmt);
795
809
  SetStatementPosition(stmt);
 
810
 
796
811
  // Keep the switch value on the stack until a case matches.
797
 
  VisitForValue(stmt->tag(), kStack);
 
812
  VisitForStackValue(stmt->tag());
 
813
  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
798
814
 
799
815
  ZoneList<CaseClause*>* clauses = stmt->cases();
800
816
  CaseClause* default_clause = NULL;  // Can occur anywhere in the list.
803
819
  // Compile all the tests with branches to their bodies.
804
820
  for (int i = 0; i < clauses->length(); i++) {
805
821
    CaseClause* clause = clauses->at(i);
 
822
    clause->body_target()->entry_label()->Unuse();
 
823
 
806
824
    // The default is not a test, but remember it as final fall through.
807
825
    if (clause->is_default()) {
808
826
      default_clause = clause;
814
832
    next_test.Unuse();
815
833
 
816
834
    // Compile the label expression.
817
 
    VisitForValue(clause->label(), kAccumulator);
 
835
    VisitForAccumulatorValue(clause->label());
818
836
 
819
 
    // Perform the comparison as if via '==='.  The comparison stub expects
820
 
    // the smi vs. smi case to be handled before it is called.
821
 
    Label slow_case;
 
837
    // Perform the comparison as if via '==='.
822
838
    __ ldr(r1, MemOperand(sp, 0));  // Switch value.
823
 
    __ orr(r2, r1, r0);
824
 
    __ tst(r2, Operand(kSmiTagMask));
825
 
    __ b(ne, &slow_case);
826
 
    __ cmp(r1, r0);
827
 
    __ b(ne, &next_test);
828
 
    __ Drop(1);  // Switch value is no longer needed.
829
 
    __ b(clause->body_target()->entry_label());
830
 
 
831
 
    __ bind(&slow_case);
832
 
    CompareStub stub(eq, true, kBothCouldBeNaN, true, r1, r0);
833
 
    __ CallStub(&stub);
 
839
    bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
 
840
    JumpPatchSite patch_site(masm_);
 
841
    if (inline_smi_code) {
 
842
      Label slow_case;
 
843
      __ orr(r2, r1, r0);
 
844
      patch_site.EmitJumpIfNotSmi(r2, &slow_case);
 
845
 
 
846
      __ cmp(r1, r0);
 
847
      __ b(ne, &next_test);
 
848
      __ Drop(1);  // Switch value is no longer needed.
 
849
      __ b(clause->body_target()->entry_label());
 
850
      __ bind(&slow_case);
 
851
    }
 
852
 
 
853
    // Record position before stub call for type feedback.
 
854
    SetSourcePosition(clause->position());
 
855
    Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
 
856
    EmitCallIC(ic, &patch_site);
834
857
    __ cmp(r0, Operand(0));
835
858
    __ b(ne, &next_test);
836
859
    __ Drop(1);  // Switch value is no longer needed.
856
879
  }
857
880
 
858
881
  __ bind(nested_statement.break_target());
 
882
  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
859
883
}
860
884
 
861
885
 
870
894
  // Get the object to enumerate over. Both SpiderMonkey and JSC
871
895
  // ignore null and undefined in contrast to the specification; see
872
896
  // ECMA-262 section 12.6.4.
873
 
  VisitForValue(stmt->enumerable(), kAccumulator);
 
897
  VisitForAccumulatorValue(stmt->enumerable());
874
898
  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
875
899
  __ cmp(r0, ip);
876
900
  __ b(eq, &exit);
877
 
  __ LoadRoot(ip, Heap::kNullValueRootIndex);
878
 
  __ cmp(r0, ip);
 
901
  Register null_value = r5;
 
902
  __ LoadRoot(null_value, Heap::kNullValueRootIndex);
 
903
  __ cmp(r0, null_value);
879
904
  __ b(eq, &exit);
880
905
 
881
906
  // Convert the object to a JS object.
882
907
  Label convert, done_convert;
883
 
  __ BranchOnSmi(r0, &convert);
 
908
  __ JumpIfSmi(r0, &convert);
884
909
  __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
885
910
  __ b(hs, &done_convert);
886
911
  __ bind(&convert);
889
914
  __ bind(&done_convert);
890
915
  __ push(r0);
891
916
 
892
 
  // TODO(kasperl): Check cache validity in generated code. This is a
893
 
  // fast case for the JSObject::IsSimpleEnum cache validity
894
 
  // checks. If we cannot guarantee cache validity, call the runtime
895
 
  // system to check cache validity or get the property names in a
896
 
  // fixed array.
 
917
  // Check cache validity in generated code. This is a fast case for
 
918
  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
 
919
  // guarantee cache validity, call the runtime system to check cache
 
920
  // validity or get the property names in a fixed array.
 
921
  Label next, call_runtime;
 
922
  // Preload a couple of values used in the loop.
 
923
  Register  empty_fixed_array_value = r6;
 
924
  __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
 
925
  Register empty_descriptor_array_value = r7;
 
926
  __ LoadRoot(empty_descriptor_array_value,
 
927
              Heap::kEmptyDescriptorArrayRootIndex);
 
928
  __ mov(r1, r0);
 
929
  __ bind(&next);
 
930
 
 
931
  // Check that there are no elements.  Register r1 contains the
 
932
  // current JS object we've reached through the prototype chain.
 
933
  __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
 
934
  __ cmp(r2, empty_fixed_array_value);
 
935
  __ b(ne, &call_runtime);
 
936
 
 
937
  // Check that instance descriptors are not empty so that we can
 
938
  // check for an enum cache.  Leave the map in r2 for the subsequent
 
939
  // prototype load.
 
940
  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
 
941
  __ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOffset));
 
942
  __ cmp(r3, empty_descriptor_array_value);
 
943
  __ b(eq, &call_runtime);
 
944
 
 
945
  // Check that there is an enum cache in the non-empty instance
 
946
  // descriptors (r3).  This is the case if the next enumeration
 
947
  // index field does not contain a smi.
 
948
  __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumerationIndexOffset));
 
949
  __ JumpIfSmi(r3, &call_runtime);
 
950
 
 
951
  // For all objects but the receiver, check that the cache is empty.
 
952
  Label check_prototype;
 
953
  __ cmp(r1, r0);
 
954
  __ b(eq, &check_prototype);
 
955
  __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumCacheBridgeCacheOffset));
 
956
  __ cmp(r3, empty_fixed_array_value);
 
957
  __ b(ne, &call_runtime);
 
958
 
 
959
  // Load the prototype from the map and loop if non-null.
 
960
  __ bind(&check_prototype);
 
961
  __ ldr(r1, FieldMemOperand(r2, Map::kPrototypeOffset));
 
962
  __ cmp(r1, null_value);
 
963
  __ b(ne, &next);
 
964
 
 
965
  // The enum cache is valid.  Load the map of the object being
 
966
  // iterated over and use the cache for the iteration.
 
967
  Label use_cache;
 
968
  __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
 
969
  __ b(&use_cache);
897
970
 
898
971
  // Get the set of properties to enumerate.
 
972
  __ bind(&call_runtime);
899
973
  __ push(r0);  // Duplicate the enumerable object on the stack.
900
974
  __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
901
975
 
910
984
  __ b(ne, &fixed_array);
911
985
 
912
986
  // We got a map in register r0. Get the enumeration cache from it.
 
987
  __ bind(&use_cache);
913
988
  __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset));
914
989
  __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
915
990
  __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
968
1043
  __ bind(&update_each);
969
1044
  __ mov(result_register(), r3);
970
1045
  // Perform the assignment as if via '='.
971
 
  EmitAssignment(stmt->each());
 
1046
  { EffectContext context(this);
 
1047
    EmitAssignment(stmt->each(), stmt->AssignmentId());
 
1048
  }
972
1049
 
973
1050
  // Generate code for the body of the loop.
974
 
  Label stack_limit_hit, stack_check_done;
975
1051
  Visit(stmt->body());
976
1052
 
977
 
  __ StackLimitCheck(&stack_limit_hit);
978
 
  __ bind(&stack_check_done);
979
 
 
980
1053
  // Generate code for the going to the next element by incrementing
981
1054
  // the index (smi) stored on top of the stack.
982
1055
  __ bind(loop_statement.continue_target());
983
1056
  __ pop(r0);
984
1057
  __ add(r0, r0, Operand(Smi::FromInt(1)));
985
1058
  __ push(r0);
 
1059
 
 
1060
  EmitStackCheck(stmt);
986
1061
  __ b(&loop);
987
1062
 
988
 
  // Slow case for the stack limit check.
989
 
  StackCheckStub stack_check_stub;
990
 
  __ bind(&stack_limit_hit);
991
 
  __ CallStub(&stack_check_stub);
992
 
  __ b(&stack_check_done);
993
 
 
994
1063
  // Remove the pointers stored on the stack.
995
1064
  __ bind(loop_statement.break_target());
996
1065
  __ Drop(5);
1001
1070
}
1002
1071
 
1003
1072
 
1004
 
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
 
1073
void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
 
1074
                                       bool pretenure) {
1005
1075
  // Use the fast case closure allocation code that allocates in new
1006
 
  // space for nested functions that don't need literals cloning.
1007
 
  if (scope()->is_function_scope() && info->num_literals() == 0) {
 
1076
  // space for nested functions that don't need literals cloning. If
 
1077
  // we're running with the --always-opt or the --prepare-always-opt
 
1078
  // flag, we need to use the runtime function so that the new function
 
1079
  // we are creating here gets a chance to have its code optimized and
 
1080
  // doesn't just get a copy of the existing unoptimized code.
 
1081
  if (!FLAG_always_opt &&
 
1082
      !FLAG_prepare_always_opt &&
 
1083
      scope()->is_function_scope() &&
 
1084
      info->num_literals() == 0 &&
 
1085
      !pretenure) {
1008
1086
    FastNewClosureStub stub;
1009
1087
    __ mov(r0, Operand(info));
1010
1088
    __ push(r0);
1011
1089
    __ CallStub(&stub);
1012
1090
  } else {
1013
1091
    __ mov(r0, Operand(info));
1014
 
    __ Push(cp, r0);
1015
 
    __ CallRuntime(Runtime::kNewClosure, 2);
 
1092
    __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
 
1093
                              : Heap::kFalseValueRootIndex);
 
1094
    __ Push(cp, r0, r1);
 
1095
    __ CallRuntime(Runtime::kNewClosure, 3);
1016
1096
  }
1017
 
  Apply(context_, r0);
 
1097
  context()->Plug(r0);
1018
1098
}
1019
1099
 
1020
1100
 
1021
1101
void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1022
1102
  Comment cmnt(masm_, "[ VariableProxy");
1023
 
  EmitVariableLoad(expr->var(), context_);
1024
 
}
1025
 
 
1026
 
 
1027
 
void FullCodeGenerator::EmitVariableLoad(Variable* var,
1028
 
                                         Expression::Context context) {
 
1103
  EmitVariableLoad(expr->var());
 
1104
}
 
1105
 
 
1106
 
 
1107
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
 
1108
    Slot* slot,
 
1109
    Label* slow) {
 
1110
  ASSERT(slot->type() == Slot::CONTEXT);
 
1111
  Register context = cp;
 
1112
  Register next = r3;
 
1113
  Register temp = r4;
 
1114
 
 
1115
  for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
 
1116
    if (s->num_heap_slots() > 0) {
 
1117
      if (s->calls_eval()) {
 
1118
        // Check that extension is NULL.
 
1119
        __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
 
1120
        __ tst(temp, temp);
 
1121
        __ b(ne, slow);
 
1122
      }
 
1123
      __ ldr(next, ContextOperand(context, Context::CLOSURE_INDEX));
 
1124
      __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
 
1125
      // Walk the rest of the chain without clobbering cp.
 
1126
      context = next;
 
1127
    }
 
1128
  }
 
1129
  // Check that last extension is NULL.
 
1130
  __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
 
1131
  __ tst(temp, temp);
 
1132
  __ b(ne, slow);
 
1133
 
 
1134
  // This function is used only for loads, not stores, so it's safe to
 
1135
  // return an cp-based operand (the write barrier cannot be allowed to
 
1136
  // destroy the cp register).
 
1137
  return ContextOperand(context, slot->index());
 
1138
}
 
1139
 
 
1140
 
 
1141
void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
 
1142
    Slot* slot,
 
1143
    TypeofState typeof_state,
 
1144
    Label* slow,
 
1145
    Label* done) {
 
1146
  // Generate fast-case code for variables that might be shadowed by
 
1147
  // eval-introduced variables.  Eval is used a lot without
 
1148
  // introducing variables.  In those cases, we do not want to
 
1149
  // perform a runtime call for all variables in the scope
 
1150
  // containing the eval.
 
1151
  if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
 
1152
    EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
 
1153
    __ jmp(done);
 
1154
  } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
 
1155
    Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
 
1156
    Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
 
1157
    if (potential_slot != NULL) {
 
1158
      // Generate fast case for locals that rewrite to slots.
 
1159
      __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow));
 
1160
      if (potential_slot->var()->mode() == Variable::CONST) {
 
1161
        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
 
1162
        __ cmp(r0, ip);
 
1163
        __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
 
1164
      }
 
1165
      __ jmp(done);
 
1166
    } else if (rewrite != NULL) {
 
1167
      // Generate fast case for calls of an argument function.
 
1168
      Property* property = rewrite->AsProperty();
 
1169
      if (property != NULL) {
 
1170
        VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
 
1171
        Literal* key_literal = property->key()->AsLiteral();
 
1172
        if (obj_proxy != NULL &&
 
1173
            key_literal != NULL &&
 
1174
            obj_proxy->IsArguments() &&
 
1175
            key_literal->handle()->IsSmi()) {
 
1176
          // Load arguments object if there are no eval-introduced
 
1177
          // variables. Then load the argument from the arguments
 
1178
          // object using keyed load.
 
1179
          __ ldr(r1,
 
1180
                 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
 
1181
                                                   slow));
 
1182
          __ mov(r0, Operand(key_literal->handle()));
 
1183
          Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
 
1184
          EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
1185
          __ jmp(done);
 
1186
        }
 
1187
      }
 
1188
    }
 
1189
  }
 
1190
}
 
1191
 
 
1192
 
 
1193
void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
 
1194
    Slot* slot,
 
1195
    TypeofState typeof_state,
 
1196
    Label* slow) {
 
1197
  Register current = cp;
 
1198
  Register next = r1;
 
1199
  Register temp = r2;
 
1200
 
 
1201
  Scope* s = scope();
 
1202
  while (s != NULL) {
 
1203
    if (s->num_heap_slots() > 0) {
 
1204
      if (s->calls_eval()) {
 
1205
        // Check that extension is NULL.
 
1206
        __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
 
1207
        __ tst(temp, temp);
 
1208
        __ b(ne, slow);
 
1209
      }
 
1210
      // Load next context in chain.
 
1211
      __ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX));
 
1212
      __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
 
1213
      // Walk the rest of the chain without clobbering cp.
 
1214
      current = next;
 
1215
    }
 
1216
    // If no outer scope calls eval, we do not need to check more
 
1217
    // context extensions.
 
1218
    if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
 
1219
    s = s->outer_scope();
 
1220
  }
 
1221
 
 
1222
  if (s->is_eval_scope()) {
 
1223
    Label loop, fast;
 
1224
    if (!current.is(next)) {
 
1225
      __ Move(next, current);
 
1226
    }
 
1227
    __ bind(&loop);
 
1228
    // Terminate at global context.
 
1229
    __ ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset));
 
1230
    __ LoadRoot(ip, Heap::kGlobalContextMapRootIndex);
 
1231
    __ cmp(temp, ip);
 
1232
    __ b(eq, &fast);
 
1233
    // Check that extension is NULL.
 
1234
    __ ldr(temp, ContextOperand(next, Context::EXTENSION_INDEX));
 
1235
    __ tst(temp, temp);
 
1236
    __ b(ne, slow);
 
1237
    // Load next context in chain.
 
1238
    __ ldr(next, ContextOperand(next, Context::CLOSURE_INDEX));
 
1239
    __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
 
1240
    __ b(&loop);
 
1241
    __ bind(&fast);
 
1242
  }
 
1243
 
 
1244
  __ ldr(r0, GlobalObjectOperand());
 
1245
  __ mov(r2, Operand(slot->var()->name()));
 
1246
  RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
 
1247
      ? RelocInfo::CODE_TARGET
 
1248
      : RelocInfo::CODE_TARGET_CONTEXT;
 
1249
  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
 
1250
  EmitCallIC(ic, mode);
 
1251
}
 
1252
 
 
1253
 
 
1254
void FullCodeGenerator::EmitVariableLoad(Variable* var) {
1029
1255
  // Four cases: non-this global variables, lookup slots, all other
1030
1256
  // types of slots, and parameters that rewrite to explicit property
1031
1257
  // accesses on the arguments object.
1032
 
  Slot* slot = var->slot();
 
1258
  Slot* slot = var->AsSlot();
1033
1259
  Property* property = var->AsProperty();
1034
1260
 
1035
1261
  if (var->is_global() && !var->is_this()) {
1036
1262
    Comment cmnt(masm_, "Global variable");
1037
1263
    // Use inline caching. Variable name is passed in r2 and the global
1038
1264
    // object (receiver) in r0.
1039
 
    __ ldr(r0, CodeGenerator::GlobalObject());
 
1265
    __ ldr(r0, GlobalObjectOperand());
1040
1266
    __ mov(r2, Operand(var->name()));
1041
1267
    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1042
 
    __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
1043
 
    Apply(context, r0);
 
1268
    EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
 
1269
    context()->Plug(r0);
1044
1270
 
1045
1271
  } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
 
1272
    Label done, slow;
 
1273
 
 
1274
    // Generate code for loading from variables potentially shadowed
 
1275
    // by eval-introduced variables.
 
1276
    EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
 
1277
 
 
1278
    __ bind(&slow);
1046
1279
    Comment cmnt(masm_, "Lookup slot");
1047
1280
    __ mov(r1, Operand(var->name()));
1048
1281
    __ Push(cp, r1);  // Context and name.
1049
1282
    __ CallRuntime(Runtime::kLoadContextSlot, 2);
1050
 
    Apply(context, r0);
 
1283
    __ bind(&done);
 
1284
 
 
1285
    context()->Plug(r0);
1051
1286
 
1052
1287
  } else if (slot != NULL) {
1053
1288
    Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1054
1289
                            ? "Context slot"
1055
1290
                            : "Stack slot");
1056
1291
    if (var->mode() == Variable::CONST) {
1057
 
       // Constants may be the hole value if they have not been initialized.
1058
 
       // Unhole them.
1059
 
       Label done;
1060
 
       MemOperand slot_operand = EmitSlotSearch(slot, r0);
1061
 
       __ ldr(r0, slot_operand);
1062
 
       __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1063
 
       __ cmp(r0, ip);
1064
 
       __ b(ne, &done);
1065
 
       __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1066
 
       __ bind(&done);
1067
 
       Apply(context, r0);
1068
 
     } else {
1069
 
       Apply(context, slot);
1070
 
     }
 
1292
      // Constants may be the hole value if they have not been initialized.
 
1293
      // Unhole them.
 
1294
      MemOperand slot_operand = EmitSlotSearch(slot, r0);
 
1295
      __ ldr(r0, slot_operand);
 
1296
      __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
 
1297
      __ cmp(r0, ip);
 
1298
      __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
 
1299
      context()->Plug(r0);
 
1300
    } else {
 
1301
      context()->Plug(slot);
 
1302
    }
1071
1303
  } else {
1072
1304
    Comment cmnt(masm_, "Rewritten parameter");
1073
1305
    ASSERT_NOT_NULL(property);
1076
1308
    // Assert that the object is in a slot.
1077
1309
    Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1078
1310
    ASSERT_NOT_NULL(object_var);
1079
 
    Slot* object_slot = object_var->slot();
 
1311
    Slot* object_slot = object_var->AsSlot();
1080
1312
    ASSERT_NOT_NULL(object_slot);
1081
1313
 
1082
1314
    // Load the object.
1092
1324
 
1093
1325
    // Call keyed load IC. It has arguments key and receiver in r0 and r1.
1094
1326
    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1095
 
    __ Call(ic, RelocInfo::CODE_TARGET);
1096
 
    Apply(context, r0);
 
1327
    EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
1328
    context()->Plug(r0);
1097
1329
  }
1098
1330
}
1099
1331
 
1102
1334
  Comment cmnt(masm_, "[ RegExpLiteral");
1103
1335
  Label materialized;
1104
1336
  // Registers will be used as follows:
 
1337
  // r5 = materialized value (RegExp literal)
1105
1338
  // r4 = JS function, literals array
1106
1339
  // r3 = literal index
1107
1340
  // r2 = RegExp pattern
1108
1341
  // r1 = RegExp flags
1109
 
  // r0 = temp + materialized value (RegExp literal)
1110
 
  __ ldr(r0, MemOperand(fp,  JavaScriptFrameConstants::kFunctionOffset));
1111
 
  __ ldr(r4,  FieldMemOperand(r0, JSFunction::kLiteralsOffset));
 
1342
  // r0 = RegExp literal clone
 
1343
  __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
 
1344
  __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
1112
1345
  int literal_offset =
1113
 
    FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1114
 
  __ ldr(r0, FieldMemOperand(r4, literal_offset));
 
1346
      FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
 
1347
  __ ldr(r5, FieldMemOperand(r4, literal_offset));
1115
1348
  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1116
 
  __ cmp(r0, ip);
 
1349
  __ cmp(r5, ip);
1117
1350
  __ b(ne, &materialized);
 
1351
 
 
1352
  // Create regexp literal using runtime function.
 
1353
  // Result will be in r0.
1118
1354
  __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
1119
1355
  __ mov(r2, Operand(expr->pattern()));
1120
1356
  __ mov(r1, Operand(expr->flags()));
1121
1357
  __ Push(r4, r3, r2, r1);
1122
1358
  __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
 
1359
  __ mov(r5, r0);
 
1360
 
1123
1361
  __ bind(&materialized);
1124
1362
  int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1125
 
  __ push(r0);
 
1363
  Label allocated, runtime_allocate;
 
1364
  __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
 
1365
  __ jmp(&allocated);
 
1366
 
 
1367
  __ bind(&runtime_allocate);
 
1368
  __ push(r5);
1126
1369
  __ mov(r0, Operand(Smi::FromInt(size)));
1127
1370
  __ push(r0);
1128
1371
  __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
 
1372
  __ pop(r5);
 
1373
 
 
1374
  __ bind(&allocated);
1129
1375
  // After this, registers are used as follows:
1130
1376
  // r0: Newly allocated regexp.
1131
 
  // r1: Materialized regexp
 
1377
  // r5: Materialized regexp.
1132
1378
  // r2: temp.
1133
 
  __ pop(r1);
1134
 
  __ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
1135
 
  Apply(context_, r0);
 
1379
  __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
 
1380
  context()->Plug(r0);
1136
1381
}
1137
1382
 
1138
1383
 
1154
1399
  // result_saved is false the result is in r0.
1155
1400
  bool result_saved = false;
1156
1401
 
 
1402
  // Mark all computed expressions that are bound to a key that
 
1403
  // is shadowed by a later occurrence of the same key. For the
 
1404
  // marked expressions, no store code is emitted.
 
1405
  expr->CalculateEmitStore();
 
1406
 
1157
1407
  for (int i = 0; i < expr->properties()->length(); i++) {
1158
1408
    ObjectLiteral::Property* property = expr->properties()->at(i);
1159
1409
    if (property->IsCompileTimeValue()) continue;
1172
1422
        // Fall through.
1173
1423
      case ObjectLiteral::Property::COMPUTED:
1174
1424
        if (key->handle()->IsSymbol()) {
1175
 
          VisitForValue(value, kAccumulator);
1176
 
          __ mov(r2, Operand(key->handle()));
1177
 
          __ ldr(r1, MemOperand(sp));
1178
 
          Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1179
 
          __ Call(ic, RelocInfo::CODE_TARGET);
 
1425
          if (property->emit_store()) {
 
1426
            VisitForAccumulatorValue(value);
 
1427
            __ mov(r2, Operand(key->handle()));
 
1428
            __ ldr(r1, MemOperand(sp));
 
1429
            Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
 
1430
            EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
1431
            PrepareForBailoutForId(key->id(), NO_REGISTERS);
 
1432
          } else {
 
1433
            VisitForEffect(value);
 
1434
          }
1180
1435
          break;
1181
1436
        }
1182
1437
        // Fall through.
1184
1439
        // Duplicate receiver on stack.
1185
1440
        __ ldr(r0, MemOperand(sp));
1186
1441
        __ push(r0);
1187
 
        VisitForValue(key, kStack);
1188
 
        VisitForValue(value, kStack);
1189
 
        __ CallRuntime(Runtime::kSetProperty, 3);
 
1442
        VisitForStackValue(key);
 
1443
        VisitForStackValue(value);
 
1444
        if (property->emit_store()) {
 
1445
          __ mov(r0, Operand(Smi::FromInt(NONE)));  // PropertyAttributes
 
1446
          __ push(r0);
 
1447
          __ CallRuntime(Runtime::kSetProperty, 4);
 
1448
        } else {
 
1449
          __ Drop(3);
 
1450
        }
1190
1451
        break;
1191
1452
      case ObjectLiteral::Property::GETTER:
1192
1453
      case ObjectLiteral::Property::SETTER:
1193
1454
        // Duplicate receiver on stack.
1194
1455
        __ ldr(r0, MemOperand(sp));
1195
1456
        __ push(r0);
1196
 
        VisitForValue(key, kStack);
 
1457
        VisitForStackValue(key);
1197
1458
        __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
1198
1459
                           Smi::FromInt(1) :
1199
1460
                           Smi::FromInt(0)));
1200
1461
        __ push(r1);
1201
 
        VisitForValue(value, kStack);
 
1462
        VisitForStackValue(value);
1202
1463
        __ CallRuntime(Runtime::kDefineAccessor, 4);
1203
1464
        break;
1204
1465
    }
1205
1466
  }
1206
1467
 
1207
1468
  if (result_saved) {
1208
 
    ApplyTOS(context_);
 
1469
    context()->PlugTOS();
1209
1470
  } else {
1210
 
    Apply(context_, r0);
 
1471
    context()->Plug(r0);
1211
1472
  }
1212
1473
}
1213
1474
 
1223
1484
  __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
1224
1485
  __ mov(r1, Operand(expr->constant_elements()));
1225
1486
  __ Push(r3, r2, r1);
1226
 
  if (expr->depth() > 1) {
 
1487
  if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
 
1488
    FastCloneShallowArrayStub stub(
 
1489
        FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
 
1490
    __ CallStub(&stub);
 
1491
    __ IncrementCounter(&Counters::cow_arrays_created_stub, 1, r1, r2);
 
1492
  } else if (expr->depth() > 1) {
1227
1493
    __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1228
 
  } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
 
1494
  } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
1229
1495
    __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
1230
1496
  } else {
1231
 
    FastCloneShallowArrayStub stub(length);
 
1497
    FastCloneShallowArrayStub stub(
 
1498
        FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
1232
1499
    __ CallStub(&stub);
1233
1500
  }
1234
1501
 
1249
1516
      __ push(r0);
1250
1517
      result_saved = true;
1251
1518
    }
1252
 
    VisitForValue(subexpr, kAccumulator);
 
1519
    VisitForAccumulatorValue(subexpr);
1253
1520
 
1254
1521
    // Store the subexpression value in the array's elements.
1255
1522
    __ ldr(r1, MemOperand(sp));  // Copy of array literal.
1260
1527
    // Update the write barrier for the array store with r0 as the scratch
1261
1528
    // register.
1262
1529
    __ RecordWrite(r1, Operand(offset), r2, result_register());
 
1530
 
 
1531
    PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
1263
1532
  }
1264
1533
 
1265
1534
  if (result_saved) {
1266
 
    ApplyTOS(context_);
 
1535
    context()->PlugTOS();
1267
1536
  } else {
1268
 
    Apply(context_, r0);
 
1537
    context()->Plug(r0);
1269
1538
  }
1270
1539
}
1271
1540
 
1283
1552
  // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1284
1553
  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1285
1554
  LhsKind assign_type = VARIABLE;
1286
 
  Property* prop = expr->target()->AsProperty();
1287
 
  if (prop != NULL) {
1288
 
    assign_type =
1289
 
        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
 
1555
  Property* property = expr->target()->AsProperty();
 
1556
  if (property != NULL) {
 
1557
    assign_type = (property->key()->IsPropertyName())
 
1558
        ? NAMED_PROPERTY
 
1559
        : KEYED_PROPERTY;
1290
1560
  }
1291
1561
 
1292
1562
  // Evaluate LHS expression.
1297
1567
    case NAMED_PROPERTY:
1298
1568
      if (expr->is_compound()) {
1299
1569
        // We need the receiver both on the stack and in the accumulator.
1300
 
        VisitForValue(prop->obj(), kAccumulator);
 
1570
        VisitForAccumulatorValue(property->obj());
1301
1571
        __ push(result_register());
1302
1572
      } else {
1303
 
        VisitForValue(prop->obj(), kStack);
 
1573
        VisitForStackValue(property->obj());
1304
1574
      }
1305
1575
      break;
1306
1576
    case KEYED_PROPERTY:
1307
 
      // We need the key and receiver on both the stack and in r0 and r1.
1308
1577
      if (expr->is_compound()) {
1309
 
        VisitForValue(prop->obj(), kStack);
1310
 
        VisitForValue(prop->key(), kAccumulator);
 
1578
        if (property->is_arguments_access()) {
 
1579
          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
 
1580
          __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0));
 
1581
          __ push(r0);
 
1582
          __ mov(r0, Operand(property->key()->AsLiteral()->handle()));
 
1583
        } else {
 
1584
          VisitForStackValue(property->obj());
 
1585
          VisitForAccumulatorValue(property->key());
 
1586
        }
1311
1587
        __ ldr(r1, MemOperand(sp, 0));
1312
1588
        __ push(r0);
1313
1589
      } else {
1314
 
        VisitForValue(prop->obj(), kStack);
1315
 
        VisitForValue(prop->key(), kStack);
 
1590
        if (property->is_arguments_access()) {
 
1591
          VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
 
1592
          __ ldr(r1, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0));
 
1593
          __ mov(r0, Operand(property->key()->AsLiteral()->handle()));
 
1594
          __ Push(r1, r0);
 
1595
        } else {
 
1596
          VisitForStackValue(property->obj());
 
1597
          VisitForStackValue(property->key());
 
1598
        }
1316
1599
      }
1317
1600
      break;
1318
1601
  }
1319
1602
 
1320
 
  // If we have a compound assignment: Get value of LHS expression and
1321
 
  // store in on top of the stack.
1322
 
  if (expr->is_compound()) {
1323
 
    Location saved_location = location_;
1324
 
    location_ = kStack;
1325
 
    switch (assign_type) {
1326
 
      case VARIABLE:
1327
 
        EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
1328
 
                         Expression::kValue);
1329
 
        break;
1330
 
      case NAMED_PROPERTY:
1331
 
        EmitNamedPropertyLoad(prop);
1332
 
        __ push(result_register());
1333
 
        break;
1334
 
      case KEYED_PROPERTY:
1335
 
        EmitKeyedPropertyLoad(prop);
1336
 
        __ push(result_register());
1337
 
        break;
1338
 
    }
1339
 
    location_ = saved_location;
1340
 
  }
1341
 
 
1342
 
  // Evaluate RHS expression.
1343
 
  Expression* rhs = expr->value();
1344
 
  VisitForValue(rhs, kAccumulator);
1345
 
 
1346
 
  // If we have a compound assignment: Apply operator.
1347
 
  if (expr->is_compound()) {
1348
 
    Location saved_location = location_;
1349
 
    location_ = kAccumulator;
1350
 
    EmitBinaryOp(expr->binary_op(), Expression::kValue);
1351
 
    location_ = saved_location;
 
1603
  if (expr->is_compound()) {
 
1604
    { AccumulatorValueContext context(this);
 
1605
      switch (assign_type) {
 
1606
        case VARIABLE:
 
1607
          EmitVariableLoad(expr->target()->AsVariableProxy()->var());
 
1608
          break;
 
1609
        case NAMED_PROPERTY:
 
1610
          EmitNamedPropertyLoad(property);
 
1611
          break;
 
1612
        case KEYED_PROPERTY:
 
1613
          EmitKeyedPropertyLoad(property);
 
1614
          break;
 
1615
      }
 
1616
    }
 
1617
 
 
1618
    // For property compound assignments we need another deoptimization
 
1619
    // point after the property load.
 
1620
    if (property != NULL) {
 
1621
      PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
 
1622
    }
 
1623
 
 
1624
    Token::Value op = expr->binary_op();
 
1625
    __ push(r0);  // Left operand goes on the stack.
 
1626
    VisitForAccumulatorValue(expr->value());
 
1627
 
 
1628
    OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
 
1629
        ? OVERWRITE_RIGHT
 
1630
        : NO_OVERWRITE;
 
1631
    SetSourcePosition(expr->position() + 1);
 
1632
    AccumulatorValueContext context(this);
 
1633
    if (ShouldInlineSmiCase(op)) {
 
1634
      EmitInlineSmiBinaryOp(expr,
 
1635
                            op,
 
1636
                            mode,
 
1637
                            expr->target(),
 
1638
                            expr->value());
 
1639
    } else {
 
1640
      EmitBinaryOp(op, mode);
 
1641
    }
 
1642
 
 
1643
    // Deoptimization point in case the binary operation may have side effects.
 
1644
    PrepareForBailout(expr->binary_operation(), TOS_REG);
 
1645
  } else {
 
1646
    VisitForAccumulatorValue(expr->value());
1352
1647
  }
1353
1648
 
1354
1649
  // Record source position before possible IC call.
1358
1653
  switch (assign_type) {
1359
1654
    case VARIABLE:
1360
1655
      EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1361
 
                             expr->op(),
1362
 
                             context_);
 
1656
                             expr->op());
 
1657
      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
 
1658
      context()->Plug(r0);
1363
1659
      break;
1364
1660
    case NAMED_PROPERTY:
1365
1661
      EmitNamedPropertyAssignment(expr);
1377
1673
  __ mov(r2, Operand(key->handle()));
1378
1674
  // Call load IC. It has arguments receiver and property name r0 and r2.
1379
1675
  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1380
 
  __ Call(ic, RelocInfo::CODE_TARGET);
 
1676
  EmitCallIC(ic, RelocInfo::CODE_TARGET);
1381
1677
}
1382
1678
 
1383
1679
 
1385
1681
  SetSourcePosition(prop->position());
1386
1682
  // Call keyed load IC. It has arguments key and receiver in r0 and r1.
1387
1683
  Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1388
 
  __ Call(ic, RelocInfo::CODE_TARGET);
 
1684
  EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
1685
}
 
1686
 
 
1687
 
 
1688
void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
 
1689
                                              Token::Value op,
 
1690
                                              OverwriteMode mode,
 
1691
                                              Expression* left_expr,
 
1692
                                              Expression* right_expr) {
 
1693
  Label done, smi_case, stub_call;
 
1694
 
 
1695
  Register scratch1 = r2;
 
1696
  Register scratch2 = r3;
 
1697
 
 
1698
  // Get the arguments.
 
1699
  Register left = r1;
 
1700
  Register right = r0;
 
1701
  __ pop(left);
 
1702
 
 
1703
  // Perform combined smi check on both operands.
 
1704
  __ orr(scratch1, left, Operand(right));
 
1705
  STATIC_ASSERT(kSmiTag == 0);
 
1706
  JumpPatchSite patch_site(masm_);
 
1707
  patch_site.EmitJumpIfSmi(scratch1, &smi_case);
 
1708
 
 
1709
  __ bind(&stub_call);
 
1710
  TypeRecordingBinaryOpStub stub(op, mode);
 
1711
  EmitCallIC(stub.GetCode(), &patch_site);
 
1712
  __ jmp(&done);
 
1713
 
 
1714
  __ bind(&smi_case);
 
1715
  // Smi case. This code works the same way as the smi-smi case in the type
 
1716
  // recording binary operation stub, see
 
1717
  // TypeRecordingBinaryOpStub::GenerateSmiSmiOperation for comments.
 
1718
  switch (op) {
 
1719
    case Token::SAR:
 
1720
      __ b(&stub_call);
 
1721
      __ GetLeastBitsFromSmi(scratch1, right, 5);
 
1722
      __ mov(right, Operand(left, ASR, scratch1));
 
1723
      __ bic(right, right, Operand(kSmiTagMask));
 
1724
      break;
 
1725
    case Token::SHL: {
 
1726
      __ b(&stub_call);
 
1727
      __ SmiUntag(scratch1, left);
 
1728
      __ GetLeastBitsFromSmi(scratch2, right, 5);
 
1729
      __ mov(scratch1, Operand(scratch1, LSL, scratch2));
 
1730
      __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
 
1731
      __ b(mi, &stub_call);
 
1732
      __ SmiTag(right, scratch1);
 
1733
      break;
 
1734
    }
 
1735
    case Token::SHR: {
 
1736
      __ b(&stub_call);
 
1737
      __ SmiUntag(scratch1, left);
 
1738
      __ GetLeastBitsFromSmi(scratch2, right, 5);
 
1739
      __ mov(scratch1, Operand(scratch1, LSR, scratch2));
 
1740
      __ tst(scratch1, Operand(0xc0000000));
 
1741
      __ b(ne, &stub_call);
 
1742
      __ SmiTag(right, scratch1);
 
1743
      break;
 
1744
    }
 
1745
    case Token::ADD:
 
1746
      __ add(scratch1, left, Operand(right), SetCC);
 
1747
      __ b(vs, &stub_call);
 
1748
      __ mov(right, scratch1);
 
1749
      break;
 
1750
    case Token::SUB:
 
1751
      __ sub(scratch1, left, Operand(right), SetCC);
 
1752
      __ b(vs, &stub_call);
 
1753
      __ mov(right, scratch1);
 
1754
      break;
 
1755
    case Token::MUL: {
 
1756
      __ SmiUntag(ip, right);
 
1757
      __ smull(scratch1, scratch2, left, ip);
 
1758
      __ mov(ip, Operand(scratch1, ASR, 31));
 
1759
      __ cmp(ip, Operand(scratch2));
 
1760
      __ b(ne, &stub_call);
 
1761
      __ tst(scratch1, Operand(scratch1));
 
1762
      __ mov(right, Operand(scratch1), LeaveCC, ne);
 
1763
      __ b(ne, &done);
 
1764
      __ add(scratch2, right, Operand(left), SetCC);
 
1765
      __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
 
1766
      __ b(mi, &stub_call);
 
1767
      break;
 
1768
    }
 
1769
    case Token::BIT_OR:
 
1770
      __ orr(right, left, Operand(right));
 
1771
      break;
 
1772
    case Token::BIT_AND:
 
1773
      __ and_(right, left, Operand(right));
 
1774
      break;
 
1775
    case Token::BIT_XOR:
 
1776
      __ eor(right, left, Operand(right));
 
1777
      break;
 
1778
    default:
 
1779
      UNREACHABLE();
 
1780
  }
 
1781
 
 
1782
  __ bind(&done);
 
1783
  context()->Plug(r0);
1389
1784
}
1390
1785
 
1391
1786
 
1392
1787
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
1393
 
                                     Expression::Context context) {
 
1788
                                     OverwriteMode mode) {
1394
1789
  __ pop(r1);
1395
 
  GenericBinaryOpStub stub(op, NO_OVERWRITE, r1, r0);
1396
 
  __ CallStub(&stub);
1397
 
  Apply(context, r0);
 
1790
  TypeRecordingBinaryOpStub stub(op, mode);
 
1791
  EmitCallIC(stub.GetCode(), NULL);
 
1792
  context()->Plug(r0);
1398
1793
}
1399
1794
 
1400
1795
 
1401
 
void FullCodeGenerator::EmitAssignment(Expression* expr) {
 
1796
void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
1402
1797
  // Invalid left-hand sides are rewritten to have a 'throw
1403
1798
  // ReferenceError' on the left-hand side.
1404
1799
  if (!expr->IsValidLeftHandSide()) {
1420
1815
  switch (assign_type) {
1421
1816
    case VARIABLE: {
1422
1817
      Variable* var = expr->AsVariableProxy()->var();
1423
 
      EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
 
1818
      EffectContext context(this);
 
1819
      EmitVariableAssignment(var, Token::ASSIGN);
1424
1820
      break;
1425
1821
    }
1426
1822
    case NAMED_PROPERTY: {
1427
1823
      __ push(r0);  // Preserve value.
1428
 
      VisitForValue(prop->obj(), kAccumulator);
 
1824
      VisitForAccumulatorValue(prop->obj());
1429
1825
      __ mov(r1, r0);
1430
1826
      __ pop(r0);  // Restore value.
1431
1827
      __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
1432
 
      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1433
 
      __ Call(ic, RelocInfo::CODE_TARGET);
 
1828
      Handle<Code> ic(Builtins::builtin(
 
1829
          is_strict() ? Builtins::StoreIC_Initialize_Strict
 
1830
                      : Builtins::StoreIC_Initialize));
 
1831
      EmitCallIC(ic, RelocInfo::CODE_TARGET);
1434
1832
      break;
1435
1833
    }
1436
1834
    case KEYED_PROPERTY: {
1437
1835
      __ push(r0);  // Preserve value.
1438
 
      VisitForValue(prop->obj(), kStack);
1439
 
      VisitForValue(prop->key(), kAccumulator);
1440
 
      __ mov(r1, r0);
1441
 
      __ pop(r2);
 
1836
      if (prop->is_synthetic()) {
 
1837
        ASSERT(prop->obj()->AsVariableProxy() != NULL);
 
1838
        ASSERT(prop->key()->AsLiteral() != NULL);
 
1839
        { AccumulatorValueContext for_object(this);
 
1840
          EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
 
1841
        }
 
1842
        __ mov(r2, r0);
 
1843
        __ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
 
1844
      } else {
 
1845
        VisitForStackValue(prop->obj());
 
1846
        VisitForAccumulatorValue(prop->key());
 
1847
        __ mov(r1, r0);
 
1848
        __ pop(r2);
 
1849
      }
1442
1850
      __ pop(r0);  // Restore value.
1443
 
      Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1444
 
      __ Call(ic, RelocInfo::CODE_TARGET);
 
1851
      Handle<Code> ic(Builtins::builtin(
 
1852
          is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
 
1853
                      : Builtins::KeyedStoreIC_Initialize));
 
1854
      EmitCallIC(ic, RelocInfo::CODE_TARGET);
1445
1855
      break;
1446
1856
    }
1447
1857
  }
 
1858
  PrepareForBailoutForId(bailout_ast_id, TOS_REG);
 
1859
  context()->Plug(r0);
1448
1860
}
1449
1861
 
1450
1862
 
1451
1863
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1452
 
                                               Token::Value op,
1453
 
                                               Expression::Context context) {
 
1864
                                               Token::Value op) {
1454
1865
  // Left-hand sides that rewrite to explicit property accesses do not reach
1455
1866
  // here.
1456
1867
  ASSERT(var != NULL);
1457
 
  ASSERT(var->is_global() || var->slot() != NULL);
 
1868
  ASSERT(var->is_global() || var->AsSlot() != NULL);
1458
1869
 
1459
1870
  if (var->is_global()) {
1460
1871
    ASSERT(!var->is_this());
1462
1873
    // assignment.  Right-hand-side value is passed in r0, variable name in
1463
1874
    // r2, and the global object in r1.
1464
1875
    __ mov(r2, Operand(var->name()));
1465
 
    __ ldr(r1, CodeGenerator::GlobalObject());
1466
 
    Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1467
 
    __ Call(ic, RelocInfo::CODE_TARGET);
1468
 
 
1469
 
  } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
1470
 
    // Perform the assignment for non-const variables and for initialization
1471
 
    // of const variables.  Const assignments are simply skipped.
1472
 
    Label done;
1473
 
    Slot* slot = var->slot();
1474
 
    switch (slot->type()) {
1475
 
      case Slot::PARAMETER:
1476
 
      case Slot::LOCAL:
1477
 
        if (op == Token::INIT_CONST) {
1478
 
          // Detect const reinitialization by checking for the hole value.
1479
 
          __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
1480
 
          __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1481
 
          __ cmp(r1, ip);
1482
 
          __ b(ne, &done);
1483
 
        }
 
1876
    __ ldr(r1, GlobalObjectOperand());
 
1877
    Handle<Code> ic(Builtins::builtin(
 
1878
        is_strict() ? Builtins::StoreIC_Initialize_Strict
 
1879
                    : Builtins::StoreIC_Initialize));
 
1880
    EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
 
1881
 
 
1882
  } else if (op == Token::INIT_CONST) {
 
1883
    // Like var declarations, const declarations are hoisted to function
 
1884
    // scope.  However, unlike var initializers, const initializers are able
 
1885
    // to drill a hole to that function context, even from inside a 'with'
 
1886
    // context.  We thus bypass the normal static scope lookup.
 
1887
    Slot* slot = var->AsSlot();
 
1888
    Label skip;
 
1889
    switch (slot->type()) {
 
1890
      case Slot::PARAMETER:
 
1891
        // No const parameters.
 
1892
        UNREACHABLE();
 
1893
        break;
 
1894
      case Slot::LOCAL:
 
1895
        // Detect const reinitialization by checking for the hole value.
 
1896
        __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
 
1897
        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
 
1898
        __ cmp(r1, ip);
 
1899
        __ b(ne, &skip);
 
1900
        __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
 
1901
        break;
 
1902
      case Slot::CONTEXT: {
 
1903
        __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
 
1904
        __ ldr(r2, ContextOperand(r1, slot->index()));
 
1905
        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
 
1906
        __ cmp(r2, ip);
 
1907
        __ b(ne, &skip);
 
1908
        __ str(r0, ContextOperand(r1, slot->index()));
 
1909
        int offset = Context::SlotOffset(slot->index());
 
1910
        __ mov(r3, r0);  // Preserve the stored value in r0.
 
1911
        __ RecordWrite(r1, Operand(offset), r3, r2);
 
1912
        break;
 
1913
      }
 
1914
      case Slot::LOOKUP:
 
1915
        __ push(r0);
 
1916
        __ mov(r0, Operand(slot->var()->name()));
 
1917
        __ Push(cp, r0);  // Context and name.
 
1918
        __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
 
1919
        break;
 
1920
    }
 
1921
    __ bind(&skip);
 
1922
 
 
1923
  } else if (var->mode() != Variable::CONST) {
 
1924
    // Perform the assignment for non-const variables.  Const assignments
 
1925
    // are simply skipped.
 
1926
    Slot* slot = var->AsSlot();
 
1927
    switch (slot->type()) {
 
1928
      case Slot::PARAMETER:
 
1929
      case Slot::LOCAL:
1484
1930
        // Perform the assignment.
1485
1931
        __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1486
1932
        break;
1487
1933
 
1488
1934
      case Slot::CONTEXT: {
1489
1935
        MemOperand target = EmitSlotSearch(slot, r1);
1490
 
        if (op == Token::INIT_CONST) {
1491
 
          // Detect const reinitialization by checking for the hole value.
1492
 
          __ ldr(r2, target);
1493
 
          __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1494
 
          __ cmp(r2, ip);
1495
 
          __ b(ne, &done);
1496
 
        }
1497
1936
        // Perform the assignment and issue the write barrier.
1498
1937
        __ str(result_register(), target);
1499
1938
        // RecordWrite may destroy all its register arguments.
1504
1943
      }
1505
1944
 
1506
1945
      case Slot::LOOKUP:
1507
 
        // Call the runtime for the assignment.  The runtime will ignore
1508
 
        // const reinitialization.
 
1946
        // Call the runtime for the assignment.
1509
1947
        __ push(r0);  // Value.
1510
 
        __ mov(r0, Operand(slot->var()->name()));
1511
 
        __ Push(cp, r0);  // Context and name.
1512
 
        if (op == Token::INIT_CONST) {
1513
 
          // The runtime will ignore const redeclaration.
1514
 
          __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1515
 
        } else {
1516
 
          __ CallRuntime(Runtime::kStoreContextSlot, 3);
1517
 
        }
 
1948
        __ mov(r1, Operand(slot->var()->name()));
 
1949
        __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
 
1950
        __ Push(cp, r1, r0);  // Context, name, strict mode.
 
1951
        __ CallRuntime(Runtime::kStoreContextSlot, 4);
1518
1952
        break;
1519
1953
    }
1520
 
    __ bind(&done);
1521
1954
  }
1522
 
 
1523
 
  Apply(context, result_register());
1524
1955
}
1525
1956
 
1526
1957
 
1552
1983
    __ pop(r1);
1553
1984
  }
1554
1985
 
1555
 
  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1556
 
  __ Call(ic, RelocInfo::CODE_TARGET);
 
1986
  Handle<Code> ic(Builtins::builtin(
 
1987
      is_strict() ? Builtins::StoreIC_Initialize_Strict
 
1988
                  : Builtins::StoreIC_Initialize));
 
1989
  EmitCallIC(ic, RelocInfo::CODE_TARGET);
1557
1990
 
1558
1991
  // If the assignment ends an initialization block, revert to fast case.
1559
1992
  if (expr->ends_initialization_block()) {
1563
1996
    __ push(ip);
1564
1997
    __ CallRuntime(Runtime::kToFastProperties, 1);
1565
1998
    __ pop(r0);
1566
 
    DropAndApply(1, context_, r0);
1567
 
  } else {
1568
 
    Apply(context_, r0);
 
1999
    __ Drop(1);
1569
2000
  }
 
2001
  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
 
2002
  context()->Plug(r0);
1570
2003
}
1571
2004
 
1572
2005
 
1596
2029
    __ pop(r2);
1597
2030
  }
1598
2031
 
1599
 
  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1600
 
  __ Call(ic, RelocInfo::CODE_TARGET);
 
2032
  Handle<Code> ic(Builtins::builtin(
 
2033
      is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
 
2034
                  : Builtins::KeyedStoreIC_Initialize));
 
2035
  EmitCallIC(ic, RelocInfo::CODE_TARGET);
1601
2036
 
1602
2037
  // If the assignment ends an initialization block, revert to fast case.
1603
2038
  if (expr->ends_initialization_block()) {
1607
2042
    __ push(ip);
1608
2043
    __ CallRuntime(Runtime::kToFastProperties, 1);
1609
2044
    __ pop(r0);
1610
 
    DropAndApply(1, context_, r0);
1611
 
  } else {
1612
 
    Apply(context_, r0);
 
2045
    __ Drop(1);
1613
2046
  }
 
2047
  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
 
2048
  context()->Plug(r0);
1614
2049
}
1615
2050
 
1616
2051
 
1619
2054
  Expression* key = expr->key();
1620
2055
 
1621
2056
  if (key->IsPropertyName()) {
1622
 
    VisitForValue(expr->obj(), kAccumulator);
 
2057
    VisitForAccumulatorValue(expr->obj());
1623
2058
    EmitNamedPropertyLoad(expr);
1624
 
    Apply(context_, r0);
 
2059
    context()->Plug(r0);
1625
2060
  } else {
1626
 
    VisitForValue(expr->obj(), kStack);
1627
 
    VisitForValue(expr->key(), kAccumulator);
 
2061
    VisitForStackValue(expr->obj());
 
2062
    VisitForAccumulatorValue(expr->key());
1628
2063
    __ pop(r1);
1629
2064
    EmitKeyedPropertyLoad(expr);
1630
 
    Apply(context_, r0);
 
2065
    context()->Plug(r0);
1631
2066
  }
1632
2067
}
1633
2068
 
1637
2072
  // Code common for calls using the IC.
1638
2073
  ZoneList<Expression*>* args = expr->arguments();
1639
2074
  int arg_count = args->length();
1640
 
  for (int i = 0; i < arg_count; i++) {
1641
 
    VisitForValue(args->at(i), kStack);
 
2075
  { PreservePositionScope scope(masm()->positions_recorder());
 
2076
    for (int i = 0; i < arg_count; i++) {
 
2077
      VisitForStackValue(args->at(i));
 
2078
    }
 
2079
    __ mov(r2, Operand(name));
1642
2080
  }
1643
 
  __ mov(r2, Operand(name));
1644
2081
  // Record source position for debugger.
1645
2082
  SetSourcePosition(expr->position());
1646
2083
  // Call the IC initialization code.
1647
2084
  InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1648
 
  Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
1649
 
  __ Call(ic, mode);
 
2085
  Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
 
2086
  EmitCallIC(ic, mode);
 
2087
  RecordJSReturnSite(expr);
1650
2088
  // Restore context register.
1651
2089
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1652
 
  Apply(context_, r0);
 
2090
  context()->Plug(r0);
1653
2091
}
1654
2092
 
1655
2093
 
1656
2094
void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
1657
2095
                                            Expression* key,
1658
2096
                                            RelocInfo::Mode mode) {
 
2097
  // Load the key.
 
2098
  VisitForAccumulatorValue(key);
 
2099
 
 
2100
  // Swap the name of the function and the receiver on the stack to follow
 
2101
  // the calling convention for call ICs.
 
2102
  __ pop(r1);
 
2103
  __ push(r0);
 
2104
  __ push(r1);
 
2105
 
1659
2106
  // Code common for calls using the IC.
1660
2107
  ZoneList<Expression*>* args = expr->arguments();
1661
2108
  int arg_count = args->length();
1662
 
  for (int i = 0; i < arg_count; i++) {
1663
 
    VisitForValue(args->at(i), kStack);
 
2109
  { PreservePositionScope scope(masm()->positions_recorder());
 
2110
    for (int i = 0; i < arg_count; i++) {
 
2111
      VisitForStackValue(args->at(i));
 
2112
    }
1664
2113
  }
1665
 
  VisitForValue(key, kAccumulator);
1666
 
  __ mov(r2, r0);
1667
2114
  // Record source position for debugger.
1668
2115
  SetSourcePosition(expr->position());
1669
2116
  // Call the IC initialization code.
1670
2117
  InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1671
 
  Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
1672
 
                                                              in_loop);
1673
 
  __ Call(ic, mode);
 
2118
  Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
 
2119
  __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize));  // Key.
 
2120
  EmitCallIC(ic, mode);
 
2121
  RecordJSReturnSite(expr);
1674
2122
  // Restore context register.
1675
2123
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1676
 
  Apply(context_, r0);
 
2124
  context()->DropAndPlug(1, r0);  // Drop the key still on the stack.
1677
2125
}
1678
2126
 
1679
2127
 
1681
2129
  // Code common for calls using the call stub.
1682
2130
  ZoneList<Expression*>* args = expr->arguments();
1683
2131
  int arg_count = args->length();
1684
 
  for (int i = 0; i < arg_count; i++) {
1685
 
    VisitForValue(args->at(i), kStack);
 
2132
  { PreservePositionScope scope(masm()->positions_recorder());
 
2133
    for (int i = 0; i < arg_count; i++) {
 
2134
      VisitForStackValue(args->at(i));
 
2135
    }
1686
2136
  }
1687
2137
  // Record source position for debugger.
1688
2138
  SetSourcePosition(expr->position());
1689
2139
  InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1690
2140
  CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1691
2141
  __ CallStub(&stub);
 
2142
  RecordJSReturnSite(expr);
1692
2143
  // Restore context register.
1693
2144
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1694
 
  DropAndApply(1, context_, r0);
 
2145
  context()->DropAndPlug(1, r0);
 
2146
}
 
2147
 
 
2148
 
 
2149
void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
 
2150
                                                      int arg_count) {
 
2151
  // Push copy of the first argument or undefined if it doesn't exist.
 
2152
  if (arg_count > 0) {
 
2153
    __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
 
2154
  } else {
 
2155
    __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
 
2156
  }
 
2157
  __ push(r1);
 
2158
 
 
2159
  // Push the receiver of the enclosing function and do runtime call.
 
2160
  __ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
 
2161
  __ push(r1);
 
2162
  // Push the strict mode flag.
 
2163
  __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
 
2164
  __ push(r1);
 
2165
 
 
2166
  __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
 
2167
                 ? Runtime::kResolvePossiblyDirectEvalNoLookup
 
2168
                 : Runtime::kResolvePossiblyDirectEval, 4);
1695
2169
}
1696
2170
 
1697
2171
 
1698
2172
void FullCodeGenerator::VisitCall(Call* expr) {
 
2173
#ifdef DEBUG
 
2174
  // We want to verify that RecordJSReturnSite gets called on all paths
 
2175
  // through this function.  Avoid early returns.
 
2176
  expr->return_is_recorded_ = false;
 
2177
#endif
 
2178
 
1699
2179
  Comment cmnt(masm_, "[ Call");
1700
2180
  Expression* fun = expr->expression();
1701
2181
  Variable* var = fun->AsVariableProxy()->AsVariable();
1705
2185
    // resolve the function we need to call and the receiver of the
1706
2186
    // call.  Then we call the resolved function using the given
1707
2187
    // arguments.
1708
 
    VisitForValue(fun, kStack);
1709
 
    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
1710
 
    __ push(r2);  // Reserved receiver slot.
1711
 
 
1712
 
    // Push the arguments.
1713
2188
    ZoneList<Expression*>* args = expr->arguments();
1714
2189
    int arg_count = args->length();
1715
 
    for (int i = 0; i < arg_count; i++) {
1716
 
      VisitForValue(args->at(i), kStack);
1717
 
    }
1718
 
 
1719
 
    // Push copy of the function - found below the arguments.
1720
 
    __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
1721
 
    __ push(r1);
1722
 
 
1723
 
    // Push copy of the first argument or undefined if it doesn't exist.
1724
 
    if (arg_count > 0) {
1725
 
      __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
 
2190
 
 
2191
    { PreservePositionScope pos_scope(masm()->positions_recorder());
 
2192
      VisitForStackValue(fun);
 
2193
      __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
 
2194
      __ push(r2);  // Reserved receiver slot.
 
2195
 
 
2196
      // Push the arguments.
 
2197
      for (int i = 0; i < arg_count; i++) {
 
2198
        VisitForStackValue(args->at(i));
 
2199
      }
 
2200
 
 
2201
      // If we know that eval can only be shadowed by eval-introduced
 
2202
      // variables we attempt to load the global eval function directly
 
2203
      // in generated code. If we succeed, there is no need to perform a
 
2204
      // context lookup in the runtime system.
 
2205
      Label done;
 
2206
      if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
 
2207
        Label slow;
 
2208
        EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
 
2209
                                          NOT_INSIDE_TYPEOF,
 
2210
                                          &slow);
 
2211
        // Push the function and resolve eval.
 
2212
        __ push(r0);
 
2213
        EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
 
2214
        __ jmp(&done);
 
2215
        __ bind(&slow);
 
2216
      }
 
2217
 
 
2218
      // Push copy of the function (found below the arguments) and
 
2219
      // resolve eval.
 
2220
      __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
1726
2221
      __ push(r1);
1727
 
    } else {
1728
 
      __ push(r2);
 
2222
      EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
 
2223
      if (done.is_linked()) {
 
2224
        __ bind(&done);
 
2225
      }
 
2226
 
 
2227
      // The runtime call returns a pair of values in r0 (function) and
 
2228
      // r1 (receiver). Touch up the stack with the right values.
 
2229
      __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
 
2230
      __ str(r1, MemOperand(sp, arg_count * kPointerSize));
1729
2231
    }
1730
2232
 
1731
 
    // Push the receiver of the enclosing function and do runtime call.
1732
 
    __ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
1733
 
    __ push(r1);
1734
 
    __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
1735
 
 
1736
 
    // The runtime call returns a pair of values in r0 (function) and
1737
 
    // r1 (receiver). Touch up the stack with the right values.
1738
 
    __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
1739
 
    __ str(r1, MemOperand(sp, arg_count * kPointerSize));
1740
 
 
1741
2233
    // Record source position for debugger.
1742
2234
    SetSourcePosition(expr->position());
1743
2235
    InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1744
2236
    CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1745
2237
    __ CallStub(&stub);
 
2238
    RecordJSReturnSite(expr);
1746
2239
    // Restore context register.
1747
2240
    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1748
 
    DropAndApply(1, context_, r0);
 
2241
    context()->DropAndPlug(1, r0);
1749
2242
  } else if (var != NULL && !var->is_this() && var->is_global()) {
1750
2243
    // Push global object as receiver for the call IC.
1751
 
    __ ldr(r0, CodeGenerator::GlobalObject());
 
2244
    __ ldr(r0, GlobalObjectOperand());
1752
2245
    __ push(r0);
1753
2246
    EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1754
 
  } else if (var != NULL && var->slot() != NULL &&
1755
 
             var->slot()->type() == Slot::LOOKUP) {
1756
 
    // Call to a lookup slot (dynamically introduced variable).  Call the
1757
 
    // runtime to find the function to call (returned in eax) and the object
1758
 
    // holding it (returned in edx).
 
2247
  } else if (var != NULL && var->AsSlot() != NULL &&
 
2248
             var->AsSlot()->type() == Slot::LOOKUP) {
 
2249
    // Call to a lookup slot (dynamically introduced variable).
 
2250
    Label slow, done;
 
2251
 
 
2252
    { PreservePositionScope scope(masm()->positions_recorder());
 
2253
      // Generate code for loading from variables potentially shadowed
 
2254
      // by eval-introduced variables.
 
2255
      EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
 
2256
                                      NOT_INSIDE_TYPEOF,
 
2257
                                      &slow,
 
2258
                                      &done);
 
2259
    }
 
2260
 
 
2261
    __ bind(&slow);
 
2262
    // Call the runtime to find the function to call (returned in r0)
 
2263
    // and the object holding it (returned in edx).
1759
2264
    __ push(context_register());
1760
2265
    __ mov(r2, Operand(var->name()));
1761
2266
    __ push(r2);
1762
2267
    __ CallRuntime(Runtime::kLoadContextSlot, 2);
1763
 
    __ push(r0);  // Function.
1764
 
    __ push(r1);  // Receiver.
 
2268
    __ Push(r0, r1);  // Function, receiver.
 
2269
 
 
2270
    // If fast case code has been generated, emit code to push the
 
2271
    // function and receiver and have the slow path jump around this
 
2272
    // code.
 
2273
    if (done.is_linked()) {
 
2274
      Label call;
 
2275
      __ b(&call);
 
2276
      __ bind(&done);
 
2277
      // Push function.
 
2278
      __ push(r0);
 
2279
      // Push global receiver.
 
2280
      __ ldr(r1, GlobalObjectOperand());
 
2281
      __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
 
2282
      __ push(r1);
 
2283
      __ bind(&call);
 
2284
    }
 
2285
 
1765
2286
    EmitCallWithStub(expr);
1766
2287
  } else if (fun->AsProperty() != NULL) {
1767
2288
    // Call to an object property.
1769
2290
    Literal* key = prop->key()->AsLiteral();
1770
2291
    if (key != NULL && key->handle()->IsSymbol()) {
1771
2292
      // Call to a named property, use call IC.
1772
 
      VisitForValue(prop->obj(), kStack);
 
2293
      { PreservePositionScope scope(masm()->positions_recorder());
 
2294
        VisitForStackValue(prop->obj());
 
2295
      }
1773
2296
      EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1774
2297
    } else {
1775
2298
      // Call to a keyed property.
1776
2299
      // For a synthetic property use keyed load IC followed by function call,
1777
2300
      // for a regular property use keyed CallIC.
1778
 
      VisitForValue(prop->obj(), kStack);
1779
2301
      if (prop->is_synthetic()) {
1780
 
        VisitForValue(prop->key(), kAccumulator);
 
2302
        // Do not visit the object and key subexpressions (they are shared
 
2303
        // by all occurrences of the same rewritten parameter).
 
2304
        ASSERT(prop->obj()->AsVariableProxy() != NULL);
 
2305
        ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
 
2306
        Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
 
2307
        MemOperand operand = EmitSlotSearch(slot, r1);
 
2308
        __ ldr(r1, operand);
 
2309
 
 
2310
        ASSERT(prop->key()->AsLiteral() != NULL);
 
2311
        ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
 
2312
        __ mov(r0, Operand(prop->key()->AsLiteral()->handle()));
 
2313
 
1781
2314
        // Record source code position for IC call.
1782
2315
        SetSourcePosition(prop->position());
1783
 
        __ pop(r1);  // We do not need to keep the receiver.
1784
2316
 
1785
2317
        Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1786
 
        __ Call(ic, RelocInfo::CODE_TARGET);
1787
 
        // Push result (function).
1788
 
        __ push(r0);
1789
 
        // Push Global receiver.
1790
 
        __ ldr(r1, CodeGenerator::GlobalObject());
 
2318
        EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
2319
        __ ldr(r1, GlobalObjectOperand());
1791
2320
        __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1792
 
        __ push(r1);
 
2321
        __ Push(r0, r1);  // Function, receiver.
1793
2322
        EmitCallWithStub(expr);
1794
2323
      } else {
 
2324
        { PreservePositionScope scope(masm()->positions_recorder());
 
2325
          VisitForStackValue(prop->obj());
 
2326
        }
1795
2327
        EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
1796
2328
      }
1797
2329
    }
1805
2337
        loop_depth() == 0) {
1806
2338
      lit->set_try_full_codegen(true);
1807
2339
    }
1808
 
    VisitForValue(fun, kStack);
 
2340
 
 
2341
    { PreservePositionScope scope(masm()->positions_recorder());
 
2342
      VisitForStackValue(fun);
 
2343
    }
1809
2344
    // Load global receiver object.
1810
 
    __ ldr(r1, CodeGenerator::GlobalObject());
 
2345
    __ ldr(r1, GlobalObjectOperand());
1811
2346
    __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1812
2347
    __ push(r1);
1813
2348
    // Emit function call.
1814
2349
    EmitCallWithStub(expr);
1815
2350
  }
 
2351
 
 
2352
#ifdef DEBUG
 
2353
  // RecordJSReturnSite should have been called.
 
2354
  ASSERT(expr->return_is_recorded_);
 
2355
#endif
1816
2356
}
1817
2357
 
1818
2358
 
1821
2361
  // According to ECMA-262, section 11.2.2, page 44, the function
1822
2362
  // expression in new calls must be evaluated before the
1823
2363
  // arguments.
1824
 
  // Push function on the stack.
1825
 
  VisitForValue(expr->expression(), kStack);
1826
 
 
1827
 
  // Push global object (receiver).
1828
 
  __ ldr(r0, CodeGenerator::GlobalObject());
1829
 
  __ push(r0);
 
2364
 
 
2365
  // Push constructor on the stack.  If it's not a function it's used as
 
2366
  // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
 
2367
  // ignored.
 
2368
  VisitForStackValue(expr->expression());
 
2369
 
1830
2370
  // Push the arguments ("left-to-right") on the stack.
1831
2371
  ZoneList<Expression*>* args = expr->arguments();
1832
2372
  int arg_count = args->length();
1833
2373
  for (int i = 0; i < arg_count; i++) {
1834
 
    VisitForValue(args->at(i), kStack);
 
2374
    VisitForStackValue(args->at(i));
1835
2375
  }
1836
2376
 
1837
2377
  // Call the construct call builtin that handles allocation and
1838
2378
  // constructor invocation.
1839
2379
  SetSourcePosition(expr->position());
1840
2380
 
1841
 
  // Load function, arg_count into r1 and r0.
 
2381
  // Load function and argument count into r1 and r0.
1842
2382
  __ mov(r0, Operand(arg_count));
1843
 
  // Function is in sp[arg_count + 1].
1844
 
  __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
 
2383
  __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
1845
2384
 
1846
2385
  Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1847
2386
  __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1848
 
 
1849
 
  // Replace function on TOS with result in r0, or pop it.
1850
 
  DropAndApply(1, context_, r0);
 
2387
  context()->Plug(r0);
1851
2388
}
1852
2389
 
1853
2390
 
1854
2391
void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
1855
2392
  ASSERT(args->length() == 1);
1856
2393
 
1857
 
  VisitForValue(args->at(0), kAccumulator);
 
2394
  VisitForAccumulatorValue(args->at(0));
1858
2395
 
1859
2396
  Label materialize_true, materialize_false;
1860
2397
  Label* if_true = NULL;
1861
2398
  Label* if_false = NULL;
1862
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1863
 
 
1864
 
  __ BranchOnSmi(r0, if_true);
1865
 
  __ b(if_false);
1866
 
 
1867
 
  Apply(context_, if_true, if_false);
 
2399
  Label* fall_through = NULL;
 
2400
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2401
                         &if_true, &if_false, &fall_through);
 
2402
 
 
2403
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2404
  __ tst(r0, Operand(kSmiTagMask));
 
2405
  Split(eq, if_true, if_false, fall_through);
 
2406
 
 
2407
  context()->Plug(if_true, if_false);
1868
2408
}
1869
2409
 
1870
2410
 
1871
2411
void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
1872
2412
  ASSERT(args->length() == 1);
1873
2413
 
1874
 
  VisitForValue(args->at(0), kAccumulator);
 
2414
  VisitForAccumulatorValue(args->at(0));
1875
2415
 
1876
2416
  Label materialize_true, materialize_false;
1877
2417
  Label* if_true = NULL;
1878
2418
  Label* if_false = NULL;
1879
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2419
  Label* fall_through = NULL;
 
2420
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2421
                         &if_true, &if_false, &fall_through);
1880
2422
 
 
2423
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
1881
2424
  __ tst(r0, Operand(kSmiTagMask | 0x80000000));
1882
 
  __ b(eq, if_true);
1883
 
  __ b(if_false);
 
2425
  Split(eq, if_true, if_false, fall_through);
1884
2426
 
1885
 
  Apply(context_, if_true, if_false);
 
2427
  context()->Plug(if_true, if_false);
1886
2428
}
1887
2429
 
1888
2430
 
1889
2431
void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
1890
2432
  ASSERT(args->length() == 1);
1891
2433
 
1892
 
  VisitForValue(args->at(0), kAccumulator);
 
2434
  VisitForAccumulatorValue(args->at(0));
1893
2435
 
1894
2436
  Label materialize_true, materialize_false;
1895
2437
  Label* if_true = NULL;
1896
2438
  Label* if_false = NULL;
1897
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1898
 
  __ BranchOnSmi(r0, if_false);
 
2439
  Label* fall_through = NULL;
 
2440
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2441
                         &if_true, &if_false, &fall_through);
 
2442
 
 
2443
  __ JumpIfSmi(r0, if_false);
1899
2444
  __ LoadRoot(ip, Heap::kNullValueRootIndex);
1900
2445
  __ cmp(r0, ip);
1901
2446
  __ b(eq, if_true);
1908
2453
  __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
1909
2454
  __ b(lt, if_false);
1910
2455
  __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
1911
 
  __ b(le, if_true);
1912
 
  __ b(if_false);
 
2456
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2457
  Split(le, if_true, if_false, fall_through);
1913
2458
 
1914
 
  Apply(context_, if_true, if_false);
 
2459
  context()->Plug(if_true, if_false);
1915
2460
}
1916
2461
 
1917
2462
 
1918
2463
void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
1919
2464
  ASSERT(args->length() == 1);
1920
2465
 
1921
 
  VisitForValue(args->at(0), kAccumulator);
 
2466
  VisitForAccumulatorValue(args->at(0));
1922
2467
 
1923
2468
  Label materialize_true, materialize_false;
1924
2469
  Label* if_true = NULL;
1925
2470
  Label* if_false = NULL;
1926
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2471
  Label* fall_through = NULL;
 
2472
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2473
                         &if_true, &if_false, &fall_through);
1927
2474
 
1928
 
  __ BranchOnSmi(r0, if_false);
 
2475
  __ JumpIfSmi(r0, if_false);
1929
2476
  __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
1930
 
  __ b(ge, if_true);
1931
 
  __ b(if_false);
 
2477
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2478
  Split(ge, if_true, if_false, fall_through);
1932
2479
 
1933
 
  Apply(context_, if_true, if_false);
 
2480
  context()->Plug(if_true, if_false);
1934
2481
}
1935
2482
 
1936
2483
 
1937
2484
void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
1938
2485
  ASSERT(args->length() == 1);
1939
2486
 
1940
 
  VisitForValue(args->at(0), kAccumulator);
 
2487
  VisitForAccumulatorValue(args->at(0));
1941
2488
 
1942
2489
  Label materialize_true, materialize_false;
1943
2490
  Label* if_true = NULL;
1944
2491
  Label* if_false = NULL;
1945
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2492
  Label* fall_through = NULL;
 
2493
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2494
                         &if_true, &if_false, &fall_through);
1946
2495
 
1947
 
  __ BranchOnSmi(r0, if_false);
 
2496
  __ JumpIfSmi(r0, if_false);
1948
2497
  __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
1949
2498
  __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
1950
2499
  __ tst(r1, Operand(1 << Map::kIsUndetectable));
1951
 
  __ b(ne, if_true);
1952
 
  __ b(if_false);
 
2500
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2501
  Split(ne, if_true, if_false, fall_through);
1953
2502
 
1954
 
  Apply(context_, if_true, if_false);
 
2503
  context()->Plug(if_true, if_false);
1955
2504
}
1956
2505
 
1957
2506
 
1960
2509
 
1961
2510
  ASSERT(args->length() == 1);
1962
2511
 
1963
 
  VisitForValue(args->at(0), kAccumulator);
 
2512
  VisitForAccumulatorValue(args->at(0));
1964
2513
 
1965
2514
  Label materialize_true, materialize_false;
1966
2515
  Label* if_true = NULL;
1967
2516
  Label* if_false = NULL;
1968
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2517
  Label* fall_through = NULL;
 
2518
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2519
                         &if_true, &if_false, &fall_through);
1969
2520
 
1970
2521
  // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
1971
2522
  // used in a few functions in runtime.js which should not normally be hit by
1972
2523
  // this compiler.
 
2524
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
1973
2525
  __ jmp(if_false);
1974
 
  Apply(context_, if_true, if_false);
 
2526
  context()->Plug(if_true, if_false);
1975
2527
}
1976
2528
 
1977
2529
 
1978
2530
void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
1979
2531
  ASSERT(args->length() == 1);
1980
2532
 
1981
 
  VisitForValue(args->at(0), kAccumulator);
 
2533
  VisitForAccumulatorValue(args->at(0));
1982
2534
 
1983
2535
  Label materialize_true, materialize_false;
1984
2536
  Label* if_true = NULL;
1985
2537
  Label* if_false = NULL;
1986
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2538
  Label* fall_through = NULL;
 
2539
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2540
                         &if_true, &if_false, &fall_through);
1987
2541
 
1988
 
  __ BranchOnSmi(r0, if_false);
 
2542
  __ JumpIfSmi(r0, if_false);
1989
2543
  __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
1990
 
  __ b(eq, if_true);
1991
 
  __ b(if_false);
 
2544
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2545
  Split(eq, if_true, if_false, fall_through);
1992
2546
 
1993
 
  Apply(context_, if_true, if_false);
 
2547
  context()->Plug(if_true, if_false);
1994
2548
}
1995
2549
 
1996
2550
 
1997
2551
void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
1998
2552
  ASSERT(args->length() == 1);
1999
2553
 
2000
 
  VisitForValue(args->at(0), kAccumulator);
 
2554
  VisitForAccumulatorValue(args->at(0));
2001
2555
 
2002
2556
  Label materialize_true, materialize_false;
2003
2557
  Label* if_true = NULL;
2004
2558
  Label* if_false = NULL;
2005
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2559
  Label* fall_through = NULL;
 
2560
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2561
                         &if_true, &if_false, &fall_through);
2006
2562
 
2007
 
  __ BranchOnSmi(r0, if_false);
 
2563
  __ JumpIfSmi(r0, if_false);
2008
2564
  __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
2009
 
  __ b(eq, if_true);
2010
 
  __ b(if_false);
 
2565
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2566
  Split(eq, if_true, if_false, fall_through);
2011
2567
 
2012
 
  Apply(context_, if_true, if_false);
 
2568
  context()->Plug(if_true, if_false);
2013
2569
}
2014
2570
 
2015
2571
 
2016
2572
void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2017
2573
  ASSERT(args->length() == 1);
2018
2574
 
2019
 
  VisitForValue(args->at(0), kAccumulator);
 
2575
  VisitForAccumulatorValue(args->at(0));
2020
2576
 
2021
2577
  Label materialize_true, materialize_false;
2022
2578
  Label* if_true = NULL;
2023
2579
  Label* if_false = NULL;
2024
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2580
  Label* fall_through = NULL;
 
2581
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2582
                         &if_true, &if_false, &fall_through);
2025
2583
 
2026
 
  __ BranchOnSmi(r0, if_false);
 
2584
  __ JumpIfSmi(r0, if_false);
2027
2585
  __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
2028
 
  __ b(eq, if_true);
2029
 
  __ b(if_false);
 
2586
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2587
  Split(eq, if_true, if_false, fall_through);
2030
2588
 
2031
 
  Apply(context_, if_true, if_false);
 
2589
  context()->Plug(if_true, if_false);
2032
2590
}
2033
2591
 
2034
2592
 
2039
2597
  Label materialize_true, materialize_false;
2040
2598
  Label* if_true = NULL;
2041
2599
  Label* if_false = NULL;
2042
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2600
  Label* fall_through = NULL;
 
2601
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2602
                         &if_true, &if_false, &fall_through);
2043
2603
 
2044
2604
  // Get the frame pointer for the calling frame.
2045
2605
  __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2055
2615
  __ bind(&check_frame_marker);
2056
2616
  __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
2057
2617
  __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
2058
 
  __ b(eq, if_true);
2059
 
  __ b(if_false);
 
2618
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2619
  Split(eq, if_true, if_false, fall_through);
2060
2620
 
2061
 
  Apply(context_, if_true, if_false);
 
2621
  context()->Plug(if_true, if_false);
2062
2622
}
2063
2623
 
2064
2624
 
2066
2626
  ASSERT(args->length() == 2);
2067
2627
 
2068
2628
  // Load the two objects into registers and perform the comparison.
2069
 
  VisitForValue(args->at(0), kStack);
2070
 
  VisitForValue(args->at(1), kAccumulator);
 
2629
  VisitForStackValue(args->at(0));
 
2630
  VisitForAccumulatorValue(args->at(1));
2071
2631
 
2072
2632
  Label materialize_true, materialize_false;
2073
2633
  Label* if_true = NULL;
2074
2634
  Label* if_false = NULL;
2075
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
 
2635
  Label* fall_through = NULL;
 
2636
  context()->PrepareTest(&materialize_true, &materialize_false,
 
2637
                         &if_true, &if_false, &fall_through);
2076
2638
 
2077
2639
  __ pop(r1);
2078
2640
  __ cmp(r0, r1);
2079
 
  __ b(eq, if_true);
2080
 
  __ b(if_false);
 
2641
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
2642
  Split(eq, if_true, if_false, fall_through);
2081
2643
 
2082
 
  Apply(context_, if_true, if_false);
 
2644
  context()->Plug(if_true, if_false);
2083
2645
}
2084
2646
 
2085
2647
 
2087
2649
  ASSERT(args->length() == 1);
2088
2650
 
2089
2651
  // ArgumentsAccessStub expects the key in edx and the formal
2090
 
  // parameter count in eax.
2091
 
  VisitForValue(args->at(0), kAccumulator);
 
2652
  // parameter count in r0.
 
2653
  VisitForAccumulatorValue(args->at(0));
2092
2654
  __ mov(r1, r0);
2093
2655
  __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters())));
2094
2656
  ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2095
2657
  __ CallStub(&stub);
2096
 
  Apply(context_, r0);
 
2658
  context()->Plug(r0);
2097
2659
}
2098
2660
 
2099
2661
 
2115
2677
  __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2116
2678
 
2117
2679
  __ bind(&exit);
2118
 
  Apply(context_, r0);
 
2680
  context()->Plug(r0);
2119
2681
}
2120
2682
 
2121
2683
 
2123
2685
  ASSERT(args->length() == 1);
2124
2686
  Label done, null, function, non_function_constructor;
2125
2687
 
2126
 
  VisitForValue(args->at(0), kAccumulator);
 
2688
  VisitForAccumulatorValue(args->at(0));
2127
2689
 
2128
2690
  // If the object is a smi, we return null.
2129
 
  __ BranchOnSmi(r0, &null);
 
2691
  __ JumpIfSmi(r0, &null);
2130
2692
 
2131
2693
  // Check that the object is a JS object but take special care of JS
2132
2694
  // functions to make sure they have 'Function' as their class.
2169
2731
  // All done.
2170
2732
  __ bind(&done);
2171
2733
 
2172
 
  Apply(context_, r0);
 
2734
  context()->Plug(r0);
2173
2735
}
2174
2736
 
2175
2737
 
2184
2746
  ASSERT_EQ(args->length(), 3);
2185
2747
#ifdef ENABLE_LOGGING_AND_PROFILING
2186
2748
  if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2187
 
    VisitForValue(args->at(1), kStack);
2188
 
    VisitForValue(args->at(2), kStack);
 
2749
    VisitForStackValue(args->at(1));
 
2750
    VisitForStackValue(args->at(2));
2189
2751
    __ CallRuntime(Runtime::kLog, 2);
2190
2752
  }
2191
2753
#endif
2192
2754
  // Finally, we're expected to leave a value on the top of the stack.
2193
2755
  __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2194
 
  Apply(context_, r0);
 
2756
  context()->Plug(r0);
2195
2757
}
2196
2758
 
2197
2759
 
2227
2789
    // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
2228
2790
    __ vmov(d7, r0, r1);
2229
2791
    // Move 0x4130000000000000 to VFP.
2230
 
    __ mov(r0, Operand(0));
 
2792
    __ mov(r0, Operand(0, RelocInfo::NONE));
2231
2793
    __ vmov(d8, r0, r1);
2232
2794
    // Subtract and store the result in the heap number.
2233
2795
    __ vsub(d7, d7, d8);
2241
2803
        ExternalReference::fill_heap_number_with_random_function(), 1);
2242
2804
  }
2243
2805
 
2244
 
  Apply(context_, r0);
 
2806
  context()->Plug(r0);
2245
2807
}
2246
2808
 
2247
2809
 
2249
2811
  // Load the arguments on the stack and call the stub.
2250
2812
  SubStringStub stub;
2251
2813
  ASSERT(args->length() == 3);
2252
 
  VisitForValue(args->at(0), kStack);
2253
 
  VisitForValue(args->at(1), kStack);
2254
 
  VisitForValue(args->at(2), kStack);
 
2814
  VisitForStackValue(args->at(0));
 
2815
  VisitForStackValue(args->at(1));
 
2816
  VisitForStackValue(args->at(2));
2255
2817
  __ CallStub(&stub);
2256
 
  Apply(context_, r0);
 
2818
  context()->Plug(r0);
2257
2819
}
2258
2820
 
2259
2821
 
2261
2823
  // Load the arguments on the stack and call the stub.
2262
2824
  RegExpExecStub stub;
2263
2825
  ASSERT(args->length() == 4);
2264
 
  VisitForValue(args->at(0), kStack);
2265
 
  VisitForValue(args->at(1), kStack);
2266
 
  VisitForValue(args->at(2), kStack);
2267
 
  VisitForValue(args->at(3), kStack);
 
2826
  VisitForStackValue(args->at(0));
 
2827
  VisitForStackValue(args->at(1));
 
2828
  VisitForStackValue(args->at(2));
 
2829
  VisitForStackValue(args->at(3));
2268
2830
  __ CallStub(&stub);
2269
 
  Apply(context_, r0);
 
2831
  context()->Plug(r0);
2270
2832
}
2271
2833
 
2272
2834
 
2273
2835
void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2274
2836
  ASSERT(args->length() == 1);
2275
2837
 
2276
 
  VisitForValue(args->at(0), kAccumulator);  // Load the object.
 
2838
  VisitForAccumulatorValue(args->at(0));  // Load the object.
2277
2839
 
2278
2840
  Label done;
2279
2841
  // If the object is a smi return the object.
2280
 
  __ BranchOnSmi(r0, &done);
 
2842
  __ JumpIfSmi(r0, &done);
2281
2843
  // If the object is not a value type, return the object.
2282
2844
  __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE);
2283
2845
  __ b(ne, &done);
2284
2846
  __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
2285
2847
 
2286
2848
  __ bind(&done);
2287
 
  Apply(context_, r0);
 
2849
  context()->Plug(r0);
2288
2850
}
2289
2851
 
2290
2852
 
2291
2853
void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2292
2854
  // Load the arguments on the stack and call the runtime function.
2293
2855
  ASSERT(args->length() == 2);
2294
 
  VisitForValue(args->at(0), kStack);
2295
 
  VisitForValue(args->at(1), kStack);
 
2856
  VisitForStackValue(args->at(0));
 
2857
  VisitForStackValue(args->at(1));
2296
2858
  __ CallRuntime(Runtime::kMath_pow, 2);
2297
 
  Apply(context_, r0);
 
2859
  context()->Plug(r0);
2298
2860
}
2299
2861
 
2300
2862
 
2301
2863
void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2302
2864
  ASSERT(args->length() == 2);
2303
2865
 
2304
 
  VisitForValue(args->at(0), kStack);  // Load the object.
2305
 
  VisitForValue(args->at(1), kAccumulator);  // Load the value.
 
2866
  VisitForStackValue(args->at(0));  // Load the object.
 
2867
  VisitForAccumulatorValue(args->at(1));  // Load the value.
2306
2868
  __ pop(r1);  // r0 = value. r1 = object.
2307
2869
 
2308
2870
  Label done;
2309
2871
  // If the object is a smi, return the value.
2310
 
  __ BranchOnSmi(r1, &done);
 
2872
  __ JumpIfSmi(r1, &done);
2311
2873
 
2312
2874
  // If the object is not a value type, return the value.
2313
2875
  __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE);
2320
2882
  __ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3);
2321
2883
 
2322
2884
  __ bind(&done);
2323
 
  Apply(context_, r0);
 
2885
  context()->Plug(r0);
2324
2886
}
2325
2887
 
2326
2888
 
2328
2890
  ASSERT_EQ(args->length(), 1);
2329
2891
 
2330
2892
  // Load the argument on the stack and call the stub.
2331
 
  VisitForValue(args->at(0), kStack);
 
2893
  VisitForStackValue(args->at(0));
2332
2894
 
2333
2895
  NumberToStringStub stub;
2334
2896
  __ CallStub(&stub);
2335
 
  Apply(context_, r0);
 
2897
  context()->Plug(r0);
2336
2898
}
2337
2899
 
2338
2900
 
2339
2901
void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
2340
2902
  ASSERT(args->length() == 1);
2341
2903
 
2342
 
  VisitForValue(args->at(0), kAccumulator);
 
2904
  VisitForAccumulatorValue(args->at(0));
2343
2905
 
2344
2906
  Label done;
2345
2907
  StringCharFromCodeGenerator generator(r0, r1);
2350
2912
  generator.GenerateSlow(masm_, call_helper);
2351
2913
 
2352
2914
  __ bind(&done);
2353
 
  Apply(context_, r1);
 
2915
  context()->Plug(r1);
2354
2916
}
2355
2917
 
2356
2918
 
2357
2919
void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2358
2920
  ASSERT(args->length() == 2);
2359
2921
 
2360
 
  VisitForValue(args->at(0), kStack);
2361
 
  VisitForValue(args->at(1), kAccumulator);
 
2922
  VisitForStackValue(args->at(0));
 
2923
  VisitForAccumulatorValue(args->at(1));
2362
2924
 
2363
2925
  Register object = r1;
2364
2926
  Register index = r0;
2397
2959
  generator.GenerateSlow(masm_, call_helper);
2398
2960
 
2399
2961
  __ bind(&done);
2400
 
  Apply(context_, result);
 
2962
  context()->Plug(result);
2401
2963
}
2402
2964
 
2403
2965
 
2404
2966
void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2405
2967
  ASSERT(args->length() == 2);
2406
2968
 
2407
 
  VisitForValue(args->at(0), kStack);
2408
 
  VisitForValue(args->at(1), kAccumulator);
 
2969
  VisitForStackValue(args->at(0));
 
2970
  VisitForAccumulatorValue(args->at(1));
2409
2971
 
2410
2972
  Register object = r1;
2411
2973
  Register index = r0;
2446
3008
  generator.GenerateSlow(masm_, call_helper);
2447
3009
 
2448
3010
  __ bind(&done);
2449
 
  Apply(context_, result);
 
3011
  context()->Plug(result);
2450
3012
}
2451
3013
 
2452
3014
 
2453
3015
void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2454
3016
  ASSERT_EQ(2, args->length());
2455
3017
 
2456
 
  VisitForValue(args->at(0), kStack);
2457
 
  VisitForValue(args->at(1), kStack);
 
3018
  VisitForStackValue(args->at(0));
 
3019
  VisitForStackValue(args->at(1));
2458
3020
 
2459
3021
  StringAddStub stub(NO_STRING_ADD_FLAGS);
2460
3022
  __ CallStub(&stub);
2461
 
  Apply(context_, r0);
 
3023
  context()->Plug(r0);
2462
3024
}
2463
3025
 
2464
3026
 
2465
3027
void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2466
3028
  ASSERT_EQ(2, args->length());
2467
3029
 
2468
 
  VisitForValue(args->at(0), kStack);
2469
 
  VisitForValue(args->at(1), kStack);
 
3030
  VisitForStackValue(args->at(0));
 
3031
  VisitForStackValue(args->at(1));
2470
3032
 
2471
3033
  StringCompareStub stub;
2472
3034
  __ CallStub(&stub);
2473
 
  Apply(context_, r0);
 
3035
  context()->Plug(r0);
2474
3036
}
2475
3037
 
2476
3038
 
2477
3039
void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2478
 
  // Load the argument on the stack and call the runtime.
 
3040
  // Load the argument on the stack and call the stub.
 
3041
  TranscendentalCacheStub stub(TranscendentalCache::SIN);
2479
3042
  ASSERT(args->length() == 1);
2480
 
  VisitForValue(args->at(0), kStack);
2481
 
  __ CallRuntime(Runtime::kMath_sin, 1);
2482
 
  Apply(context_, r0);
 
3043
  VisitForStackValue(args->at(0));
 
3044
  __ CallStub(&stub);
 
3045
  context()->Plug(r0);
2483
3046
}
2484
3047
 
2485
3048
 
2486
3049
void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2487
 
  // Load the argument on the stack and call the runtime.
2488
 
  ASSERT(args->length() == 1);
2489
 
  VisitForValue(args->at(0), kStack);
2490
 
  __ CallRuntime(Runtime::kMath_cos, 1);
2491
 
  Apply(context_, r0);
 
3050
  // Load the argument on the stack and call the stub.
 
3051
  TranscendentalCacheStub stub(TranscendentalCache::COS);
 
3052
  ASSERT(args->length() == 1);
 
3053
  VisitForStackValue(args->at(0));
 
3054
  __ CallStub(&stub);
 
3055
  context()->Plug(r0);
 
3056
}
 
3057
 
 
3058
 
 
3059
void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
 
3060
  // Load the argument on the stack and call the stub.
 
3061
  TranscendentalCacheStub stub(TranscendentalCache::LOG);
 
3062
  ASSERT(args->length() == 1);
 
3063
  VisitForStackValue(args->at(0));
 
3064
  __ CallStub(&stub);
 
3065
  context()->Plug(r0);
2492
3066
}
2493
3067
 
2494
3068
 
2495
3069
void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2496
3070
  // Load the argument on the stack and call the runtime function.
2497
3071
  ASSERT(args->length() == 1);
2498
 
  VisitForValue(args->at(0), kStack);
 
3072
  VisitForStackValue(args->at(0));
2499
3073
  __ CallRuntime(Runtime::kMath_sqrt, 1);
2500
 
  Apply(context_, r0);
 
3074
  context()->Plug(r0);
2501
3075
}
2502
3076
 
2503
3077
 
2505
3079
  ASSERT(args->length() >= 2);
2506
3080
 
2507
3081
  int arg_count = args->length() - 2;  // For receiver and function.
2508
 
  VisitForValue(args->at(0), kStack);  // Receiver.
 
3082
  VisitForStackValue(args->at(0));  // Receiver.
2509
3083
  for (int i = 0; i < arg_count; i++) {
2510
 
    VisitForValue(args->at(i + 1), kStack);
 
3084
    VisitForStackValue(args->at(i + 1));
2511
3085
  }
2512
 
  VisitForValue(args->at(arg_count + 1), kAccumulator);  // Function.
 
3086
  VisitForAccumulatorValue(args->at(arg_count + 1));  // Function.
2513
3087
 
2514
3088
  // InvokeFunction requires function in r1. Move it in there.
2515
3089
  if (!result_register().is(r1)) __ mov(r1, result_register());
2516
3090
  ParameterCount count(arg_count);
2517
3091
  __ InvokeFunction(r1, count, CALL_FUNCTION);
2518
3092
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2519
 
  Apply(context_, r0);
 
3093
  context()->Plug(r0);
2520
3094
}
2521
3095
 
2522
3096
 
2523
3097
void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
 
3098
  RegExpConstructResultStub stub;
2524
3099
  ASSERT(args->length() == 3);
2525
 
  VisitForValue(args->at(0), kStack);
2526
 
  VisitForValue(args->at(1), kStack);
2527
 
  VisitForValue(args->at(2), kStack);
2528
 
  __ CallRuntime(Runtime::kRegExpConstructResult, 3);
2529
 
  Apply(context_, r0);
 
3100
  VisitForStackValue(args->at(0));
 
3101
  VisitForStackValue(args->at(1));
 
3102
  VisitForStackValue(args->at(2));
 
3103
  __ CallStub(&stub);
 
3104
  context()->Plug(r0);
2530
3105
}
2531
3106
 
2532
3107
 
2533
3108
void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2534
3109
  ASSERT(args->length() == 3);
2535
 
  VisitForValue(args->at(0), kStack);
2536
 
  VisitForValue(args->at(1), kStack);
2537
 
  VisitForValue(args->at(2), kStack);
 
3110
  VisitForStackValue(args->at(0));
 
3111
  VisitForStackValue(args->at(1));
 
3112
  VisitForStackValue(args->at(2));
2538
3113
  __ CallRuntime(Runtime::kSwapElements, 3);
2539
 
  Apply(context_, r0);
 
3114
  context()->Plug(r0);
2540
3115
}
2541
3116
 
2542
3117
 
2551
3126
  if (jsfunction_result_caches->length() <= cache_id) {
2552
3127
    __ Abort("Attempt to use undefined cache.");
2553
3128
    __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2554
 
    Apply(context_, r0);
 
3129
    context()->Plug(r0);
2555
3130
    return;
2556
3131
  }
2557
3132
 
2558
 
  VisitForValue(args->at(1), kAccumulator);
 
3133
  VisitForAccumulatorValue(args->at(1));
2559
3134
 
2560
3135
  Register key = r0;
2561
3136
  Register cache = r1;
2562
 
  __ ldr(cache, CodeGenerator::ContextOperand(cp, Context::GLOBAL_INDEX));
 
3137
  __ ldr(cache, ContextOperand(cp, Context::GLOBAL_INDEX));
2563
3138
  __ ldr(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset));
2564
 
  __ ldr(cache,
2565
 
         CodeGenerator::ContextOperand(
2566
 
             cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
 
3139
  __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
2567
3140
  __ ldr(cache,
2568
3141
         FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
2569
3142
 
2589
3162
  __ CallRuntime(Runtime::kGetFromCache, 2);
2590
3163
 
2591
3164
  __ bind(&done);
2592
 
  Apply(context_, r0);
 
3165
  context()->Plug(r0);
2593
3166
}
2594
3167
 
2595
3168
 
2601
3174
  Register tmp = r2;
2602
3175
  Register tmp2 = r3;
2603
3176
 
2604
 
  VisitForValue(args->at(0), kStack);
2605
 
  VisitForValue(args->at(1), kAccumulator);
 
3177
  VisitForStackValue(args->at(0));
 
3178
  VisitForAccumulatorValue(args->at(1));
2606
3179
  __ pop(left);
2607
3180
 
2608
3181
  Label done, fail, ok;
2630
3203
  __ LoadRoot(r0, Heap::kTrueValueRootIndex);
2631
3204
  __ bind(&done);
2632
3205
 
2633
 
  Apply(context_, r0);
 
3206
  context()->Plug(r0);
 
3207
}
 
3208
 
 
3209
 
 
3210
void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
 
3211
  VisitForAccumulatorValue(args->at(0));
 
3212
 
 
3213
  Label materialize_true, materialize_false;
 
3214
  Label* if_true = NULL;
 
3215
  Label* if_false = NULL;
 
3216
  Label* fall_through = NULL;
 
3217
  context()->PrepareTest(&materialize_true, &materialize_false,
 
3218
                         &if_true, &if_false, &fall_through);
 
3219
 
 
3220
  __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
 
3221
  __ tst(r0, Operand(String::kContainsCachedArrayIndexMask));
 
3222
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
3223
  Split(eq, if_true, if_false, fall_through);
 
3224
 
 
3225
  context()->Plug(if_true, if_false);
 
3226
}
 
3227
 
 
3228
 
 
3229
void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
 
3230
  ASSERT(args->length() == 1);
 
3231
  VisitForAccumulatorValue(args->at(0));
 
3232
 
 
3233
  if (FLAG_debug_code) {
 
3234
    __ AbortIfNotString(r0);
 
3235
  }
 
3236
 
 
3237
  __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
 
3238
  __ IndexFromHash(r0, r0);
 
3239
 
 
3240
  context()->Plug(r0);
 
3241
}
 
3242
 
 
3243
 
 
3244
void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
 
3245
  Label bailout, done, one_char_separator, long_separator,
 
3246
      non_trivial_array, not_size_one_array, loop,
 
3247
      empty_separator_loop, one_char_separator_loop,
 
3248
      one_char_separator_loop_entry, long_separator_loop;
 
3249
 
 
3250
  ASSERT(args->length() == 2);
 
3251
  VisitForStackValue(args->at(1));
 
3252
  VisitForAccumulatorValue(args->at(0));
 
3253
 
 
3254
  // All aliases of the same register have disjoint lifetimes.
 
3255
  Register array = r0;
 
3256
  Register elements = no_reg;  // Will be r0.
 
3257
  Register result = no_reg;  // Will be r0.
 
3258
  Register separator = r1;
 
3259
  Register array_length = r2;
 
3260
  Register result_pos = no_reg;  // Will be r2
 
3261
  Register string_length = r3;
 
3262
  Register string = r4;
 
3263
  Register element = r5;
 
3264
  Register elements_end = r6;
 
3265
  Register scratch1 = r7;
 
3266
  Register scratch2 = r9;
 
3267
 
 
3268
  // Separator operand is on the stack.
 
3269
  __ pop(separator);
 
3270
 
 
3271
  // Check that the array is a JSArray.
 
3272
  __ JumpIfSmi(array, &bailout);
 
3273
  __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE);
 
3274
  __ b(ne, &bailout);
 
3275
 
 
3276
  // Check that the array has fast elements.
 
3277
  __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
 
3278
  __ tst(scratch2, Operand(1 << Map::kHasFastElements));
 
3279
  __ b(eq, &bailout);
 
3280
 
 
3281
  // If the array has length zero, return the empty string.
 
3282
  __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
 
3283
  __ SmiUntag(array_length, SetCC);
 
3284
  __ b(ne, &non_trivial_array);
 
3285
  __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
 
3286
  __ b(&done);
 
3287
 
 
3288
  __ bind(&non_trivial_array);
 
3289
 
 
3290
  // Get the FixedArray containing array's elements.
 
3291
  elements = array;
 
3292
  __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset));
 
3293
  array = no_reg;  // End of array's live range.
 
3294
 
 
3295
  // Check that all array elements are sequential ASCII strings, and
 
3296
  // accumulate the sum of their lengths, as a smi-encoded value.
 
3297
  __ mov(string_length, Operand(0));
 
3298
  __ add(element,
 
3299
         elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
 
3300
  __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
 
3301
  // Loop condition: while (element < elements_end).
 
3302
  // Live values in registers:
 
3303
  //   elements: Fixed array of strings.
 
3304
  //   array_length: Length of the fixed array of strings (not smi)
 
3305
  //   separator: Separator string
 
3306
  //   string_length: Accumulated sum of string lengths (smi).
 
3307
  //   element: Current array element.
 
3308
  //   elements_end: Array end.
 
3309
  if (FLAG_debug_code) {
 
3310
    __ cmp(array_length, Operand(0));
 
3311
    __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin");
 
3312
  }
 
3313
  __ bind(&loop);
 
3314
  __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
 
3315
  __ JumpIfSmi(string, &bailout);
 
3316
  __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
 
3317
  __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
 
3318
  __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
 
3319
  __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset));
 
3320
  __ add(string_length, string_length, Operand(scratch1));
 
3321
  __ b(vs, &bailout);
 
3322
  __ cmp(element, elements_end);
 
3323
  __ b(lt, &loop);
 
3324
 
 
3325
  // If array_length is 1, return elements[0], a string.
 
3326
  __ cmp(array_length, Operand(1));
 
3327
  __ b(ne, &not_size_one_array);
 
3328
  __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize));
 
3329
  __ b(&done);
 
3330
 
 
3331
  __ bind(&not_size_one_array);
 
3332
 
 
3333
  // Live values in registers:
 
3334
  //   separator: Separator string
 
3335
  //   array_length: Length of the array.
 
3336
  //   string_length: Sum of string lengths (smi).
 
3337
  //   elements: FixedArray of strings.
 
3338
 
 
3339
  // Check that the separator is a flat ASCII string.
 
3340
  __ JumpIfSmi(separator, &bailout);
 
3341
  __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
 
3342
  __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
 
3343
  __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
 
3344
 
 
3345
  // Add (separator length times array_length) - separator length to the
 
3346
  // string_length to get the length of the result string. array_length is not
 
3347
  // smi but the other values are, so the result is a smi
 
3348
  __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
 
3349
  __ sub(string_length, string_length, Operand(scratch1));
 
3350
  __ smull(scratch2, ip, array_length, scratch1);
 
3351
  // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
 
3352
  // zero.
 
3353
  __ cmp(ip, Operand(0));
 
3354
  __ b(ne, &bailout);
 
3355
  __ tst(scratch2, Operand(0x80000000));
 
3356
  __ b(ne, &bailout);
 
3357
  __ add(string_length, string_length, Operand(scratch2));
 
3358
  __ b(vs, &bailout);
 
3359
  __ SmiUntag(string_length);
 
3360
 
 
3361
  // Get first element in the array to free up the elements register to be used
 
3362
  // for the result.
 
3363
  __ add(element,
 
3364
         elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
 
3365
  result = elements;  // End of live range for elements.
 
3366
  elements = no_reg;
 
3367
  // Live values in registers:
 
3368
  //   element: First array element
 
3369
  //   separator: Separator string
 
3370
  //   string_length: Length of result string (not smi)
 
3371
  //   array_length: Length of the array.
 
3372
  __ AllocateAsciiString(result,
 
3373
                         string_length,
 
3374
                         scratch1,
 
3375
                         scratch2,
 
3376
                         elements_end,
 
3377
                         &bailout);
 
3378
  // Prepare for looping. Set up elements_end to end of the array. Set
 
3379
  // result_pos to the position of the result where to write the first
 
3380
  // character.
 
3381
  __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
 
3382
  result_pos = array_length;  // End of live range for array_length.
 
3383
  array_length = no_reg;
 
3384
  __ add(result_pos,
 
3385
         result,
 
3386
         Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
3387
 
 
3388
  // Check the length of the separator.
 
3389
  __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
 
3390
  __ cmp(scratch1, Operand(Smi::FromInt(1)));
 
3391
  __ b(eq, &one_char_separator);
 
3392
  __ b(gt, &long_separator);
 
3393
 
 
3394
  // Empty separator case
 
3395
  __ bind(&empty_separator_loop);
 
3396
  // Live values in registers:
 
3397
  //   result_pos: the position to which we are currently copying characters.
 
3398
  //   element: Current array element.
 
3399
  //   elements_end: Array end.
 
3400
 
 
3401
  // Copy next array element to the result.
 
3402
  __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
 
3403
  __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
 
3404
  __ SmiUntag(string_length);
 
3405
  __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
3406
  __ CopyBytes(string, result_pos, string_length, scratch1);
 
3407
  __ cmp(element, elements_end);
 
3408
  __ b(lt, &empty_separator_loop);  // End while (element < elements_end).
 
3409
  ASSERT(result.is(r0));
 
3410
  __ b(&done);
 
3411
 
 
3412
  // One-character separator case
 
3413
  __ bind(&one_char_separator);
 
3414
  // Replace separator with its ascii character value.
 
3415
  __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize));
 
3416
  // Jump into the loop after the code that copies the separator, so the first
 
3417
  // element is not preceded by a separator
 
3418
  __ jmp(&one_char_separator_loop_entry);
 
3419
 
 
3420
  __ bind(&one_char_separator_loop);
 
3421
  // Live values in registers:
 
3422
  //   result_pos: the position to which we are currently copying characters.
 
3423
  //   element: Current array element.
 
3424
  //   elements_end: Array end.
 
3425
  //   separator: Single separator ascii char (in lower byte).
 
3426
 
 
3427
  // Copy the separator character to the result.
 
3428
  __ strb(separator, MemOperand(result_pos, 1, PostIndex));
 
3429
 
 
3430
  // Copy next array element to the result.
 
3431
  __ bind(&one_char_separator_loop_entry);
 
3432
  __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
 
3433
  __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
 
3434
  __ SmiUntag(string_length);
 
3435
  __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
3436
  __ CopyBytes(string, result_pos, string_length, scratch1);
 
3437
  __ cmp(element, elements_end);
 
3438
  __ b(lt, &one_char_separator_loop);  // End while (element < elements_end).
 
3439
  ASSERT(result.is(r0));
 
3440
  __ b(&done);
 
3441
 
 
3442
  // Long separator case (separator is more than one character). Entry is at the
 
3443
  // label long_separator below.
 
3444
  __ bind(&long_separator_loop);
 
3445
  // Live values in registers:
 
3446
  //   result_pos: the position to which we are currently copying characters.
 
3447
  //   element: Current array element.
 
3448
  //   elements_end: Array end.
 
3449
  //   separator: Separator string.
 
3450
 
 
3451
  // Copy the separator to the result.
 
3452
  __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset));
 
3453
  __ SmiUntag(string_length);
 
3454
  __ add(string,
 
3455
         separator,
 
3456
         Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
3457
  __ CopyBytes(string, result_pos, string_length, scratch1);
 
3458
 
 
3459
  __ bind(&long_separator);
 
3460
  __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
 
3461
  __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
 
3462
  __ SmiUntag(string_length);
 
3463
  __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
3464
  __ CopyBytes(string, result_pos, string_length, scratch1);
 
3465
  __ cmp(element, elements_end);
 
3466
  __ b(lt, &long_separator_loop);  // End while (element < elements_end).
 
3467
  ASSERT(result.is(r0));
 
3468
  __ b(&done);
 
3469
 
 
3470
  __ bind(&bailout);
 
3471
  __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
 
3472
  __ bind(&done);
 
3473
  context()->Plug(r0);
2634
3474
}
2635
3475
 
2636
3476
 
2647
3487
 
2648
3488
  if (expr->is_jsruntime()) {
2649
3489
    // Prepare for calling JS runtime function.
2650
 
    __ ldr(r0, CodeGenerator::GlobalObject());
 
3490
    __ ldr(r0, GlobalObjectOperand());
2651
3491
    __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
2652
3492
    __ push(r0);
2653
3493
  }
2655
3495
  // Push the arguments ("left-to-right").
2656
3496
  int arg_count = args->length();
2657
3497
  for (int i = 0; i < arg_count; i++) {
2658
 
    VisitForValue(args->at(i), kStack);
 
3498
    VisitForStackValue(args->at(i));
2659
3499
  }
2660
3500
 
2661
3501
  if (expr->is_jsruntime()) {
2662
3502
    // Call the JS runtime function.
2663
3503
    __ mov(r2, Operand(expr->name()));
2664
 
    Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
2665
 
                                                           NOT_IN_LOOP);
2666
 
    __ Call(ic, RelocInfo::CODE_TARGET);
 
3504
    Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, NOT_IN_LOOP);
 
3505
    EmitCallIC(ic, RelocInfo::CODE_TARGET);
2667
3506
    // Restore context register.
2668
3507
    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2669
3508
  } else {
2670
3509
    // Call the C runtime function.
2671
3510
    __ CallRuntime(expr->function(), arg_count);
2672
3511
  }
2673
 
  Apply(context_, r0);
 
3512
  context()->Plug(r0);
2674
3513
}
2675
3514
 
2676
3515
 
2680
3519
      Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2681
3520
      Property* prop = expr->expression()->AsProperty();
2682
3521
      Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
2683
 
      if (prop == NULL && var == NULL) {
 
3522
 
 
3523
      if (prop != NULL) {
 
3524
        if (prop->is_synthetic()) {
 
3525
          // Result of deleting parameters is false, even when they rewrite
 
3526
          // to accesses on the arguments object.
 
3527
          context()->Plug(false);
 
3528
        } else {
 
3529
          VisitForStackValue(prop->obj());
 
3530
          VisitForStackValue(prop->key());
 
3531
          __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
 
3532
          __ push(r1);
 
3533
          __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
 
3534
          context()->Plug(r0);
 
3535
        }
 
3536
      } else if (var != NULL) {
 
3537
        // Delete of an unqualified identifier is disallowed in strict mode
 
3538
        // but "delete this" is.
 
3539
        ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
 
3540
        if (var->is_global()) {
 
3541
          __ ldr(r2, GlobalObjectOperand());
 
3542
          __ mov(r1, Operand(var->name()));
 
3543
          __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
 
3544
          __ Push(r2, r1, r0);
 
3545
          __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
 
3546
          context()->Plug(r0);
 
3547
        } else if (var->AsSlot() != NULL &&
 
3548
                   var->AsSlot()->type() != Slot::LOOKUP) {
 
3549
          // Result of deleting non-global, non-dynamic variables is false.
 
3550
          // The subexpression does not have side effects.
 
3551
          context()->Plug(false);
 
3552
        } else {
 
3553
          // Non-global variable.  Call the runtime to try to delete from the
 
3554
          // context where the variable was introduced.
 
3555
          __ push(context_register());
 
3556
          __ mov(r2, Operand(var->name()));
 
3557
          __ push(r2);
 
3558
          __ CallRuntime(Runtime::kDeleteContextSlot, 2);
 
3559
          context()->Plug(r0);
 
3560
        }
 
3561
      } else {
2684
3562
        // Result of deleting non-property, non-variable reference is true.
2685
3563
        // The subexpression may have side effects.
2686
3564
        VisitForEffect(expr->expression());
2687
 
        Apply(context_, true);
2688
 
      } else if (var != NULL &&
2689
 
                 !var->is_global() &&
2690
 
                 var->slot() != NULL &&
2691
 
                 var->slot()->type() != Slot::LOOKUP) {
2692
 
        // Result of deleting non-global, non-dynamic variables is false.
2693
 
        // The subexpression does not have side effects.
2694
 
        Apply(context_, false);
2695
 
      } else {
2696
 
        // Property or variable reference.  Call the delete builtin with
2697
 
        // object and property name as arguments.
2698
 
        if (prop != NULL) {
2699
 
          VisitForValue(prop->obj(), kStack);
2700
 
          VisitForValue(prop->key(), kStack);
2701
 
        } else if (var->is_global()) {
2702
 
          __ ldr(r1, CodeGenerator::GlobalObject());
2703
 
          __ mov(r0, Operand(var->name()));
2704
 
          __ Push(r1, r0);
2705
 
        } else {
2706
 
          // Non-global variable.  Call the runtime to look up the context
2707
 
          // where the variable was introduced.
2708
 
          __ push(context_register());
2709
 
          __ mov(r2, Operand(var->name()));
2710
 
          __ push(r2);
2711
 
          __ CallRuntime(Runtime::kLookupContext, 2);
2712
 
          __ push(r0);
2713
 
          __ mov(r2, Operand(var->name()));
2714
 
          __ push(r2);
2715
 
        }
2716
 
        __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
2717
 
        Apply(context_, r0);
 
3565
        context()->Plug(true);
2718
3566
      }
2719
3567
      break;
2720
3568
    }
2722
3570
    case Token::VOID: {
2723
3571
      Comment cmnt(masm_, "[ UnaryOperation (VOID)");
2724
3572
      VisitForEffect(expr->expression());
2725
 
      switch (context_) {
2726
 
        case Expression::kUninitialized:
2727
 
          UNREACHABLE();
2728
 
          break;
2729
 
        case Expression::kEffect:
2730
 
          break;
2731
 
        case Expression::kValue:
2732
 
          __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
2733
 
          switch (location_) {
2734
 
            case kAccumulator:
2735
 
              break;
2736
 
            case kStack:
2737
 
              __ push(result_register());
2738
 
              break;
2739
 
          }
2740
 
          break;
2741
 
        case Expression::kTestValue:
2742
 
          // Value is false so it's needed.
2743
 
          __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
2744
 
          switch (location_) {
2745
 
            case kAccumulator:
2746
 
              break;
2747
 
            case kStack:
2748
 
              __ push(result_register());
2749
 
              break;
2750
 
          }
2751
 
          // Fall through.
2752
 
        case Expression::kTest:
2753
 
        case Expression::kValueTest:
2754
 
          __ jmp(false_label_);
2755
 
          break;
2756
 
      }
 
3573
      context()->Plug(Heap::kUndefinedValueRootIndex);
2757
3574
      break;
2758
3575
    }
2759
3576
 
2760
3577
    case Token::NOT: {
2761
3578
      Comment cmnt(masm_, "[ UnaryOperation (NOT)");
2762
 
      Label materialize_true, materialize_false;
2763
 
      Label* if_true = NULL;
2764
 
      Label* if_false = NULL;
2765
 
 
2766
 
      // Notice that the labels are swapped.
2767
 
      PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
2768
 
 
2769
 
      VisitForControl(expr->expression(), if_true, if_false);
2770
 
 
2771
 
      Apply(context_, if_false, if_true);  // Labels swapped.
 
3579
      if (context()->IsEffect()) {
 
3580
        // Unary NOT has no side effects so it's only necessary to visit the
 
3581
        // subexpression.  Match the optimizing compiler by not branching.
 
3582
        VisitForEffect(expr->expression());
 
3583
      } else {
 
3584
        Label materialize_true, materialize_false;
 
3585
        Label* if_true = NULL;
 
3586
        Label* if_false = NULL;
 
3587
        Label* fall_through = NULL;
 
3588
 
 
3589
        // Notice that the labels are swapped.
 
3590
        context()->PrepareTest(&materialize_true, &materialize_false,
 
3591
                               &if_false, &if_true, &fall_through);
 
3592
        if (context()->IsTest()) ForwardBailoutToChild(expr);
 
3593
        VisitForControl(expr->expression(), if_true, if_false, fall_through);
 
3594
        context()->Plug(if_false, if_true);  // Labels swapped.
 
3595
      }
2772
3596
      break;
2773
3597
    }
2774
3598
 
2775
3599
    case Token::TYPEOF: {
2776
3600
      Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
2777
 
      VariableProxy* proxy = expr->expression()->AsVariableProxy();
2778
 
      if (proxy != NULL &&
2779
 
          !proxy->var()->is_this() &&
2780
 
          proxy->var()->is_global()) {
2781
 
        Comment cmnt(masm_, "Global variable");
2782
 
        __ ldr(r0, CodeGenerator::GlobalObject());
2783
 
        __ mov(r2, Operand(proxy->name()));
2784
 
        Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
2785
 
        // Use a regular load, not a contextual load, to avoid a reference
2786
 
        // error.
2787
 
        __ Call(ic, RelocInfo::CODE_TARGET);
2788
 
        __ push(r0);
2789
 
      } else if (proxy != NULL &&
2790
 
                 proxy->var()->slot() != NULL &&
2791
 
                 proxy->var()->slot()->type() == Slot::LOOKUP) {
2792
 
        __ mov(r0, Operand(proxy->name()));
2793
 
        __ Push(cp, r0);
2794
 
        __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
2795
 
        __ push(r0);
2796
 
      } else {
2797
 
        // This expression cannot throw a reference error at the top level.
2798
 
        VisitForValue(expr->expression(), kStack);
 
3601
      { StackValueContext context(this);
 
3602
        VisitForTypeofValue(expr->expression());
2799
3603
      }
2800
 
 
2801
3604
      __ CallRuntime(Runtime::kTypeof, 1);
2802
 
      Apply(context_, r0);
 
3605
      context()->Plug(r0);
2803
3606
      break;
2804
3607
    }
2805
3608
 
2806
3609
    case Token::ADD: {
2807
3610
      Comment cmt(masm_, "[ UnaryOperation (ADD)");
2808
 
      VisitForValue(expr->expression(), kAccumulator);
 
3611
      VisitForAccumulatorValue(expr->expression());
2809
3612
      Label no_conversion;
2810
3613
      __ tst(result_register(), Operand(kSmiTagMask));
2811
3614
      __ b(eq, &no_conversion);
2812
 
      __ push(r0);
2813
 
      __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
 
3615
      ToNumberStub convert_stub;
 
3616
      __ CallStub(&convert_stub);
2814
3617
      __ bind(&no_conversion);
2815
 
      Apply(context_, result_register());
 
3618
      context()->Plug(result_register());
2816
3619
      break;
2817
3620
    }
2818
3621
 
2819
3622
    case Token::SUB: {
2820
3623
      Comment cmt(masm_, "[ UnaryOperation (SUB)");
2821
 
      bool can_overwrite =
2822
 
          (expr->expression()->AsBinaryOperation() != NULL &&
2823
 
           expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
 
3624
      bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
2824
3625
      UnaryOverwriteMode overwrite =
2825
3626
          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
2826
 
      GenericUnaryOpStub stub(Token::SUB, overwrite);
 
3627
      GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
2827
3628
      // GenericUnaryOpStub expects the argument to be in the
2828
3629
      // accumulator register r0.
2829
 
      VisitForValue(expr->expression(), kAccumulator);
 
3630
      VisitForAccumulatorValue(expr->expression());
2830
3631
      __ CallStub(&stub);
2831
 
      Apply(context_, r0);
 
3632
      context()->Plug(r0);
2832
3633
      break;
2833
3634
    }
2834
3635
 
2835
3636
    case Token::BIT_NOT: {
2836
3637
      Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
2837
 
      bool can_overwrite =
2838
 
          (expr->expression()->AsBinaryOperation() != NULL &&
2839
 
           expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
2840
 
      UnaryOverwriteMode overwrite =
2841
 
          can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
2842
 
      GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
2843
 
      // GenericUnaryOpStub expects the argument to be in the
2844
 
      // accumulator register r0.
2845
 
      VisitForValue(expr->expression(), kAccumulator);
2846
 
      // Avoid calling the stub for Smis.
2847
 
      Label smi, done;
2848
 
      __ BranchOnSmi(result_register(), &smi);
2849
 
      // Non-smi: call stub leaving result in accumulator register.
 
3638
      // The generic unary operation stub expects the argument to be
 
3639
      // in the accumulator register r0.
 
3640
      VisitForAccumulatorValue(expr->expression());
 
3641
      Label done;
 
3642
      bool inline_smi_code = ShouldInlineSmiCase(expr->op());
 
3643
      if (inline_smi_code) {
 
3644
        Label call_stub;
 
3645
        __ JumpIfNotSmi(r0, &call_stub);
 
3646
        __ mvn(r0, Operand(r0));
 
3647
        // Bit-clear inverted smi-tag.
 
3648
        __ bic(r0, r0, Operand(kSmiTagMask));
 
3649
        __ b(&done);
 
3650
        __ bind(&call_stub);
 
3651
      }
 
3652
      bool overwrite = expr->expression()->ResultOverwriteAllowed();
 
3653
      UnaryOpFlags flags = inline_smi_code
 
3654
          ? NO_UNARY_SMI_CODE_IN_STUB
 
3655
          : NO_UNARY_FLAGS;
 
3656
      UnaryOverwriteMode mode =
 
3657
          overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
 
3658
      GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
2850
3659
      __ CallStub(&stub);
2851
 
      __ b(&done);
2852
 
      // Perform operation directly on Smis.
2853
 
      __ bind(&smi);
2854
 
      __ mvn(result_register(), Operand(result_register()));
2855
 
      // Bit-clear inverted smi-tag.
2856
 
      __ bic(result_register(), result_register(), Operand(kSmiTagMask));
2857
3660
      __ bind(&done);
2858
 
      Apply(context_, result_register());
 
3661
      context()->Plug(r0);
2859
3662
      break;
2860
3663
    }
2861
3664
 
2867
3670
 
2868
3671
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
2869
3672
  Comment cmnt(masm_, "[ CountOperation");
 
3673
  SetSourcePosition(expr->position());
 
3674
 
2870
3675
  // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
2871
3676
  // as the left-hand side.
2872
3677
  if (!expr->expression()->IsValidLeftHandSide()) {
2889
3694
  // Evaluate expression and get value.
2890
3695
  if (assign_type == VARIABLE) {
2891
3696
    ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
2892
 
    Location saved_location = location_;
2893
 
    location_ = kAccumulator;
2894
 
    EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
2895
 
                     Expression::kValue);
2896
 
    location_ = saved_location;
 
3697
    AccumulatorValueContext context(this);
 
3698
    EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
2897
3699
  } else {
2898
3700
    // Reserve space for result of postfix operation.
2899
 
    if (expr->is_postfix() && context_ != Expression::kEffect) {
 
3701
    if (expr->is_postfix() && !context()->IsEffect()) {
2900
3702
      __ mov(ip, Operand(Smi::FromInt(0)));
2901
3703
      __ push(ip);
2902
3704
    }
2903
3705
    if (assign_type == NAMED_PROPERTY) {
2904
3706
      // Put the object both on the stack and in the accumulator.
2905
 
      VisitForValue(prop->obj(), kAccumulator);
 
3707
      VisitForAccumulatorValue(prop->obj());
2906
3708
      __ push(r0);
2907
3709
      EmitNamedPropertyLoad(prop);
2908
3710
    } else {
2909
 
      VisitForValue(prop->obj(), kStack);
2910
 
      VisitForValue(prop->key(), kAccumulator);
 
3711
      if (prop->is_arguments_access()) {
 
3712
        VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
 
3713
        __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0));
 
3714
        __ push(r0);
 
3715
        __ mov(r0, Operand(prop->key()->AsLiteral()->handle()));
 
3716
      } else {
 
3717
        VisitForStackValue(prop->obj());
 
3718
        VisitForAccumulatorValue(prop->key());
 
3719
      }
2911
3720
      __ ldr(r1, MemOperand(sp, 0));
2912
3721
      __ push(r0);
2913
3722
      EmitKeyedPropertyLoad(prop);
2914
3723
    }
2915
3724
  }
2916
3725
 
 
3726
  // We need a second deoptimization point after loading the value
 
3727
  // in case evaluating the property load my have a side effect.
 
3728
  PrepareForBailout(expr->increment(), TOS_REG);
 
3729
 
2917
3730
  // Call ToNumber only if operand is not a smi.
2918
3731
  Label no_conversion;
2919
 
  __ BranchOnSmi(r0, &no_conversion);
2920
 
  __ push(r0);
2921
 
  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
 
3732
  __ JumpIfSmi(r0, &no_conversion);
 
3733
  ToNumberStub convert_stub;
 
3734
  __ CallStub(&convert_stub);
2922
3735
  __ bind(&no_conversion);
2923
3736
 
2924
3737
  // Save result for postfix expressions.
2925
3738
  if (expr->is_postfix()) {
2926
 
    switch (context_) {
2927
 
      case Expression::kUninitialized:
2928
 
        UNREACHABLE();
2929
 
      case Expression::kEffect:
2930
 
        // Do not save result.
2931
 
        break;
2932
 
      case Expression::kValue:
2933
 
      case Expression::kTest:
2934
 
      case Expression::kValueTest:
2935
 
      case Expression::kTestValue:
2936
 
        // Save the result on the stack. If we have a named or keyed property
2937
 
        // we store the result under the receiver that is currently on top
2938
 
        // of the stack.
2939
 
        switch (assign_type) {
2940
 
          case VARIABLE:
2941
 
            __ push(r0);
2942
 
            break;
2943
 
          case NAMED_PROPERTY:
2944
 
            __ str(r0, MemOperand(sp, kPointerSize));
2945
 
            break;
2946
 
          case KEYED_PROPERTY:
2947
 
            __ str(r0, MemOperand(sp, 2 * kPointerSize));
2948
 
            break;
2949
 
        }
2950
 
        break;
 
3739
    if (!context()->IsEffect()) {
 
3740
      // Save the result on the stack. If we have a named or keyed property
 
3741
      // we store the result under the receiver that is currently on top
 
3742
      // of the stack.
 
3743
      switch (assign_type) {
 
3744
        case VARIABLE:
 
3745
          __ push(r0);
 
3746
          break;
 
3747
        case NAMED_PROPERTY:
 
3748
          __ str(r0, MemOperand(sp, kPointerSize));
 
3749
          break;
 
3750
        case KEYED_PROPERTY:
 
3751
          __ str(r0, MemOperand(sp, 2 * kPointerSize));
 
3752
          break;
 
3753
      }
2951
3754
    }
2952
3755
  }
2953
3756
 
2954
3757
 
2955
3758
  // Inline smi case if we are in a loop.
2956
3759
  Label stub_call, done;
 
3760
  JumpPatchSite patch_site(masm_);
 
3761
 
2957
3762
  int count_value = expr->op() == Token::INC ? 1 : -1;
2958
 
  if (loop_depth() > 0) {
 
3763
  if (ShouldInlineSmiCase(expr->op())) {
2959
3764
    __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
2960
3765
    __ b(vs, &stub_call);
2961
3766
    // We could eliminate this smi check if we split the code at
2962
3767
    // the first smi check before calling ToNumber.
2963
 
    __ BranchOnSmi(r0, &done);
 
3768
    patch_site.EmitJumpIfSmi(r0, &done);
 
3769
 
2964
3770
    __ bind(&stub_call);
2965
3771
    // Call stub. Undo operation first.
2966
3772
    __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
2967
3773
  }
2968
3774
  __ mov(r1, Operand(Smi::FromInt(count_value)));
2969
 
  GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0);
2970
 
  __ CallStub(&stub);
 
3775
 
 
3776
  // Record position before stub call.
 
3777
  SetSourcePosition(expr->position());
 
3778
 
 
3779
  TypeRecordingBinaryOpStub stub(Token::ADD, NO_OVERWRITE);
 
3780
  EmitCallIC(stub.GetCode(), &patch_site);
2971
3781
  __ bind(&done);
2972
3782
 
2973
3783
  // Store the value returned in r0.
2974
3784
  switch (assign_type) {
2975
3785
    case VARIABLE:
2976
3786
      if (expr->is_postfix()) {
2977
 
        EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
2978
 
                               Token::ASSIGN,
2979
 
                               Expression::kEffect);
2980
 
        // For all contexts except kEffect: We have the result on
 
3787
        { EffectContext context(this);
 
3788
          EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
 
3789
                                 Token::ASSIGN);
 
3790
          PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
 
3791
          context.Plug(r0);
 
3792
        }
 
3793
        // For all contexts except EffectConstant We have the result on
2981
3794
        // top of the stack.
2982
 
        if (context_ != Expression::kEffect) {
2983
 
          ApplyTOS(context_);
 
3795
        if (!context()->IsEffect()) {
 
3796
          context()->PlugTOS();
2984
3797
        }
2985
3798
      } else {
2986
3799
        EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
2987
 
                               Token::ASSIGN,
2988
 
                               context_);
 
3800
                               Token::ASSIGN);
 
3801
        PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
 
3802
        context()->Plug(r0);
2989
3803
      }
2990
3804
      break;
2991
3805
    case NAMED_PROPERTY: {
2992
3806
      __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
2993
3807
      __ pop(r1);
2994
 
      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
2995
 
      __ Call(ic, RelocInfo::CODE_TARGET);
 
3808
      Handle<Code> ic(Builtins::builtin(
 
3809
          is_strict() ? Builtins::StoreIC_Initialize_Strict
 
3810
                      : Builtins::StoreIC_Initialize));
 
3811
      EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
3812
      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2996
3813
      if (expr->is_postfix()) {
2997
 
        if (context_ != Expression::kEffect) {
2998
 
          ApplyTOS(context_);
 
3814
        if (!context()->IsEffect()) {
 
3815
          context()->PlugTOS();
2999
3816
        }
3000
3817
      } else {
3001
 
        Apply(context_, r0);
 
3818
        context()->Plug(r0);
3002
3819
      }
3003
3820
      break;
3004
3821
    }
3005
3822
    case KEYED_PROPERTY: {
3006
3823
      __ pop(r1);  // Key.
3007
3824
      __ pop(r2);  // Receiver.
3008
 
      Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
3009
 
      __ Call(ic, RelocInfo::CODE_TARGET);
 
3825
      Handle<Code> ic(Builtins::builtin(
 
3826
          is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
 
3827
                      : Builtins::KeyedStoreIC_Initialize));
 
3828
      EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
3829
      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3010
3830
      if (expr->is_postfix()) {
3011
 
        if (context_ != Expression::kEffect) {
3012
 
          ApplyTOS(context_);
 
3831
        if (!context()->IsEffect()) {
 
3832
          context()->PlugTOS();
3013
3833
        }
3014
3834
      } else {
3015
 
        Apply(context_, r0);
 
3835
        context()->Plug(r0);
3016
3836
      }
3017
3837
      break;
3018
3838
    }
3020
3840
}
3021
3841
 
3022
3842
 
3023
 
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
3024
 
  Comment cmnt(masm_, "[ BinaryOperation");
3025
 
  switch (expr->op()) {
3026
 
    case Token::COMMA:
3027
 
      VisitForEffect(expr->left());
3028
 
      Visit(expr->right());
3029
 
      break;
3030
 
 
3031
 
    case Token::OR:
3032
 
    case Token::AND:
3033
 
      EmitLogicalOperation(expr);
3034
 
      break;
3035
 
 
3036
 
    case Token::ADD:
3037
 
    case Token::SUB:
3038
 
    case Token::DIV:
3039
 
    case Token::MOD:
3040
 
    case Token::MUL:
3041
 
    case Token::BIT_OR:
3042
 
    case Token::BIT_AND:
3043
 
    case Token::BIT_XOR:
3044
 
    case Token::SHL:
3045
 
    case Token::SHR:
3046
 
    case Token::SAR:
3047
 
      VisitForValue(expr->left(), kStack);
3048
 
      VisitForValue(expr->right(), kAccumulator);
3049
 
      EmitBinaryOp(expr->op(), context_);
3050
 
      break;
3051
 
 
3052
 
    default:
3053
 
      UNREACHABLE();
3054
 
  }
3055
 
}
3056
 
 
3057
 
 
3058
 
void FullCodeGenerator::EmitNullCompare(bool strict,
3059
 
                                        Register obj,
3060
 
                                        Register null_const,
3061
 
                                        Label* if_true,
3062
 
                                        Label* if_false,
3063
 
                                        Register scratch) {
3064
 
  __ cmp(obj, null_const);
3065
 
  if (strict) {
3066
 
    __ b(eq, if_true);
 
3843
void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
 
3844
  ASSERT(!context()->IsEffect());
 
3845
  ASSERT(!context()->IsTest());
 
3846
  VariableProxy* proxy = expr->AsVariableProxy();
 
3847
  if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
 
3848
    Comment cmnt(masm_, "Global variable");
 
3849
    __ ldr(r0, GlobalObjectOperand());
 
3850
    __ mov(r2, Operand(proxy->name()));
 
3851
    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
 
3852
    // Use a regular load, not a contextual load, to avoid a reference
 
3853
    // error.
 
3854
    EmitCallIC(ic, RelocInfo::CODE_TARGET);
 
3855
    PrepareForBailout(expr, TOS_REG);
 
3856
    context()->Plug(r0);
 
3857
  } else if (proxy != NULL &&
 
3858
             proxy->var()->AsSlot() != NULL &&
 
3859
             proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
 
3860
    Label done, slow;
 
3861
 
 
3862
    // Generate code for loading from variables potentially shadowed
 
3863
    // by eval-introduced variables.
 
3864
    Slot* slot = proxy->var()->AsSlot();
 
3865
    EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
 
3866
 
 
3867
    __ bind(&slow);
 
3868
    __ mov(r0, Operand(proxy->name()));
 
3869
    __ Push(cp, r0);
 
3870
    __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
 
3871
    PrepareForBailout(expr, TOS_REG);
 
3872
    __ bind(&done);
 
3873
 
 
3874
    context()->Plug(r0);
3067
3875
  } else {
3068
 
    __ b(eq, if_true);
 
3876
    // This expression cannot throw a reference error at the top level.
 
3877
    context()->HandleExpression(expr);
 
3878
  }
 
3879
}
 
3880
 
 
3881
 
 
3882
bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
 
3883
                                          Expression* left,
 
3884
                                          Expression* right,
 
3885
                                          Label* if_true,
 
3886
                                          Label* if_false,
 
3887
                                          Label* fall_through) {
 
3888
  if (op != Token::EQ && op != Token::EQ_STRICT) return false;
 
3889
 
 
3890
  // Check for the pattern: typeof <expression> == <string literal>.
 
3891
  Literal* right_literal = right->AsLiteral();
 
3892
  if (right_literal == NULL) return false;
 
3893
  Handle<Object> right_literal_value = right_literal->handle();
 
3894
  if (!right_literal_value->IsString()) return false;
 
3895
  UnaryOperation* left_unary = left->AsUnaryOperation();
 
3896
  if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
 
3897
  Handle<String> check = Handle<String>::cast(right_literal_value);
 
3898
 
 
3899
  { AccumulatorValueContext context(this);
 
3900
    VisitForTypeofValue(left_unary->expression());
 
3901
  }
 
3902
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
3903
 
 
3904
  if (check->Equals(Heap::number_symbol())) {
 
3905
    __ tst(r0, Operand(kSmiTagMask));
 
3906
    __ b(eq, if_true);
 
3907
    __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
 
3908
    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
 
3909
    __ cmp(r0, ip);
 
3910
    Split(eq, if_true, if_false, fall_through);
 
3911
  } else if (check->Equals(Heap::string_symbol())) {
 
3912
    __ tst(r0, Operand(kSmiTagMask));
 
3913
    __ b(eq, if_false);
 
3914
    // Check for undetectable objects => false.
 
3915
    __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
 
3916
    __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
 
3917
    __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
 
3918
    __ cmp(r1, Operand(1 << Map::kIsUndetectable));
 
3919
    __ b(eq, if_false);
 
3920
    __ ldrb(r1, FieldMemOperand(r0, Map::kInstanceTypeOffset));
 
3921
    __ cmp(r1, Operand(FIRST_NONSTRING_TYPE));
 
3922
    Split(lt, if_true, if_false, fall_through);
 
3923
  } else if (check->Equals(Heap::boolean_symbol())) {
 
3924
    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
 
3925
    __ cmp(r0, ip);
 
3926
    __ b(eq, if_true);
 
3927
    __ LoadRoot(ip, Heap::kFalseValueRootIndex);
 
3928
    __ cmp(r0, ip);
 
3929
    Split(eq, if_true, if_false, fall_through);
 
3930
  } else if (check->Equals(Heap::undefined_symbol())) {
3069
3931
    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
3070
 
    __ cmp(obj, ip);
3071
 
    __ b(eq, if_true);
3072
 
    __ BranchOnSmi(obj, if_false);
3073
 
    // It can be an undetectable object.
3074
 
    __ ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
3075
 
    __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
3076
 
    __ tst(scratch, Operand(1 << Map::kIsUndetectable));
3077
 
    __ b(ne, if_true);
 
3932
    __ cmp(r0, ip);
 
3933
    __ b(eq, if_true);
 
3934
    __ tst(r0, Operand(kSmiTagMask));
 
3935
    __ b(eq, if_false);
 
3936
    // Check for undetectable objects => true.
 
3937
    __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
 
3938
    __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
 
3939
    __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
 
3940
    __ cmp(r1, Operand(1 << Map::kIsUndetectable));
 
3941
    Split(eq, if_true, if_false, fall_through);
 
3942
  } else if (check->Equals(Heap::function_symbol())) {
 
3943
    __ tst(r0, Operand(kSmiTagMask));
 
3944
    __ b(eq, if_false);
 
3945
    __ CompareObjectType(r0, r1, r0, JS_FUNCTION_TYPE);
 
3946
    __ b(eq, if_true);
 
3947
    // Regular expressions => 'function' (they are callable).
 
3948
    __ CompareInstanceType(r1, r0, JS_REGEXP_TYPE);
 
3949
    Split(eq, if_true, if_false, fall_through);
 
3950
  } else if (check->Equals(Heap::object_symbol())) {
 
3951
    __ tst(r0, Operand(kSmiTagMask));
 
3952
    __ b(eq, if_false);
 
3953
    __ LoadRoot(ip, Heap::kNullValueRootIndex);
 
3954
    __ cmp(r0, ip);
 
3955
    __ b(eq, if_true);
 
3956
    // Regular expressions => 'function', not 'object'.
 
3957
    __ CompareObjectType(r0, r1, r0, JS_REGEXP_TYPE);
 
3958
    __ b(eq, if_false);
 
3959
    // Check for undetectable objects => false.
 
3960
    __ ldrb(r0, FieldMemOperand(r1, Map::kBitFieldOffset));
 
3961
    __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
 
3962
    __ cmp(r0, Operand(1 << Map::kIsUndetectable));
 
3963
    __ b(eq, if_false);
 
3964
    // Check for JS objects => true.
 
3965
    __ ldrb(r0, FieldMemOperand(r1, Map::kInstanceTypeOffset));
 
3966
    __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE));
 
3967
    __ b(lt, if_false);
 
3968
    __ cmp(r0, Operand(LAST_JS_OBJECT_TYPE));
 
3969
    Split(le, if_true, if_false, fall_through);
 
3970
  } else {
 
3971
    if (if_false != fall_through) __ jmp(if_false);
3078
3972
  }
3079
 
  __ jmp(if_false);
 
3973
 
 
3974
  return true;
3080
3975
}
3081
3976
 
3082
3977
 
3083
3978
void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3084
3979
  Comment cmnt(masm_, "[ CompareOperation");
 
3980
  SetSourcePosition(expr->position());
3085
3981
 
3086
3982
  // Always perform the comparison for its control flow.  Pack the result
3087
3983
  // into the expression's context after the comparison is performed.
3089
3985
  Label materialize_true, materialize_false;
3090
3986
  Label* if_true = NULL;
3091
3987
  Label* if_false = NULL;
3092
 
  PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
3093
 
 
3094
 
  VisitForValue(expr->left(), kStack);
3095
 
  switch (expr->op()) {
 
3988
  Label* fall_through = NULL;
 
3989
  context()->PrepareTest(&materialize_true, &materialize_false,
 
3990
                         &if_true, &if_false, &fall_through);
 
3991
 
 
3992
  // First we try a fast inlined version of the compare when one of
 
3993
  // the operands is a literal.
 
3994
  Token::Value op = expr->op();
 
3995
  Expression* left = expr->left();
 
3996
  Expression* right = expr->right();
 
3997
  if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
 
3998
    context()->Plug(if_true, if_false);
 
3999
    return;
 
4000
  }
 
4001
 
 
4002
  VisitForStackValue(expr->left());
 
4003
  switch (op) {
3096
4004
    case Token::IN:
3097
 
      VisitForValue(expr->right(), kStack);
 
4005
      VisitForStackValue(expr->right());
3098
4006
      __ InvokeBuiltin(Builtins::IN, CALL_JS);
 
4007
      PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
3099
4008
      __ LoadRoot(ip, Heap::kTrueValueRootIndex);
3100
4009
      __ cmp(r0, ip);
3101
 
      __ b(eq, if_true);
3102
 
      __ jmp(if_false);
 
4010
      Split(eq, if_true, if_false, fall_through);
3103
4011
      break;
3104
4012
 
3105
4013
    case Token::INSTANCEOF: {
3106
 
      VisitForValue(expr->right(), kStack);
3107
 
      InstanceofStub stub;
 
4014
      VisitForStackValue(expr->right());
 
4015
      InstanceofStub stub(InstanceofStub::kNoFlags);
3108
4016
      __ CallStub(&stub);
 
4017
      PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
4018
      // The stub returns 0 for true.
3109
4019
      __ tst(r0, r0);
3110
 
      __ b(eq, if_true);  // The stub returns 0 for true.
3111
 
      __ jmp(if_false);
 
4020
      Split(eq, if_true, if_false, fall_through);
3112
4021
      break;
3113
4022
    }
3114
4023
 
3115
4024
    default: {
3116
 
      VisitForValue(expr->right(), kAccumulator);
3117
 
      Condition cc = eq;
 
4025
      VisitForAccumulatorValue(expr->right());
 
4026
      Condition cond = eq;
3118
4027
      bool strict = false;
3119
 
      switch (expr->op()) {
 
4028
      switch (op) {
3120
4029
        case Token::EQ_STRICT:
3121
4030
          strict = true;
3122
4031
          // Fall through
3123
 
        case Token::EQ: {
3124
 
          cc = eq;
 
4032
        case Token::EQ:
 
4033
          cond = eq;
3125
4034
          __ pop(r1);
3126
 
          // If either operand is constant null we do a fast compare
3127
 
          // against null.
3128
 
          Literal* right_literal = expr->right()->AsLiteral();
3129
 
          Literal* left_literal = expr->left()->AsLiteral();
3130
 
          if (right_literal != NULL && right_literal->handle()->IsNull()) {
3131
 
            EmitNullCompare(strict, r1, r0, if_true, if_false, r2);
3132
 
            Apply(context_, if_true, if_false);
3133
 
            return;
3134
 
          } else if (left_literal != NULL && left_literal->handle()->IsNull()) {
3135
 
            EmitNullCompare(strict, r0, r1, if_true, if_false, r2);
3136
 
            Apply(context_, if_true, if_false);
3137
 
            return;
3138
 
          }
3139
4035
          break;
3140
 
        }
3141
4036
        case Token::LT:
3142
 
          cc = lt;
 
4037
          cond = lt;
3143
4038
          __ pop(r1);
3144
4039
          break;
3145
4040
        case Token::GT:
3146
4041
          // Reverse left and right sides to obtain ECMA-262 conversion order.
3147
 
          cc = lt;
 
4042
          cond = lt;
3148
4043
          __ mov(r1, result_register());
3149
4044
          __ pop(r0);
3150
4045
         break;
3151
4046
        case Token::LTE:
3152
4047
          // Reverse left and right sides to obtain ECMA-262 conversion order.
3153
 
          cc = ge;
 
4048
          cond = ge;
3154
4049
          __ mov(r1, result_register());
3155
4050
          __ pop(r0);
3156
4051
          break;
3157
4052
        case Token::GTE:
3158
 
          cc = ge;
 
4053
          cond = ge;
3159
4054
          __ pop(r1);
3160
4055
          break;
3161
4056
        case Token::IN:
3164
4059
          UNREACHABLE();
3165
4060
      }
3166
4061
 
3167
 
      // The comparison stub expects the smi vs. smi case to be handled
3168
 
      // before it is called.
3169
 
      Label slow_case;
3170
 
      __ orr(r2, r0, Operand(r1));
3171
 
      __ BranchOnNotSmi(r2, &slow_case);
3172
 
      __ cmp(r1, r0);
3173
 
      __ b(cc, if_true);
3174
 
      __ jmp(if_false);
 
4062
      bool inline_smi_code = ShouldInlineSmiCase(op);
 
4063
      JumpPatchSite patch_site(masm_);
 
4064
      if (inline_smi_code) {
 
4065
        Label slow_case;
 
4066
        __ orr(r2, r0, Operand(r1));
 
4067
        patch_site.EmitJumpIfNotSmi(r2, &slow_case);
 
4068
        __ cmp(r1, r0);
 
4069
        Split(cond, if_true, if_false, NULL);
 
4070
        __ bind(&slow_case);
 
4071
      }
3175
4072
 
3176
 
      __ bind(&slow_case);
3177
 
      CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0);
3178
 
      __ CallStub(&stub);
 
4073
      // Record position and call the compare IC.
 
4074
      SetSourcePosition(expr->position());
 
4075
      Handle<Code> ic = CompareIC::GetUninitialized(op);
 
4076
      EmitCallIC(ic, &patch_site);
 
4077
      PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3179
4078
      __ cmp(r0, Operand(0));
3180
 
      __ b(cc, if_true);
3181
 
      __ jmp(if_false);
 
4079
      Split(cond, if_true, if_false, fall_through);
3182
4080
    }
3183
4081
  }
3184
4082
 
3185
4083
  // Convert the result of the comparison into one expected for this
3186
4084
  // expression's context.
3187
 
  Apply(context_, if_true, if_false);
 
4085
  context()->Plug(if_true, if_false);
 
4086
}
 
4087
 
 
4088
 
 
4089
void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
 
4090
  Comment cmnt(masm_, "[ CompareToNull");
 
4091
  Label materialize_true, materialize_false;
 
4092
  Label* if_true = NULL;
 
4093
  Label* if_false = NULL;
 
4094
  Label* fall_through = NULL;
 
4095
  context()->PrepareTest(&materialize_true, &materialize_false,
 
4096
                         &if_true, &if_false, &fall_through);
 
4097
 
 
4098
  VisitForAccumulatorValue(expr->expression());
 
4099
  PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
 
4100
  __ LoadRoot(r1, Heap::kNullValueRootIndex);
 
4101
  __ cmp(r0, r1);
 
4102
  if (expr->is_strict()) {
 
4103
    Split(eq, if_true, if_false, fall_through);
 
4104
  } else {
 
4105
    __ b(eq, if_true);
 
4106
    __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
 
4107
    __ cmp(r0, r1);
 
4108
    __ b(eq, if_true);
 
4109
    __ tst(r0, Operand(kSmiTagMask));
 
4110
    __ b(eq, if_false);
 
4111
    // It can be an undetectable object.
 
4112
    __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
 
4113
    __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
 
4114
    __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
 
4115
    __ cmp(r1, Operand(1 << Map::kIsUndetectable));
 
4116
    Split(eq, if_true, if_false, fall_through);
 
4117
  }
 
4118
  context()->Plug(if_true, if_false);
3188
4119
}
3189
4120
 
3190
4121
 
3191
4122
void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
3192
4123
  __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
3193
 
  Apply(context_, r0);
3194
 
}
3195
 
 
3196
 
 
3197
 
Register FullCodeGenerator::result_register() { return r0; }
3198
 
 
3199
 
 
3200
 
Register FullCodeGenerator::context_register() { return cp; }
 
4124
  context()->Plug(r0);
 
4125
}
 
4126
 
 
4127
 
 
4128
Register FullCodeGenerator::result_register() {
 
4129
  return r0;
 
4130
}
 
4131
 
 
4132
 
 
4133
Register FullCodeGenerator::context_register() {
 
4134
  return cp;
 
4135
}
 
4136
 
 
4137
 
 
4138
void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
 
4139
  ASSERT(mode == RelocInfo::CODE_TARGET ||
 
4140
         mode == RelocInfo::CODE_TARGET_CONTEXT);
 
4141
  switch (ic->kind()) {
 
4142
    case Code::LOAD_IC:
 
4143
      __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
 
4144
      break;
 
4145
    case Code::KEYED_LOAD_IC:
 
4146
      __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
 
4147
      break;
 
4148
    case Code::STORE_IC:
 
4149
      __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
 
4150
      break;
 
4151
    case Code::KEYED_STORE_IC:
 
4152
      __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
 
4153
    default:
 
4154
      break;
 
4155
  }
 
4156
 
 
4157
  __ Call(ic, mode);
 
4158
}
 
4159
 
 
4160
 
 
4161
void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
 
4162
  switch (ic->kind()) {
 
4163
    case Code::LOAD_IC:
 
4164
      __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
 
4165
      break;
 
4166
    case Code::KEYED_LOAD_IC:
 
4167
      __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
 
4168
      break;
 
4169
    case Code::STORE_IC:
 
4170
      __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
 
4171
      break;
 
4172
    case Code::KEYED_STORE_IC:
 
4173
      __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
 
4174
    default:
 
4175
      break;
 
4176
  }
 
4177
 
 
4178
  __ Call(ic, RelocInfo::CODE_TARGET);
 
4179
  if (patch_site != NULL && patch_site->is_bound()) {
 
4180
    patch_site->EmitPatchInfo();
 
4181
  } else {
 
4182
    __ nop();  // Signals no inlined code.
 
4183
  }
 
4184
}
3201
4185
 
3202
4186
 
3203
4187
void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3207
4191
 
3208
4192
 
3209
4193
void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3210
 
  __ ldr(dst, CodeGenerator::ContextOperand(cp, context_index));
 
4194
  __ ldr(dst, ContextOperand(cp, context_index));
3211
4195
}
3212
4196
 
3213
4197