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

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / arm / lithium-arm.cc @ f230a1cf

History | View | Annotate | Download (88.3 KB)

1 60040a4f Ryan Dahl
// Copyright 2012 the V8 project authors. All rights reserved.
2 c30f1137 Ryan Dahl
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 e5564a3f Ryan Dahl
#include "v8.h"
29
30 a0702b54 Ryan Dahl
#include "lithium-allocator-inl.h"
31 c30f1137 Ryan Dahl
#include "arm/lithium-arm.h"
32
#include "arm/lithium-codegen-arm.h"
33 a53c763c Timothy J Fontaine
#include "hydrogen-osr.h"
34 c30f1137 Ryan Dahl
35
namespace v8 {
36
namespace internal {
37
38
#define DEFINE_COMPILE(type)                            \
39
  void L##type::CompileToNative(LCodeGen* generator) {  \
40
    generator->Do##type(this);                          \
41
  }
42
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
43
#undef DEFINE_COMPILE
44
45 a0702b54 Ryan Dahl
#ifdef DEBUG
46
void LInstruction::VerifyCall() {
47 e5564a3f Ryan Dahl
  // Call instructions can use only fixed registers as temporaries and
48
  // outputs because all registers are blocked by the calling convention.
49
  // Inputs operands must use a fixed register or use-at-start policy or
50
  // a non-register policy.
51 a0702b54 Ryan Dahl
  ASSERT(Output() == NULL ||
52
         LUnallocated::cast(Output())->HasFixedPolicy() ||
53
         !LUnallocated::cast(Output())->HasRegisterPolicy());
54 e5564a3f Ryan Dahl
  for (UseIterator it(this); !it.Done(); it.Advance()) {
55
    LUnallocated* operand = LUnallocated::cast(it.Current());
56
    ASSERT(operand->HasFixedPolicy() ||
57
           operand->IsUsedAtStart());
58 a0702b54 Ryan Dahl
  }
59 e5564a3f Ryan Dahl
  for (TempIterator it(this); !it.Done(); it.Advance()) {
60
    LUnallocated* operand = LUnallocated::cast(it.Current());
61
    ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
62 a0702b54 Ryan Dahl
  }
63
}
64
#endif
65
66
67 4c5e5707 Ryan Dahl
void LInstruction::PrintTo(StringStream* stream) {
68 c30f1137 Ryan Dahl
  stream->Add("%s ", this->Mnemonic());
69 a0702b54 Ryan Dahl
70
  PrintOutputOperandTo(stream);
71 4c5e5707 Ryan Dahl
72 c30f1137 Ryan Dahl
  PrintDataTo(stream);
73
74
  if (HasEnvironment()) {
75
    stream->Add(" ");
76
    environment()->PrintTo(stream);
77
  }
78
79
  if (HasPointerMap()) {
80
    stream->Add(" ");
81
    pointer_map()->PrintTo(stream);
82
  }
83
}
84
85
86 50464cd4 Bert Belder
void LInstruction::PrintDataTo(StringStream* stream) {
87 4c5e5707 Ryan Dahl
  stream->Add("= ");
88 50464cd4 Bert Belder
  for (int i = 0; i < InputCount(); i++) {
89 e5564a3f Ryan Dahl
    if (i > 0) stream->Add(" ");
90 83261e78 Trevor Norris
    if (InputAt(i) == NULL) {
91
      stream->Add("NULL");
92
    } else {
93
      InputAt(i)->PrintTo(stream);
94
    }
95 e5564a3f Ryan Dahl
  }
96 4c5e5707 Ryan Dahl
}
97
98
99 50464cd4 Bert Belder
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
100
  if (HasResult()) result()->PrintTo(stream);
101 4c5e5707 Ryan Dahl
}
102
103
104
void LLabel::PrintDataTo(StringStream* stream) {
105 c30f1137 Ryan Dahl
  LGap::PrintDataTo(stream);
106
  LLabel* rep = replacement();
107
  if (rep != NULL) {
108
    stream->Add(" Dead block replaced with B%d", rep->block_id());
109
  }
110
}
111
112
113
bool LGap::IsRedundant() const {
114
  for (int i = 0; i < 4; i++) {
115
    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
116
      return false;
117
    }
118
  }
119
120
  return true;
121
}
122
123
124 e5564a3f Ryan Dahl
void LGap::PrintDataTo(StringStream* stream) {
125 c30f1137 Ryan Dahl
  for (int i = 0; i < 4; i++) {
126
    stream->Add("(");
127
    if (parallel_moves_[i] != NULL) {
128
      parallel_moves_[i]->PrintDataTo(stream);
129
    }
130
    stream->Add(") ");
131
  }
132
}
133
134
135
const char* LArithmeticD::Mnemonic() const {
136
  switch (op()) {
137
    case Token::ADD: return "add-d";
138
    case Token::SUB: return "sub-d";
139
    case Token::MUL: return "mul-d";
140
    case Token::DIV: return "div-d";
141
    case Token::MOD: return "mod-d";
142
    default:
143
      UNREACHABLE();
144
      return NULL;
145
  }
146
}
147
148
149
const char* LArithmeticT::Mnemonic() const {
150
  switch (op()) {
151
    case Token::ADD: return "add-t";
152
    case Token::SUB: return "sub-t";
153
    case Token::MUL: return "mul-t";
154
    case Token::MOD: return "mod-t";
155
    case Token::DIV: return "div-t";
156 a0702b54 Ryan Dahl
    case Token::BIT_AND: return "bit-and-t";
157
    case Token::BIT_OR: return "bit-or-t";
158
    case Token::BIT_XOR: return "bit-xor-t";
159 83261e78 Trevor Norris
    case Token::ROR: return "ror-t";
160 550f73ae Ryan Dahl
    case Token::SHL: return "shl-t";
161
    case Token::SAR: return "sar-t";
162
    case Token::SHR: return "shr-t";
163 c30f1137 Ryan Dahl
    default:
164
      UNREACHABLE();
165
      return NULL;
166
  }
167
}
168
169
170 2f75785c Ben Noordhuis
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
171
  return !gen->IsNextEmittedBlock(block_id());
172
}
173
174
175 4c5e5707 Ryan Dahl
void LGoto::PrintDataTo(StringStream* stream) {
176 c30f1137 Ryan Dahl
  stream->Add("B%d", block_id());
177
}
178
179
180 4c5e5707 Ryan Dahl
void LBranch::PrintDataTo(StringStream* stream) {
181 c30f1137 Ryan Dahl
  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
182 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
183 c30f1137 Ryan Dahl
}
184
185
186 5777d7ab Trevor Norris
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
187 c30f1137 Ryan Dahl
  stream->Add("if ");
188 7b4d95a9 Fedor Indutny
  left()->PrintTo(stream);
189 c30f1137 Ryan Dahl
  stream->Add(" %s ", Token::String(op()));
190 7b4d95a9 Fedor Indutny
  right()->PrintTo(stream);
191 c30f1137 Ryan Dahl
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
192
}
193
194
195 4c5e5707 Ryan Dahl
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
196 7d425a0a Ryan Dahl
  stream->Add("if is_object(");
197 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
198 7d425a0a Ryan Dahl
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
199
}
200
201
202 21d081fd Ryan Dahl
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
203
  stream->Add("if is_string(");
204 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
205 21d081fd Ryan Dahl
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
206
}
207
208
209 4c5e5707 Ryan Dahl
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
210 c30f1137 Ryan Dahl
  stream->Add("if is_smi(");
211 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
212 c30f1137 Ryan Dahl
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
213
}
214
215
216 e5564a3f Ryan Dahl
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
217
  stream->Add("if is_undetectable(");
218 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
219 e5564a3f Ryan Dahl
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
220
}
221
222
223 21d081fd Ryan Dahl
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
224
  stream->Add("if string_compare(");
225 7b4d95a9 Fedor Indutny
  left()->PrintTo(stream);
226
  right()->PrintTo(stream);
227 21d081fd Ryan Dahl
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
228
}
229
230
231 4c5e5707 Ryan Dahl
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
232 c30f1137 Ryan Dahl
  stream->Add("if has_instance_type(");
233 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
234 c30f1137 Ryan Dahl
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
235
}
236
237
238 4c5e5707 Ryan Dahl
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
239 c30f1137 Ryan Dahl
  stream->Add("if has_cached_array_index(");
240 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
241 c30f1137 Ryan Dahl
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
242
}
243
244
245 4c5e5707 Ryan Dahl
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
246 c30f1137 Ryan Dahl
  stream->Add("if class_of_test(");
247 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
248 c30f1137 Ryan Dahl
  stream->Add(", \"%o\") then B%d else B%d",
249
              *hydrogen()->class_name(),
250
              true_block_id(),
251
              false_block_id());
252
}
253
254
255 4c5e5707 Ryan Dahl
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
256 c30f1137 Ryan Dahl
  stream->Add("if typeof ");
257 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
258 c30f1137 Ryan Dahl
  stream->Add(" == \"%s\" then B%d else B%d",
259
              *hydrogen()->type_literal()->ToCString(),
260
              true_block_id(), false_block_id());
261
}
262
263
264 a53c763c Timothy J Fontaine
void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
265
  stream->Add(" = ");
266
  function()->PrintTo(stream);
267
  stream->Add(".code_entry = ");
268
  code_object()->PrintTo(stream);
269
}
270
271
272 83261e78 Trevor Norris
void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
273
  stream->Add(" = ");
274
  base_object()->PrintTo(stream);
275
  stream->Add(" + %d", offset());
276
}
277
278
279 4c5e5707 Ryan Dahl
void LCallConstantFunction::PrintDataTo(StringStream* stream) {
280 c30f1137 Ryan Dahl
  stream->Add("#%d / ", arity());
281
}
282
283
284 cf2e4f44 Ryan Dahl
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
285 7b4d95a9 Fedor Indutny
  context()->PrintTo(stream);
286 a0702b54 Ryan Dahl
  stream->Add("[%d]", slot_index());
287
}
288
289
290
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
291 7b4d95a9 Fedor Indutny
  context()->PrintTo(stream);
292 a0702b54 Ryan Dahl
  stream->Add("[%d] <- ", slot_index());
293 7b4d95a9 Fedor Indutny
  value()->PrintTo(stream);
294 cf2e4f44 Ryan Dahl
}
295
296
297 e5564a3f Ryan Dahl
void LInvokeFunction::PrintDataTo(StringStream* stream) {
298
  stream->Add("= ");
299 7b4d95a9 Fedor Indutny
  function()->PrintTo(stream);
300 e5564a3f Ryan Dahl
  stream->Add(" #%d / ", arity());
301
}
302
303
304 4c5e5707 Ryan Dahl
void LCallKeyed::PrintDataTo(StringStream* stream) {
305 c30f1137 Ryan Dahl
  stream->Add("[r2] #%d / ", arity());
306
}
307
308
309 4c5e5707 Ryan Dahl
void LCallNamed::PrintDataTo(StringStream* stream) {
310 1b15af9d Ryan Dahl
  SmartArrayPointer<char> name_string = name()->ToCString();
311 c30f1137 Ryan Dahl
  stream->Add("%s #%d / ", *name_string, arity());
312
}
313
314
315 4c5e5707 Ryan Dahl
void LCallGlobal::PrintDataTo(StringStream* stream) {
316 1b15af9d Ryan Dahl
  SmartArrayPointer<char> name_string = name()->ToCString();
317 c30f1137 Ryan Dahl
  stream->Add("%s #%d / ", *name_string, arity());
318
}
319
320
321 4c5e5707 Ryan Dahl
void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
322 c30f1137 Ryan Dahl
  stream->Add("#%d / ", arity());
323
}
324
325
326 4c5e5707 Ryan Dahl
void LCallNew::PrintDataTo(StringStream* stream) {
327
  stream->Add("= ");
328 7b4d95a9 Fedor Indutny
  constructor()->PrintTo(stream);
329 c30f1137 Ryan Dahl
  stream->Add(" #%d / ", arity());
330
}
331
332
333 83261e78 Trevor Norris
void LCallNewArray::PrintDataTo(StringStream* stream) {
334
  stream->Add("= ");
335
  constructor()->PrintTo(stream);
336
  stream->Add(" #%d / ", arity());
337 704fd8f3 Ben Noordhuis
  ElementsKind kind = hydrogen()->elements_kind();
338 83261e78 Trevor Norris
  stream->Add(" (%s) ", ElementsKindToString(kind));
339
}
340
341
342 4c5e5707 Ryan Dahl
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
343 c30f1137 Ryan Dahl
  arguments()->PrintTo(stream);
344
  stream->Add(" length ");
345
  length()->PrintTo(stream);
346
  stream->Add(" index ");
347
  index()->PrintTo(stream);
348
}
349
350
351 e33e7d1a Ryan Dahl
void LStoreNamedField::PrintDataTo(StringStream* stream) {
352 4c5e5707 Ryan Dahl
  object()->PrintTo(stream);
353 6dd78074 Ben Noordhuis
  hydrogen()->access().PrintTo(stream);
354 4c5e5707 Ryan Dahl
  stream->Add(" <- ");
355
  value()->PrintTo(stream);
356
}
357
358
359 e33e7d1a Ryan Dahl
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
360
  object()->PrintTo(stream);
361
  stream->Add(".");
362
  stream->Add(*String::cast(*name())->ToCString());
363
  stream->Add(" <- ");
364
  value()->PrintTo(stream);
365
}
366
367
368 83261e78 Trevor Norris
void LLoadKeyed::PrintDataTo(StringStream* stream) {
369
  elements()->PrintTo(stream);
370 e33e7d1a Ryan Dahl
  stream->Add("[");
371
  key()->PrintTo(stream);
372 83261e78 Trevor Norris
  if (hydrogen()->IsDehoisted()) {
373
    stream->Add(" + %d]", additional_index());
374
  } else {
375
    stream->Add("]");
376
  }
377 e33e7d1a Ryan Dahl
}
378
379
380 83261e78 Trevor Norris
void LStoreKeyed::PrintDataTo(StringStream* stream) {
381 f319e126 Ryan Dahl
  elements()->PrintTo(stream);
382
  stream->Add("[");
383
  key()->PrintTo(stream);
384 83261e78 Trevor Norris
  if (hydrogen()->IsDehoisted()) {
385
    stream->Add(" + %d] <-", additional_index());
386
  } else {
387
    stream->Add("] <- ");
388
  }
389 6dd78074 Ben Noordhuis
390
  if (value() == NULL) {
391
    ASSERT(hydrogen()->IsConstantHoleStore() &&
392
           hydrogen()->value()->representation().IsDouble());
393
    stream->Add("<the hole(nan)>");
394
  } else {
395
    value()->PrintTo(stream);
396
  }
397 f319e126 Ryan Dahl
}
398
399
400 e33e7d1a Ryan Dahl
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
401 4c5e5707 Ryan Dahl
  object()->PrintTo(stream);
402
  stream->Add("[");
403
  key()->PrintTo(stream);
404
  stream->Add("] <- ");
405
  value()->PrintTo(stream);
406
}
407
408
409 21d081fd Ryan Dahl
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
410
  object()->PrintTo(stream);
411
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
412
}
413
414
415 f230a1cf Ben Noordhuis
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
416 c30f1137 Ryan Dahl
  // Skip a slot if for a double-width slot.
417 f230a1cf Ben Noordhuis
  if (kind == DOUBLE_REGISTERS) spill_slot_count_++;
418 c30f1137 Ryan Dahl
  return spill_slot_count_++;
419
}
420
421
422 f230a1cf Ben Noordhuis
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind)  {
423
  int index = GetNextSpillIndex(kind);
424
  if (kind == DOUBLE_REGISTERS) {
425 50464cd4 Bert Belder
    return LDoubleStackSlot::Create(index, zone());
426 c30f1137 Ryan Dahl
  } else {
427 f230a1cf Ben Noordhuis
    ASSERT(kind == GENERAL_REGISTERS);
428 50464cd4 Bert Belder
    return LStackSlot::Create(index, zone());
429 c30f1137 Ryan Dahl
  }
430
}
431
432
433 3411a03d isaacs
LPlatformChunk* LChunkBuilder::Build() {
434 c30f1137 Ryan Dahl
  ASSERT(is_unused());
435 3411a03d isaacs
  chunk_ = new(zone()) LPlatformChunk(info(), graph());
436 704fd8f3 Ben Noordhuis
  LPhase phase("L_Building chunk", chunk_);
437 c30f1137 Ryan Dahl
  status_ = BUILDING;
438 a53c763c Timothy J Fontaine
439
  // If compiling for OSR, reserve space for the unoptimized frame,
440
  // which will be subsumed into this frame.
441
  if (graph()->has_osr()) {
442
    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
443 f230a1cf Ben Noordhuis
      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
444 a53c763c Timothy J Fontaine
    }
445
  }
446
447 c30f1137 Ryan Dahl
  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
448
  for (int i = 0; i < blocks->length(); i++) {
449
    HBasicBlock* next = NULL;
450
    if (i < blocks->length() - 1) next = blocks->at(i + 1);
451
    DoBasicBlock(blocks->at(i), next);
452
    if (is_aborted()) return NULL;
453
  }
454
  status_ = DONE;
455
  return chunk_;
456
}
457
458
459 f69be329 Ben Noordhuis
void LChunkBuilder::Abort(BailoutReason reason) {
460 3411a03d isaacs
  info()->set_bailout_reason(reason);
461 c30f1137 Ryan Dahl
  status_ = ABORTED;
462
}
463
464
465
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
466 e4fc2cbf isaacs
  return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
467
                                  Register::ToAllocationIndex(reg));
468 c30f1137 Ryan Dahl
}
469
470
471
LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
472 e4fc2cbf isaacs
  return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
473
                                  DoubleRegister::ToAllocationIndex(reg));
474 c30f1137 Ryan Dahl
}
475
476
477
LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
478
  return Use(value, ToUnallocated(fixed_register));
479
}
480
481
482
LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
483
  return Use(value, ToUnallocated(reg));
484
}
485
486
487
LOperand* LChunkBuilder::UseRegister(HValue* value) {
488 e4fc2cbf isaacs
  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
489 c30f1137 Ryan Dahl
}
490
491
492
LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
493
  return Use(value,
494 e4fc2cbf isaacs
             new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
495
                                      LUnallocated::USED_AT_START));
496 c30f1137 Ryan Dahl
}
497
498
499
LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
500 e4fc2cbf isaacs
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
501 c30f1137 Ryan Dahl
}
502
503
504
LOperand* LChunkBuilder::Use(HValue* value) {
505 e4fc2cbf isaacs
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
506 c30f1137 Ryan Dahl
}
507
508
509
LOperand* LChunkBuilder::UseAtStart(HValue* value) {
510 e4fc2cbf isaacs
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
511
                                             LUnallocated::USED_AT_START));
512 c30f1137 Ryan Dahl
}
513
514
515
LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
516
  return value->IsConstant()
517
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
518
      : Use(value);
519
}
520
521
522
LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
523
  return value->IsConstant()
524
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
525
      : UseAtStart(value);
526
}
527
528
529
LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
530
  return value->IsConstant()
531
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
532
      : UseRegister(value);
533
}
534
535
536
LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
537
  return value->IsConstant()
538
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
539
      : UseRegisterAtStart(value);
540
}
541
542
543 7ee538dd Ben Noordhuis
LOperand* LChunkBuilder::UseConstant(HValue* value) {
544
  return chunk_->DefineConstantOperand(HConstant::cast(value));
545
}
546
547
548 b8f006ef Ryan Dahl
LOperand* LChunkBuilder::UseAny(HValue* value) {
549
  return value->IsConstant()
550
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
551 e4fc2cbf isaacs
      :  Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
552 b8f006ef Ryan Dahl
}
553
554
555 c30f1137 Ryan Dahl
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
556
  if (value->EmitAtUses()) {
557
    HInstruction* instr = HInstruction::cast(value);
558
    VisitInstruction(instr);
559
  }
560 8be69949 isaacs
  operand->set_virtual_register(value->id());
561 c30f1137 Ryan Dahl
  return operand;
562
}
563
564
565 4c5e5707 Ryan Dahl
template<int I, int T>
566
LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
567
                                    LUnallocated* result) {
568 8be69949 isaacs
  result->set_virtual_register(current_instruction_->id());
569 4c5e5707 Ryan Dahl
  instr->set_result(result);
570
  return instr;
571
}
572
573
574
template<int I, int T>
575
LInstruction* LChunkBuilder::DefineAsRegister(
576
    LTemplateInstruction<1, I, T>* instr) {
577 e4fc2cbf isaacs
  return Define(instr,
578
                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
579 c30f1137 Ryan Dahl
}
580
581
582 4c5e5707 Ryan Dahl
template<int I, int T>
583
LInstruction* LChunkBuilder::DefineAsSpilled(
584
    LTemplateInstruction<1, I, T>* instr, int index) {
585 e4fc2cbf isaacs
  return Define(instr,
586
                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
587 c30f1137 Ryan Dahl
}
588
589
590 4c5e5707 Ryan Dahl
template<int I, int T>
591
LInstruction* LChunkBuilder::DefineSameAsFirst(
592
    LTemplateInstruction<1, I, T>* instr) {
593 e4fc2cbf isaacs
  return Define(instr,
594
                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
595 c30f1137 Ryan Dahl
}
596
597
598 4c5e5707 Ryan Dahl
template<int I, int T>
599
LInstruction* LChunkBuilder::DefineFixed(
600
    LTemplateInstruction<1, I, T>* instr, Register reg) {
601 c30f1137 Ryan Dahl
  return Define(instr, ToUnallocated(reg));
602
}
603
604
605 4c5e5707 Ryan Dahl
template<int I, int T>
606
LInstruction* LChunkBuilder::DefineFixedDouble(
607
    LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) {
608 c30f1137 Ryan Dahl
  return Define(instr, ToUnallocated(reg));
609
}
610
611
612
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
613
  HEnvironment* hydrogen_env = current_block_->last_environment();
614 21d081fd Ryan Dahl
  int argument_index_accumulator = 0;
615 26bc8db3 Trevor Norris
  ZoneList<HValue*> objects_to_materialize(0, zone());
616 21d081fd Ryan Dahl
  instr->set_environment(CreateEnvironment(hydrogen_env,
617 26bc8db3 Trevor Norris
                                           &argument_index_accumulator,
618
                                           &objects_to_materialize));
619 c30f1137 Ryan Dahl
  return instr;
620
}
621
622
623
LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
624
                                        HInstruction* hinstr,
625
                                        CanDeoptimize can_deoptimize) {
626 83261e78 Trevor Norris
  info()->MarkAsNonDeferredCalling();
627 a0702b54 Ryan Dahl
#ifdef DEBUG
628
  instr->VerifyCall();
629
#endif
630
  instr->MarkAsCall();
631 c30f1137 Ryan Dahl
  instr = AssignPointerMap(instr);
632
633 21d081fd Ryan Dahl
  if (hinstr->HasObservableSideEffects()) {
634 c30f1137 Ryan Dahl
    ASSERT(hinstr->next()->IsSimulate());
635
    HSimulate* sim = HSimulate::cast(hinstr->next());
636 50464cd4 Bert Belder
    ASSERT(instruction_pending_deoptimization_environment_ == NULL);
637 3411a03d isaacs
    ASSERT(pending_deoptimization_ast_id_.IsNone());
638 50464cd4 Bert Belder
    instruction_pending_deoptimization_environment_ = instr;
639
    pending_deoptimization_ast_id_ = sim->ast_id();
640 c30f1137 Ryan Dahl
  }
641
642
  // If instruction does not have side-effects lazy deoptimization
643
  // after the call will try to deoptimize to the point before the call.
644
  // Thus we still need to attach environment to this call even if
645
  // call sequence can not deoptimize eagerly.
646
  bool needs_environment =
647 21d081fd Ryan Dahl
      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
648
      !hinstr->HasObservableSideEffects();
649 c30f1137 Ryan Dahl
  if (needs_environment && !instr->HasEnvironment()) {
650
    instr = AssignEnvironment(instr);
651
  }
652
653
  return instr;
654
}
655
656
657 4c5e5707 Ryan Dahl
LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
658
  ASSERT(!instr->HasPointerMap());
659 f230a1cf Ben Noordhuis
  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
660 c30f1137 Ryan Dahl
  return instr;
661
}
662
663
664
LUnallocated* LChunkBuilder::TempRegister() {
665 e4fc2cbf isaacs
  LUnallocated* operand =
666
      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
667 83261e78 Trevor Norris
  int vreg = allocator_->GetVirtualRegister();
668
  if (!allocator_->AllocationOk()) {
669 f69be329 Ben Noordhuis
    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
670 7ee538dd Ben Noordhuis
    vreg = 0;
671 83261e78 Trevor Norris
  }
672
  operand->set_virtual_register(vreg);
673 c30f1137 Ryan Dahl
  return operand;
674
}
675
676
677
LOperand* LChunkBuilder::FixedTemp(Register reg) {
678
  LUnallocated* operand = ToUnallocated(reg);
679 8be69949 isaacs
  ASSERT(operand->HasFixedPolicy());
680 c30f1137 Ryan Dahl
  return operand;
681
}
682
683
684
LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
685
  LUnallocated* operand = ToUnallocated(reg);
686 8be69949 isaacs
  ASSERT(operand->HasFixedPolicy());
687 c30f1137 Ryan Dahl
  return operand;
688
}
689
690
691
LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
692 e4fc2cbf isaacs
  return new(zone()) LLabel(instr->block());
693 c30f1137 Ryan Dahl
}
694
695
696 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
697
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
698
}
699
700
701 6dd78074 Ben Noordhuis
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
702
  UNREACHABLE();
703
  return NULL;
704
}
705
706
707 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
708 e4fc2cbf isaacs
  return AssignEnvironment(new(zone()) LDeoptimize);
709 c30f1137 Ryan Dahl
}
710
711
712
LInstruction* LChunkBuilder::DoShift(Token::Value op,
713
                                     HBitwiseBinaryOperation* instr) {
714 f230a1cf Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
715
    ASSERT(instr->left()->representation().Equals(instr->representation()));
716
    ASSERT(instr->right()->representation().Equals(instr->representation()));
717
    LOperand* left = UseRegisterAtStart(instr->left());
718 c30f1137 Ryan Dahl
719 f230a1cf Ben Noordhuis
    HValue* right_value = instr->right();
720
    LOperand* right = NULL;
721
    int constant_value = 0;
722
    bool does_deopt = false;
723
    if (right_value->IsConstant()) {
724
      HConstant* constant = HConstant::cast(right_value);
725
      right = chunk_->DefineConstantOperand(constant);
726
      constant_value = constant->Integer32Value() & 0x1f;
727
      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
728
      // truncated to smi.
729
      if (instr->representation().IsSmi() && constant_value > 0) {
730
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
731
      }
732
    } else {
733
      right = UseRegisterAtStart(right_value);
734 2fc47ab1 Ben Noordhuis
    }
735 c30f1137 Ryan Dahl
736 f230a1cf Ben Noordhuis
    // Shift operations can only deoptimize if we do a logical shift
737
    // by 0 and the result cannot be truncated to int32.
738
    if (op == Token::SHR && constant_value == 0) {
739
      if (FLAG_opt_safe_uint32_operations) {
740
        does_deopt = !instr->CheckFlag(HInstruction::kUint32);
741
      } else {
742
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
743
      }
744 c30f1137 Ryan Dahl
    }
745
746 f230a1cf Ben Noordhuis
    LInstruction* result =
747
        DefineAsRegister(new(zone()) LShiftI(op, left, right, does_deopt));
748
    return does_deopt ? AssignEnvironment(result) : result;
749
  } else {
750
    return DoArithmeticT(op, instr);
751
  }
752 c30f1137 Ryan Dahl
}
753
754
755
LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
756
                                           HArithmeticBinaryOperation* instr) {
757
  ASSERT(instr->representation().IsDouble());
758
  ASSERT(instr->left()->representation().IsDouble());
759
  ASSERT(instr->right()->representation().IsDouble());
760 f230a1cf Ben Noordhuis
  if (op == Token::MOD) {
761
    LOperand* left = UseFixedDouble(instr->left(), d1);
762
    LOperand* right = UseFixedDouble(instr->right(), d2);
763
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
764
    // We call a C function for double modulo. It can't trigger a GC. We need
765
    // to use fixed result register for the call.
766
    // TODO(fschneider): Allow any register as input registers.
767
    return MarkAsCall(DefineFixedDouble(result, d1), instr);
768
  } else {
769
    LOperand* left = UseRegisterAtStart(instr->left());
770
    LOperand* right = UseRegisterAtStart(instr->right());
771
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
772
    return DefineAsRegister(result);
773
  }
774 c30f1137 Ryan Dahl
}
775
776
777
LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
778 f230a1cf Ben Noordhuis
                                           HBinaryOperation* instr) {
779 c30f1137 Ryan Dahl
  HValue* left = instr->left();
780
  HValue* right = instr->right();
781 1bd711c8 Ben Noordhuis
  ASSERT(left->representation().IsTagged());
782
  ASSERT(right->representation().IsTagged());
783 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
784 c30f1137 Ryan Dahl
  LOperand* left_operand = UseFixed(left, r1);
785
  LOperand* right_operand = UseFixed(right, r0);
786 e4fc2cbf isaacs
  LArithmeticT* result =
787 f230a1cf Ben Noordhuis
      new(zone()) LArithmeticT(op, context, left_operand, right_operand);
788 c30f1137 Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
789
}
790
791 7eaa956b Ryan Dahl
792 c30f1137 Ryan Dahl
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
793
  ASSERT(is_building());
794
  current_block_ = block;
795
  next_block_ = next_block;
796
  if (block->IsStartBlock()) {
797
    block->UpdateEnvironment(graph_->start_environment());
798
    argument_count_ = 0;
799
  } else if (block->predecessors()->length() == 1) {
800
    // We have a single predecessor => copy environment and outgoing
801
    // argument count from the predecessor.
802
    ASSERT(block->phis()->length() == 0);
803
    HBasicBlock* pred = block->predecessors()->at(0);
804
    HEnvironment* last_environment = pred->last_environment();
805
    ASSERT(last_environment != NULL);
806
    // Only copy the environment, if it is later used again.
807
    if (pred->end()->SecondSuccessor() == NULL) {
808
      ASSERT(pred->end()->FirstSuccessor() == block);
809
    } else {
810
      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
811
          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
812
        last_environment = last_environment->Copy();
813
      }
814
    }
815
    block->UpdateEnvironment(last_environment);
816
    ASSERT(pred->argument_count() >= 0);
817
    argument_count_ = pred->argument_count();
818
  } else {
819
    // We are at a state join => process phis.
820
    HBasicBlock* pred = block->predecessors()->at(0);
821
    // No need to copy the environment, it cannot be used later.
822
    HEnvironment* last_environment = pred->last_environment();
823
    for (int i = 0; i < block->phis()->length(); ++i) {
824
      HPhi* phi = block->phis()->at(i);
825 26bc8db3 Trevor Norris
      if (phi->HasMergedIndex()) {
826 50624a50 isaacs
        last_environment->SetValueAt(phi->merged_index(), phi);
827
      }
828 c30f1137 Ryan Dahl
    }
829
    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
830 50624a50 isaacs
      if (block->deleted_phis()->at(i) < last_environment->length()) {
831
        last_environment->SetValueAt(block->deleted_phis()->at(i),
832
                                     graph_->GetConstantUndefined());
833
      }
834 c30f1137 Ryan Dahl
    }
835
    block->UpdateEnvironment(last_environment);
836
    // Pick up the outgoing argument count of one of the predecessors.
837
    argument_count_ = pred->argument_count();
838
  }
839
  HInstruction* current = block->first();
840
  int start = chunk_->instructions()->length();
841
  while (current != NULL && !is_aborted()) {
842
    // Code for constants in registers is generated lazily.
843
    if (!current->EmitAtUses()) {
844
      VisitInstruction(current);
845
    }
846
    current = current->next();
847
  }
848
  int end = chunk_->instructions()->length() - 1;
849
  if (end >= start) {
850
    block->set_first_instruction_index(start);
851
    block->set_last_instruction_index(end);
852
  }
853
  block->set_argument_count(argument_count_);
854
  next_block_ = NULL;
855
  current_block_ = NULL;
856
}
857
858
859
void LChunkBuilder::VisitInstruction(HInstruction* current) {
860
  HInstruction* old_current = current_instruction_;
861
  current_instruction_ = current;
862
  if (current->has_position()) position_ = current->position();
863 f230a1cf Ben Noordhuis
864
  LInstruction* instr = NULL;
865
  if (current->CanReplaceWithDummyUses()) {
866
    HValue* first_operand = current->OperandCount() == 0
867
        ? graph()->GetConstant1()
868
        : current->OperandAt(0);
869
    instr = DefineAsRegister(new(zone()) LDummyUse(UseAny(first_operand)));
870
    for (int i = 1; i < current->OperandCount(); ++i) {
871
      LInstruction* dummy =
872
          new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
873
      dummy->set_hydrogen_value(current);
874
      chunk_->AddInstruction(dummy, current_block_);
875
    }
876
  } else {
877
    instr = current->CompileToLithium(this);
878
  }
879
880
  argument_count_ += current->argument_delta();
881
  ASSERT(argument_count_ >= 0);
882 c30f1137 Ryan Dahl
883
  if (instr != NULL) {
884 f230a1cf Ben Noordhuis
    // Associate the hydrogen instruction first, since we may need it for
885
    // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
886
    instr->set_hydrogen_value(current);
887
888 587e83c6 Ben Noordhuis
#if DEBUG
889
    // Make sure that the lithium instruction has either no fixed register
890
    // constraints in temps or the result OR no uses that are only used at
891
    // start. If this invariant doesn't hold, the register allocator can decide
892
    // to insert a split of a range immediately before the instruction due to an
893
    // already allocated register needing to be used for the instruction's fixed
894
    // register constraint. In this case, The register allocator won't see an
895
    // interference between the split child and the use-at-start (it would if
896
    // the it was just a plain use), so it is free to move the split child into
897
    // the same register that is used for the use-at-start.
898
    // See https://code.google.com/p/chromium/issues/detail?id=201590
899
    if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) {
900
      int fixed = 0;
901
      int used_at_start = 0;
902
      for (UseIterator it(instr); !it.Done(); it.Advance()) {
903
        LUnallocated* operand = LUnallocated::cast(it.Current());
904
        if (operand->IsUsedAtStart()) ++used_at_start;
905
      }
906
      if (instr->Output() != NULL) {
907
        if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
908
      }
909
      for (TempIterator it(instr); !it.Done(); it.Advance()) {
910
        LUnallocated* operand = LUnallocated::cast(it.Current());
911
        if (operand->HasFixedPolicy()) ++fixed;
912
      }
913
      ASSERT(fixed == 0 || used_at_start == 0);
914
    }
915
#endif
916
917 c30f1137 Ryan Dahl
    if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
918
      instr = AssignPointerMap(instr);
919
    }
920
    if (FLAG_stress_environments && !instr->HasEnvironment()) {
921
      instr = AssignEnvironment(instr);
922
    }
923 a0702b54 Ryan Dahl
    chunk_->AddInstruction(instr, current_block_);
924 c30f1137 Ryan Dahl
  }
925
  current_instruction_ = old_current;
926
}
927
928
929 21d081fd Ryan Dahl
LEnvironment* LChunkBuilder::CreateEnvironment(
930
    HEnvironment* hydrogen_env,
931 26bc8db3 Trevor Norris
    int* argument_index_accumulator,
932
    ZoneList<HValue*>* objects_to_materialize) {
933 c30f1137 Ryan Dahl
  if (hydrogen_env == NULL) return NULL;
934
935 26bc8db3 Trevor Norris
  LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(),
936
                                          argument_index_accumulator,
937
                                          objects_to_materialize);
938 3411a03d isaacs
  BailoutId ast_id = hydrogen_env->ast_id();
939
  ASSERT(!ast_id.IsNone() ||
940 e4fc2cbf isaacs
         hydrogen_env->frame_type() != JS_FUNCTION);
941 704fd8f3 Ben Noordhuis
  int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
942 e4fc2cbf isaacs
  LEnvironment* result = new(zone()) LEnvironment(
943
      hydrogen_env->closure(),
944
      hydrogen_env->frame_type(),
945
      ast_id,
946
      hydrogen_env->parameter_count(),
947
      argument_count_,
948
      value_count,
949 50464cd4 Bert Belder
      outer,
950 7b4d95a9 Fedor Indutny
      hydrogen_env->entry(),
951 50464cd4 Bert Belder
      zone());
952 05471f5c isaacs
  int argument_index = *argument_index_accumulator;
953 26bc8db3 Trevor Norris
  int object_index = objects_to_materialize->length();
954 704fd8f3 Ben Noordhuis
  for (int i = 0; i < hydrogen_env->length(); ++i) {
955 e5564a3f Ryan Dahl
    if (hydrogen_env->is_special_index(i)) continue;
956
957 26bc8db3 Trevor Norris
    LOperand* op;
958 c30f1137 Ryan Dahl
    HValue* value = hydrogen_env->values()->at(i);
959 26bc8db3 Trevor Norris
    if (value->IsArgumentsObject() || value->IsCapturedObject()) {
960
      objects_to_materialize->Add(value, zone());
961
      op = LEnvironment::materialization_marker();
962 c30f1137 Ryan Dahl
    } else if (value->IsPushArgument()) {
963 e4fc2cbf isaacs
      op = new(zone()) LArgument(argument_index++);
964 c30f1137 Ryan Dahl
    } else {
965 b8f006ef Ryan Dahl
      op = UseAny(value);
966 c30f1137 Ryan Dahl
    }
967 3411a03d isaacs
    result->AddValue(op,
968
                     value->representation(),
969
                     value->CheckFlag(HInstruction::kUint32));
970 c30f1137 Ryan Dahl
  }
971
972 26bc8db3 Trevor Norris
  for (int i = object_index; i < objects_to_materialize->length(); ++i) {
973
    HValue* object_to_materialize = objects_to_materialize->at(i);
974
    int previously_materialized_object = -1;
975
    for (int prev = 0; prev < i; ++prev) {
976
      if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) {
977
        previously_materialized_object = prev;
978
        break;
979
      }
980
    }
981
    int length = object_to_materialize->OperandCount();
982
    bool is_arguments = object_to_materialize->IsArgumentsObject();
983
    if (previously_materialized_object >= 0) {
984
      result->AddDuplicateObject(previously_materialized_object);
985
      continue;
986
    } else {
987
      result->AddNewObject(is_arguments ? length - 1 : length, is_arguments);
988
    }
989
    for (int i = is_arguments ? 1 : 0; i < length; ++i) {
990
      LOperand* op;
991
      HValue* value = object_to_materialize->OperandAt(i);
992
      if (value->IsArgumentsObject() || value->IsCapturedObject()) {
993
        objects_to_materialize->Add(value, zone());
994
        op = LEnvironment::materialization_marker();
995
      } else {
996
        ASSERT(!value->IsPushArgument());
997
        op = UseAny(value);
998
      }
999 704fd8f3 Ben Noordhuis
      result->AddValue(op,
1000
                       value->representation(),
1001
                       value->CheckFlag(HInstruction::kUint32));
1002
    }
1003
  }
1004
1005 e4fc2cbf isaacs
  if (hydrogen_env->frame_type() == JS_FUNCTION) {
1006 05471f5c isaacs
    *argument_index_accumulator = argument_index;
1007
  }
1008
1009 c30f1137 Ryan Dahl
  return result;
1010
}
1011
1012
1013
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1014 f230a1cf Ben Noordhuis
  return new(zone()) LGoto(instr->FirstSuccessor());
1015 c30f1137 Ryan Dahl
}
1016
1017
1018 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1019 f230a1cf Ben Noordhuis
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1020
  if (goto_instr != NULL) return goto_instr;
1021 60040a4f Ryan Dahl
1022 f230a1cf Ben Noordhuis
  HValue* value = instr->value();
1023 e4fc2cbf isaacs
  LBranch* result = new(zone()) LBranch(UseRegister(value));
1024 60040a4f Ryan Dahl
  // Tagged values that are not known smis or booleans require a
1025 704fd8f3 Ben Noordhuis
  // deoptimization environment. If the instruction is generic no
1026
  // environment is needed since all cases are handled.
1027 60040a4f Ryan Dahl
  Representation rep = value->representation();
1028
  HType type = value->type();
1029 704fd8f3 Ben Noordhuis
  ToBooleanStub::Types expected = instr->expected_input_types();
1030
  if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean() &&
1031
      !expected.IsGeneric()) {
1032 60040a4f Ryan Dahl
    return AssignEnvironment(result);
1033
  }
1034
  return result;
1035 c30f1137 Ryan Dahl
}
1036
1037
1038 506fc4de Trevor Norris
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
1039
  return new(zone()) LDebugBreak();
1040
}
1041
1042 e5564a3f Ryan Dahl
1043 4c5e5707 Ryan Dahl
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1044 c30f1137 Ryan Dahl
  ASSERT(instr->value()->representation().IsTagged());
1045
  LOperand* value = UseRegisterAtStart(instr->value());
1046 cf2e4f44 Ryan Dahl
  LOperand* temp = TempRegister();
1047 e4fc2cbf isaacs
  return new(zone()) LCmpMapAndBranch(value, temp);
1048 c30f1137 Ryan Dahl
}
1049
1050
1051 e4fc2cbf isaacs
LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
1052 2f75785c Ben Noordhuis
  info()->MarkAsRequiresFrame();
1053 e4fc2cbf isaacs
  LOperand* value = UseRegister(instr->value());
1054
  return DefineAsRegister(new(zone()) LArgumentsLength(value));
1055 c30f1137 Ryan Dahl
}
1056
1057
1058
LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1059 2f75785c Ben Noordhuis
  info()->MarkAsRequiresFrame();
1060 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LArgumentsElements);
1061 c30f1137 Ryan Dahl
}
1062
1063
1064
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1065 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1066 4c5e5707 Ryan Dahl
  LInstanceOf* result =
1067 f230a1cf Ben Noordhuis
      new(zone()) LInstanceOf(context, UseFixed(instr->left(), r0),
1068
                              UseFixed(instr->right(), r1));
1069 cf2e4f44 Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
1070
}
1071
1072
1073
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1074
    HInstanceOfKnownGlobal* instr) {
1075 4c5e5707 Ryan Dahl
  LInstanceOfKnownGlobal* result =
1076 f230a1cf Ben Noordhuis
      new(zone()) LInstanceOfKnownGlobal(
1077
          UseFixed(instr->context(), cp),
1078
          UseFixed(instr->left(), r0),
1079
          FixedTemp(r4));
1080 14475c77 Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
1081 c30f1137 Ryan Dahl
}
1082
1083
1084 4b64542f isaacs
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
1085
  LOperand* receiver = UseRegisterAtStart(instr->receiver());
1086
  LOperand* function = UseRegisterAtStart(instr->function());
1087
  LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
1088
  return AssignEnvironment(DefineSameAsFirst(result));
1089
}
1090
1091
1092 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1093
  LOperand* function = UseFixed(instr->function(), r1);
1094
  LOperand* receiver = UseFixed(instr->receiver(), r0);
1095 550f73ae Ryan Dahl
  LOperand* length = UseFixed(instr->length(), r2);
1096
  LOperand* elements = UseFixed(instr->elements(), r3);
1097 e4fc2cbf isaacs
  LApplyArguments* result = new(zone()) LApplyArguments(function,
1098 4c5e5707 Ryan Dahl
                                                receiver,
1099
                                                length,
1100
                                                elements);
1101 c30f1137 Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1102
}
1103
1104
1105
LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1106
  LOperand* argument = Use(instr->argument());
1107 e4fc2cbf isaacs
  return new(zone()) LPushArgument(argument);
1108 c30f1137 Ryan Dahl
}
1109
1110
1111 a53c763c Timothy J Fontaine
LInstruction* LChunkBuilder::DoStoreCodeEntry(
1112
    HStoreCodeEntry* store_code_entry) {
1113
  LOperand* function = UseRegister(store_code_entry->function());
1114
  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
1115
  return new(zone()) LStoreCodeEntry(function, code_object);
1116
}
1117
1118
1119 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1120
    HInnerAllocatedObject* inner_object) {
1121
  LOperand* base_object = UseRegisterAtStart(inner_object->base_object());
1122
  LInnerAllocatedObject* result =
1123
    new(zone()) LInnerAllocatedObject(base_object);
1124
  return DefineAsRegister(result);
1125
}
1126
1127
1128 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1129 e4fc2cbf isaacs
  return instr->HasNoUses()
1130
      ? NULL
1131
      : DefineAsRegister(new(zone()) LThisFunction);
1132 e5564a3f Ryan Dahl
}
1133
1134
1135 a0702b54 Ryan Dahl
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1136 f230a1cf Ben Noordhuis
  if (instr->HasNoUses()) return NULL;
1137
1138
  if (info()->IsStub()) {
1139
    return DefineFixed(new(zone()) LContext, cp);
1140 83261e78 Trevor Norris
  }
1141
1142 f230a1cf Ben Noordhuis
  return DefineAsRegister(new(zone()) LContext);
1143 a0702b54 Ryan Dahl
}
1144
1145
1146
LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1147
  LOperand* context = UseRegisterAtStart(instr->value());
1148 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LOuterContext(context));
1149 a0702b54 Ryan Dahl
}
1150
1151
1152 f4641bd4 isaacs
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1153 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1154
  return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1155 f4641bd4 isaacs
}
1156
1157
1158 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1159 a0702b54 Ryan Dahl
  LOperand* context = UseRegisterAtStart(instr->value());
1160 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LGlobalObject(context));
1161 c30f1137 Ryan Dahl
}
1162
1163
1164
LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1165 a0702b54 Ryan Dahl
  LOperand* global_object = UseRegisterAtStart(instr->value());
1166 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LGlobalReceiver(global_object));
1167 c30f1137 Ryan Dahl
}
1168
1169
1170
LInstruction* LChunkBuilder::DoCallConstantFunction(
1171
    HCallConstantFunction* instr) {
1172 e4fc2cbf isaacs
  return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, r0), instr);
1173 c30f1137 Ryan Dahl
}
1174
1175
1176 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1177 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1178 e5564a3f Ryan Dahl
  LOperand* function = UseFixed(instr->function(), r1);
1179 f230a1cf Ben Noordhuis
  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1180 e5564a3f Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1181
}
1182
1183
1184 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1185 9f682265 Ben Noordhuis
  switch (instr->op()) {
1186
    case kMathFloor: return DoMathFloor(instr);
1187
    case kMathRound: return DoMathRound(instr);
1188
    case kMathAbs: return DoMathAbs(instr);
1189
    case kMathLog: return DoMathLog(instr);
1190
    case kMathSin: return DoMathSin(instr);
1191
    case kMathCos: return DoMathCos(instr);
1192
    case kMathTan: return DoMathTan(instr);
1193
    case kMathExp: return DoMathExp(instr);
1194
    case kMathSqrt: return DoMathSqrt(instr);
1195
    case kMathPowHalf: return DoMathPowHalf(instr);
1196
    default:
1197
      UNREACHABLE();
1198
      return NULL;
1199 c30f1137 Ryan Dahl
  }
1200
}
1201
1202
1203 9f682265 Ben Noordhuis
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1204
  LOperand* input = UseRegister(instr->value());
1205
  LMathFloor* result = new(zone()) LMathFloor(input);
1206
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1207
}
1208
1209
1210
LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1211
  LOperand* input = UseRegister(instr->value());
1212
  LOperand* temp = FixedTemp(d3);
1213
  LMathRound* result = new(zone()) LMathRound(input, temp);
1214
  return AssignEnvironment(DefineAsRegister(result));
1215
}
1216
1217
1218
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1219 f230a1cf Ben Noordhuis
  Representation r = instr->value()->representation();
1220
  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
1221
      ? NULL
1222
      : UseFixed(instr->context(), cp);
1223 9f682265 Ben Noordhuis
  LOperand* input = UseRegister(instr->value());
1224 f230a1cf Ben Noordhuis
  LMathAbs* result = new(zone()) LMathAbs(context, input);
1225 9f682265 Ben Noordhuis
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1226
}
1227
1228
1229
LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1230
  LOperand* input = UseFixedDouble(instr->value(), d2);
1231
  LMathLog* result = new(zone()) LMathLog(input);
1232
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1233
}
1234
1235
1236
LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1237
  LOperand* input = UseFixedDouble(instr->value(), d2);
1238
  LMathSin* result = new(zone()) LMathSin(input);
1239
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1240
}
1241
1242
1243
LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1244
  LOperand* input = UseFixedDouble(instr->value(), d2);
1245
  LMathCos* result = new(zone()) LMathCos(input);
1246
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1247
}
1248
1249
1250
LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) {
1251
  LOperand* input = UseFixedDouble(instr->value(), d2);
1252
  LMathTan* result = new(zone()) LMathTan(input);
1253
  return MarkAsCall(DefineFixedDouble(result, d2), instr);
1254
}
1255
1256
1257
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1258
  ASSERT(instr->representation().IsDouble());
1259
  ASSERT(instr->value()->representation().IsDouble());
1260 f230a1cf Ben Noordhuis
  LOperand* input = UseRegister(instr->value());
1261 9f682265 Ben Noordhuis
  LOperand* temp1 = TempRegister();
1262
  LOperand* temp2 = TempRegister();
1263
  LOperand* double_temp = FixedTemp(d3);  // Chosen by fair dice roll.
1264
  LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
1265
  return DefineAsRegister(result);
1266
}
1267
1268
1269
LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1270
  LOperand* input = UseRegister(instr->value());
1271
  LMathSqrt* result = new(zone()) LMathSqrt(input);
1272
  return DefineAsRegister(result);
1273
}
1274
1275
1276
LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1277
  LOperand* input = UseFixedDouble(instr->value(), d2);
1278
  LOperand* temp = FixedTemp(d3);
1279
  LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
1280
  return DefineFixedDouble(result, d2);
1281
}
1282
1283
1284 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1285
  ASSERT(instr->key()->representation().IsTagged());
1286 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1287 4c5e5707 Ryan Dahl
  LOperand* key = UseFixed(instr->key(), r2);
1288 f230a1cf Ben Noordhuis
  return MarkAsCall(
1289
        DefineFixed(new(zone()) LCallKeyed(context, key), r0), instr);
1290 c30f1137 Ryan Dahl
}
1291
1292
1293
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1294 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1295
  return MarkAsCall(DefineFixed(new(zone()) LCallNamed(context), r0), instr);
1296 c30f1137 Ryan Dahl
}
1297
1298
1299
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1300 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1301
  return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(context), r0), instr);
1302 c30f1137 Ryan Dahl
}
1303
1304
1305
LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1306 e4fc2cbf isaacs
  return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, r0), instr);
1307 c30f1137 Ryan Dahl
}
1308
1309
1310
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1311 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1312 c30f1137 Ryan Dahl
  LOperand* constructor = UseFixed(instr->constructor(), r1);
1313 f230a1cf Ben Noordhuis
  LCallNew* result = new(zone()) LCallNew(context, constructor);
1314 c30f1137 Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
1315
}
1316
1317
1318 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1319 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1320 83261e78 Trevor Norris
  LOperand* constructor = UseFixed(instr->constructor(), r1);
1321 f230a1cf Ben Noordhuis
  LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1322 83261e78 Trevor Norris
  return MarkAsCall(DefineFixed(result, r0), instr);
1323
}
1324
1325
1326 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1327 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1328 21d081fd Ryan Dahl
  LOperand* function = UseFixed(instr->function(), r1);
1329 f230a1cf Ben Noordhuis
  return MarkAsCall(
1330
      DefineFixed(new(zone()) LCallFunction(context, function), r0), instr);
1331 c30f1137 Ryan Dahl
}
1332
1333
1334
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1335 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1336
  return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), r0), instr);
1337 c30f1137 Ryan Dahl
}
1338
1339
1340 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1341
  return DoShift(Token::ROR, instr);
1342
}
1343
1344
1345 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1346
  return DoShift(Token::SHR, instr);
1347
}
1348
1349
1350
LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1351
  return DoShift(Token::SAR, instr);
1352
}
1353
1354
1355
LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1356
  return DoShift(Token::SHL, instr);
1357
}
1358
1359
1360 21d081fd Ryan Dahl
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1361 1bd711c8 Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
1362
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1363
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1364 f230a1cf Ben Noordhuis
    ASSERT(instr->CheckFlag(HValue::kTruncatingToInt32));
1365 21d081fd Ryan Dahl
1366 7ee538dd Ben Noordhuis
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1367
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1368 e4fc2cbf isaacs
    return DefineAsRegister(new(zone()) LBitI(left, right));
1369 21d081fd Ryan Dahl
  } else {
1370 f230a1cf Ben Noordhuis
    return DoArithmeticT(instr->op(), instr);
1371 21d081fd Ryan Dahl
  }
1372 c30f1137 Ryan Dahl
}
1373
1374
1375
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1376 f230a1cf Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
1377 1bd711c8 Ben Noordhuis
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1378
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1379 83261e78 Trevor Norris
    if (instr->HasPowerOf2Divisor()) {
1380
      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1381
      LOperand* value = UseRegisterAtStart(instr->left());
1382 f230a1cf Ben Noordhuis
      LDivI* div = new(zone()) LDivI(value, UseConstant(instr->right()), NULL);
1383
      return AssignEnvironment(DefineAsRegister(div));
1384 83261e78 Trevor Norris
    }
1385 6dd78074 Ben Noordhuis
    LOperand* dividend = UseRegister(instr->left());
1386
    LOperand* divisor = UseRegister(instr->right());
1387
    LOperand* temp = CpuFeatures::IsSupported(SUDIV) ? NULL : FixedTemp(d4);
1388
    LDivI* div = new(zone()) LDivI(dividend, divisor, temp);
1389
    return AssignEnvironment(DefineAsRegister(div));
1390 f230a1cf Ben Noordhuis
  } else if (instr->representation().IsDouble()) {
1391
    return DoArithmeticD(Token::DIV, instr);
1392 c30f1137 Ryan Dahl
  } else {
1393
    return DoArithmeticT(Token::DIV, instr);
1394
  }
1395
}
1396
1397
1398 50464cd4 Bert Belder
bool LChunkBuilder::HasMagicNumberForDivisor(int32_t divisor) {
1399
  uint32_t divisor_abs = abs(divisor);
1400
  // Dividing by 0, 1, and powers of 2 is easy.
1401
  // Note that IsPowerOf2(0) returns true;
1402
  ASSERT(IsPowerOf2(0) == true);
1403
  if (IsPowerOf2(divisor_abs)) return true;
1404
1405
  // We have magic numbers for a few specific divisors.
1406
  // Details and proofs can be found in:
1407
  // - Hacker's Delight, Henry S. Warren, Jr.
1408
  // - The PowerPC Compiler Writer’s Guide
1409
  // and probably many others.
1410
  //
1411
  // We handle
1412
  //   <divisor with magic numbers> * <power of 2>
1413
  // but not
1414
  //   <divisor with magic numbers> * <other divisor with magic numbers>
1415
  int32_t power_of_2_factor =
1416
    CompilerIntrinsics::CountTrailingZeros(divisor_abs);
1417
  DivMagicNumbers magic_numbers =
1418
    DivMagicNumberFor(divisor_abs >> power_of_2_factor);
1419
  if (magic_numbers.M != InvalidDivMagicNumber.M) return true;
1420
1421
  return false;
1422
}
1423
1424
1425
HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) {
1426 83261e78 Trevor Norris
  if (CpuFeatures::IsSupported(SUDIV)) {
1427
    // A value with an integer representation does not need to be transformed.
1428
    if (divisor->representation().IsInteger32()) {
1429
      return divisor;
1430
    // A change from an integer32 can be replaced by the integer32 value.
1431
    } else if (divisor->IsChange() &&
1432
               HChange::cast(divisor)->from().IsInteger32()) {
1433
      return HChange::cast(divisor)->value();
1434
    }
1435
  }
1436
1437
  if (divisor->IsConstant() && HConstant::cast(divisor)->HasInteger32Value()) {
1438 50464cd4 Bert Belder
    HConstant* constant_val = HConstant::cast(divisor);
1439
    int32_t int32_val = constant_val->Integer32Value();
1440 83261e78 Trevor Norris
    if (LChunkBuilder::HasMagicNumberForDivisor(int32_val) ||
1441
        CpuFeatures::IsSupported(SUDIV)) {
1442 50464cd4 Bert Belder
      return constant_val->CopyToRepresentation(Representation::Integer32(),
1443
                                                divisor->block()->zone());
1444
    }
1445
  }
1446 83261e78 Trevor Norris
1447 50464cd4 Bert Belder
  return NULL;
1448
}
1449
1450
1451
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1452 83261e78 Trevor Norris
  HValue* right = instr->right();
1453
  LOperand* dividend = UseRegister(instr->left());
1454
  LOperand* divisor = CpuFeatures::IsSupported(SUDIV)
1455
      ? UseRegister(right)
1456
      : UseOrConstant(right);
1457
  LOperand* remainder = TempRegister();
1458
  ASSERT(CpuFeatures::IsSupported(SUDIV) ||
1459
         (right->IsConstant() &&
1460
          HConstant::cast(right)->HasInteger32Value() &&
1461
          HasMagicNumberForDivisor(HConstant::cast(right)->Integer32Value())));
1462
  return AssignEnvironment(DefineAsRegister(
1463 50464cd4 Bert Belder
          new(zone()) LMathFloorOfDiv(dividend, divisor, remainder)));
1464
}
1465
1466
1467 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1468 6dd78074 Ben Noordhuis
  HValue* left = instr->left();
1469
  HValue* right = instr->right();
1470 1bd711c8 Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
1471
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1472
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1473 e5564a3f Ryan Dahl
    if (instr->HasPowerOf2Divisor()) {
1474 6dd78074 Ben Noordhuis
      ASSERT(!right->CanBeZero());
1475
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1476
                                     UseOrConstant(right));
1477
      LInstruction* result = DefineAsRegister(mod);
1478
      return (left->CanBeNegative() &&
1479
              instr->CheckFlag(HValue::kBailoutOnMinusZero))
1480
          ? AssignEnvironment(result)
1481
          : result;
1482 704fd8f3 Ben Noordhuis
    } else if (instr->fixed_right_arg().has_value) {
1483 6dd78074 Ben Noordhuis
      LModI* mod = new(zone()) LModI(UseRegisterAtStart(left),
1484
                                     UseRegisterAtStart(right));
1485 e5564a3f Ryan Dahl
      return AssignEnvironment(DefineAsRegister(mod));
1486 6dd78074 Ben Noordhuis
    } else if (CpuFeatures::IsSupported(SUDIV)) {
1487
      LModI* mod = new(zone()) LModI(UseRegister(left),
1488
                                     UseRegister(right));
1489
      LInstruction* result = DefineAsRegister(mod);
1490
      return (right->CanBeZero() ||
1491
              (left->RangeCanInclude(kMinInt) &&
1492
               right->RangeCanInclude(-1) &&
1493
               instr->CheckFlag(HValue::kBailoutOnMinusZero)) ||
1494
              (left->CanBeNegative() &&
1495
               instr->CanBeZero() &&
1496
               instr->CheckFlag(HValue::kBailoutOnMinusZero)))
1497
          ? AssignEnvironment(result)
1498
          : result;
1499 e5564a3f Ryan Dahl
    } else {
1500 6dd78074 Ben Noordhuis
      LModI* mod = new(zone()) LModI(UseRegister(left),
1501
                                     UseRegister(right),
1502
                                     FixedTemp(d10),
1503
                                     FixedTemp(d11));
1504
      LInstruction* result = DefineAsRegister(mod);
1505
      return (right->CanBeZero() ||
1506
              (left->CanBeNegative() &&
1507
               instr->CanBeZero() &&
1508
               instr->CheckFlag(HValue::kBailoutOnMinusZero)))
1509
          ? AssignEnvironment(result)
1510
          : result;
1511 e5564a3f Ryan Dahl
    }
1512 f230a1cf Ben Noordhuis
  } else if (instr->representation().IsDouble()) {
1513
    return DoArithmeticD(Token::MOD, instr);
1514 c30f1137 Ryan Dahl
  } else {
1515 f230a1cf Ben Noordhuis
    return DoArithmeticT(Token::MOD, instr);
1516 c30f1137 Ryan Dahl
  }
1517
}
1518
1519
1520
LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1521 1bd711c8 Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
1522
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1523
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1524 a53c763c Timothy J Fontaine
    HValue* left = instr->BetterLeftOperand();
1525
    HValue* right = instr->BetterRightOperand();
1526
    LOperand* left_op;
1527
    LOperand* right_op;
1528
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1529
    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1530
1531
    if (right->IsConstant()) {
1532
      HConstant* constant = HConstant::cast(right);
1533
      int32_t constant_value = constant->Integer32Value();
1534
      // Constants -1, 0 and 1 can be optimized if the result can overflow.
1535
      // For other constants, it can be optimized only without overflow.
1536
      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1537
        left_op = UseRegisterAtStart(left);
1538
        right_op = UseConstant(right);
1539
      } else {
1540
        if (bailout_on_minus_zero) {
1541
          left_op = UseRegister(left);
1542
        } else {
1543
          left_op = UseRegisterAtStart(left);
1544
        }
1545
        right_op = UseRegister(right);
1546
      }
1547 e5564a3f Ryan Dahl
    } else {
1548 a53c763c Timothy J Fontaine
      if (bailout_on_minus_zero) {
1549
        left_op = UseRegister(left);
1550
      } else {
1551
        left_op = UseRegisterAtStart(left);
1552
      }
1553
      right_op = UseRegister(right);
1554 c30f1137 Ryan Dahl
    }
1555 a53c763c Timothy J Fontaine
    LMulI* mul = new(zone()) LMulI(left_op, right_op);
1556
    if (can_overflow || bailout_on_minus_zero) {
1557 60040a4f Ryan Dahl
      AssignEnvironment(mul);
1558
    }
1559
    return DefineAsRegister(mul);
1560 e5564a3f Ryan Dahl
1561 c30f1137 Ryan Dahl
  } else if (instr->representation().IsDouble()) {
1562 83261e78 Trevor Norris
    if (instr->UseCount() == 1 && (instr->uses().value()->IsAdd() ||
1563
                                   instr->uses().value()->IsSub())) {
1564
      HBinaryOperation* use = HBinaryOperation::cast(instr->uses().value());
1565
1566
      if (use->IsAdd() && instr == use->left()) {
1567
        // This mul is the lhs of an add. The add and mul will be folded into a
1568
        // multiply-add in DoAdd.
1569
        return NULL;
1570
      }
1571
      if (instr == use->right() && use->IsAdd() && !use->left()->IsMul()) {
1572
        // This mul is the rhs of an add, where the lhs is not another mul.
1573
        // The add and mul will be folded into a multiply-add in DoAdd.
1574
        return NULL;
1575
      }
1576
      if (instr == use->right() && use->IsSub()) {
1577
        // This mul is the rhs of a sub. The sub and mul will be folded into a
1578
        // multiply-sub in DoSub.
1579
        return NULL;
1580
      }
1581
    }
1582 b15a10e7 Ben Noordhuis
1583 83261e78 Trevor Norris
    return DoArithmeticD(Token::MUL, instr);
1584 c30f1137 Ryan Dahl
  } else {
1585
    return DoArithmeticT(Token::MUL, instr);
1586
  }
1587
}
1588
1589
1590
LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1591 1bd711c8 Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
1592
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1593
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1594 83261e78 Trevor Norris
1595
    if (instr->left()->IsConstant()) {
1596
      // If lhs is constant, do reverse subtraction instead.
1597
      return DoRSub(instr);
1598
    }
1599
1600 7eaa956b Ryan Dahl
    LOperand* left = UseRegisterAtStart(instr->left());
1601
    LOperand* right = UseOrConstantAtStart(instr->right());
1602 e4fc2cbf isaacs
    LSubI* sub = new(zone()) LSubI(left, right);
1603 e5564a3f Ryan Dahl
    LInstruction* result = DefineAsRegister(sub);
1604 c30f1137 Ryan Dahl
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1605
      result = AssignEnvironment(result);
1606
    }
1607
    return result;
1608
  } else if (instr->representation().IsDouble()) {
1609 83261e78 Trevor Norris
    if (instr->right()->IsMul()) {
1610
      return DoMultiplySub(instr->left(), HMul::cast(instr->right()));
1611
    }
1612
1613 c30f1137 Ryan Dahl
    return DoArithmeticD(Token::SUB, instr);
1614
  } else {
1615
    return DoArithmeticT(Token::SUB, instr);
1616
  }
1617
}
1618
1619
1620 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
1621 1bd711c8 Ben Noordhuis
  ASSERT(instr->representation().IsSmiOrInteger32());
1622
  ASSERT(instr->left()->representation().Equals(instr->representation()));
1623
  ASSERT(instr->right()->representation().Equals(instr->representation()));
1624 83261e78 Trevor Norris
1625
  // Note: The lhs of the subtraction becomes the rhs of the
1626
  // reverse-subtraction.
1627
  LOperand* left = UseRegisterAtStart(instr->right());
1628
  LOperand* right = UseOrConstantAtStart(instr->left());
1629
  LRSubI* rsb = new(zone()) LRSubI(left, right);
1630
  LInstruction* result = DefineAsRegister(rsb);
1631
  if (instr->CheckFlag(HValue::kCanOverflow)) {
1632
    result = AssignEnvironment(result);
1633
  }
1634
  return result;
1635
}
1636
1637
1638
LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1639
  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1640
  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1641
  LOperand* addend_op = UseRegisterAtStart(addend);
1642
  return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op,
1643
                                                     multiplicand_op));
1644
}
1645
1646
1647
LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
1648
  LOperand* minuend_op = UseRegisterAtStart(minuend);
1649
  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
1650
  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
1651
1652
  return DefineSameAsFirst(new(zone()) LMultiplySubD(minuend_op,
1653
                                                     multiplier_op,
1654
                                                     multiplicand_op));
1655
}
1656
1657
1658 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1659 1bd711c8 Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
1660
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1661
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1662 7ee538dd Ben Noordhuis
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1663
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1664 e4fc2cbf isaacs
    LAddI* add = new(zone()) LAddI(left, right);
1665 e5564a3f Ryan Dahl
    LInstruction* result = DefineAsRegister(add);
1666 c30f1137 Ryan Dahl
    if (instr->CheckFlag(HValue::kCanOverflow)) {
1667
      result = AssignEnvironment(result);
1668
    }
1669
    return result;
1670
  } else if (instr->representation().IsDouble()) {
1671 83261e78 Trevor Norris
    if (instr->left()->IsMul()) {
1672
      return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
1673
    }
1674
1675
    if (instr->right()->IsMul()) {
1676
      ASSERT(!instr->left()->IsMul());
1677
      return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
1678
    }
1679
1680 c30f1137 Ryan Dahl
    return DoArithmeticD(Token::ADD, instr);
1681
  } else {
1682
    return DoArithmeticT(Token::ADD, instr);
1683
  }
1684
}
1685
1686
1687 3411a03d isaacs
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1688
  LOperand* left = NULL;
1689
  LOperand* right = NULL;
1690 1bd711c8 Ben Noordhuis
  if (instr->representation().IsSmiOrInteger32()) {
1691
    ASSERT(instr->left()->representation().Equals(instr->representation()));
1692
    ASSERT(instr->right()->representation().Equals(instr->representation()));
1693 7ee538dd Ben Noordhuis
    left = UseRegisterAtStart(instr->BetterLeftOperand());
1694
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1695 3411a03d isaacs
  } else {
1696
    ASSERT(instr->representation().IsDouble());
1697
    ASSERT(instr->left()->representation().IsDouble());
1698
    ASSERT(instr->right()->representation().IsDouble());
1699
    left = UseRegisterAtStart(instr->left());
1700
    right = UseRegisterAtStart(instr->right());
1701
  }
1702
  return DefineAsRegister(new(zone()) LMathMinMax(left, right));
1703
}
1704
1705
1706 7d425a0a Ryan Dahl
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1707 e33e7d1a Ryan Dahl
  ASSERT(instr->representation().IsDouble());
1708
  // We call a C function for double power. It can't trigger a GC.
1709
  // We need to use fixed result register for the call.
1710
  Representation exponent_type = instr->right()->representation();
1711
  ASSERT(instr->left()->representation().IsDouble());
1712
  LOperand* left = UseFixedDouble(instr->left(), d1);
1713
  LOperand* right = exponent_type.IsDouble() ?
1714
      UseFixedDouble(instr->right(), d2) :
1715 b3a7de15 Ryan Dahl
      UseFixed(instr->right(), r2);
1716 e4fc2cbf isaacs
  LPower* result = new(zone()) LPower(left, right);
1717 e33e7d1a Ryan Dahl
  return MarkAsCall(DefineFixedDouble(result, d3),
1718
                    instr,
1719
                    CAN_DEOPTIMIZE_EAGERLY);
1720 7d425a0a Ryan Dahl
}
1721
1722
1723 60040a4f Ryan Dahl
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
1724
  ASSERT(instr->representation().IsDouble());
1725
  ASSERT(instr->global_object()->representation().IsTagged());
1726 a53c763c Timothy J Fontaine
  LOperand* global_object = UseTempRegister(instr->global_object());
1727
  LOperand* scratch = TempRegister();
1728
  LOperand* scratch2 = TempRegister();
1729
  LOperand* scratch3 = TempRegister();
1730
  LRandom* result = new(zone()) LRandom(
1731
      global_object, scratch, scratch2, scratch3);
1732
  return DefineFixedDouble(result, d7);
1733 60040a4f Ryan Dahl
}
1734
1735
1736 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1737
  ASSERT(instr->left()->representation().IsTagged());
1738
  ASSERT(instr->right()->representation().IsTagged());
1739 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1740 21d081fd Ryan Dahl
  LOperand* left = UseFixed(instr->left(), r1);
1741
  LOperand* right = UseFixed(instr->right(), r0);
1742 f230a1cf Ben Noordhuis
  LCmpT* result = new(zone()) LCmpT(context, left, right);
1743 e5564a3f Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
1744
}
1745
1746
1747 5777d7ab Trevor Norris
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1748
    HCompareNumericAndBranch* instr) {
1749 83261e78 Trevor Norris
  Representation r = instr->representation();
1750 6dd78074 Ben Noordhuis
  if (r.IsSmiOrInteger32()) {
1751 26bc8db3 Trevor Norris
    ASSERT(instr->left()->representation().Equals(r));
1752
    ASSERT(instr->right()->representation().Equals(r));
1753 21d081fd Ryan Dahl
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1754
    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1755 5777d7ab Trevor Norris
    return new(zone()) LCompareNumericAndBranch(left, right);
1756 e5564a3f Ryan Dahl
  } else {
1757
    ASSERT(r.IsDouble());
1758 cf2e4f44 Ryan Dahl
    ASSERT(instr->left()->representation().IsDouble());
1759 c30f1137 Ryan Dahl
    ASSERT(instr->right()->representation().IsDouble());
1760
    LOperand* left = UseRegisterAtStart(instr->left());
1761
    LOperand* right = UseRegisterAtStart(instr->right());
1762 5777d7ab Trevor Norris
    return new(zone()) LCompareNumericAndBranch(left, right);
1763 c30f1137 Ryan Dahl
  }
1764
}
1765
1766
1767 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1768
    HCompareObjectEqAndBranch* instr) {
1769 f230a1cf Ben Noordhuis
  LInstruction* goto_instr = CheckElideControlInstruction(instr);
1770
  if (goto_instr != NULL) return goto_instr;
1771 c30f1137 Ryan Dahl
  LOperand* left = UseRegisterAtStart(instr->left());
1772
  LOperand* right = UseRegisterAtStart(instr->right());
1773 e4fc2cbf isaacs
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1774 33af2720 Ryan Dahl
}
1775
1776
1777 26bc8db3 Trevor Norris
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1778
    HCompareHoleAndBranch* instr) {
1779 f230a1cf Ben Noordhuis
  LOperand* value = UseRegisterAtStart(instr->value());
1780
  return new(zone()) LCmpHoleAndBranch(value);
1781 26bc8db3 Trevor Norris
}
1782
1783
1784 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1785 33af2720 Ryan Dahl
  ASSERT(instr->value()->representation().IsTagged());
1786 e4fc2cbf isaacs
  LOperand* value = UseRegisterAtStart(instr->value());
1787 e5564a3f Ryan Dahl
  LOperand* temp = TempRegister();
1788 e4fc2cbf isaacs
  return new(zone()) LIsObjectAndBranch(value, temp);
1789 e5564a3f Ryan Dahl
}
1790
1791 14956255 Ryan Dahl
1792 21d081fd Ryan Dahl
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1793
  ASSERT(instr->value()->representation().IsTagged());
1794 e4fc2cbf isaacs
  LOperand* value = UseRegisterAtStart(instr->value());
1795 21d081fd Ryan Dahl
  LOperand* temp = TempRegister();
1796 e4fc2cbf isaacs
  return new(zone()) LIsStringAndBranch(value, temp);
1797 21d081fd Ryan Dahl
}
1798
1799
1800 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1801
  ASSERT(instr->value()->representation().IsTagged());
1802 e4fc2cbf isaacs
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1803 33af2720 Ryan Dahl
}
1804
1805
1806 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1807
    HIsUndetectableAndBranch* instr) {
1808 c30f1137 Ryan Dahl
  ASSERT(instr->value()->representation().IsTagged());
1809 e4fc2cbf isaacs
  LOperand* value = UseRegisterAtStart(instr->value());
1810
  return new(zone()) LIsUndetectableAndBranch(value, TempRegister());
1811 e5564a3f Ryan Dahl
}
1812 14956255 Ryan Dahl
1813 e5564a3f Ryan Dahl
1814 21d081fd Ryan Dahl
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1815
    HStringCompareAndBranch* instr) {
1816
  ASSERT(instr->left()->representation().IsTagged());
1817
  ASSERT(instr->right()->representation().IsTagged());
1818 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1819 21d081fd Ryan Dahl
  LOperand* left = UseFixed(instr->left(), r1);
1820
  LOperand* right = UseFixed(instr->right(), r0);
1821 e4fc2cbf isaacs
  LStringCompareAndBranch* result =
1822 f230a1cf Ben Noordhuis
      new(zone()) LStringCompareAndBranch(context, left, right);
1823 21d081fd Ryan Dahl
  return MarkAsCall(result, instr);
1824
}
1825
1826
1827 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1828
    HHasInstanceTypeAndBranch* instr) {
1829
  ASSERT(instr->value()->representation().IsTagged());
1830 e4fc2cbf isaacs
  LOperand* value = UseRegisterAtStart(instr->value());
1831
  return new(zone()) LHasInstanceTypeAndBranch(value);
1832 c30f1137 Ryan Dahl
}
1833
1834
1835 550f73ae Ryan Dahl
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1836
    HGetCachedArrayIndex* instr)  {
1837
  ASSERT(instr->value()->representation().IsTagged());
1838 e5564a3f Ryan Dahl
  LOperand* value = UseRegisterAtStart(instr->value());
1839 550f73ae Ryan Dahl
1840 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1841 550f73ae Ryan Dahl
}
1842
1843
1844 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1845
    HHasCachedArrayIndexAndBranch* instr) {
1846 c30f1137 Ryan Dahl
  ASSERT(instr->value()->representation().IsTagged());
1847 e4fc2cbf isaacs
  return new(zone()) LHasCachedArrayIndexAndBranch(
1848 e5564a3f Ryan Dahl
      UseRegisterAtStart(instr->value()));
1849 c30f1137 Ryan Dahl
}
1850
1851
1852 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1853
    HClassOfTestAndBranch* instr) {
1854 c30f1137 Ryan Dahl
  ASSERT(instr->value()->representation().IsTagged());
1855 e4fc2cbf isaacs
  LOperand* value = UseRegister(instr->value());
1856
  return new(zone()) LClassOfTestAndBranch(value, TempRegister());
1857 c30f1137 Ryan Dahl
}
1858
1859
1860 3411a03d isaacs
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
1861
  LOperand* map = UseRegisterAtStart(instr->value());
1862
  return DefineAsRegister(new(zone()) LMapEnumLength(map));
1863
}
1864
1865
1866 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1867
  LOperand* object = UseRegisterAtStart(instr->value());
1868 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LElementsKind(object));
1869 e5564a3f Ryan Dahl
}
1870
1871
1872 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1873
  LOperand* object = UseRegister(instr->value());
1874 e4fc2cbf isaacs
  LValueOf* result = new(zone()) LValueOf(object, TempRegister());
1875 60040a4f Ryan Dahl
  return DefineAsRegister(result);
1876 c30f1137 Ryan Dahl
}
1877
1878
1879 e4fc2cbf isaacs
LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1880
  LOperand* object = UseFixed(instr->value(), r0);
1881 50464cd4 Bert Belder
  LDateField* result =
1882
      new(zone()) LDateField(object, FixedTemp(r1), instr->index());
1883 3411a03d isaacs
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1884 e4fc2cbf isaacs
}
1885
1886
1887 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1888
  LOperand* string = UseRegister(instr->string());
1889 f230a1cf Ben Noordhuis
  LOperand* index = UseRegisterOrConstant(instr->index());
1890
  LOperand* value = UseRegister(instr->value());
1891
  return new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value);
1892 83261e78 Trevor Norris
}
1893
1894
1895 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1896 3411a03d isaacs
  LOperand* value = UseRegisterOrConstantAtStart(instr->index());
1897 e4fc2cbf isaacs
  LOperand* length = UseRegister(instr->length());
1898
  return AssignEnvironment(new(zone()) LBoundsCheck(value, length));
1899 c30f1137 Ryan Dahl
}
1900
1901
1902 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
1903
    HBoundsCheckBaseIndexInformation* instr) {
1904
  UNREACHABLE();
1905
  return NULL;
1906
}
1907
1908
1909 f230a1cf Ben Noordhuis
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1910
  // The control instruction marking the end of a block that completed
1911
  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1912
  return NULL;
1913
}
1914
1915
1916 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1917 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
1918 c30f1137 Ryan Dahl
  LOperand* value = UseFixed(instr->value(), r0);
1919 f230a1cf Ben Noordhuis
  return MarkAsCall(new(zone()) LThrow(context, value), instr);
1920 c30f1137 Ryan Dahl
}
1921
1922
1923 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1924
  return NULL;
1925
}
1926
1927
1928
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1929
  // All HForceRepresentation instructions should be eliminated in the
1930
  // representation change phase of Hydrogen.
1931
  UNREACHABLE();
1932
  return NULL;
1933
}
1934
1935
1936 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1937
  Representation from = instr->from();
1938
  Representation to = instr->to();
1939 6dd78074 Ben Noordhuis
  if (from.IsSmi()) {
1940
    if (to.IsTagged()) {
1941
      LOperand* value = UseRegister(instr->value());
1942
      return DefineSameAsFirst(new(zone()) LDummyUse(value));
1943
    }
1944
    from = Representation::Tagged();
1945
  }
1946 c30f1137 Ryan Dahl
  if (from.IsTagged()) {
1947
    if (to.IsDouble()) {
1948
      LOperand* value = UseRegister(instr->value());
1949 e4fc2cbf isaacs
      LNumberUntagD* res = new(zone()) LNumberUntagD(value);
1950 c30f1137 Ryan Dahl
      return AssignEnvironment(DefineAsRegister(res));
1951 6dd78074 Ben Noordhuis
    } else if (to.IsSmi()) {
1952
      HValue* val = instr->value();
1953
      LOperand* value = UseRegister(val);
1954
      if (val->type().IsSmi()) {
1955
        return DefineSameAsFirst(new(zone()) LDummyUse(value));
1956
      }
1957
      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1958 c30f1137 Ryan Dahl
    } else {
1959
      ASSERT(to.IsInteger32());
1960 587e83c6 Ben Noordhuis
      LOperand* value = NULL;
1961 c30f1137 Ryan Dahl
      LInstruction* res = NULL;
1962 a53c763c Timothy J Fontaine
      HValue* val = instr->value();
1963
      if (val->type().IsSmi() || val->representation().IsSmi()) {
1964
        value = UseRegisterAtStart(val);
1965 50464cd4 Bert Belder
        res = DefineAsRegister(new(zone()) LSmiUntag(value, false));
1966 e5564a3f Ryan Dahl
      } else {
1967 a53c763c Timothy J Fontaine
        value = UseRegister(val);
1968 e5564a3f Ryan Dahl
        LOperand* temp1 = TempRegister();
1969 a53c763c Timothy J Fontaine
        LOperand* temp2 = FixedTemp(d11);
1970 e4fc2cbf isaacs
        res = DefineSameAsFirst(new(zone()) LTaggedToI(value,
1971
                                                       temp1,
1972 a53c763c Timothy J Fontaine
                                                       temp2));
1973 c30f1137 Ryan Dahl
        res = AssignEnvironment(res);
1974
      }
1975
      return res;
1976
    }
1977
  } else if (from.IsDouble()) {
1978
    if (to.IsTagged()) {
1979 83261e78 Trevor Norris
      info()->MarkAsDeferredCalling();
1980 c30f1137 Ryan Dahl
      LOperand* value = UseRegister(instr->value());
1981 7d425a0a Ryan Dahl
      LOperand* temp1 = TempRegister();
1982
      LOperand* temp2 = TempRegister();
1983 c30f1137 Ryan Dahl
1984 7d425a0a Ryan Dahl
      // Make sure that the temp and result_temp registers are
1985
      // different.
1986 c30f1137 Ryan Dahl
      LUnallocated* result_temp = TempRegister();
1987 e4fc2cbf isaacs
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
1988 c30f1137 Ryan Dahl
      Define(result, result_temp);
1989
      return AssignPointerMap(result);
1990 6dd78074 Ben Noordhuis
    } else if (to.IsSmi()) {
1991
      LOperand* value = UseRegister(instr->value());
1992 a53c763c Timothy J Fontaine
      return AssignEnvironment(
1993
          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1994 c30f1137 Ryan Dahl
    } else {
1995
      ASSERT(to.IsInteger32());
1996
      LOperand* value = UseRegister(instr->value());
1997 a53c763c Timothy J Fontaine
      LDoubleToI* res = new(zone()) LDoubleToI(value);
1998 c30f1137 Ryan Dahl
      return AssignEnvironment(DefineAsRegister(res));
1999
    }
2000
  } else if (from.IsInteger32()) {
2001 83261e78 Trevor Norris
    info()->MarkAsDeferredCalling();
2002 c30f1137 Ryan Dahl
    if (to.IsTagged()) {
2003
      HValue* val = instr->value();
2004 8be69949 isaacs
      LOperand* value = UseRegisterAtStart(val);
2005 3411a03d isaacs
      if (val->CheckFlag(HInstruction::kUint32)) {
2006
        LNumberTagU* result = new(zone()) LNumberTagU(value);
2007
        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
2008
      } else if (val->HasRange() && val->range()->IsInSmiRange()) {
2009 e4fc2cbf isaacs
        return DefineAsRegister(new(zone()) LSmiTag(value));
2010 c30f1137 Ryan Dahl
      } else {
2011 e4fc2cbf isaacs
        LNumberTagI* result = new(zone()) LNumberTagI(value);
2012 8be69949 isaacs
        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2013 c30f1137 Ryan Dahl
      }
2014 6dd78074 Ben Noordhuis
    } else if (to.IsSmi()) {
2015
      HValue* val = instr->value();
2016
      LOperand* value = UseRegister(val);
2017 f230a1cf Ben Noordhuis
      LInstruction* result = val->CheckFlag(HInstruction::kUint32)
2018
          ? DefineSameAsFirst(new(zone()) LUint32ToSmi(value))
2019
          : DefineSameAsFirst(new(zone()) LInteger32ToSmi(value));
2020 6dd78074 Ben Noordhuis
      if (val->HasRange() && val->range()->IsInSmiRange()) {
2021
        return result;
2022
      }
2023
      return AssignEnvironment(result);
2024 c30f1137 Ryan Dahl
    } else {
2025
      ASSERT(to.IsDouble());
2026 3411a03d isaacs
      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
2027
        return DefineAsRegister(
2028
            new(zone()) LUint32ToDouble(UseRegister(instr->value())));
2029
      } else {
2030
        return DefineAsRegister(
2031
            new(zone()) LInteger32ToDouble(Use(instr->value())));
2032
      }
2033 c30f1137 Ryan Dahl
    }
2034
  }
2035
  UNREACHABLE();
2036
  return NULL;
2037
}
2038
2039
2040 704fd8f3 Ben Noordhuis
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
2041 c30f1137 Ryan Dahl
  LOperand* value = UseRegisterAtStart(instr->value());
2042 e4fc2cbf isaacs
  return AssignEnvironment(new(zone()) LCheckNonSmi(value));
2043 c30f1137 Ryan Dahl
}
2044
2045
2046 5777d7ab Trevor Norris
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
2047
  LOperand* value = UseRegisterAtStart(instr->value());
2048
  return AssignEnvironment(new(zone()) LCheckSmi(value));
2049
}
2050
2051
2052 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
2053
  LOperand* value = UseRegisterAtStart(instr->value());
2054 e4fc2cbf isaacs
  LInstruction* result = new(zone()) LCheckInstanceType(value);
2055 c30f1137 Ryan Dahl
  return AssignEnvironment(result);
2056
}
2057
2058
2059 a53c763c Timothy J Fontaine
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
2060 c30f1137 Ryan Dahl
  LOperand* value = UseRegisterAtStart(instr->value());
2061 a53c763c Timothy J Fontaine
  return AssignEnvironment(new(zone()) LCheckValue(value));
2062 c30f1137 Ryan Dahl
}
2063
2064
2065 50464cd4 Bert Belder
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
2066 1bd711c8 Ben Noordhuis
  LOperand* value = NULL;
2067 f69be329 Ben Noordhuis
  if (!instr->CanOmitMapChecks()) {
2068
    value = UseRegisterAtStart(instr->value());
2069
    if (instr->has_migration_target()) info()->MarkAsDeferredCalling();
2070
  }
2071
  LCheckMaps* result = new(zone()) LCheckMaps(value);
2072
  if (!instr->CanOmitMapChecks()) {
2073
    AssignEnvironment(result);
2074
    if (instr->has_migration_target()) return AssignPointerMap(result);
2075
  }
2076
  return result;
2077 c30f1137 Ryan Dahl
}
2078
2079
2080 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
2081
  HValue* value = instr->value();
2082
  Representation input_rep = value->representation();
2083
  LOperand* reg = UseRegister(value);
2084
  if (input_rep.IsDouble()) {
2085 1bd711c8 Ben Noordhuis
    return DefineAsRegister(new(zone()) LClampDToUint8(reg));
2086 e5564a3f Ryan Dahl
  } else if (input_rep.IsInteger32()) {
2087 e4fc2cbf isaacs
    return DefineAsRegister(new(zone()) LClampIToUint8(reg));
2088 e5564a3f Ryan Dahl
  } else {
2089 6dd78074 Ben Noordhuis
    ASSERT(input_rep.IsSmiOrTagged());
2090 e5564a3f Ryan Dahl
    // Register allocator doesn't (yet) support allocation of double
2091
    // temps. Reserve d1 explicitly.
2092 e4fc2cbf isaacs
    LClampTToUint8* result = new(zone()) LClampTToUint8(reg, FixedTemp(d11));
2093 e5564a3f Ryan Dahl
    return AssignEnvironment(DefineAsRegister(result));
2094
  }
2095
}
2096
2097
2098 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2099 f230a1cf Ben Noordhuis
  LOperand* context = info()->IsStub()
2100
      ? UseFixed(instr->context(), cp)
2101
      : NULL;
2102 83261e78 Trevor Norris
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2103 f230a1cf Ben Noordhuis
  return new(zone()) LReturn(UseFixed(instr->value(), r0), context,
2104 83261e78 Trevor Norris
                             parameter_count);
2105 c30f1137 Ryan Dahl
}
2106
2107
2108
LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
2109
  Representation r = instr->representation();
2110 6dd78074 Ben Noordhuis
  if (r.IsSmi()) {
2111
    return DefineAsRegister(new(zone()) LConstantS);
2112
  } else if (r.IsInteger32()) {
2113 e4fc2cbf isaacs
    return DefineAsRegister(new(zone()) LConstantI);
2114 c30f1137 Ryan Dahl
  } else if (r.IsDouble()) {
2115 e4fc2cbf isaacs
    return DefineAsRegister(new(zone()) LConstantD);
2116 2fc47ab1 Ben Noordhuis
  } else if (r.IsExternal()) {
2117
    return DefineAsRegister(new(zone()) LConstantE);
2118 c30f1137 Ryan Dahl
  } else if (r.IsTagged()) {
2119 e4fc2cbf isaacs
    return DefineAsRegister(new(zone()) LConstantT);
2120 c30f1137 Ryan Dahl
  } else {
2121 cf2e4f44 Ryan Dahl
    UNREACHABLE();
2122 c30f1137 Ryan Dahl
    return NULL;
2123
  }
2124
}
2125
2126
2127 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
2128 e4fc2cbf isaacs
  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
2129 21d081fd Ryan Dahl
  return instr->RequiresHoleCheck()
2130 c30f1137 Ryan Dahl
      ? AssignEnvironment(DefineAsRegister(result))
2131
      : DefineAsRegister(result);
2132
}
2133
2134
2135 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2136 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2137 e5564a3f Ryan Dahl
  LOperand* global_object = UseFixed(instr->global_object(), r0);
2138 f230a1cf Ben Noordhuis
  LLoadGlobalGeneric* result =
2139
      new(zone()) LLoadGlobalGeneric(context, global_object);
2140 e5564a3f Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
2141
}
2142
2143
2144
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2145 4eaf4ce2 Ryan Dahl
  LOperand* value = UseRegister(instr->value());
2146
  // Use a temp to check the value in the cell in the case where we perform
2147
  // a hole check.
2148
  return instr->RequiresHoleCheck()
2149 e4fc2cbf isaacs
      ? AssignEnvironment(new(zone()) LStoreGlobalCell(value, TempRegister()))
2150
      : new(zone()) LStoreGlobalCell(value, NULL);
2151 c30f1137 Ryan Dahl
}
2152
2153
2154 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
2155 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2156 e5564a3f Ryan Dahl
  LOperand* global_object = UseFixed(instr->global_object(), r1);
2157
  LOperand* value = UseFixed(instr->value(), r0);
2158
  LStoreGlobalGeneric* result =
2159 f230a1cf Ben Noordhuis
      new(zone()) LStoreGlobalGeneric(context, global_object, value);
2160 e5564a3f Ryan Dahl
  return MarkAsCall(result, instr);
2161
}
2162
2163
2164 cf2e4f44 Ryan Dahl
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2165 a0702b54 Ryan Dahl
  LOperand* context = UseRegisterAtStart(instr->value());
2166 e4fc2cbf isaacs
  LInstruction* result =
2167
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2168 b3a7de15 Ryan Dahl
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2169 a0702b54 Ryan Dahl
}
2170
2171
2172
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2173 e33e7d1a Ryan Dahl
  LOperand* context;
2174 a0702b54 Ryan Dahl
  LOperand* value;
2175
  if (instr->NeedsWriteBarrier()) {
2176 e33e7d1a Ryan Dahl
    context = UseTempRegister(instr->context());
2177 a0702b54 Ryan Dahl
    value = UseTempRegister(instr->value());
2178
  } else {
2179 e33e7d1a Ryan Dahl
    context = UseRegister(instr->context());
2180 a0702b54 Ryan Dahl
    value = UseRegister(instr->value());
2181
  }
2182 e4fc2cbf isaacs
  LInstruction* result = new(zone()) LStoreContextSlot(context, value);
2183 b3a7de15 Ryan Dahl
  return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2184 cf2e4f44 Ryan Dahl
}
2185
2186
2187 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2188 7ee538dd Ben Noordhuis
  LOperand* obj = UseRegisterAtStart(instr->object());
2189
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2190 c30f1137 Ryan Dahl
}
2191
2192
2193
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2194 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2195 c30f1137 Ryan Dahl
  LOperand* object = UseFixed(instr->object(), r0);
2196 f230a1cf Ben Noordhuis
  LInstruction* result =
2197
      DefineFixed(new(zone()) LLoadNamedGeneric(context, object), r0);
2198 c30f1137 Ryan Dahl
  return MarkAsCall(result, instr);
2199
}
2200
2201
2202 cf2e4f44 Ryan Dahl
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2203
    HLoadFunctionPrototype* instr) {
2204
  return AssignEnvironment(DefineAsRegister(
2205 e4fc2cbf isaacs
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2206 cf2e4f44 Ryan Dahl
}
2207
2208
2209 f230a1cf Ben Noordhuis
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2210
  return DefineAsRegister(new(zone()) LLoadRoot);
2211
}
2212
2213
2214 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
2215
    HLoadExternalArrayPointer* instr) {
2216 550f73ae Ryan Dahl
  LOperand* input = UseRegisterAtStart(instr->value());
2217 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input));
2218 c30f1137 Ryan Dahl
}
2219
2220
2221 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2222 1bd711c8 Ben Noordhuis
  ASSERT(instr->key()->representation().IsSmiOrInteger32());
2223 83261e78 Trevor Norris
  ElementsKind elements_kind = instr->elements_kind();
2224 b15a10e7 Ben Noordhuis
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2225 83261e78 Trevor Norris
  LLoadKeyed* result = NULL;
2226 b15a10e7 Ben Noordhuis
2227 83261e78 Trevor Norris
  if (!instr->is_external()) {
2228
    LOperand* obj = NULL;
2229
    if (instr->representation().IsDouble()) {
2230 f230a1cf Ben Noordhuis
      obj = UseRegister(instr->elements());
2231 83261e78 Trevor Norris
    } else {
2232 6dd78074 Ben Noordhuis
      ASSERT(instr->representation().IsSmiOrTagged());
2233 83261e78 Trevor Norris
      obj = UseRegisterAtStart(instr->elements());
2234
    }
2235
    result = new(zone()) LLoadKeyed(obj, key);
2236
  } else {
2237
    ASSERT(
2238
        (instr->representation().IsInteger32() &&
2239
         (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2240
         (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2241
        (instr->representation().IsDouble() &&
2242
         ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2243
          (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2244 9f682265 Ben Noordhuis
    LOperand* external_pointer = UseRegister(instr->elements());
2245 83261e78 Trevor Norris
    result = new(zone()) LLoadKeyed(external_pointer, key);
2246
  }
2247 b15a10e7 Ben Noordhuis
2248 83261e78 Trevor Norris
  DefineAsRegister(result);
2249 e5564a3f Ryan Dahl
  // An unsigned int array load might overflow and cause a deopt, make sure it
2250
  // has an environment.
2251 83261e78 Trevor Norris
  bool can_deoptimize = instr->RequiresHoleCheck() ||
2252
      (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
2253
  return can_deoptimize ? AssignEnvironment(result) : result;
2254 550f73ae Ryan Dahl
}
2255
2256
2257 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2258 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2259 c30f1137 Ryan Dahl
  LOperand* object = UseFixed(instr->object(), r1);
2260
  LOperand* key = UseFixed(instr->key(), r0);
2261
2262
  LInstruction* result =
2263 f230a1cf Ben Noordhuis
      DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key), r0);
2264 c30f1137 Ryan Dahl
  return MarkAsCall(result, instr);
2265
}
2266
2267
2268 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2269
  if (!instr->is_external()) {
2270
    ASSERT(instr->elements()->representation().IsTagged());
2271
    bool needs_write_barrier = instr->NeedsWriteBarrier();
2272
    LOperand* object = NULL;
2273
    LOperand* key = NULL;
2274
    LOperand* val = NULL;
2275
2276
    if (instr->value()->representation().IsDouble()) {
2277
      object = UseRegisterAtStart(instr->elements());
2278 f230a1cf Ben Noordhuis
      val = UseRegister(instr->value());
2279 83261e78 Trevor Norris
      key = UseRegisterOrConstantAtStart(instr->key());
2280
    } else {
2281 6dd78074 Ben Noordhuis
      ASSERT(instr->value()->representation().IsSmiOrTagged());
2282 f230a1cf Ben Noordhuis
      if (needs_write_barrier) {
2283
        object = UseTempRegister(instr->elements());
2284
        val = UseTempRegister(instr->value());
2285
        key = UseTempRegister(instr->key());
2286
      } else {
2287
        object = UseRegisterAtStart(instr->elements());
2288
        val = UseRegisterAtStart(instr->value());
2289
        key = UseRegisterOrConstantAtStart(instr->key());
2290
      }
2291 83261e78 Trevor Norris
    }
2292 b15a10e7 Ben Noordhuis
2293 83261e78 Trevor Norris
    return new(zone()) LStoreKeyed(object, key, val);
2294
  }
2295 b15a10e7 Ben Noordhuis
2296 e5564a3f Ryan Dahl
  ASSERT(
2297 05471f5c isaacs
      (instr->value()->representation().IsInteger32() &&
2298 f230a1cf Ben Noordhuis
       (instr->elements_kind() != EXTERNAL_FLOAT_ELEMENTS) &&
2299
       (instr->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS)) ||
2300 05471f5c isaacs
      (instr->value()->representation().IsDouble() &&
2301 f230a1cf Ben Noordhuis
       ((instr->elements_kind() == EXTERNAL_FLOAT_ELEMENTS) ||
2302
        (instr->elements_kind() == EXTERNAL_DOUBLE_ELEMENTS))));
2303 83261e78 Trevor Norris
  ASSERT(instr->elements()->representation().IsExternal());
2304 f230a1cf Ben Noordhuis
  LOperand* val = UseRegister(instr->value());
2305 83261e78 Trevor Norris
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2306
  LOperand* external_pointer = UseRegister(instr->elements());
2307
  return new(zone()) LStoreKeyed(external_pointer, key, val);
2308 e33e7d1a Ryan Dahl
}
2309
2310
2311 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2312 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2313 c30f1137 Ryan Dahl
  LOperand* obj = UseFixed(instr->object(), r2);
2314
  LOperand* key = UseFixed(instr->key(), r1);
2315
  LOperand* val = UseFixed(instr->value(), r0);
2316
2317
  ASSERT(instr->object()->representation().IsTagged());
2318
  ASSERT(instr->key()->representation().IsTagged());
2319
  ASSERT(instr->value()->representation().IsTagged());
2320
2321 f230a1cf Ben Noordhuis
  return MarkAsCall(
2322
      new(zone()) LStoreKeyedGeneric(context, obj, key, val), instr);
2323 c30f1137 Ryan Dahl
}
2324
2325
2326 21d081fd Ryan Dahl
LInstruction* LChunkBuilder::DoTransitionElementsKind(
2327
    HTransitionElementsKind* instr) {
2328 83261e78 Trevor Norris
  LOperand* object = UseRegister(instr->object());
2329
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2330 21d081fd Ryan Dahl
    LOperand* new_map_reg = TempRegister();
2331
    LTransitionElementsKind* result =
2332 f230a1cf Ben Noordhuis
        new(zone()) LTransitionElementsKind(object, NULL, new_map_reg);
2333 587e83c6 Ben Noordhuis
    return result;
2334 21d081fd Ryan Dahl
  } else {
2335 f230a1cf Ben Noordhuis
    LOperand* context = UseFixed(instr->context(), cp);
2336 21d081fd Ryan Dahl
    LTransitionElementsKind* result =
2337 f230a1cf Ben Noordhuis
        new(zone()) LTransitionElementsKind(object, context, NULL);
2338 2fc47ab1 Ben Noordhuis
    return AssignPointerMap(result);
2339 21d081fd Ryan Dahl
  }
2340
}
2341
2342
2343 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2344
    HTrapAllocationMemento* instr) {
2345
  LOperand* object = UseRegister(instr->object());
2346
  LOperand* temp = TempRegister();
2347
  LTrapAllocationMemento* result =
2348
      new(zone()) LTrapAllocationMemento(object, temp);
2349
  return AssignEnvironment(result);
2350
}
2351
2352
2353 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2354 6dd78074 Ben Noordhuis
  bool is_in_object = instr->access().IsInobject();
2355 cf2e4f44 Ryan Dahl
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2356 f69be329 Ben Noordhuis
  bool needs_write_barrier_for_map = instr->has_transition() &&
2357 50464cd4 Bert Belder
      instr->NeedsWriteBarrierForMap();
2358
2359
  LOperand* obj;
2360
  if (needs_write_barrier) {
2361 6dd78074 Ben Noordhuis
    obj = is_in_object
2362 50464cd4 Bert Belder
        ? UseRegister(instr->object())
2363
        : UseTempRegister(instr->object());
2364
  } else {
2365
    obj = needs_write_barrier_for_map
2366
        ? UseRegister(instr->object())
2367
        : UseRegisterAtStart(instr->object());
2368
  }
2369 c30f1137 Ryan Dahl
2370 7ee538dd Ben Noordhuis
  LOperand* val;
2371
  if (needs_write_barrier ||
2372
      (FLAG_track_fields && instr->field_representation().IsSmi())) {
2373
    val = UseTempRegister(instr->value());
2374
  } else if (FLAG_track_double_fields &&
2375
             instr->field_representation().IsDouble()) {
2376
    val = UseRegisterAtStart(instr->value());
2377
  } else {
2378
    val = UseRegister(instr->value());
2379
  }
2380 c30f1137 Ryan Dahl
2381 50464cd4 Bert Belder
  // We need a temporary register for write barrier of the map field.
2382
  LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
2383
2384 7ee538dd Ben Noordhuis
  LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
2385 6dd78074 Ben Noordhuis
  if (FLAG_track_heap_object_fields &&
2386
      instr->field_representation().IsHeapObject()) {
2387
    if (!instr->value()->type().IsHeapObject()) {
2388
      return AssignEnvironment(result);
2389
    }
2390 7ee538dd Ben Noordhuis
  }
2391
  return result;
2392 c30f1137 Ryan Dahl
}
2393
2394
2395
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2396 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2397 c30f1137 Ryan Dahl
  LOperand* obj = UseFixed(instr->object(), r1);
2398
  LOperand* val = UseFixed(instr->value(), r0);
2399
2400 f230a1cf Ben Noordhuis
  LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
2401 c30f1137 Ryan Dahl
  return MarkAsCall(result, instr);
2402
}
2403
2404
2405 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2406 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2407 e5564a3f Ryan Dahl
  LOperand* left = UseRegisterAtStart(instr->left());
2408
  LOperand* right = UseRegisterAtStart(instr->right());
2409 f230a1cf Ben Noordhuis
  return MarkAsCall(
2410
      DefineFixed(new(zone()) LStringAdd(context, left, right), r0),
2411
      instr);
2412 e5564a3f Ryan Dahl
}
2413
2414
2415 4c5e5707 Ryan Dahl
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2416 da00ff49 Ryan Dahl
  LOperand* string = UseTempRegister(instr->string());
2417
  LOperand* index = UseTempRegister(instr->index());
2418 f230a1cf Ben Noordhuis
  LOperand* context = UseAny(instr->context());
2419
  LStringCharCodeAt* result =
2420
      new(zone()) LStringCharCodeAt(context, string, index);
2421 4c5e5707 Ryan Dahl
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2422
}
2423
2424
2425 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2426
  LOperand* char_code = UseRegister(instr->value());
2427 f230a1cf Ben Noordhuis
  LOperand* context = UseAny(instr->context());
2428
  LStringCharFromCode* result =
2429
      new(zone()) LStringCharFromCode(context, char_code);
2430 e5564a3f Ryan Dahl
  return AssignPointerMap(DefineAsRegister(result));
2431
}
2432
2433
2434 83261e78 Trevor Norris
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2435
  info()->MarkAsDeferredCalling();
2436 f230a1cf Ben Noordhuis
  LOperand* context = UseAny(instr->context());
2437 7ee538dd Ben Noordhuis
  LOperand* size = instr->size()->IsConstant()
2438
      ? UseConstant(instr->size())
2439
      : UseTempRegister(instr->size());
2440 83261e78 Trevor Norris
  LOperand* temp1 = TempRegister();
2441
  LOperand* temp2 = TempRegister();
2442 f230a1cf Ben Noordhuis
  LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2);
2443 83261e78 Trevor Norris
  return AssignPointerMap(DefineAsRegister(result));
2444
}
2445
2446
2447 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2448 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2449
  return MarkAsCall(
2450
      DefineFixed(new(zone()) LRegExpLiteral(context), r0), instr);
2451 c30f1137 Ryan Dahl
}
2452
2453
2454
LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2455 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2456
  return MarkAsCall(
2457
      DefineFixed(new(zone()) LFunctionLiteral(context), r0), instr);
2458 c30f1137 Ryan Dahl
}
2459
2460
2461
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2462 7b4d95a9 Fedor Indutny
  ASSERT(argument_count_ == 0);
2463 c30f1137 Ryan Dahl
  allocator_->MarkAsOsrEntry();
2464
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2465 e4fc2cbf isaacs
  return AssignEnvironment(new(zone()) LOsrEntry);
2466 c30f1137 Ryan Dahl
}
2467
2468
2469
LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2470 83261e78 Trevor Norris
  LParameter* result = new(zone()) LParameter;
2471
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2472
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2473
    return DefineAsSpilled(result, spill_index);
2474
  } else {
2475
    ASSERT(info()->IsStub());
2476
    CodeStubInterfaceDescriptor* descriptor =
2477
        info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
2478 2f75785c Ben Noordhuis
    int index = static_cast<int>(instr->index());
2479
    Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
2480 83261e78 Trevor Norris
    return DefineFixed(result, reg);
2481
  }
2482 c30f1137 Ryan Dahl
}
2483
2484
2485
LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2486 a53c763c Timothy J Fontaine
  // Use an index that corresponds to the location in the unoptimized frame,
2487
  // which the optimized frame will subsume.
2488
  int env_index = instr->index();
2489
  int spill_index = 0;
2490
  if (instr->environment()->is_parameter_index(env_index)) {
2491
    spill_index = chunk()->GetParameterStackSlot(env_index);
2492
  } else {
2493
    spill_index = env_index - instr->environment()->first_local_index();
2494
    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2495
      Abort(kTooManySpillSlotsNeededForOSR);
2496
      spill_index = 0;
2497
    }
2498 61553ccd Ryan Dahl
  }
2499 e4fc2cbf isaacs
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2500 c30f1137 Ryan Dahl
}
2501
2502
2503
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2504 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2505
  return MarkAsCall(DefineFixed(new(zone()) LCallStub(context), r0), instr);
2506 c30f1137 Ryan Dahl
}
2507
2508
2509
LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2510 e33e7d1a Ryan Dahl
  // There are no real uses of the arguments object.
2511
  // arguments.length and element access are supported directly on
2512
  // stack arguments, and any real arguments object use causes a bailout.
2513
  // So this value is never used.
2514 c30f1137 Ryan Dahl
  return NULL;
2515
}
2516
2517
2518 26bc8db3 Trevor Norris
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2519 a53c763c Timothy J Fontaine
  instr->ReplayEnvironment(current_block_->last_environment());
2520
2521 26bc8db3 Trevor Norris
  // There are no real uses of a captured object.
2522
  return NULL;
2523
}
2524
2525
2526 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2527 2f75785c Ben Noordhuis
  info()->MarkAsRequiresFrame();
2528 7b4d95a9 Fedor Indutny
  LOperand* args = UseRegister(instr->arguments());
2529 2f75785c Ben Noordhuis
  LOperand* length;
2530
  LOperand* index;
2531
  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2532
    length = UseRegisterOrConstant(instr->length());
2533
    index = UseOrConstant(instr->index());
2534
  } else {
2535
    length = UseTempRegister(instr->length());
2536 6dd78074 Ben Noordhuis
    index = UseRegisterAtStart(instr->index());
2537 2f75785c Ben Noordhuis
  }
2538 7b4d95a9 Fedor Indutny
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2539 c30f1137 Ryan Dahl
}
2540
2541
2542 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2543
  LOperand* object = UseFixed(instr->value(), r0);
2544 e4fc2cbf isaacs
  LToFastProperties* result = new(zone()) LToFastProperties(object);
2545 e5564a3f Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
2546
}
2547
2548
2549 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2550 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2551
  LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), r0));
2552 c30f1137 Ryan Dahl
  return MarkAsCall(DefineFixed(result, r0), instr);
2553
}
2554
2555
2556 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2557 e4fc2cbf isaacs
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2558 c30f1137 Ryan Dahl
}
2559
2560 550f73ae Ryan Dahl
2561 e5564a3f Ryan Dahl
LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2562
    HIsConstructCallAndBranch* instr) {
2563 e4fc2cbf isaacs
  return new(zone()) LIsConstructCallAndBranch(TempRegister());
2564 550f73ae Ryan Dahl
}
2565
2566
2567 c30f1137 Ryan Dahl
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2568 a53c763c Timothy J Fontaine
  instr->ReplayEnvironment(current_block_->last_environment());
2569 c30f1137 Ryan Dahl
2570
  // If there is an instruction pending deoptimization environment create a
2571
  // lazy bailout instruction to capture the environment.
2572
  if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2573 e4fc2cbf isaacs
    LInstruction* result = new(zone()) LLazyBailout;
2574 c30f1137 Ryan Dahl
    result = AssignEnvironment(result);
2575 50464cd4 Bert Belder
    // Store the lazy deopt environment with the instruction if needed. Right
2576
    // now it is only used for LInstanceOfKnownGlobal.
2577 ee092f62 Ryan Dahl
    instruction_pending_deoptimization_environment_->
2578 50464cd4 Bert Belder
        SetDeferredLazyDeoptimizationEnvironment(result->environment());
2579
    instruction_pending_deoptimization_environment_ = NULL;
2580 3411a03d isaacs
    pending_deoptimization_ast_id_ = BailoutId::None();
2581 c30f1137 Ryan Dahl
    return result;
2582
  }
2583
2584
  return NULL;
2585
}
2586
2587
2588
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2589 e5564a3f Ryan Dahl
  if (instr->is_function_entry()) {
2590 f230a1cf Ben Noordhuis
    LOperand* context = UseFixed(instr->context(), cp);
2591
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2592 e5564a3f Ryan Dahl
  } else {
2593
    ASSERT(instr->is_backwards_branch());
2594 f230a1cf Ben Noordhuis
    LOperand* context = UseAny(instr->context());
2595
    return AssignEnvironment(
2596
        AssignPointerMap(new(zone()) LStackCheck(context)));
2597 e5564a3f Ryan Dahl
  }
2598 c30f1137 Ryan Dahl
}
2599
2600
2601
LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2602
  HEnvironment* outer = current_block_->last_environment();
2603
  HConstant* undefined = graph()->GetConstantUndefined();
2604
  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2605 05471f5c isaacs
                                               instr->arguments_count(),
2606 c30f1137 Ryan Dahl
                                               instr->function(),
2607 e5564a3f Ryan Dahl
                                               undefined,
2608 83261e78 Trevor Norris
                                               instr->inlining_kind(),
2609
                                               instr->undefined_receiver());
2610 704fd8f3 Ben Noordhuis
  // Only replay binding of arguments object if it wasn't removed from graph.
2611
  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2612
    inner->Bind(instr->arguments_var(), instr->arguments_object());
2613 3f3f958c isaacs
  }
2614 7b4d95a9 Fedor Indutny
  inner->set_entry(instr);
2615 c30f1137 Ryan Dahl
  current_block_->UpdateEnvironment(inner);
2616
  chunk_->AddInlinedClosure(instr->closure());
2617
  return NULL;
2618
}
2619
2620
2621
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2622 50464cd4 Bert Belder
  LInstruction* pop = NULL;
2623
2624
  HEnvironment* env = current_block_->last_environment();
2625
2626 7b4d95a9 Fedor Indutny
  if (env->entry()->arguments_pushed()) {
2627 50464cd4 Bert Belder
    int argument_count = env->arguments_environment()->parameter_count();
2628
    pop = new(zone()) LDrop(argument_count);
2629 f230a1cf Ben Noordhuis
    ASSERT(instr->argument_delta() == -argument_count);
2630 50464cd4 Bert Belder
  }
2631
2632 05471f5c isaacs
  HEnvironment* outer = current_block_->last_environment()->
2633
      DiscardInlined(false);
2634 c30f1137 Ryan Dahl
  current_block_->UpdateEnvironment(outer);
2635 50464cd4 Bert Belder
2636
  return pop;
2637 c30f1137 Ryan Dahl
}
2638
2639
2640 f4641bd4 isaacs
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2641 f230a1cf Ben Noordhuis
  LOperand* context = UseFixed(instr->context(), cp);
2642 f4641bd4 isaacs
  LOperand* object = UseFixed(instr->enumerable(), r0);
2643 f230a1cf Ben Noordhuis
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2644 f4641bd4 isaacs
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
2645
}
2646
2647
2648
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2649
  LOperand* map = UseRegister(instr->map());
2650 7b4d95a9 Fedor Indutny
  return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
2651 f4641bd4 isaacs
}
2652
2653
2654
LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2655
  LOperand* value = UseRegisterAtStart(instr->value());
2656
  LOperand* map = UseRegisterAtStart(instr->map());
2657 e4fc2cbf isaacs
  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2658 f4641bd4 isaacs
}
2659
2660
2661
LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2662
  LOperand* object = UseRegister(instr->object());
2663
  LOperand* index = UseRegister(instr->index());
2664 e4fc2cbf isaacs
  return DefineAsRegister(new(zone()) LLoadFieldByIndex(object, index));
2665 f4641bd4 isaacs
}
2666
2667
2668 c30f1137 Ryan Dahl
} }  // namespace v8::internal