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