blob: 893ec597d42bd43ee9c1b1c82399483a33e8fa1a [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002// 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 defined(V8_TARGET_ARCH_X64)
31
32#include "x64/lithium-codegen-x64.h"
33#include "code-stubs.h"
34#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000040// When invoking builtins, we need to record the safepoint in the middle of
41// the invoke instruction sequence generated by the macro assembler.
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +000042class SafepointGenerator : public CallWrapper {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000043 public:
44 SafepointGenerator(LCodeGen* codegen,
45 LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +000046 Safepoint::DeoptMode mode)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000047 : codegen_(codegen),
48 pointers_(pointers),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000049 deopt_mode_(mode) { }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000050 virtual ~SafepointGenerator() { }
51
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000052 virtual void BeforeCall(int call_size) const {
53 codegen_->EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - call_size);
54 }
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +000055
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056 virtual void AfterCall() const {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000057 codegen_->RecordSafepoint(pointers_, deopt_mode_);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000058 }
59
60 private:
61 LCodeGen* codegen_;
62 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000063 Safepoint::DeoptMode deopt_mode_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000064};
65
66
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000067#define __ masm()->
68
69bool LCodeGen::GenerateCode() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000070 HPhase phase("Z_Code generation", chunk());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000071 ASSERT(is_unused());
72 status_ = GENERATING;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000073
74 // Open a frame scope to indicate that there is a frame on the stack. The
75 // MANUAL indicates that the scope shouldn't actually generate code to set up
76 // the frame (that is done in GeneratePrologue).
77 FrameScope frame_scope(masm_, StackFrame::MANUAL);
78
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000079 return GeneratePrologue() &&
80 GenerateBody() &&
81 GenerateDeferredCode() &&
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000082 GenerateJumpTable() &&
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000083 GenerateSafepointTable();
84}
85
86
87void LCodeGen::FinishCode(Handle<Code> code) {
88 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000089 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000090 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000091 PopulateDeoptimizationData(code);
92}
93
94
95void LCodeGen::Abort(const char* format, ...) {
96 if (FLAG_trace_bailout) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000097 SmartArrayPointer<char> name(
98 info()->shared_info()->DebugName()->ToCString());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000099 PrintF("Aborting LCodeGen in @\"%s\": ", *name);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000100 va_list arguments;
101 va_start(arguments, format);
102 OS::VPrint(format, arguments);
103 va_end(arguments);
104 PrintF("\n");
105 }
106 status_ = ABORTED;
107}
108
109
110void LCodeGen::Comment(const char* format, ...) {
111 if (!FLAG_code_comments) return;
112 char buffer[4 * KB];
113 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
114 va_list arguments;
115 va_start(arguments, format);
116 builder.AddFormattedList(format, arguments);
117 va_end(arguments);
118
119 // Copy the string before recording it in the assembler to avoid
120 // issues when the stack allocated buffer goes out of scope.
121 int length = builder.position();
122 Vector<char> copy = Vector<char>::New(length + 1);
123 memcpy(copy.start(), builder.Finalize(), copy.length());
124 masm()->RecordComment(copy.start());
125}
126
127
128bool LCodeGen::GeneratePrologue() {
129 ASSERT(is_generating());
130
131#ifdef DEBUG
132 if (strlen(FLAG_stop_at) > 0 &&
133 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
134 __ int3();
135 }
136#endif
137
danno@chromium.org40cb8782011-05-25 07:58:50 +0000138 // Strict mode functions need to replace the receiver with undefined
139 // when called as functions (without an explicit receiver
140 // object). rcx is zero for method calls and non-zero for function
141 // calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000142 if (!info_->is_classic_mode() || info_->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000143 Label ok;
144 __ testq(rcx, rcx);
145 __ j(zero, &ok, Label::kNear);
146 // +1 for return address.
147 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
148 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
149 __ movq(Operand(rsp, receiver_offset), kScratchRegister);
150 __ bind(&ok);
151 }
152
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000153 __ push(rbp); // Caller's frame pointer.
154 __ movq(rbp, rsp);
155 __ push(rsi); // Callee's context.
156 __ push(rdi); // Callee's JS function.
157
158 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000159 int slots = GetStackSlotCount();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000160 if (slots > 0) {
161 if (FLAG_debug_code) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000162 __ Set(rax, slots);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000163 __ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE);
164 Label loop;
165 __ bind(&loop);
166 __ push(kScratchRegister);
167 __ decl(rax);
168 __ j(not_zero, &loop);
169 } else {
170 __ subq(rsp, Immediate(slots * kPointerSize));
171#ifdef _MSC_VER
172 // On windows, you may not access the stack more than one page below
173 // the most recently mapped page. To make the allocated area randomly
174 // accessible, we write to each page in turn (the value is irrelevant).
175 const int kPageSize = 4 * KB;
176 for (int offset = slots * kPointerSize - kPageSize;
177 offset > 0;
178 offset -= kPageSize) {
179 __ movq(Operand(rsp, offset), rax);
180 }
181#endif
182 }
183 }
184
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000185 // Possibly allocate a local context.
186 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
187 if (heap_slots > 0) {
188 Comment(";;; Allocate local context");
189 // Argument to NewContext is the function, which is still in rdi.
190 __ push(rdi);
191 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
192 FastNewContextStub stub(heap_slots);
193 __ CallStub(&stub);
194 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000195 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000196 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000197 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000198 // Context is returned in both rax and rsi. It replaces the context
199 // passed to us. It's saved in the stack and kept live in rsi.
200 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
201
202 // Copy any necessary parameters into the context.
203 int num_parameters = scope()->num_parameters();
204 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000205 Variable* var = scope()->parameter(i);
206 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000207 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
208 (num_parameters - 1 - i) * kPointerSize;
209 // Load parameter from stack.
210 __ movq(rax, Operand(rbp, parameter_offset));
211 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000212 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000213 __ movq(Operand(rsi, context_offset), rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000214 // Update the write barrier. This clobbers rax and rbx.
215 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000216 }
217 }
218 Comment(";;; End allocate local context");
219 }
220
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000221 // Trace the call.
222 if (FLAG_trace) {
223 __ CallRuntime(Runtime::kTraceEnter, 0);
224 }
225 return !is_aborted();
226}
227
228
229bool LCodeGen::GenerateBody() {
230 ASSERT(is_generating());
231 bool emit_instructions = true;
232 for (current_instruction_ = 0;
233 !is_aborted() && current_instruction_ < instructions_->length();
234 current_instruction_++) {
235 LInstruction* instr = instructions_->at(current_instruction_);
236 if (instr->IsLabel()) {
237 LLabel* label = LLabel::cast(instr);
238 emit_instructions = !label->HasReplacement();
239 }
240
241 if (emit_instructions) {
242 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
243 instr->CompileToNative(this);
244 }
245 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000246 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000247 return !is_aborted();
248}
249
250
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000251bool LCodeGen::GenerateJumpTable() {
252 for (int i = 0; i < jump_table_.length(); i++) {
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000253 __ bind(&jump_table_[i].label);
254 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000255 }
256 return !is_aborted();
257}
258
259
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000260bool LCodeGen::GenerateDeferredCode() {
261 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000262 if (deferred_.length() > 0) {
263 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
264 LDeferredCode* code = deferred_[i];
265 __ bind(code->entry());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000266 Comment(";;; Deferred code @%d: %s.",
267 code->instruction_index(),
268 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000269 code->Generate();
270 __ jmp(code->exit());
271 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000272 }
273
274 // Deferred code is the last part of the instruction sequence. Mark
275 // the generated code as done unless we bailed out.
276 if (!is_aborted()) status_ = DONE;
277 return !is_aborted();
278}
279
280
281bool LCodeGen::GenerateSafepointTable() {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000282 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000283 safepoints_.Emit(masm(), GetStackSlotCount());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000284 return !is_aborted();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000285}
286
287
288Register LCodeGen::ToRegister(int index) const {
289 return Register::FromAllocationIndex(index);
290}
291
292
293XMMRegister LCodeGen::ToDoubleRegister(int index) const {
294 return XMMRegister::FromAllocationIndex(index);
295}
296
297
298Register LCodeGen::ToRegister(LOperand* op) const {
299 ASSERT(op->IsRegister());
300 return ToRegister(op->index());
301}
302
303
304XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
305 ASSERT(op->IsDoubleRegister());
306 return ToDoubleRegister(op->index());
307}
308
309
310bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
311 return op->IsConstantOperand() &&
312 chunk_->LookupLiteralRepresentation(op).IsInteger32();
313}
314
315
316bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
317 return op->IsConstantOperand() &&
318 chunk_->LookupLiteralRepresentation(op).IsTagged();
319}
320
321
322int LCodeGen::ToInteger32(LConstantOperand* op) const {
323 Handle<Object> value = chunk_->LookupLiteral(op);
324 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
325 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
326 value->Number());
327 return static_cast<int32_t>(value->Number());
328}
329
330
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000331double LCodeGen::ToDouble(LConstantOperand* op) const {
332 Handle<Object> value = chunk_->LookupLiteral(op);
333 return value->Number();
334}
335
336
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000337Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
338 Handle<Object> literal = chunk_->LookupLiteral(op);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000339 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000340 return literal;
341}
342
343
344Operand LCodeGen::ToOperand(LOperand* op) const {
345 // Does not handle registers. In X64 assembler, plain registers are not
346 // representable as an Operand.
347 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
348 int index = op->index();
349 if (index >= 0) {
350 // Local or spill slot. Skip the frame pointer, function, and
351 // context in the fixed part of the frame.
352 return Operand(rbp, -(index + 3) * kPointerSize);
353 } else {
354 // Incoming parameter. Skip the return address.
355 return Operand(rbp, -(index - 1) * kPointerSize);
356 }
357}
358
359
360void LCodeGen::WriteTranslation(LEnvironment* environment,
361 Translation* translation) {
362 if (environment == NULL) return;
363
364 // The translation includes one command per value in the environment.
365 int translation_size = environment->values()->length();
366 // The output frame height does not include the parameters.
367 int height = translation_size - environment->parameter_count();
368
369 WriteTranslation(environment->outer(), translation);
370 int closure_id = DefineDeoptimizationLiteral(environment->closure());
ulan@chromium.org967e2702012-02-28 09:49:15 +0000371 switch (environment->frame_type()) {
372 case JS_FUNCTION:
373 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
374 break;
375 case JS_CONSTRUCT:
376 translation->BeginConstructStubFrame(closure_id, translation_size);
377 break;
378 case ARGUMENTS_ADAPTOR:
379 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
380 break;
381 default:
382 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000383 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000384 for (int i = 0; i < translation_size; ++i) {
385 LOperand* value = environment->values()->at(i);
386 // spilled_registers_ and spilled_double_registers_ are either
387 // both NULL or both set.
388 if (environment->spilled_registers() != NULL && value != NULL) {
389 if (value->IsRegister() &&
390 environment->spilled_registers()[value->index()] != NULL) {
391 translation->MarkDuplicate();
392 AddToTranslation(translation,
393 environment->spilled_registers()[value->index()],
394 environment->HasTaggedValueAt(i));
395 } else if (
396 value->IsDoubleRegister() &&
397 environment->spilled_double_registers()[value->index()] != NULL) {
398 translation->MarkDuplicate();
399 AddToTranslation(
400 translation,
401 environment->spilled_double_registers()[value->index()],
402 false);
403 }
404 }
405
406 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
407 }
408}
409
410
411void LCodeGen::AddToTranslation(Translation* translation,
412 LOperand* op,
413 bool is_tagged) {
414 if (op == NULL) {
415 // TODO(twuerthinger): Introduce marker operands to indicate that this value
416 // is not present and must be reconstructed from the deoptimizer. Currently
417 // this is only used for the arguments object.
418 translation->StoreArgumentsObject();
419 } else if (op->IsStackSlot()) {
420 if (is_tagged) {
421 translation->StoreStackSlot(op->index());
422 } else {
423 translation->StoreInt32StackSlot(op->index());
424 }
425 } else if (op->IsDoubleStackSlot()) {
426 translation->StoreDoubleStackSlot(op->index());
427 } else if (op->IsArgument()) {
428 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000429 int src_index = GetStackSlotCount() + op->index();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000430 translation->StoreStackSlot(src_index);
431 } else if (op->IsRegister()) {
432 Register reg = ToRegister(op);
433 if (is_tagged) {
434 translation->StoreRegister(reg);
435 } else {
436 translation->StoreInt32Register(reg);
437 }
438 } else if (op->IsDoubleRegister()) {
439 XMMRegister reg = ToDoubleRegister(op);
440 translation->StoreDoubleRegister(reg);
441 } else if (op->IsConstantOperand()) {
442 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
443 int src_index = DefineDeoptimizationLiteral(literal);
444 translation->StoreLiteral(src_index);
445 } else {
446 UNREACHABLE();
447 }
448}
449
450
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000451void LCodeGen::CallCodeGeneric(Handle<Code> code,
452 RelocInfo::Mode mode,
453 LInstruction* instr,
454 SafepointMode safepoint_mode,
455 int argc) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000456 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code));
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000457 ASSERT(instr != NULL);
458 LPointerMap* pointers = instr->pointer_map();
459 RecordPosition(pointers->position());
460 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000461 RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000462
463 // Signal that we don't inline smi code before these stubs in the
464 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000465 if (code->kind() == Code::BINARY_OP_IC ||
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000466 code->kind() == Code::COMPARE_IC) {
467 __ nop();
468 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000469}
470
471
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000472void LCodeGen::CallCode(Handle<Code> code,
473 RelocInfo::Mode mode,
474 LInstruction* instr) {
475 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0);
476}
477
478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000479void LCodeGen::CallRuntime(const Runtime::Function* function,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000480 int num_arguments,
481 LInstruction* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000482 ASSERT(instr != NULL);
483 ASSERT(instr->HasPointerMap());
484 LPointerMap* pointers = instr->pointer_map();
485 RecordPosition(pointers->position());
486
487 __ CallRuntime(function, num_arguments);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000488 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000489}
490
491
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000492void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
493 int argc,
494 LInstruction* instr) {
495 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
496 __ CallRuntimeSaveDoubles(id);
497 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000498 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000499}
500
501
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000502void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
503 Safepoint::DeoptMode mode) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000504 if (!environment->HasBeenRegistered()) {
505 // Physical stack frame layout:
506 // -x ............. -4 0 ..................................... y
507 // [incoming arguments] [spill slots] [pushed outgoing arguments]
508
509 // Layout of the environment:
510 // 0 ..................................................... size-1
511 // [parameters] [locals] [expression stack including arguments]
512
513 // Layout of the translation:
514 // 0 ........................................................ size - 1 + 4
515 // [expression stack including arguments] [locals] [4 words] [parameters]
516 // |>------------ translation_size ------------<|
517
518 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000519 int jsframe_count = 0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000520 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
521 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000522 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000523 ++jsframe_count;
524 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000525 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000526 Translation translation(&translations_, frame_count, jsframe_count);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000527 WriteTranslation(environment, &translation);
528 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000529 int pc_offset = masm()->pc_offset();
530 environment->Register(deoptimization_index,
531 translation.index(),
532 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000533 deoptimizations_.Add(environment);
534 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000535}
536
537
538void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000539 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000540 ASSERT(environment->HasBeenRegistered());
541 int id = environment->deoptimization_index();
542 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
543 ASSERT(entry != NULL);
544 if (entry == NULL) {
545 Abort("bailout was not prepared");
546 return;
547 }
548
549 if (cc == no_condition) {
550 __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
551 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000552 // We often have several deopts to the same entry, reuse the last
553 // jump entry if this is the case.
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000554 if (jump_table_.is_empty() ||
555 jump_table_.last().address != entry) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000556 jump_table_.Add(JumpTableEntry(entry));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000557 }
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000558 __ j(cc, &jump_table_.last().label);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000559 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000560}
561
562
563void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
564 int length = deoptimizations_.length();
565 if (length == 0) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000566 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 factory()->NewDeoptimizationInputData(length, TENURED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000568
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000569 Handle<ByteArray> translations = translations_.CreateByteArray();
570 data->SetTranslationByteArray(*translations);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000571 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
572
573 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000575 for (int i = 0; i < deoptimization_literals_.length(); i++) {
576 literals->set(i, *deoptimization_literals_[i]);
577 }
578 data->SetLiteralArray(*literals);
579
580 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
581 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
582
583 // Populate the deoptimization entries.
584 for (int i = 0; i < length; i++) {
585 LEnvironment* env = deoptimizations_[i];
586 data->SetAstId(i, Smi::FromInt(env->ast_id()));
587 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
588 data->SetArgumentsStackHeight(i,
589 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000590 data->SetPc(i, Smi::FromInt(env->pc_offset()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000591 }
592 code->set_deoptimization_data(*data);
593}
594
595
596int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
597 int result = deoptimization_literals_.length();
598 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
599 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
600 }
601 deoptimization_literals_.Add(literal);
602 return result;
603}
604
605
606void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
607 ASSERT(deoptimization_literals_.length() == 0);
608
609 const ZoneList<Handle<JSFunction> >* inlined_closures =
610 chunk()->inlined_closures();
611
612 for (int i = 0, length = inlined_closures->length();
613 i < length;
614 i++) {
615 DefineDeoptimizationLiteral(inlined_closures->at(i));
616 }
617
618 inlined_function_count_ = deoptimization_literals_.length();
619}
620
621
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000622void LCodeGen::RecordSafepointWithLazyDeopt(
623 LInstruction* instr, SafepointMode safepoint_mode, int argc) {
624 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
625 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
626 } else {
627 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
628 RecordSafepointWithRegisters(
629 instr->pointer_map(), argc, Safepoint::kLazyDeopt);
630 }
631}
632
633
ager@chromium.org378b34e2011-01-28 08:04:38 +0000634void LCodeGen::RecordSafepoint(
635 LPointerMap* pointers,
636 Safepoint::Kind kind,
637 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000638 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000639 ASSERT(kind == expected_safepoint_kind_);
640
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000641 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000642
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000643 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000644 kind, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000645 for (int i = 0; i < operands->length(); i++) {
646 LOperand* pointer = operands->at(i);
647 if (pointer->IsStackSlot()) {
648 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000649 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
650 safepoint.DefinePointerRegister(ToRegister(pointer));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000651 }
652 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000653 if (kind & Safepoint::kWithRegisters) {
654 // Register rsi always contains a pointer to the context.
655 safepoint.DefinePointerRegister(rsi);
656 }
657}
658
659
660void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000661 Safepoint::DeoptMode deopt_mode) {
662 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000663}
664
665
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000666void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000667 LPointerMap empty_pointers(RelocInfo::kNoPosition);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000668 RecordSafepoint(&empty_pointers, deopt_mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000669}
670
671
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000672void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
673 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000674 Safepoint::DeoptMode deopt_mode) {
675 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000676}
677
678
679void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000680 if (position == RelocInfo::kNoPosition) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000681 masm()->positions_recorder()->RecordPosition(position);
682}
683
684
685void LCodeGen::DoLabel(LLabel* label) {
686 if (label->is_loop_header()) {
687 Comment(";;; B%d - LOOP entry", label->block_id());
688 } else {
689 Comment(";;; B%d", label->block_id());
690 }
691 __ bind(label->label());
692 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000693 DoGap(label);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000694}
695
696
697void LCodeGen::DoParallelMove(LParallelMove* move) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000698 resolver_.Resolve(move);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000699}
700
701
702void LCodeGen::DoGap(LGap* gap) {
703 for (int i = LGap::FIRST_INNER_POSITION;
704 i <= LGap::LAST_INNER_POSITION;
705 i++) {
706 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
707 LParallelMove* move = gap->GetParallelMove(inner_pos);
708 if (move != NULL) DoParallelMove(move);
709 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000710}
711
712
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000713void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
714 DoGap(instr);
715}
716
717
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000718void LCodeGen::DoParameter(LParameter* instr) {
719 // Nothing to do.
720}
721
722
723void LCodeGen::DoCallStub(LCallStub* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000724 ASSERT(ToRegister(instr->result()).is(rax));
725 switch (instr->hydrogen()->major_key()) {
726 case CodeStub::RegExpConstructResult: {
727 RegExpConstructResultStub stub;
728 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
729 break;
730 }
731 case CodeStub::RegExpExec: {
732 RegExpExecStub stub;
733 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
734 break;
735 }
736 case CodeStub::SubString: {
737 SubStringStub stub;
738 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
739 break;
740 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000741 case CodeStub::NumberToString: {
742 NumberToStringStub stub;
743 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
744 break;
745 }
746 case CodeStub::StringAdd: {
747 StringAddStub stub(NO_STRING_ADD_FLAGS);
748 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
749 break;
750 }
751 case CodeStub::StringCompare: {
752 StringCompareStub stub;
753 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
754 break;
755 }
756 case CodeStub::TranscendentalCache: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000757 TranscendentalCacheStub stub(instr->transcendental_type(),
758 TranscendentalCacheStub::TAGGED);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000759 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
760 break;
761 }
762 default:
763 UNREACHABLE();
764 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000765}
766
767
768void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
769 // Nothing to do.
770}
771
772
773void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000774 if (instr->hydrogen()->HasPowerOf2Divisor()) {
775 Register dividend = ToRegister(instr->InputAt(0));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000776
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000777 int32_t divisor =
778 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000779
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000780 if (divisor < 0) divisor = -divisor;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000781
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000782 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000783 __ testl(dividend, dividend);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000784 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000785 __ negl(dividend);
786 __ andl(dividend, Immediate(divisor - 1));
787 __ negl(dividend);
788 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000789 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000790 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +0000791 } else {
792 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000793 }
794 __ bind(&positive_dividend);
795 __ andl(dividend, Immediate(divisor - 1));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000796 __ bind(&done);
797 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000798 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000799 Register left_reg = ToRegister(instr->InputAt(0));
800 Register right_reg = ToRegister(instr->InputAt(1));
801 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000802
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000803 ASSERT(left_reg.is(rax));
804 ASSERT(result_reg.is(rdx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000805 ASSERT(!right_reg.is(rax));
806 ASSERT(!right_reg.is(rdx));
807
808 // Check for x % 0.
809 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
810 __ testl(right_reg, right_reg);
811 DeoptimizeIf(zero, instr->environment());
812 }
813
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000814 __ testl(left_reg, left_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000815 __ j(zero, &remainder_eq_dividend, Label::kNear);
816 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000817
818 __ testl(right_reg, right_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000819 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000820 // The sign of the divisor doesn't matter.
821 __ neg(right_reg);
822
823 __ bind(&both_positive);
824 // If the dividend is smaller than the nonnegative
825 // divisor, the dividend is the result.
826 __ cmpl(left_reg, right_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000827 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000828
829 // Check if the divisor is a PowerOfTwo integer.
830 Register scratch = ToRegister(instr->TempAt(0));
831 __ movl(scratch, right_reg);
832 __ subl(scratch, Immediate(1));
833 __ testl(scratch, right_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000834 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000835 __ andl(left_reg, scratch);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000836 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000837
838 __ bind(&do_subtraction);
839 const int kUnfolds = 3;
840 // Try a few subtractions of the dividend.
841 __ movl(scratch, left_reg);
842 for (int i = 0; i < kUnfolds; i++) {
843 // Reduce the dividend by the divisor.
844 __ subl(left_reg, right_reg);
845 // Check if the dividend is less than the divisor.
846 __ cmpl(left_reg, right_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000847 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000848 }
849 __ movl(left_reg, scratch);
850
851 // Slow case, using idiv instruction.
852 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000853 // Sign extend eax to edx.
854 // (We are using only the low 32 bits of the values.)
855 __ cdq();
856
857 // Check for (0 % -x) that will produce negative zero.
858 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000859 Label positive_left;
860 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000861 __ testl(left_reg, left_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000862 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000863 __ idivl(right_reg);
864
865 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000866 __ testl(result_reg, result_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000867 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000868
869 DeoptimizeIf(no_condition, instr->environment());
870 __ bind(&positive_left);
871 __ idivl(right_reg);
872 __ bind(&done);
873 } else {
874 __ idivl(right_reg);
875 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000876 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000877
878 __ bind(&remainder_eq_dividend);
879 __ movl(result_reg, left_reg);
880
881 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000882 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000883}
884
885
886void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000887 LOperand* right = instr->InputAt(1);
888 ASSERT(ToRegister(instr->result()).is(rax));
889 ASSERT(ToRegister(instr->InputAt(0)).is(rax));
890 ASSERT(!ToRegister(instr->InputAt(1)).is(rax));
891 ASSERT(!ToRegister(instr->InputAt(1)).is(rdx));
892
893 Register left_reg = rax;
894
895 // Check for x / 0.
896 Register right_reg = ToRegister(right);
897 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
898 __ testl(right_reg, right_reg);
899 DeoptimizeIf(zero, instr->environment());
900 }
901
902 // Check for (0 / -x) that will produce negative zero.
903 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000904 Label left_not_zero;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000905 __ testl(left_reg, left_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000906 __ j(not_zero, &left_not_zero, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000907 __ testl(right_reg, right_reg);
908 DeoptimizeIf(sign, instr->environment());
909 __ bind(&left_not_zero);
910 }
911
912 // Check for (-kMinInt / -1).
913 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000914 Label left_not_min_int;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000915 __ cmpl(left_reg, Immediate(kMinInt));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000916 __ j(not_zero, &left_not_min_int, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000917 __ cmpl(right_reg, Immediate(-1));
918 DeoptimizeIf(zero, instr->environment());
919 __ bind(&left_not_min_int);
920 }
921
922 // Sign extend to rdx.
923 __ cdq();
924 __ idivl(right_reg);
925
926 // Deoptimize if remainder is not 0.
927 __ testl(rdx, rdx);
928 DeoptimizeIf(not_zero, instr->environment());
929}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000930
931
932void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000933 Register left = ToRegister(instr->InputAt(0));
934 LOperand* right = instr->InputAt(1);
935
936 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
937 __ movl(kScratchRegister, left);
938 }
939
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000940 bool can_overflow =
941 instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000942 if (right->IsConstantOperand()) {
943 int right_value = ToInteger32(LConstantOperand::cast(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000944 if (right_value == -1) {
945 __ negl(left);
946 } else if (right_value == 0) {
947 __ xorl(left, left);
948 } else if (right_value == 2) {
949 __ addl(left, left);
950 } else if (!can_overflow) {
951 // If the multiplication is known to not overflow, we
952 // can use operations that don't set the overflow flag
953 // correctly.
954 switch (right_value) {
955 case 1:
956 // Do nothing.
957 break;
958 case 3:
959 __ leal(left, Operand(left, left, times_2, 0));
960 break;
961 case 4:
962 __ shll(left, Immediate(2));
963 break;
964 case 5:
965 __ leal(left, Operand(left, left, times_4, 0));
966 break;
967 case 8:
968 __ shll(left, Immediate(3));
969 break;
970 case 9:
971 __ leal(left, Operand(left, left, times_8, 0));
972 break;
973 case 16:
974 __ shll(left, Immediate(4));
975 break;
976 default:
977 __ imull(left, left, Immediate(right_value));
978 break;
979 }
980 } else {
981 __ imull(left, left, Immediate(right_value));
982 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000983 } else if (right->IsStackSlot()) {
984 __ imull(left, ToOperand(right));
985 } else {
986 __ imull(left, ToRegister(right));
987 }
988
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000989 if (can_overflow) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000990 DeoptimizeIf(overflow, instr->environment());
991 }
992
993 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
994 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000995 Label done;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000996 __ testl(left, left);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000997 __ j(not_zero, &done, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000998 if (right->IsConstantOperand()) {
999 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
1000 DeoptimizeIf(no_condition, instr->environment());
1001 }
1002 } else if (right->IsStackSlot()) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001003 __ orl(kScratchRegister, ToOperand(right));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001004 DeoptimizeIf(sign, instr->environment());
1005 } else {
1006 // Test the non-zero operand for negative sign.
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001007 __ orl(kScratchRegister, ToRegister(right));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001008 DeoptimizeIf(sign, instr->environment());
1009 }
1010 __ bind(&done);
1011 }
1012}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001013
1014
1015void LCodeGen::DoBitI(LBitI* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001016 LOperand* left = instr->InputAt(0);
1017 LOperand* right = instr->InputAt(1);
1018 ASSERT(left->Equals(instr->result()));
1019 ASSERT(left->IsRegister());
1020
1021 if (right->IsConstantOperand()) {
1022 int right_operand = ToInteger32(LConstantOperand::cast(right));
1023 switch (instr->op()) {
1024 case Token::BIT_AND:
1025 __ andl(ToRegister(left), Immediate(right_operand));
1026 break;
1027 case Token::BIT_OR:
1028 __ orl(ToRegister(left), Immediate(right_operand));
1029 break;
1030 case Token::BIT_XOR:
1031 __ xorl(ToRegister(left), Immediate(right_operand));
1032 break;
1033 default:
1034 UNREACHABLE();
1035 break;
1036 }
1037 } else if (right->IsStackSlot()) {
1038 switch (instr->op()) {
1039 case Token::BIT_AND:
1040 __ andl(ToRegister(left), ToOperand(right));
1041 break;
1042 case Token::BIT_OR:
1043 __ orl(ToRegister(left), ToOperand(right));
1044 break;
1045 case Token::BIT_XOR:
1046 __ xorl(ToRegister(left), ToOperand(right));
1047 break;
1048 default:
1049 UNREACHABLE();
1050 break;
1051 }
1052 } else {
1053 ASSERT(right->IsRegister());
1054 switch (instr->op()) {
1055 case Token::BIT_AND:
1056 __ andl(ToRegister(left), ToRegister(right));
1057 break;
1058 case Token::BIT_OR:
1059 __ orl(ToRegister(left), ToRegister(right));
1060 break;
1061 case Token::BIT_XOR:
1062 __ xorl(ToRegister(left), ToRegister(right));
1063 break;
1064 default:
1065 UNREACHABLE();
1066 break;
1067 }
1068 }
1069}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001070
1071
1072void LCodeGen::DoShiftI(LShiftI* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001073 LOperand* left = instr->InputAt(0);
1074 LOperand* right = instr->InputAt(1);
1075 ASSERT(left->Equals(instr->result()));
1076 ASSERT(left->IsRegister());
1077 if (right->IsRegister()) {
1078 ASSERT(ToRegister(right).is(rcx));
1079
1080 switch (instr->op()) {
1081 case Token::SAR:
1082 __ sarl_cl(ToRegister(left));
1083 break;
1084 case Token::SHR:
1085 __ shrl_cl(ToRegister(left));
1086 if (instr->can_deopt()) {
1087 __ testl(ToRegister(left), ToRegister(left));
1088 DeoptimizeIf(negative, instr->environment());
1089 }
1090 break;
1091 case Token::SHL:
1092 __ shll_cl(ToRegister(left));
1093 break;
1094 default:
1095 UNREACHABLE();
1096 break;
1097 }
1098 } else {
1099 int value = ToInteger32(LConstantOperand::cast(right));
1100 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1101 switch (instr->op()) {
1102 case Token::SAR:
1103 if (shift_count != 0) {
1104 __ sarl(ToRegister(left), Immediate(shift_count));
1105 }
1106 break;
1107 case Token::SHR:
1108 if (shift_count == 0 && instr->can_deopt()) {
1109 __ testl(ToRegister(left), ToRegister(left));
1110 DeoptimizeIf(negative, instr->environment());
1111 } else {
1112 __ shrl(ToRegister(left), Immediate(shift_count));
1113 }
1114 break;
1115 case Token::SHL:
1116 if (shift_count != 0) {
1117 __ shll(ToRegister(left), Immediate(shift_count));
1118 }
1119 break;
1120 default:
1121 UNREACHABLE();
1122 break;
1123 }
1124 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001125}
1126
1127
1128void LCodeGen::DoSubI(LSubI* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001129 LOperand* left = instr->InputAt(0);
1130 LOperand* right = instr->InputAt(1);
1131 ASSERT(left->Equals(instr->result()));
1132
1133 if (right->IsConstantOperand()) {
1134 __ subl(ToRegister(left),
1135 Immediate(ToInteger32(LConstantOperand::cast(right))));
1136 } else if (right->IsRegister()) {
1137 __ subl(ToRegister(left), ToRegister(right));
1138 } else {
1139 __ subl(ToRegister(left), ToOperand(right));
1140 }
1141
1142 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1143 DeoptimizeIf(overflow, instr->environment());
1144 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001145}
1146
1147
1148void LCodeGen::DoConstantI(LConstantI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001149 ASSERT(instr->result()->IsRegister());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001150 __ Set(ToRegister(instr->result()), instr->value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001151}
1152
1153
1154void LCodeGen::DoConstantD(LConstantD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001155 ASSERT(instr->result()->IsDoubleRegister());
1156 XMMRegister res = ToDoubleRegister(instr->result());
1157 double v = instr->value();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001158 uint64_t int_val = BitCast<uint64_t, double>(v);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001159 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1160 // do so if the constant is -0.0.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001161 if (int_val == 0) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001162 __ xorps(res, res);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001163 } else {
1164 Register tmp = ToRegister(instr->TempAt(0));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001165 __ Set(tmp, int_val);
1166 __ movq(res, tmp);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001167 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001168}
1169
1170
1171void LCodeGen::DoConstantT(LConstantT* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001172 Handle<Object> value = instr->value();
1173 if (value->IsSmi()) {
1174 __ Move(ToRegister(instr->result()), value);
1175 } else {
1176 __ LoadHeapObject(ToRegister(instr->result()),
1177 Handle<HeapObject>::cast(value));
1178 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001179}
1180
1181
1182void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001183 Register result = ToRegister(instr->result());
1184 Register array = ToRegister(instr->InputAt(0));
1185 __ movq(result, FieldOperand(array, JSArray::kLengthOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001186}
1187
1188
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001189void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001190 Register result = ToRegister(instr->result());
1191 Register array = ToRegister(instr->InputAt(0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001192 __ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001193}
1194
1195
whesse@chromium.org7b260152011-06-20 15:33:18 +00001196void LCodeGen::DoElementsKind(LElementsKind* instr) {
1197 Register result = ToRegister(instr->result());
1198 Register input = ToRegister(instr->InputAt(0));
1199
1200 // Load map into |result|.
1201 __ movq(result, FieldOperand(input, HeapObject::kMapOffset));
1202 // Load the map's "bit field 2" into |result|. We only need the first byte.
1203 __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset));
1204 // Retrieve elements_kind from bit field 2.
1205 __ and_(result, Immediate(Map::kElementsKindMask));
1206 __ shr(result, Immediate(Map::kElementsKindShift));
1207}
1208
1209
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001210void LCodeGen::DoValueOf(LValueOf* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001211 Register input = ToRegister(instr->InputAt(0));
1212 Register result = ToRegister(instr->result());
1213 ASSERT(input.is(result));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001214 Label done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001215 // If the object is a smi return the object.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001216 __ JumpIfSmi(input, &done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001217
1218 // If the object is not a value type, return the object.
1219 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001220 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001221 __ movq(result, FieldOperand(input, JSValue::kValueOffset));
1222
1223 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001224}
1225
1226
1227void LCodeGen::DoBitNotI(LBitNotI* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001228 LOperand* input = instr->InputAt(0);
1229 ASSERT(input->Equals(instr->result()));
1230 __ not_(ToRegister(input));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001231}
1232
1233
1234void LCodeGen::DoThrow(LThrow* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001235 __ push(ToRegister(instr->InputAt(0)));
1236 CallRuntime(Runtime::kThrow, 1, instr);
1237
1238 if (FLAG_debug_code) {
1239 Comment("Unreachable code.");
1240 __ int3();
1241 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001242}
1243
1244
1245void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001246 LOperand* left = instr->InputAt(0);
1247 LOperand* right = instr->InputAt(1);
1248 ASSERT(left->Equals(instr->result()));
1249
1250 if (right->IsConstantOperand()) {
1251 __ addl(ToRegister(left),
1252 Immediate(ToInteger32(LConstantOperand::cast(right))));
1253 } else if (right->IsRegister()) {
1254 __ addl(ToRegister(left), ToRegister(right));
1255 } else {
1256 __ addl(ToRegister(left), ToOperand(right));
1257 }
1258
1259 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1260 DeoptimizeIf(overflow, instr->environment());
1261 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001262}
1263
1264
1265void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001266 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1267 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1268 XMMRegister result = ToDoubleRegister(instr->result());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001269 // All operations except MOD are computed in-place.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001270 ASSERT(instr->op() == Token::MOD || left.is(result));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001271 switch (instr->op()) {
1272 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001273 __ addsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001274 break;
1275 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001276 __ subsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001277 break;
1278 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001279 __ mulsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001280 break;
1281 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001282 __ divsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001283 break;
1284 case Token::MOD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001285 __ PrepareCallCFunction(2);
danno@chromium.org160a7b02011-04-18 15:51:38 +00001286 __ movaps(xmm0, left);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001287 ASSERT(right.is(xmm1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001288 __ CallCFunction(
1289 ExternalReference::double_fp_operation(Token::MOD, isolate()), 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001290 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001291 __ movaps(result, xmm0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001292 break;
1293 default:
1294 UNREACHABLE();
1295 break;
1296 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001297}
1298
1299
1300void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001301 ASSERT(ToRegister(instr->InputAt(0)).is(rdx));
1302 ASSERT(ToRegister(instr->InputAt(1)).is(rax));
1303 ASSERT(ToRegister(instr->result()).is(rax));
1304
danno@chromium.org40cb8782011-05-25 07:58:50 +00001305 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001306 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001307 __ nop(); // Signals no inlined code.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001308}
1309
1310
1311int LCodeGen::GetNextEmittedBlock(int block) {
1312 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1313 LLabel* label = chunk_->GetLabel(i);
1314 if (!label->HasReplacement()) return i;
1315 }
1316 return -1;
1317}
1318
1319
1320void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001321 int next_block = GetNextEmittedBlock(current_block_);
1322 right_block = chunk_->LookupDestination(right_block);
1323 left_block = chunk_->LookupDestination(left_block);
1324
1325 if (right_block == left_block) {
1326 EmitGoto(left_block);
1327 } else if (left_block == next_block) {
1328 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1329 } else if (right_block == next_block) {
1330 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1331 } else {
1332 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1333 if (cc != always) {
1334 __ jmp(chunk_->GetAssemblyLabel(right_block));
1335 }
1336 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001337}
1338
1339
1340void LCodeGen::DoBranch(LBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001341 int true_block = chunk_->LookupDestination(instr->true_block_id());
1342 int false_block = chunk_->LookupDestination(instr->false_block_id());
1343
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001344 Representation r = instr->hydrogen()->value()->representation();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001345 if (r.IsInteger32()) {
1346 Register reg = ToRegister(instr->InputAt(0));
1347 __ testl(reg, reg);
1348 EmitBranch(true_block, false_block, not_zero);
1349 } else if (r.IsDouble()) {
1350 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001351 __ xorps(xmm0, xmm0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001352 __ ucomisd(reg, xmm0);
1353 EmitBranch(true_block, false_block, not_equal);
1354 } else {
1355 ASSERT(r.IsTagged());
1356 Register reg = ToRegister(instr->InputAt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001357 HType type = instr->hydrogen()->value()->type();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001358 if (type.IsBoolean()) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001359 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001360 EmitBranch(true_block, false_block, equal);
1361 } else if (type.IsSmi()) {
1362 __ SmiCompare(reg, Smi::FromInt(0));
1363 EmitBranch(true_block, false_block, not_equal);
1364 } else {
1365 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1366 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1367
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001368 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1369 // Avoid deopts in the case where we've never executed this path before.
1370 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001371
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001372 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1373 // undefined -> false.
1374 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
1375 __ j(equal, false_label);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001376 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001377 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1378 // true -> true.
1379 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
1380 __ j(equal, true_label);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001381 // false -> false.
1382 __ CompareRoot(reg, Heap::kFalseValueRootIndex);
1383 __ j(equal, false_label);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001384 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001385 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1386 // 'null' -> false.
1387 __ CompareRoot(reg, Heap::kNullValueRootIndex);
1388 __ j(equal, false_label);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001389 }
1390
1391 if (expected.Contains(ToBooleanStub::SMI)) {
1392 // Smis: 0 -> false, all other -> true.
1393 __ Cmp(reg, Smi::FromInt(0));
1394 __ j(equal, false_label);
1395 __ JumpIfSmi(reg, true_label);
1396 } else if (expected.NeedsMap()) {
1397 // If we need a map later and have a Smi -> deopt.
1398 __ testb(reg, Immediate(kSmiTagMask));
1399 DeoptimizeIf(zero, instr->environment());
1400 }
1401
1402 const Register map = kScratchRegister;
1403 if (expected.NeedsMap()) {
1404 __ movq(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001405
1406 if (expected.CanBeUndetectable()) {
1407 // Undetectable -> false.
1408 __ testb(FieldOperand(map, Map::kBitFieldOffset),
1409 Immediate(1 << Map::kIsUndetectable));
1410 __ j(not_zero, false_label);
1411 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001412 }
1413
1414 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1415 // spec object -> true.
1416 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
1417 __ j(above_equal, true_label);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001418 }
1419
1420 if (expected.Contains(ToBooleanStub::STRING)) {
1421 // String value -> false iff empty.
1422 Label not_string;
1423 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
1424 __ j(above_equal, &not_string, Label::kNear);
1425 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1426 __ j(not_zero, true_label);
1427 __ jmp(false_label);
1428 __ bind(&not_string);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001429 }
1430
1431 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1432 // heap number -> false iff +0, -0, or NaN.
1433 Label not_heap_number;
1434 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
1435 __ j(not_equal, &not_heap_number, Label::kNear);
1436 __ xorps(xmm0, xmm0);
1437 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset));
1438 __ j(zero, false_label);
1439 __ jmp(true_label);
1440 __ bind(&not_heap_number);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001441 }
1442
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001443 // We've seen something for the first time -> deopt.
1444 DeoptimizeIf(no_condition, instr->environment());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001445 }
1446 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001447}
1448
1449
ager@chromium.org04921a82011-06-27 13:21:41 +00001450void LCodeGen::EmitGoto(int block) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001451 block = chunk_->LookupDestination(block);
1452 int next_block = GetNextEmittedBlock(current_block_);
1453 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001454 __ jmp(chunk_->GetAssemblyLabel(block));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001455 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001456}
1457
1458
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001459void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001460 EmitGoto(instr->block_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001461}
1462
1463
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001464inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001465 Condition cond = no_condition;
1466 switch (op) {
1467 case Token::EQ:
1468 case Token::EQ_STRICT:
1469 cond = equal;
1470 break;
1471 case Token::LT:
1472 cond = is_unsigned ? below : less;
1473 break;
1474 case Token::GT:
1475 cond = is_unsigned ? above : greater;
1476 break;
1477 case Token::LTE:
1478 cond = is_unsigned ? below_equal : less_equal;
1479 break;
1480 case Token::GTE:
1481 cond = is_unsigned ? above_equal : greater_equal;
1482 break;
1483 case Token::IN:
1484 case Token::INSTANCEOF:
1485 default:
1486 UNREACHABLE();
1487 }
1488 return cond;
1489}
1490
1491
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001492void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001493 LOperand* left = instr->InputAt(0);
1494 LOperand* right = instr->InputAt(1);
1495 int false_block = chunk_->LookupDestination(instr->false_block_id());
1496 int true_block = chunk_->LookupDestination(instr->true_block_id());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001497 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001498
1499 if (left->IsConstantOperand() && right->IsConstantOperand()) {
1500 // We can statically evaluate the comparison.
1501 double left_val = ToDouble(LConstantOperand::cast(left));
1502 double right_val = ToDouble(LConstantOperand::cast(right));
1503 int next_block =
1504 EvalComparison(instr->op(), left_val, right_val) ? true_block
1505 : false_block;
1506 EmitGoto(next_block);
1507 } else {
1508 if (instr->is_double()) {
1509 // Don't base result on EFLAGS when a NaN is involved. Instead
1510 // jump to the false block.
1511 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1512 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1513 } else {
1514 int32_t value;
1515 if (right->IsConstantOperand()) {
1516 value = ToInteger32(LConstantOperand::cast(right));
1517 __ cmpl(ToRegister(left), Immediate(value));
1518 } else if (left->IsConstantOperand()) {
1519 value = ToInteger32(LConstantOperand::cast(left));
1520 if (right->IsRegister()) {
1521 __ cmpl(ToRegister(right), Immediate(value));
1522 } else {
1523 __ cmpl(ToOperand(right), Immediate(value));
1524 }
1525 // We transposed the operands. Reverse the condition.
1526 cc = ReverseCondition(cc);
1527 } else {
1528 if (right->IsRegister()) {
1529 __ cmpl(ToRegister(left), ToRegister(right));
1530 } else {
1531 __ cmpl(ToRegister(left), ToOperand(right));
1532 }
1533 }
1534 }
1535 EmitBranch(true_block, false_block, cc);
1536 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001537}
1538
1539
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001540void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001541 Register left = ToRegister(instr->InputAt(0));
1542 Register right = ToRegister(instr->InputAt(1));
1543 int false_block = chunk_->LookupDestination(instr->false_block_id());
1544 int true_block = chunk_->LookupDestination(instr->true_block_id());
1545
1546 __ cmpq(left, right);
1547 EmitBranch(true_block, false_block, equal);
1548}
1549
1550
whesse@chromium.org7b260152011-06-20 15:33:18 +00001551void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
1552 Register left = ToRegister(instr->InputAt(0));
1553 int true_block = chunk_->LookupDestination(instr->true_block_id());
1554 int false_block = chunk_->LookupDestination(instr->false_block_id());
1555
1556 __ cmpq(left, Immediate(instr->hydrogen()->right()));
1557 EmitBranch(true_block, false_block, equal);
1558}
1559
1560
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001561void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001562 Register reg = ToRegister(instr->InputAt(0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001563 int false_block = chunk_->LookupDestination(instr->false_block_id());
1564
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001565 // If the expression is known to be untagged or a smi, then it's definitely
1566 // not null, and it can't be a an undetectable object.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001567 if (instr->hydrogen()->representation().IsSpecialization() ||
1568 instr->hydrogen()->type().IsSmi()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001569 EmitGoto(false_block);
1570 return;
1571 }
1572
1573 int true_block = chunk_->LookupDestination(instr->true_block_id());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 Heap::RootListIndex nil_value = instr->nil() == kNullValue ?
1575 Heap::kNullValueRootIndex :
1576 Heap::kUndefinedValueRootIndex;
1577 __ CompareRoot(reg, nil_value);
1578 if (instr->kind() == kStrictEquality) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001579 EmitBranch(true_block, false_block, equal);
1580 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ?
1582 Heap::kUndefinedValueRootIndex :
1583 Heap::kNullValueRootIndex;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001584 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1585 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1586 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 __ CompareRoot(reg, other_nil_value);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001588 __ j(equal, true_label);
1589 __ JumpIfSmi(reg, false_label);
1590 // Check for undetectable objects by looking in the bit field in
1591 // the map. The object has already been smi checked.
1592 Register scratch = ToRegister(instr->TempAt(0));
1593 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1594 __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
1595 Immediate(1 << Map::kIsUndetectable));
1596 EmitBranch(true_block, false_block, not_zero);
1597 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001598}
1599
1600
1601Condition LCodeGen::EmitIsObject(Register input,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001602 Label* is_not_object,
1603 Label* is_object) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001604 ASSERT(!input.is(kScratchRegister));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001605
1606 __ JumpIfSmi(input, is_not_object);
1607
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001608 __ CompareRoot(input, Heap::kNullValueRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001609 __ j(equal, is_object);
1610
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001611 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001612 // Undetectable objects behave like undefined.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001613 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001614 Immediate(1 << Map::kIsUndetectable));
1615 __ j(not_zero, is_not_object);
1616
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001617 __ movzxbl(kScratchRegister,
1618 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001619 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001620 __ j(below, is_not_object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001621 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001622 return below_equal;
1623}
1624
1625
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001626void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001627 Register reg = ToRegister(instr->InputAt(0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001628
1629 int true_block = chunk_->LookupDestination(instr->true_block_id());
1630 int false_block = chunk_->LookupDestination(instr->false_block_id());
1631 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1632 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1633
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001634 Condition true_cond = EmitIsObject(reg, false_label, true_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001635
1636 EmitBranch(true_block, false_block, true_cond);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001637}
1638
1639
erikcorry0ad885c2011-11-21 13:51:57 +00001640Condition LCodeGen::EmitIsString(Register input,
1641 Register temp1,
1642 Label* is_not_string) {
1643 __ JumpIfSmi(input, is_not_string);
1644 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
1645
1646 return cond;
1647}
1648
1649
1650void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
1651 Register reg = ToRegister(instr->InputAt(0));
1652 Register temp = ToRegister(instr->TempAt(0));
1653
1654 int true_block = chunk_->LookupDestination(instr->true_block_id());
1655 int false_block = chunk_->LookupDestination(instr->false_block_id());
1656 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1657
1658 Condition true_cond = EmitIsString(reg, temp, false_label);
1659
1660 EmitBranch(true_block, false_block, true_cond);
1661}
1662
1663
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001664void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001665 int true_block = chunk_->LookupDestination(instr->true_block_id());
1666 int false_block = chunk_->LookupDestination(instr->false_block_id());
1667
1668 Condition is_smi;
1669 if (instr->InputAt(0)->IsRegister()) {
1670 Register input = ToRegister(instr->InputAt(0));
1671 is_smi = masm()->CheckSmi(input);
1672 } else {
1673 Operand input = ToOperand(instr->InputAt(0));
1674 is_smi = masm()->CheckSmi(input);
1675 }
1676 EmitBranch(true_block, false_block, is_smi);
1677}
1678
1679
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001680void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
1681 Register input = ToRegister(instr->InputAt(0));
1682 Register temp = ToRegister(instr->TempAt(0));
1683
1684 int true_block = chunk_->LookupDestination(instr->true_block_id());
1685 int false_block = chunk_->LookupDestination(instr->false_block_id());
1686
1687 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
1688 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
1689 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
1690 Immediate(1 << Map::kIsUndetectable));
1691 EmitBranch(true_block, false_block, not_zero);
1692}
1693
1694
erikcorry0ad885c2011-11-21 13:51:57 +00001695void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
1696 Token::Value op = instr->op();
1697 int true_block = chunk_->LookupDestination(instr->true_block_id());
1698 int false_block = chunk_->LookupDestination(instr->false_block_id());
1699
1700 Handle<Code> ic = CompareIC::GetUninitialized(op);
1701 CallCode(ic, RelocInfo::CODE_TARGET, instr);
1702
1703 Condition condition = TokenToCondition(op, false);
1704 __ testq(rax, rax);
1705
1706 EmitBranch(true_block, false_block, condition);
1707}
1708
1709
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001710static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001711 InstanceType from = instr->from();
1712 InstanceType to = instr->to();
1713 if (from == FIRST_TYPE) return to;
1714 ASSERT(from == to || to == LAST_TYPE);
1715 return from;
1716}
1717
1718
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001719static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001720 InstanceType from = instr->from();
1721 InstanceType to = instr->to();
1722 if (from == to) return equal;
1723 if (to == LAST_TYPE) return above_equal;
1724 if (from == FIRST_TYPE) return below_equal;
1725 UNREACHABLE();
1726 return equal;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001727}
1728
1729
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001730void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001731 Register input = ToRegister(instr->InputAt(0));
1732
1733 int true_block = chunk_->LookupDestination(instr->true_block_id());
1734 int false_block = chunk_->LookupDestination(instr->false_block_id());
1735
1736 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1737
1738 __ JumpIfSmi(input, false_label);
1739
1740 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
1741 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001742}
1743
1744
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001745void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1746 Register input = ToRegister(instr->InputAt(0));
1747 Register result = ToRegister(instr->result());
1748
1749 if (FLAG_debug_code) {
1750 __ AbortIfNotString(input);
1751 }
1752
1753 __ movl(result, FieldOperand(input, String::kHashFieldOffset));
1754 ASSERT(String::kHashShift >= kSmiTagSize);
1755 __ IndexFromHash(result, result);
1756}
1757
1758
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001759void LCodeGen::DoHasCachedArrayIndexAndBranch(
1760 LHasCachedArrayIndexAndBranch* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001761 Register input = ToRegister(instr->InputAt(0));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001762
1763 int true_block = chunk_->LookupDestination(instr->true_block_id());
1764 int false_block = chunk_->LookupDestination(instr->false_block_id());
1765
1766 __ testl(FieldOperand(input, String::kHashFieldOffset),
1767 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001768 EmitBranch(true_block, false_block, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001769}
1770
1771
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001772// Branches to a label or falls through with the answer in the z flag.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001773// Trashes the temp register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001774void LCodeGen::EmitClassOfTest(Label* is_true,
1775 Label* is_false,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001776 Handle<String> class_name,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001777 Register input,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001778 Register temp,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001779 Register temp2) {
1780 ASSERT(!input.is(temp));
1781 ASSERT(!input.is(temp2));
1782 ASSERT(!temp.is(temp2));
1783
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001784 __ JumpIfSmi(input, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001785
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001786 if (class_name->IsEqualTo(CStrVector("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001787 // Assuming the following assertions, we can use the same compares to test
1788 // for both being a function type and being in the object type range.
1789 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
1790 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
1791 FIRST_SPEC_OBJECT_TYPE + 1);
1792 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
1793 LAST_SPEC_OBJECT_TYPE - 1);
1794 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1795 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
1796 __ j(below, is_false);
1797 __ j(equal, is_true);
1798 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
1799 __ j(equal, is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001800 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001801 // Faster code path to avoid two compares: subtract lower bound from the
1802 // actual type and do a signed compare with the width of the type range.
1803 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00001804 __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
1805 __ subq(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
1806 __ cmpq(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
1807 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001808 __ j(above, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001809 }
1810
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001811 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001812 // Check if the constructor in the map is a function.
1813 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset));
1814
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001815 // Objects with a non-function constructor have class 'Object'.
1816 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
1817 if (class_name->IsEqualTo(CStrVector("Object"))) {
1818 __ j(not_equal, is_true);
1819 } else {
1820 __ j(not_equal, is_false);
1821 }
1822
1823 // temp now contains the constructor function. Grab the
1824 // instance class name from there.
1825 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1826 __ movq(temp, FieldOperand(temp,
1827 SharedFunctionInfo::kInstanceClassNameOffset));
1828 // The class name we are testing against is a symbol because it's a literal.
1829 // The name in the constructor is a symbol because of the way the context is
1830 // booted. This routine isn't expected to work for random API-created
1831 // classes and it doesn't have to because you can't access it with natives
1832 // syntax. Since both sides are symbols it is sufficient to use an identity
1833 // comparison.
1834 ASSERT(class_name->IsSymbol());
1835 __ Cmp(temp, class_name);
1836 // End with the answer in the z flag.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001837}
1838
1839
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001840void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001841 Register input = ToRegister(instr->InputAt(0));
1842 Register temp = ToRegister(instr->TempAt(0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001843 Register temp2 = ToRegister(instr->TempAt(1));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001844 Handle<String> class_name = instr->hydrogen()->class_name();
1845
1846 int true_block = chunk_->LookupDestination(instr->true_block_id());
1847 int false_block = chunk_->LookupDestination(instr->false_block_id());
1848
1849 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1850 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1851
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001852 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001853
1854 EmitBranch(true_block, false_block, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001855}
1856
1857
1858void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001859 Register reg = ToRegister(instr->InputAt(0));
1860 int true_block = instr->true_block_id();
1861 int false_block = instr->false_block_id();
1862
1863 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1864 EmitBranch(true_block, false_block, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001865}
1866
1867
1868void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001869 InstanceofStub stub(InstanceofStub::kNoFlags);
1870 __ push(ToRegister(instr->InputAt(0)));
1871 __ push(ToRegister(instr->InputAt(1)));
1872 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001873 Label true_value, done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001874 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001875 __ j(zero, &true_value, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001876 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001877 __ jmp(&done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001878 __ bind(&true_value);
1879 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
1880 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001881}
1882
1883
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001884void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001885 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
1886 public:
1887 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
1888 LInstanceOfKnownGlobal* instr)
1889 : LDeferredCode(codegen), instr_(instr) { }
1890 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001891 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001892 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001893 virtual LInstruction* instr() { return instr_; }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001894 Label* map_check() { return &map_check_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001895 private:
1896 LInstanceOfKnownGlobal* instr_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001897 Label map_check_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001898 };
1899
1900
1901 DeferredInstanceOfKnownGlobal* deferred;
1902 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
1903
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001904 Label done, false_result;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001905 Register object = ToRegister(instr->InputAt(0));
1906
1907 // A Smi is not an instance of anything.
1908 __ JumpIfSmi(object, &false_result);
1909
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001910 // This is the inlined call site instanceof cache. The two occurences of the
1911 // hole value will be patched to the last map/result pair generated by the
1912 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001913 Label cache_miss;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001914 // Use a temp register to avoid memory operands with variable lengths.
1915 Register map = ToRegister(instr->TempAt(0));
1916 __ movq(map, FieldOperand(object, HeapObject::kMapOffset));
1917 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001918 Handle<JSGlobalPropertyCell> cache_cell =
1919 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
1920 __ movq(kScratchRegister, cache_cell, RelocInfo::GLOBAL_PROPERTY_CELL);
1921 __ cmpq(map, Operand(kScratchRegister, 0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001922 __ j(not_equal, &cache_miss, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001923 // Patched to load either true or false.
1924 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
1925#ifdef DEBUG
1926 // Check that the code size between patch label and patch sites is invariant.
1927 Label end_of_patched_code;
1928 __ bind(&end_of_patched_code);
1929 ASSERT(true);
1930#endif
1931 __ jmp(&done);
1932
1933 // The inlined call site cache did not match. Check for null and string
1934 // before calling the deferred code.
1935 __ bind(&cache_miss); // Null is not an instance of anything.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001936 __ CompareRoot(object, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001937 __ j(equal, &false_result, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001938
1939 // String values are not instances of anything.
1940 __ JumpIfNotString(object, kScratchRegister, deferred->entry());
1941
1942 __ bind(&false_result);
1943 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
1944
1945 __ bind(deferred->exit());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001946 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001947}
1948
1949
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001950void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
1951 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001952 {
1953 PushSafepointRegistersScope scope(this);
1954 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
1955 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck);
1956 InstanceofStub stub(flags);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001957
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001958 __ push(ToRegister(instr->InputAt(0)));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001959 __ PushHeapObject(instr->function());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001960
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001961 static const int kAdditionalDelta = 10;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001962 int delta =
1963 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001964 ASSERT(delta >= 0);
1965 __ push_imm32(delta);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001966
1967 // We are pushing three values on the stack but recording a
1968 // safepoint with two arguments because stub is going to
1969 // remove the third argument from the stack before jumping
1970 // to instanceof builtin on the slow path.
1971 CallCodeGeneric(stub.GetCode(),
1972 RelocInfo::CODE_TARGET,
1973 instr,
1974 RECORD_SAFEPOINT_WITH_REGISTERS,
1975 2);
1976 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001977 ASSERT(instr->HasDeoptimizationEnvironment());
1978 LEnvironment* env = instr->deoptimization_environment();
1979 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001980 // Move result to a register that survives the end of the
1981 // PushSafepointRegisterScope.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001982 __ movq(kScratchRegister, rax);
1983 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001984 __ testq(kScratchRegister, kScratchRegister);
1985 Label load_false;
1986 Label done;
1987 __ j(not_zero, &load_false);
1988 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
1989 __ jmp(&done);
1990 __ bind(&load_false);
1991 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
1992 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001993}
1994
1995
1996void LCodeGen::DoCmpT(LCmpT* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001997 Token::Value op = instr->op();
1998
1999 Handle<Code> ic = CompareIC::GetUninitialized(op);
2000 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2001
2002 Condition condition = TokenToCondition(op, false);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002003 Label true_value, done;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002004 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002005 __ j(condition, &true_value, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002006 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002007 __ jmp(&done, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002008 __ bind(&true_value);
2009 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2010 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002011}
2012
2013
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002014void LCodeGen::DoReturn(LReturn* instr) {
2015 if (FLAG_trace) {
2016 // Preserve the return value on the stack and rely on the runtime
2017 // call to return the value in the same register.
2018 __ push(rax);
2019 __ CallRuntime(Runtime::kTraceExit, 1);
2020 }
2021 __ movq(rsp, rbp);
2022 __ pop(rbp);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002023 __ Ret((GetParameterCount() + 1) * kPointerSize, rcx);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002024}
2025
2026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002027void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002028 Register result = ToRegister(instr->result());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002029 __ LoadGlobalCell(result, instr->hydrogen()->cell());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002030 if (instr->hydrogen()->RequiresHoleCheck()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002031 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2032 DeoptimizeIf(equal, instr->environment());
2033 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002034}
2035
2036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002037void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2038 ASSERT(ToRegister(instr->global_object()).is(rax));
2039 ASSERT(ToRegister(instr->result()).is(rax));
2040
2041 __ Move(rcx, instr->name());
2042 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2043 RelocInfo::CODE_TARGET_CONTEXT;
2044 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2045 CallCode(ic, mode, instr);
2046}
2047
2048
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002049void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002050 Register value = ToRegister(instr->value());
2051 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002052
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002053 // If the cell we are storing to contains the hole it could have
2054 // been deleted from the property dictionary. In that case, we need
2055 // to update the property details in the property dictionary to mark
2056 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002057 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002058 // We have a temp because CompareRoot might clobber kScratchRegister.
2059 Register cell = ToRegister(instr->TempAt(0));
2060 ASSERT(!value.is(cell));
2061 __ movq(cell, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL);
2062 __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002063 DeoptimizeIf(equal, instr->environment());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002064 // Store the value.
2065 __ movq(Operand(cell, 0), value);
2066 } else {
2067 // Store the value.
2068 __ movq(kScratchRegister, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL);
2069 __ movq(Operand(kScratchRegister, 0), value);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002070 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002071 // Cells are always rescanned, so no write barrier here.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002072}
2073
2074
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002075void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2076 ASSERT(ToRegister(instr->global_object()).is(rdx));
2077 ASSERT(ToRegister(instr->value()).is(rax));
2078
2079 __ Move(rcx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002080 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002081 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2082 : isolate()->builtins()->StoreIC_Initialize();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002083 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
2084}
2085
2086
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002087void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002088 Register context = ToRegister(instr->context());
2089 Register result = ToRegister(instr->result());
2090 __ movq(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002091 if (instr->hydrogen()->RequiresHoleCheck()) {
2092 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002093 if (instr->hydrogen()->DeoptimizesOnHole()) {
2094 DeoptimizeIf(equal, instr->environment());
2095 } else {
2096 Label is_not_hole;
2097 __ j(not_equal, &is_not_hole, Label::kNear);
2098 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2099 __ bind(&is_not_hole);
2100 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002101 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002102}
2103
2104
2105void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2106 Register context = ToRegister(instr->context());
2107 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002108
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002109 Operand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002110
2111 Label skip_assignment;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002112 if (instr->hydrogen()->RequiresHoleCheck()) {
2113 __ CompareRoot(target, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002114 if (instr->hydrogen()->DeoptimizesOnHole()) {
2115 DeoptimizeIf(equal, instr->environment());
2116 } else {
2117 __ j(not_equal, &skip_assignment);
2118 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002119 }
2120 __ movq(target, value);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002121
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002122 if (instr->hydrogen()->NeedsWriteBarrier()) {
2123 HType type = instr->hydrogen()->value()->type();
2124 SmiCheck check_needed =
2125 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002126 int offset = Context::SlotOffset(instr->slot_index());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002127 Register scratch = ToRegister(instr->TempAt(0));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002128 __ RecordWriteContextSlot(context,
2129 offset,
2130 value,
2131 scratch,
2132 kSaveFPRegs,
2133 EMIT_REMEMBERED_SET,
2134 check_needed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002135 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002136
2137 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002138}
2139
2140
2141void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002142 Register object = ToRegister(instr->InputAt(0));
2143 Register result = ToRegister(instr->result());
2144 if (instr->hydrogen()->is_in_object()) {
2145 __ movq(result, FieldOperand(object, instr->hydrogen()->offset()));
2146 } else {
2147 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
2148 __ movq(result, FieldOperand(result, instr->hydrogen()->offset()));
2149 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002150}
2151
2152
lrn@chromium.org1c092762011-05-09 09:42:16 +00002153void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2154 Register object,
2155 Handle<Map> type,
2156 Handle<String> name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002157 LookupResult lookup(isolate());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002158 type->LookupInDescriptors(NULL, *name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002159 ASSERT(lookup.IsFound() &&
lrn@chromium.org1c092762011-05-09 09:42:16 +00002160 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
2161 if (lookup.type() == FIELD) {
2162 int index = lookup.GetLocalFieldIndexFromMap(*type);
2163 int offset = index * kPointerSize;
2164 if (index < 0) {
2165 // Negative property indices are in-object properties, indexed
2166 // from the end of the fixed part of the object.
2167 __ movq(result, FieldOperand(object, offset + type->instance_size()));
2168 } else {
2169 // Non-negative property indices are in the properties array.
2170 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
2171 __ movq(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2172 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002173 } else {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002174 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002175 __ LoadHeapObject(result, function);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002176 }
2177}
2178
2179
2180void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2181 Register object = ToRegister(instr->object());
2182 Register result = ToRegister(instr->result());
2183
2184 int map_count = instr->hydrogen()->types()->length();
2185 Handle<String> name = instr->hydrogen()->name();
2186
2187 if (map_count == 0) {
2188 ASSERT(instr->hydrogen()->need_generic());
2189 __ Move(rcx, instr->hydrogen()->name());
2190 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2191 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2192 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002193 Label done;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002194 for (int i = 0; i < map_count - 1; ++i) {
2195 Handle<Map> map = instr->hydrogen()->types()->at(i);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002196 Label next;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002197 __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002198 __ j(not_equal, &next, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002199 EmitLoadFieldOrConstantFunction(result, object, map, name);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002200 __ jmp(&done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002201 __ bind(&next);
2202 }
2203 Handle<Map> map = instr->hydrogen()->types()->last();
2204 __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2205 if (instr->hydrogen()->need_generic()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002206 Label generic;
2207 __ j(not_equal, &generic, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002208 EmitLoadFieldOrConstantFunction(result, object, map, name);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002209 __ jmp(&done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002210 __ bind(&generic);
2211 __ Move(rcx, instr->hydrogen()->name());
2212 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2213 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2214 } else {
2215 DeoptimizeIf(not_equal, instr->environment());
lrn@chromium.org1c092762011-05-09 09:42:16 +00002216 EmitLoadFieldOrConstantFunction(result, object, map, name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002217 }
2218 __ bind(&done);
2219 }
2220}
2221
2222
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002223void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002224 ASSERT(ToRegister(instr->object()).is(rax));
2225 ASSERT(ToRegister(instr->result()).is(rax));
2226
2227 __ Move(rcx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002228 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002229 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002230}
2231
2232
2233void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002234 Register function = ToRegister(instr->function());
2235 Register result = ToRegister(instr->result());
2236
2237 // Check that the function really is a function.
2238 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2239 DeoptimizeIf(not_equal, instr->environment());
2240
2241 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002242 Label non_instance;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002243 __ testb(FieldOperand(result, Map::kBitFieldOffset),
2244 Immediate(1 << Map::kHasNonInstancePrototype));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002245 __ j(not_zero, &non_instance, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002246
2247 // Get the prototype or initial map from the function.
2248 __ movq(result,
2249 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2250
2251 // Check that the function has a prototype or an initial map.
2252 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2253 DeoptimizeIf(equal, instr->environment());
2254
2255 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002256 Label done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002257 __ CmpObjectType(result, MAP_TYPE, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002258 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002259
2260 // Get the prototype from the initial map.
2261 __ movq(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002262 __ jmp(&done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002263
2264 // Non-instance prototype: Fetch prototype from constructor field
2265 // in the function's map.
2266 __ bind(&non_instance);
2267 __ movq(result, FieldOperand(result, Map::kConstructorOffset));
2268
2269 // All done.
2270 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002271}
2272
2273
2274void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002275 Register result = ToRegister(instr->result());
2276 Register input = ToRegister(instr->InputAt(0));
2277 __ movq(result, FieldOperand(input, JSObject::kElementsOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002278 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002279 Label done, ok, fail;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00002280 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
2281 Heap::kFixedArrayMapRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002282 __ j(equal, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00002283 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset),
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00002284 Heap::kFixedCOWArrayMapRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002285 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002286 Register temp((result.is(rax)) ? rbx : rax);
2287 __ push(temp);
2288 __ movq(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002289 __ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset));
2290 __ and_(temp, Immediate(Map::kElementsKindMask));
2291 __ shr(temp, Immediate(Map::kElementsKindShift));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002292 __ cmpl(temp, Immediate(FAST_ELEMENTS));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002293 __ j(equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002294 __ cmpl(temp, Immediate(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002295 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002296 __ cmpl(temp, Immediate(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002297 __ j(less_equal, &ok, Label::kNear);
2298 __ bind(&fail);
2299 __ Abort("Check for fast or external elements failed");
2300 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002301 __ pop(temp);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002302 __ bind(&done);
2303 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002304}
2305
2306
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002307void LCodeGen::DoLoadExternalArrayPointer(
2308 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002309 Register result = ToRegister(instr->result());
2310 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002311 __ movq(result, FieldOperand(input,
2312 ExternalPixelArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002313}
2314
2315
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002316void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002317 Register arguments = ToRegister(instr->arguments());
2318 Register length = ToRegister(instr->length());
2319 Register result = ToRegister(instr->result());
2320
2321 if (instr->index()->IsRegister()) {
2322 __ subl(length, ToRegister(instr->index()));
2323 } else {
2324 __ subl(length, ToOperand(instr->index()));
2325 }
2326 DeoptimizeIf(below_equal, instr->environment());
2327
2328 // There are two words between the frame pointer and the last argument.
2329 // Subtracting from length accounts for one of them add one more.
2330 __ movq(result, Operand(arguments, length, times_pointer_size, kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002331}
2332
2333
2334void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002335 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002336
2337 // Load the result.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002338 __ movq(result,
2339 BuildFastArrayOperand(instr->elements(), instr->key(),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002340 FAST_ELEMENTS,
danno@chromium.orgb6451162011-08-17 14:33:23 +00002341 FixedArray::kHeaderSize - kHeapObjectTag));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002342
2343 // Check for the hole value.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002344 if (instr->hydrogen()->RequiresHoleCheck()) {
2345 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2346 DeoptimizeIf(equal, instr->environment());
2347 }
2348}
2349
2350
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002351void LCodeGen::DoLoadKeyedFastDoubleElement(
2352 LLoadKeyedFastDoubleElement* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002353 XMMRegister result(ToDoubleRegister(instr->result()));
2354
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002355 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2356 sizeof(kHoleNanLower32);
2357 Operand hole_check_operand = BuildFastArrayOperand(
2358 instr->elements(),
2359 instr->key(),
2360 FAST_DOUBLE_ELEMENTS,
2361 offset);
2362 __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
2363 DeoptimizeIf(equal, instr->environment());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002364
2365 Operand double_load_operand = BuildFastArrayOperand(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002366 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002367 FixedDoubleArray::kHeaderSize - kHeapObjectTag);
2368 __ movsd(result, double_load_operand);
2369}
2370
2371
2372Operand LCodeGen::BuildFastArrayOperand(
danno@chromium.orgb6451162011-08-17 14:33:23 +00002373 LOperand* elements_pointer,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002374 LOperand* key,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002375 ElementsKind elements_kind,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002376 uint32_t offset) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00002377 Register elements_pointer_reg = ToRegister(elements_pointer);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002378 int shift_size = ElementsKindToShiftSize(elements_kind);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002379 if (key->IsConstantOperand()) {
2380 int constant_value = ToInteger32(LConstantOperand::cast(key));
2381 if (constant_value & 0xF0000000) {
2382 Abort("array index constant value too big");
2383 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002384 return Operand(elements_pointer_reg,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002385 constant_value * (1 << shift_size) + offset);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002386 } else {
2387 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
danno@chromium.orgb6451162011-08-17 14:33:23 +00002388 return Operand(elements_pointer_reg, ToRegister(key),
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002389 scale_factor, offset);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002390 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002391}
2392
2393
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002394void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2395 LLoadKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002396 ElementsKind elements_kind = instr->elements_kind();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002397 Operand operand(BuildFastArrayOperand(instr->external_pointer(),
2398 instr->key(), elements_kind, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002399 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002400 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002401 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002402 __ cvtss2sd(result, result);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002403 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002404 __ movsd(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002405 } else {
2406 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002407 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002408 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002409 __ movsxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002410 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002411 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2412 case EXTERNAL_PIXEL_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002413 __ movzxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002414 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002415 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002416 __ movsxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002417 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002418 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002419 __ movzxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002420 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002421 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002422 __ movsxlq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002423 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002424 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002425 __ movl(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002426 __ testl(result, result);
2427 // TODO(danno): we could be more clever here, perhaps having a special
2428 // version of the stub that detects if the overflow case actually
2429 // happens, and generate code that returns a double rather than int.
2430 DeoptimizeIf(negative, instr->environment());
2431 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002432 case EXTERNAL_FLOAT_ELEMENTS:
2433 case EXTERNAL_DOUBLE_ELEMENTS:
2434 case FAST_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002435 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002436 case FAST_DOUBLE_ELEMENTS:
2437 case DICTIONARY_ELEMENTS:
2438 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002439 UNREACHABLE();
2440 break;
2441 }
2442 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002443}
2444
2445
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002446void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002447 ASSERT(ToRegister(instr->object()).is(rdx));
2448 ASSERT(ToRegister(instr->key()).is(rax));
2449
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002450 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002451 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002452}
2453
2454
2455void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002456 Register result = ToRegister(instr->result());
2457
2458 // Check for arguments adapter frame.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002459 Label done, adapted;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002460 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002461 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
2462 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002463 __ j(equal, &adapted, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002464
2465 // No arguments adaptor frame.
2466 __ movq(result, rbp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002467 __ jmp(&done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002468
2469 // Arguments adaptor frame present.
2470 __ bind(&adapted);
2471 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2472
2473 // Result is the frame pointer for the frame if not adapted and for the real
2474 // frame below the adaptor frame if adapted.
2475 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002476}
2477
2478
2479void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002480 Register result = ToRegister(instr->result());
2481
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002482 Label done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002483
2484 // If no arguments adaptor frame the number of arguments is fixed.
2485 if (instr->InputAt(0)->IsRegister()) {
2486 __ cmpq(rbp, ToRegister(instr->InputAt(0)));
2487 } else {
2488 __ cmpq(rbp, ToOperand(instr->InputAt(0)));
2489 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002490 __ movl(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002491 __ j(equal, &done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002492
2493 // Arguments adaptor frame present. Get argument length from there.
2494 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002495 __ SmiToInteger32(result,
2496 Operand(result,
2497 ArgumentsAdaptorFrameConstants::kLengthOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002498
2499 // Argument length is in result register.
2500 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002501}
2502
2503
2504void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002505 Register receiver = ToRegister(instr->receiver());
2506 Register function = ToRegister(instr->function());
2507 Register length = ToRegister(instr->length());
2508 Register elements = ToRegister(instr->elements());
2509 ASSERT(receiver.is(rax)); // Used for parameter count.
2510 ASSERT(function.is(rdi)); // Required by InvokeFunction.
2511 ASSERT(ToRegister(instr->result()).is(rax));
2512
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002513 // If the receiver is null or undefined, we have to pass the global
2514 // object as a receiver to normal functions. Values have to be
2515 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002516 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002517
2518 // Do not transform the receiver to object for strict mode
2519 // functions.
2520 __ movq(kScratchRegister,
2521 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2522 __ testb(FieldOperand(kScratchRegister,
2523 SharedFunctionInfo::kStrictModeByteOffset),
2524 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
2525 __ j(not_equal, &receiver_ok, Label::kNear);
2526
2527 // Do not transform the receiver to object for builtins.
2528 __ testb(FieldOperand(kScratchRegister,
2529 SharedFunctionInfo::kNativeByteOffset),
2530 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
2531 __ j(not_equal, &receiver_ok, Label::kNear);
2532
2533 // Normal function. Replace undefined or null with global receiver.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002534 __ CompareRoot(receiver, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002535 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002536 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002537 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002538
2539 // The receiver should be a JS object.
2540 Condition is_smi = __ CheckSmi(receiver);
2541 DeoptimizeIf(is_smi, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002542 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002543 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002544 __ jmp(&receiver_ok, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002545
2546 __ bind(&global_object);
2547 // TODO(kmillikin): We have a hydrogen value for the global object. See
2548 // if it's better to use it than to explicitly fetch it from the context
2549 // here.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002550 __ movq(receiver, ContextOperand(rsi, Context::GLOBAL_INDEX));
2551 __ movq(receiver,
2552 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002553 __ bind(&receiver_ok);
2554
2555 // Copy the arguments to this function possibly from the
2556 // adaptor frame below it.
2557 const uint32_t kArgumentsLimit = 1 * KB;
2558 __ cmpq(length, Immediate(kArgumentsLimit));
2559 DeoptimizeIf(above, instr->environment());
2560
2561 __ push(receiver);
2562 __ movq(receiver, length);
2563
2564 // Loop through the arguments pushing them onto the execution
2565 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002566 Label invoke, loop;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002567 // length is a small non-negative integer, due to the test above.
2568 __ testl(length, length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002569 __ j(zero, &invoke, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002570 __ bind(&loop);
2571 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2572 __ decl(length);
2573 __ j(not_zero, &loop);
2574
2575 // Invoke the function.
2576 __ bind(&invoke);
2577 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2578 LPointerMap* pointers = instr->pointer_map();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002579 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002580 SafepointGenerator safepoint_generator(
2581 this, pointers, Safepoint::kLazyDeopt);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002582 ParameterCount actual(rax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002583 __ InvokeFunction(function, actual, CALL_FUNCTION,
2584 safepoint_generator, CALL_AS_METHOD);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002585 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002586}
2587
2588
2589void LCodeGen::DoPushArgument(LPushArgument* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00002590 LOperand* argument = instr->InputAt(0);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002591 EmitPushTaggedOperand(argument);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002592}
2593
2594
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002595void LCodeGen::DoThisFunction(LThisFunction* instr) {
2596 Register result = ToRegister(instr->result());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002597 __ LoadHeapObject(result, instr->hydrogen()->closure());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002598}
2599
2600
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002601void LCodeGen::DoContext(LContext* instr) {
2602 Register result = ToRegister(instr->result());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002603 __ movq(result, rsi);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002604}
2605
2606
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002607void LCodeGen::DoOuterContext(LOuterContext* instr) {
2608 Register context = ToRegister(instr->context());
2609 Register result = ToRegister(instr->result());
2610 __ movq(result,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002611 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002612}
2613
2614
yangguo@chromium.org56454712012-02-16 15:33:53 +00002615void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
2616 __ push(rsi); // The context is the first argument.
2617 __ PushHeapObject(instr->hydrogen()->pairs());
2618 __ Push(Smi::FromInt(instr->hydrogen()->flags()));
2619 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
2620}
2621
2622
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002623void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002624 Register result = ToRegister(instr->result());
2625 __ movq(result, GlobalObjectOperand());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002626}
2627
2628
2629void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002630 Register global = ToRegister(instr->global());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002631 Register result = ToRegister(instr->result());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002632 __ movq(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002633}
2634
2635
2636void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2637 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002638 LInstruction* instr,
2639 CallKind call_kind) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002640 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
2641 function->shared()->formal_parameter_count() == arity;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002642
2643 LPointerMap* pointers = instr->pointer_map();
2644 RecordPosition(pointers->position());
2645
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002646 if (can_invoke_directly) {
2647 __ LoadHeapObject(rdi, function);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002648
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002649 // Change context if needed.
2650 bool change_context =
2651 (info()->closure()->context() != function->context()) ||
2652 scope()->contains_with() ||
2653 (scope()->num_heap_slots() > 0);
2654 if (change_context) {
2655 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2656 }
2657
2658 // Set rax to arguments count if adaption is not needed. Assumes that rax
2659 // is available to write to at this point.
2660 if (!function->NeedsArgumentsAdaption()) {
2661 __ Set(rax, arity);
2662 }
2663
2664 // Invoke function.
2665 __ SetCallKind(rcx, call_kind);
2666 if (*function == *info()->closure()) {
2667 __ CallSelf();
2668 } else {
2669 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2670 }
2671
2672 // Set up deoptimization.
2673 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
2674 } else {
2675 // We need to adapt arguments.
2676 SafepointGenerator generator(
2677 this, pointers, Safepoint::kLazyDeopt);
2678 ParameterCount count(arity);
2679 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
2680 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002681
2682 // Restore context.
2683 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002684}
2685
2686
2687void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002688 ASSERT(ToRegister(instr->result()).is(rax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002689 CallKnownFunction(instr->function(),
2690 instr->arity(),
2691 instr,
2692 CALL_AS_METHOD);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002693}
2694
2695
2696void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002697 Register input_reg = ToRegister(instr->InputAt(0));
2698 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
2699 Heap::kHeapNumberMapRootIndex);
2700 DeoptimizeIf(not_equal, instr->environment());
2701
2702 Label done;
2703 Register tmp = input_reg.is(rax) ? rcx : rax;
2704 Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx;
2705
2706 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002707 PushSafepointRegistersScope scope(this);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002708
2709 Label negative;
2710 __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2711 // Check the sign of the argument. If the argument is positive, just
2712 // return it. We do not need to patch the stack since |input| and
2713 // |result| are the same register and |input| will be restored
2714 // unchanged by popping safepoint registers.
2715 __ testl(tmp, Immediate(HeapNumber::kSignMask));
2716 __ j(not_zero, &negative);
2717 __ jmp(&done);
2718
2719 __ bind(&negative);
2720
2721 Label allocated, slow;
2722 __ AllocateHeapNumber(tmp, tmp2, &slow);
2723 __ jmp(&allocated);
2724
2725 // Slow case: Call the runtime system to do the number allocation.
2726 __ bind(&slow);
2727
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002728 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002729 // Set the pointer to the new heap number in tmp.
2730 if (!tmp.is(rax)) {
2731 __ movq(tmp, rax);
2732 }
2733
2734 // Restore input_reg after call to runtime.
2735 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
2736
2737 __ bind(&allocated);
2738 __ movq(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset));
2739 __ shl(tmp2, Immediate(1));
2740 __ shr(tmp2, Immediate(1));
2741 __ movq(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2);
2742 __ StoreToSafepointRegisterSlot(input_reg, tmp);
2743
2744 __ bind(&done);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002745}
2746
2747
2748void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
2749 Register input_reg = ToRegister(instr->InputAt(0));
2750 __ testl(input_reg, input_reg);
2751 Label is_positive;
2752 __ j(not_sign, &is_positive);
2753 __ negl(input_reg); // Sets flags.
2754 DeoptimizeIf(negative, instr->environment());
2755 __ bind(&is_positive);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002756}
2757
2758
2759void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002760 // Class for deferred case.
2761 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2762 public:
2763 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2764 LUnaryMathOperation* instr)
2765 : LDeferredCode(codegen), instr_(instr) { }
2766 virtual void Generate() {
2767 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2768 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002769 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002770 private:
2771 LUnaryMathOperation* instr_;
2772 };
2773
2774 ASSERT(instr->InputAt(0)->Equals(instr->result()));
2775 Representation r = instr->hydrogen()->value()->representation();
2776
2777 if (r.IsDouble()) {
2778 XMMRegister scratch = xmm0;
2779 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
danno@chromium.org160a7b02011-04-18 15:51:38 +00002780 __ xorps(scratch, scratch);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002781 __ subsd(scratch, input_reg);
2782 __ andpd(input_reg, scratch);
2783 } else if (r.IsInteger32()) {
2784 EmitIntegerMathAbs(instr);
2785 } else { // Tagged case.
2786 DeferredMathAbsTaggedHeapNumber* deferred =
2787 new DeferredMathAbsTaggedHeapNumber(this, instr);
2788 Register input_reg = ToRegister(instr->InputAt(0));
2789 // Smi check.
2790 __ JumpIfNotSmi(input_reg, deferred->entry());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002791 __ SmiToInteger32(input_reg, input_reg);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002792 EmitIntegerMathAbs(instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002793 __ Integer32ToSmi(input_reg, input_reg);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00002794 __ bind(deferred->exit());
2795 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002796}
2797
2798
2799void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002800 XMMRegister xmm_scratch = xmm0;
2801 Register output_reg = ToRegister(instr->result());
2802 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002803 Label done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002804
danno@chromium.org160a7b02011-04-18 15:51:38 +00002805 if (CpuFeatures::IsSupported(SSE4_1)) {
2806 CpuFeatures::Scope scope(SSE4_1);
2807 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2808 // Deoptimize if minus zero.
2809 __ movq(output_reg, input_reg);
2810 __ subq(output_reg, Immediate(1));
2811 DeoptimizeIf(overflow, instr->environment());
2812 }
2813 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
2814 __ cvttsd2si(output_reg, xmm_scratch);
2815 __ cmpl(output_reg, Immediate(0x80000000));
2816 DeoptimizeIf(equal, instr->environment());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002817 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002818 // Deoptimize on negative inputs.
danno@chromium.org160a7b02011-04-18 15:51:38 +00002819 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
2820 __ ucomisd(input_reg, xmm_scratch);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002821 DeoptimizeIf(below, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002822 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002823 // Check for negative zero.
2824 Label positive_sign;
2825 __ j(above, &positive_sign, Label::kNear);
2826 __ movmskpd(output_reg, input_reg);
2827 __ testq(output_reg, Immediate(1));
2828 DeoptimizeIf(not_zero, instr->environment());
2829 __ Set(output_reg, 0);
2830 __ jmp(&done);
2831 __ bind(&positive_sign);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002832 }
2833
2834 // Use truncating instruction (OK because input is positive).
2835 __ cvttsd2si(output_reg, input_reg);
2836
2837 // Overflow is signalled with minint.
2838 __ cmpl(output_reg, Immediate(0x80000000));
2839 DeoptimizeIf(equal, instr->environment());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002840 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002841 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002842}
2843
2844
2845void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002846 const XMMRegister xmm_scratch = xmm0;
2847 Register output_reg = ToRegister(instr->result());
2848 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
2849
danno@chromium.org160a7b02011-04-18 15:51:38 +00002850 Label done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002851 // xmm_scratch = 0.5
2852 __ movq(kScratchRegister, V8_INT64_C(0x3FE0000000000000), RelocInfo::NONE);
2853 __ movq(xmm_scratch, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002854 Label below_half;
danno@chromium.org160a7b02011-04-18 15:51:38 +00002855 __ ucomisd(xmm_scratch, input_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002856 // If input_reg is NaN, this doesn't jump.
2857 __ j(above, &below_half, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002858 // input = input + 0.5
danno@chromium.org160a7b02011-04-18 15:51:38 +00002859 // This addition might give a result that isn't the correct for
2860 // rounding, due to loss of precision, but only for a number that's
2861 // so big that the conversion below will overflow anyway.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002862 __ addsd(xmm_scratch, input_reg);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002863 // Compute Math.floor(input).
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002864 // Use truncating instruction (OK because input is positive).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002865 __ cvttsd2si(output_reg, xmm_scratch);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002866 // Overflow is signalled with minint.
2867 __ cmpl(output_reg, Immediate(0x80000000));
2868 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002869 __ jmp(&done);
2870
2871 __ bind(&below_half);
2872 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2873 // Bailout if negative (including -0).
2874 __ movq(output_reg, input_reg);
2875 __ testq(output_reg, output_reg);
2876 DeoptimizeIf(negative, instr->environment());
2877 } else {
2878 // Bailout if below -0.5, otherwise round to (positive) zero, even
2879 // if negative.
2880 // xmm_scrach = -0.5
2881 __ movq(kScratchRegister, V8_INT64_C(0xBFE0000000000000), RelocInfo::NONE);
2882 __ movq(xmm_scratch, kScratchRegister);
2883 __ ucomisd(input_reg, xmm_scratch);
2884 DeoptimizeIf(below, instr->environment());
2885 }
2886 __ xorl(output_reg, output_reg);
2887
2888 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002889}
2890
2891
2892void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002893 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
2894 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2895 __ sqrtsd(input_reg, input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002896}
2897
2898
2899void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002900 XMMRegister xmm_scratch = xmm0;
2901 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
2902 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002903
2904 // Note that according to ECMA-262 15.8.2.13:
2905 // Math.pow(-Infinity, 0.5) == Infinity
2906 // Math.sqrt(-Infinity) == NaN
2907 Label done, sqrt;
2908 // Check base for -Infinity. According to IEEE-754, double-precision
2909 // -Infinity has the highest 12 bits set and the lowest 52 bits cleared.
2910 __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000), RelocInfo::NONE);
2911 __ movq(xmm_scratch, kScratchRegister);
2912 __ ucomisd(xmm_scratch, input_reg);
2913 // Comparing -Infinity with NaN results in "unordered", which sets the
2914 // zero flag as if both were equal. However, it also sets the carry flag.
2915 __ j(not_equal, &sqrt, Label::kNear);
2916 __ j(carry, &sqrt, Label::kNear);
2917 // If input is -Infinity, return Infinity.
2918 __ xorps(input_reg, input_reg);
2919 __ subsd(input_reg, xmm_scratch);
2920 __ jmp(&done, Label::kNear);
2921
2922 // Square root.
2923 __ bind(&sqrt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002924 __ xorps(xmm_scratch, xmm_scratch);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002925 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
2926 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002927 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002928}
2929
2930
2931void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002932 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002933 // Having marked this as a call, we can use any registers.
2934 // Just make sure that the input/output registers are the expected ones.
2935
2936 // Choose register conforming to calling convention (when bailing out).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002937#ifdef _WIN64
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002938 Register exponent = rdx;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002939#else
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002940 Register exponent = rdi;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002941#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002942 ASSERT(!instr->InputAt(1)->IsRegister() ||
2943 ToRegister(instr->InputAt(1)).is(exponent));
2944 ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
2945 ToDoubleRegister(instr->InputAt(1)).is(xmm1));
2946 ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2));
2947 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002948
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002949 if (exponent_type.IsTagged()) {
2950 Label no_deopt;
2951 __ JumpIfSmi(exponent, &no_deopt);
2952 __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, rcx);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002953 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002954 __ bind(&no_deopt);
2955 MathPowStub stub(MathPowStub::TAGGED);
2956 __ CallStub(&stub);
2957 } else if (exponent_type.IsInteger32()) {
2958 MathPowStub stub(MathPowStub::INTEGER);
2959 __ CallStub(&stub);
2960 } else {
2961 ASSERT(exponent_type.IsDouble());
2962 MathPowStub stub(MathPowStub::DOUBLE);
2963 __ CallStub(&stub);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002964 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002965}
2966
2967
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002968void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002969 class DeferredDoRandom: public LDeferredCode {
2970 public:
2971 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
2972 : LDeferredCode(codegen), instr_(instr) { }
2973 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
2974 virtual LInstruction* instr() { return instr_; }
2975 private:
2976 LRandom* instr_;
2977 };
2978
2979 DeferredDoRandom* deferred = new DeferredDoRandom(this, instr);
2980
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002981 // Having marked this instruction as a call we can use any
2982 // registers.
2983 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2984
2985 // Choose the right register for the first argument depending on
2986 // calling convention.
2987#ifdef _WIN64
2988 ASSERT(ToRegister(instr->InputAt(0)).is(rcx));
2989 Register global_object = rcx;
2990#else
2991 ASSERT(ToRegister(instr->InputAt(0)).is(rdi));
2992 Register global_object = rdi;
2993#endif
2994
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002995 static const int kSeedSize = sizeof(uint32_t);
2996 STATIC_ASSERT(kPointerSize == 2 * kSeedSize);
2997
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002998 __ movq(global_object,
2999 FieldOperand(global_object, GlobalObject::kGlobalContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003000 static const int kRandomSeedOffset =
3001 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3002 __ movq(rbx, FieldOperand(global_object, kRandomSeedOffset));
3003 // rbx: FixedArray of the global context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003004
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003005 // Load state[0].
3006 __ movl(rax, FieldOperand(rbx, ByteArray::kHeaderSize));
3007 // If state[0] == 0, call runtime to initialize seeds.
3008 __ testl(rax, rax);
3009 __ j(zero, deferred->entry());
3010 // Load state[1].
3011 __ movl(rcx, FieldOperand(rbx, ByteArray::kHeaderSize + kSeedSize));
3012
3013 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3014 // Only operate on the lower 32 bit of rax.
3015 __ movl(rdx, rax);
3016 __ andl(rdx, Immediate(0xFFFF));
3017 __ imull(rdx, rdx, Immediate(18273));
3018 __ shrl(rax, Immediate(16));
3019 __ addl(rax, rdx);
3020 // Save state[0].
3021 __ movl(FieldOperand(rbx, ByteArray::kHeaderSize), rax);
3022
3023 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3024 __ movl(rdx, rcx);
3025 __ andl(rdx, Immediate(0xFFFF));
3026 __ imull(rdx, rdx, Immediate(36969));
3027 __ shrl(rcx, Immediate(16));
3028 __ addl(rcx, rdx);
3029 // Save state[1].
3030 __ movl(FieldOperand(rbx, ByteArray::kHeaderSize + kSeedSize), rcx);
3031
3032 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3033 __ shll(rax, Immediate(14));
3034 __ andl(rcx, Immediate(0x3FFFF));
3035 __ addl(rax, rcx);
3036
3037 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003038 // Convert 32 random bits in rax to 0.(32 random bits) in a double
3039 // by computing:
3040 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3041 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3042 __ movd(xmm2, rcx);
3043 __ movd(xmm1, rax);
3044 __ cvtss2sd(xmm2, xmm2);
3045 __ xorps(xmm1, xmm2);
3046 __ subsd(xmm1, xmm2);
3047}
3048
3049
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003050void LCodeGen::DoDeferredRandom(LRandom* instr) {
3051 __ PrepareCallCFunction(1);
3052 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3053 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3054 // Return value is in rax.
3055}
3056
3057
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003058void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003059 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3060 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3061 TranscendentalCacheStub::UNTAGGED);
3062 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003063}
3064
3065
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003066void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
3067 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3068 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3069 TranscendentalCacheStub::UNTAGGED);
3070 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3071}
3072
3073
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003074void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003075 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
whesse@chromium.org5c297712011-03-10 14:17:25 +00003076 TranscendentalCacheStub stub(TranscendentalCache::COS,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003077 TranscendentalCacheStub::UNTAGGED);
3078 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003079}
3080
3081
3082void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003083 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
whesse@chromium.org5c297712011-03-10 14:17:25 +00003084 TranscendentalCacheStub stub(TranscendentalCache::SIN,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003085 TranscendentalCacheStub::UNTAGGED);
3086 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003087}
3088
3089
3090void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003091 switch (instr->op()) {
3092 case kMathAbs:
3093 DoMathAbs(instr);
3094 break;
3095 case kMathFloor:
3096 DoMathFloor(instr);
3097 break;
3098 case kMathRound:
3099 DoMathRound(instr);
3100 break;
3101 case kMathSqrt:
3102 DoMathSqrt(instr);
3103 break;
3104 case kMathPowHalf:
3105 DoMathPowHalf(instr);
3106 break;
3107 case kMathCos:
3108 DoMathCos(instr);
3109 break;
3110 case kMathSin:
3111 DoMathSin(instr);
3112 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003113 case kMathTan:
3114 DoMathTan(instr);
3115 break;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003116 case kMathLog:
3117 DoMathLog(instr);
3118 break;
3119
3120 default:
3121 UNREACHABLE();
3122 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003123}
3124
3125
danno@chromium.org160a7b02011-04-18 15:51:38 +00003126void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3127 ASSERT(ToRegister(instr->function()).is(rdi));
3128 ASSERT(instr->HasPointerMap());
3129 ASSERT(instr->HasDeoptimizationEnvironment());
3130 LPointerMap* pointers = instr->pointer_map();
danno@chromium.org160a7b02011-04-18 15:51:38 +00003131 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003132 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003133 ParameterCount count(instr->arity());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003134 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003135 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3136}
3137
3138
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003139void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003140 ASSERT(ToRegister(instr->key()).is(rcx));
3141 ASSERT(ToRegister(instr->result()).is(rax));
3142
3143 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003144 Handle<Code> ic =
3145 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003146 CallCode(ic, RelocInfo::CODE_TARGET, instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003147 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003148}
3149
3150
3151void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003152 ASSERT(ToRegister(instr->result()).is(rax));
3153
3154 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003155 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3156 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003157 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003158 __ Move(rcx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003159 CallCode(ic, mode, instr);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003160 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003161}
3162
3163
3164void LCodeGen::DoCallFunction(LCallFunction* instr) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003165 ASSERT(ToRegister(instr->function()).is(rdi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003166 ASSERT(ToRegister(instr->result()).is(rax));
3167
3168 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003169 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003170 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3171 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003172}
3173
3174
3175void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003176 ASSERT(ToRegister(instr->result()).is(rax));
3177 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003178 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3179 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003180 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003181 __ Move(rcx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003182 CallCode(ic, mode, instr);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003183 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003184}
3185
3186
3187void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003188 ASSERT(ToRegister(instr->result()).is(rax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003189 CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003190}
3191
3192
3193void LCodeGen::DoCallNew(LCallNew* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003194 ASSERT(ToRegister(instr->InputAt(0)).is(rdi));
3195 ASSERT(ToRegister(instr->result()).is(rax));
3196
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003197 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003198 __ Set(rax, instr->arity());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003199 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003200}
3201
3202
3203void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003204 CallRuntime(instr->function(), instr->arity(), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003205}
3206
3207
3208void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003209 Register object = ToRegister(instr->object());
3210 Register value = ToRegister(instr->value());
3211 int offset = instr->offset();
3212
3213 if (!instr->transition().is_null()) {
3214 __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3215 }
3216
3217 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003218 HType type = instr->hydrogen()->value()->type();
3219 SmiCheck check_needed =
3220 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003221 if (instr->is_in_object()) {
3222 __ movq(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003223 if (instr->hydrogen()->NeedsWriteBarrier()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003224 Register temp = ToRegister(instr->TempAt(0));
3225 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003226 __ RecordWriteField(object,
3227 offset,
3228 value,
3229 temp,
3230 kSaveFPRegs,
3231 EMIT_REMEMBERED_SET,
3232 check_needed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003233 }
3234 } else {
3235 Register temp = ToRegister(instr->TempAt(0));
3236 __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3237 __ movq(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003238 if (instr->hydrogen()->NeedsWriteBarrier()) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003239 // Update the write barrier for the properties array.
3240 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003241 __ RecordWriteField(temp,
3242 offset,
3243 value,
3244 object,
3245 kSaveFPRegs,
3246 EMIT_REMEMBERED_SET,
3247 check_needed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003248 }
3249 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003250}
3251
3252
3253void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003254 ASSERT(ToRegister(instr->object()).is(rdx));
3255 ASSERT(ToRegister(instr->value()).is(rax));
3256
3257 __ Move(rcx, instr->hydrogen()->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003258 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003259 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3260 : isolate()->builtins()->StoreIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003261 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3262}
3263
3264
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003265void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3266 LStoreKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003267 ElementsKind elements_kind = instr->elements_kind();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003268 Operand operand(BuildFastArrayOperand(instr->external_pointer(),
3269 instr->key(), elements_kind, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003270 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003271 XMMRegister value(ToDoubleRegister(instr->value()));
3272 __ cvtsd2ss(value, value);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003273 __ movss(operand, value);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003274 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003275 __ movsd(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003276 } else {
3277 Register value(ToRegister(instr->value()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003278 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003279 case EXTERNAL_PIXEL_ELEMENTS:
3280 case EXTERNAL_BYTE_ELEMENTS:
3281 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003282 __ movb(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003283 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003284 case EXTERNAL_SHORT_ELEMENTS:
3285 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003286 __ movw(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003287 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003288 case EXTERNAL_INT_ELEMENTS:
3289 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003290 __ movl(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003291 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003292 case EXTERNAL_FLOAT_ELEMENTS:
3293 case EXTERNAL_DOUBLE_ELEMENTS:
3294 case FAST_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003295 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003296 case FAST_DOUBLE_ELEMENTS:
3297 case DICTIONARY_ELEMENTS:
3298 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003299 UNREACHABLE();
3300 break;
3301 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003302 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003303}
3304
3305
3306void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003307 if (instr->length()->IsRegister()) {
3308 Register reg = ToRegister(instr->length());
3309 if (FLAG_debug_code) {
3310 __ AbortIfNotZeroExtended(reg);
3311 }
3312 if (instr->index()->IsConstantOperand()) {
3313 __ cmpq(reg,
danno@chromium.orgb6451162011-08-17 14:33:23 +00003314 Immediate(ToInteger32(LConstantOperand::cast(instr->index()))));
3315 } else {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003316 Register reg2 = ToRegister(instr->index());
3317 if (FLAG_debug_code) {
3318 __ AbortIfNotZeroExtended(reg2);
3319 }
3320 __ cmpq(reg, reg2);
danno@chromium.orgb6451162011-08-17 14:33:23 +00003321 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003322 } else {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003323 if (instr->index()->IsConstantOperand()) {
3324 __ cmpq(ToOperand(instr->length()),
3325 Immediate(ToInteger32(LConstantOperand::cast(instr->index()))));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003326 } else {
3327 __ cmpq(ToOperand(instr->length()), ToRegister(instr->index()));
3328 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003329 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00003330 DeoptimizeIf(below_equal, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003331}
3332
3333
3334void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003335 Register value = ToRegister(instr->value());
3336 Register elements = ToRegister(instr->object());
3337 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3338
3339 // Do the store.
3340 if (instr->key()->IsConstantOperand()) {
3341 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3342 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3343 int offset =
3344 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
3345 __ movq(FieldOperand(elements, offset), value);
3346 } else {
3347 __ movq(FieldOperand(elements,
3348 key,
3349 times_pointer_size,
3350 FixedArray::kHeaderSize),
3351 value);
3352 }
3353
3354 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003355 HType type = instr->hydrogen()->value()->type();
3356 SmiCheck check_needed =
3357 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003358 // Compute address of modified element and store it into key register.
3359 __ lea(key, FieldOperand(elements,
3360 key,
3361 times_pointer_size,
3362 FixedArray::kHeaderSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003363 __ RecordWrite(elements,
3364 key,
3365 value,
3366 kSaveFPRegs,
3367 EMIT_REMEMBERED_SET,
3368 check_needed);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003369 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003370}
3371
3372
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003373void LCodeGen::DoStoreKeyedFastDoubleElement(
3374 LStoreKeyedFastDoubleElement* instr) {
3375 XMMRegister value = ToDoubleRegister(instr->value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003376 Label have_value;
3377
3378 __ ucomisd(value, value);
3379 __ j(parity_odd, &have_value); // NaN.
3380
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003381 __ Set(kScratchRegister, BitCast<uint64_t>(
3382 FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
3383 __ movq(value, kScratchRegister);
3384
3385 __ bind(&have_value);
3386 Operand double_store_operand = BuildFastArrayOperand(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003387 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003388 FixedDoubleArray::kHeaderSize - kHeapObjectTag);
3389 __ movsd(double_store_operand, value);
3390}
3391
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003392void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003393 ASSERT(ToRegister(instr->object()).is(rdx));
3394 ASSERT(ToRegister(instr->key()).is(rcx));
3395 ASSERT(ToRegister(instr->value()).is(rax));
3396
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003397 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003398 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3399 : isolate()->builtins()->KeyedStoreIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003400 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3401}
3402
3403
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003404void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
3405 Register object_reg = ToRegister(instr->object());
3406 Register new_map_reg = ToRegister(instr->new_map_reg());
3407
3408 Handle<Map> from_map = instr->original_map();
3409 Handle<Map> to_map = instr->transitioned_map();
3410 ElementsKind from_kind = from_map->elements_kind();
3411 ElementsKind to_kind = to_map->elements_kind();
3412
3413 Label not_applicable;
3414 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
3415 __ j(not_equal, &not_applicable);
3416 __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
3417 if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
3418 __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
3419 // Write barrier.
3420 ASSERT_NE(instr->temp_reg(), NULL);
3421 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
3422 ToRegister(instr->temp_reg()), kDontSaveFPRegs);
3423 } else if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
3424 to_kind == FAST_DOUBLE_ELEMENTS) {
3425 Register fixed_object_reg = ToRegister(instr->temp_reg());
3426 ASSERT(fixed_object_reg.is(rdx));
3427 ASSERT(new_map_reg.is(rbx));
3428 __ movq(fixed_object_reg, object_reg);
3429 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
3430 RelocInfo::CODE_TARGET, instr);
3431 } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
3432 Register fixed_object_reg = ToRegister(instr->temp_reg());
3433 ASSERT(fixed_object_reg.is(rdx));
3434 ASSERT(new_map_reg.is(rbx));
3435 __ movq(fixed_object_reg, object_reg);
3436 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
3437 RelocInfo::CODE_TARGET, instr);
3438 } else {
3439 UNREACHABLE();
3440 }
3441 __ bind(&not_applicable);
3442}
3443
3444
danno@chromium.org160a7b02011-04-18 15:51:38 +00003445void LCodeGen::DoStringAdd(LStringAdd* instr) {
3446 EmitPushTaggedOperand(instr->left());
3447 EmitPushTaggedOperand(instr->right());
3448 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
3449 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3450}
3451
3452
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003453void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3454 class DeferredStringCharCodeAt: public LDeferredCode {
3455 public:
3456 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3457 : LDeferredCode(codegen), instr_(instr) { }
3458 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003459 virtual LInstruction* instr() { return instr_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003460 private:
3461 LStringCharCodeAt* instr_;
3462 };
3463
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003464 DeferredStringCharCodeAt* deferred =
3465 new DeferredStringCharCodeAt(this, instr);
3466
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003467 StringCharLoadGenerator::Generate(masm(),
3468 ToRegister(instr->string()),
3469 ToRegister(instr->index()),
3470 ToRegister(instr->result()),
3471 deferred->entry());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003472 __ bind(deferred->exit());
3473}
3474
3475
3476void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3477 Register string = ToRegister(instr->string());
3478 Register result = ToRegister(instr->result());
3479
3480 // TODO(3095996): Get rid of this. For now, we need to make the
3481 // result register contain a valid pointer because it is already
3482 // contained in the register pointer map.
3483 __ Set(result, 0);
3484
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003485 PushSafepointRegistersScope scope(this);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003486 __ push(string);
3487 // Push the index as a smi. This is safe because of the checks in
3488 // DoStringCharCodeAt above.
3489 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3490 if (instr->index()->IsConstantOperand()) {
3491 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3492 __ Push(Smi::FromInt(const_index));
3493 } else {
3494 Register index = ToRegister(instr->index());
3495 __ Integer32ToSmi(index, index);
3496 __ push(index);
3497 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003498 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003499 if (FLAG_debug_code) {
3500 __ AbortIfNotSmi(rax);
3501 }
3502 __ SmiToInteger32(rax, rax);
3503 __ StoreToSafepointRegisterSlot(result, rax);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003504}
3505
3506
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003507void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
3508 class DeferredStringCharFromCode: public LDeferredCode {
3509 public:
3510 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
3511 : LDeferredCode(codegen), instr_(instr) { }
3512 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003513 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003514 private:
3515 LStringCharFromCode* instr_;
3516 };
3517
3518 DeferredStringCharFromCode* deferred =
3519 new DeferredStringCharFromCode(this, instr);
3520
3521 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
3522 Register char_code = ToRegister(instr->char_code());
3523 Register result = ToRegister(instr->result());
3524 ASSERT(!char_code.is(result));
3525
3526 __ cmpl(char_code, Immediate(String::kMaxAsciiCharCode));
3527 __ j(above, deferred->entry());
3528 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
3529 __ movq(result, FieldOperand(result,
3530 char_code, times_pointer_size,
3531 FixedArray::kHeaderSize));
3532 __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
3533 __ j(equal, deferred->entry());
3534 __ bind(deferred->exit());
3535}
3536
3537
3538void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
3539 Register char_code = ToRegister(instr->char_code());
3540 Register result = ToRegister(instr->result());
3541
3542 // TODO(3095996): Get rid of this. For now, we need to make the
3543 // result register contain a valid pointer because it is already
3544 // contained in the register pointer map.
3545 __ Set(result, 0);
3546
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003547 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003548 __ Integer32ToSmi(char_code, char_code);
3549 __ push(char_code);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003550 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003551 __ StoreToSafepointRegisterSlot(result, rax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003552}
3553
3554
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003555void LCodeGen::DoStringLength(LStringLength* instr) {
3556 Register string = ToRegister(instr->string());
3557 Register result = ToRegister(instr->result());
3558 __ movq(result, FieldOperand(string, String::kLengthOffset));
3559}
3560
3561
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003562void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003563 LOperand* input = instr->InputAt(0);
3564 ASSERT(input->IsRegister() || input->IsStackSlot());
3565 LOperand* output = instr->result();
3566 ASSERT(output->IsDoubleRegister());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003567 if (input->IsRegister()) {
3568 __ cvtlsi2sd(ToDoubleRegister(output), ToRegister(input));
3569 } else {
3570 __ cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
3571 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003572}
3573
3574
3575void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003576 LOperand* input = instr->InputAt(0);
3577 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3578 Register reg = ToRegister(input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003579
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003580 __ Integer32ToSmi(reg, reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003581}
3582
3583
3584void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003585 class DeferredNumberTagD: public LDeferredCode {
3586 public:
3587 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3588 : LDeferredCode(codegen), instr_(instr) { }
3589 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003590 virtual LInstruction* instr() { return instr_; }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003591 private:
3592 LNumberTagD* instr_;
3593 };
3594
3595 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
3596 Register reg = ToRegister(instr->result());
3597 Register tmp = ToRegister(instr->TempAt(0));
3598
3599 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3600 if (FLAG_inline_new) {
3601 __ AllocateHeapNumber(reg, tmp, deferred->entry());
3602 } else {
3603 __ jmp(deferred->entry());
3604 }
3605 __ bind(deferred->exit());
3606 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003607}
3608
3609
3610void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003611 // TODO(3095996): Get rid of this. For now, we need to make the
3612 // result register contain a valid pointer because it is already
3613 // contained in the register pointer map.
3614 Register reg = ToRegister(instr->result());
3615 __ Move(reg, Smi::FromInt(0));
3616
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003617 {
3618 PushSafepointRegistersScope scope(this);
3619 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
3620 // Ensure that value in rax survives popping registers.
3621 __ movq(kScratchRegister, rax);
3622 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003623 __ movq(reg, kScratchRegister);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003624}
3625
3626
3627void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003628 ASSERT(instr->InputAt(0)->Equals(instr->result()));
3629 Register input = ToRegister(instr->InputAt(0));
3630 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3631 __ Integer32ToSmi(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003632}
3633
3634
3635void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003636 ASSERT(instr->InputAt(0)->Equals(instr->result()));
3637 Register input = ToRegister(instr->InputAt(0));
3638 if (instr->needs_check()) {
3639 Condition is_smi = __ CheckSmi(input);
3640 DeoptimizeIf(NegateCondition(is_smi), instr->environment());
3641 }
3642 __ SmiToInteger32(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003643}
3644
3645
3646void LCodeGen::EmitNumberUntagD(Register input_reg,
3647 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003648 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003649 bool deoptimize_on_minus_zero,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003650 LEnvironment* env) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003651 Label load_smi, done;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003652
3653 // Smi check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003654 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003655
3656 // Heap number map check.
3657 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
3658 Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003659 if (deoptimize_on_undefined) {
3660 DeoptimizeIf(not_equal, env);
3661 } else {
3662 Label heap_number;
3663 __ j(equal, &heap_number, Label::kNear);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003664
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003665 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
3666 DeoptimizeIf(not_equal, env);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003667
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003668 // Convert undefined to NaN. Compute NaN as 0/0.
3669 __ xorps(result_reg, result_reg);
3670 __ divsd(result_reg, result_reg);
3671 __ jmp(&done, Label::kNear);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003672
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003673 __ bind(&heap_number);
3674 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003675 // Heap number to XMM conversion.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003676 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003677 if (deoptimize_on_minus_zero) {
3678 XMMRegister xmm_scratch = xmm0;
3679 __ xorps(xmm_scratch, xmm_scratch);
3680 __ ucomisd(xmm_scratch, result_reg);
3681 __ j(not_equal, &done, Label::kNear);
3682 __ movmskpd(kScratchRegister, result_reg);
3683 __ testq(kScratchRegister, Immediate(1));
3684 DeoptimizeIf(not_zero, env);
3685 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003686 __ jmp(&done, Label::kNear);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003687
3688 // Smi to XMM conversion
3689 __ bind(&load_smi);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003690 __ SmiToInteger32(kScratchRegister, input_reg);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003691 __ cvtlsi2sd(result_reg, kScratchRegister);
3692 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003693}
3694
3695
3696void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003697 Label done, heap_number;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003698 Register input_reg = ToRegister(instr->InputAt(0));
3699
3700 // Heap number map check.
3701 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
3702 Heap::kHeapNumberMapRootIndex);
3703
3704 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003705 __ j(equal, &heap_number, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003706 // Check for undefined. Undefined is converted to zero for truncating
3707 // conversions.
3708 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
3709 DeoptimizeIf(not_equal, instr->environment());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003710 __ Set(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003711 __ jmp(&done, Label::kNear);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003712
3713 __ bind(&heap_number);
3714
3715 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3716 __ cvttsd2siq(input_reg, xmm0);
3717 __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003718 __ cmpq(input_reg, kScratchRegister);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003719 DeoptimizeIf(equal, instr->environment());
3720 } else {
3721 // Deoptimize if we don't have a heap number.
3722 DeoptimizeIf(not_equal, instr->environment());
3723
3724 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
3725 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3726 __ cvttsd2si(input_reg, xmm0);
3727 __ cvtlsi2sd(xmm_temp, input_reg);
3728 __ ucomisd(xmm0, xmm_temp);
3729 DeoptimizeIf(not_equal, instr->environment());
3730 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3731 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3732 __ testl(input_reg, input_reg);
3733 __ j(not_zero, &done);
3734 __ movmskpd(input_reg, xmm0);
3735 __ andl(input_reg, Immediate(1));
3736 DeoptimizeIf(not_zero, instr->environment());
3737 }
3738 }
3739 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003740}
3741
3742
3743void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003744 class DeferredTaggedToI: public LDeferredCode {
3745 public:
3746 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3747 : LDeferredCode(codegen), instr_(instr) { }
3748 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3749 virtual LInstruction* instr() { return instr_; }
3750 private:
3751 LTaggedToI* instr_;
3752 };
3753
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003754 LOperand* input = instr->InputAt(0);
3755 ASSERT(input->IsRegister());
3756 ASSERT(input->Equals(instr->result()));
3757
3758 Register input_reg = ToRegister(input);
3759 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3760 __ JumpIfNotSmi(input_reg, deferred->entry());
3761 __ SmiToInteger32(input_reg, input_reg);
3762 __ bind(deferred->exit());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003763}
3764
3765
3766void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003767 LOperand* input = instr->InputAt(0);
3768 ASSERT(input->IsRegister());
3769 LOperand* result = instr->result();
3770 ASSERT(result->IsDoubleRegister());
3771
3772 Register input_reg = ToRegister(input);
3773 XMMRegister result_reg = ToDoubleRegister(result);
3774
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003775 EmitNumberUntagD(input_reg, result_reg,
3776 instr->hydrogen()->deoptimize_on_undefined(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003777 instr->hydrogen()->deoptimize_on_minus_zero(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003778 instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003779}
3780
3781
3782void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003783 LOperand* input = instr->InputAt(0);
3784 ASSERT(input->IsDoubleRegister());
3785 LOperand* result = instr->result();
3786 ASSERT(result->IsRegister());
3787
3788 XMMRegister input_reg = ToDoubleRegister(input);
3789 Register result_reg = ToRegister(result);
3790
3791 if (instr->truncating()) {
3792 // Performs a truncating conversion of a floating point number as used by
3793 // the JS bitwise operations.
3794 __ cvttsd2siq(result_reg, input_reg);
3795 __ movq(kScratchRegister, V8_INT64_C(0x8000000000000000), RelocInfo::NONE);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003796 __ cmpq(result_reg, kScratchRegister);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003797 DeoptimizeIf(equal, instr->environment());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003798 } else {
3799 __ cvttsd2si(result_reg, input_reg);
3800 __ cvtlsi2sd(xmm0, result_reg);
3801 __ ucomisd(xmm0, input_reg);
3802 DeoptimizeIf(not_equal, instr->environment());
3803 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3804 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003805 Label done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003806 // The integer converted back is equal to the original. We
3807 // only have to test if we got -0 as an input.
3808 __ testl(result_reg, result_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003809 __ j(not_zero, &done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003810 __ movmskpd(result_reg, input_reg);
3811 // Bit 0 contains the sign of the double in input_reg.
3812 // If input was positive, we are ok and return 0, otherwise
3813 // deoptimize.
3814 __ andl(result_reg, Immediate(1));
3815 DeoptimizeIf(not_zero, instr->environment());
3816 __ bind(&done);
3817 }
3818 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003819}
3820
3821
3822void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003823 LOperand* input = instr->InputAt(0);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003824 Condition cc = masm()->CheckSmi(ToRegister(input));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003825 DeoptimizeIf(NegateCondition(cc), instr->environment());
3826}
3827
3828
3829void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
3830 LOperand* input = instr->InputAt(0);
3831 Condition cc = masm()->CheckSmi(ToRegister(input));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003832 DeoptimizeIf(cc, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003833}
3834
3835
3836void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003837 Register input = ToRegister(instr->InputAt(0));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003838
3839 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
3840
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003841 if (instr->hydrogen()->is_interval_check()) {
3842 InstanceType first;
3843 InstanceType last;
3844 instr->hydrogen()->GetCheckInterval(&first, &last);
3845
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003846 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
3847 Immediate(static_cast<int8_t>(first)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003848
3849 // If there is only one type in the interval check for equality.
3850 if (first == last) {
3851 DeoptimizeIf(not_equal, instr->environment());
3852 } else {
3853 DeoptimizeIf(below, instr->environment());
3854 // Omit check for the last type.
3855 if (last != LAST_TYPE) {
3856 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
3857 Immediate(static_cast<int8_t>(last)));
3858 DeoptimizeIf(above, instr->environment());
3859 }
3860 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003861 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003862 uint8_t mask;
3863 uint8_t tag;
3864 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
3865
3866 if (IsPowerOf2(mask)) {
3867 ASSERT(tag == 0 || IsPowerOf2(tag));
3868 __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
3869 Immediate(mask));
3870 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
3871 } else {
3872 __ movzxbl(kScratchRegister,
3873 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
3874 __ andb(kScratchRegister, Immediate(mask));
3875 __ cmpb(kScratchRegister, Immediate(tag));
3876 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003877 }
3878 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003879}
3880
3881
3882void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003883 Register reg = ToRegister(instr->value());
3884 Handle<JSFunction> target = instr->hydrogen()->target();
3885 if (isolate()->heap()->InNewSpace(*target)) {
3886 Handle<JSGlobalPropertyCell> cell =
3887 isolate()->factory()->NewJSGlobalPropertyCell(target);
3888 __ movq(kScratchRegister, cell, RelocInfo::GLOBAL_PROPERTY_CELL);
3889 __ cmpq(reg, Operand(kScratchRegister, 0));
3890 } else {
3891 __ Cmp(reg, target);
3892 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003893 DeoptimizeIf(not_equal, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003894}
3895
3896
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003897void LCodeGen::DoCheckMapCommon(Register reg,
3898 Handle<Map> map,
3899 CompareMapMode mode,
3900 LEnvironment* env) {
3901 Label success;
3902 __ CompareMap(reg, map, &success, mode);
3903 DeoptimizeIf(not_equal, env);
3904 __ bind(&success);
3905}
3906
3907
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003908void LCodeGen::DoCheckMap(LCheckMap* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003909 LOperand* input = instr->InputAt(0);
3910 ASSERT(input->IsRegister());
3911 Register reg = ToRegister(input);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003912 Handle<Map> map = instr->hydrogen()->map();
3913 DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003914}
3915
3916
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003917void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
3918 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
3919 Register result_reg = ToRegister(instr->result());
3920 Register temp_reg = ToRegister(instr->TempAt(0));
3921 __ ClampDoubleToUint8(value_reg, xmm0, result_reg, temp_reg);
3922}
3923
3924
3925void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
3926 ASSERT(instr->unclamped()->Equals(instr->result()));
3927 Register value_reg = ToRegister(instr->result());
3928 __ ClampUint8(value_reg);
3929}
3930
3931
3932void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
3933 ASSERT(instr->unclamped()->Equals(instr->result()));
3934 Register input_reg = ToRegister(instr->unclamped());
3935 Register temp_reg = ToRegister(instr->TempAt(0));
3936 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->TempAt(1));
3937 Label is_smi, done, heap_number;
3938
3939 __ JumpIfSmi(input_reg, &is_smi);
3940
3941 // Check for heap number
3942 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
3943 factory()->heap_number_map());
3944 __ j(equal, &heap_number, Label::kNear);
3945
3946 // Check for undefined. Undefined is converted to zero for clamping
3947 // conversions.
3948 __ Cmp(input_reg, factory()->undefined_value());
3949 DeoptimizeIf(not_equal, instr->environment());
3950 __ movq(input_reg, Immediate(0));
3951 __ jmp(&done, Label::kNear);
3952
3953 // Heap number
3954 __ bind(&heap_number);
3955 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3956 __ ClampDoubleToUint8(xmm0, temp_xmm_reg, input_reg, temp_reg);
3957 __ jmp(&done, Label::kNear);
3958
3959 // smi
3960 __ bind(&is_smi);
3961 __ SmiToInteger32(input_reg, input_reg);
3962 __ ClampUint8(input_reg);
3963
3964 __ bind(&done);
3965}
3966
3967
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003968void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00003969 Register reg = ToRegister(instr->TempAt(0));
3970
3971 Handle<JSObject> holder = instr->holder();
3972 Handle<JSObject> current_prototype = instr->prototype();
3973
3974 // Load prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003975 __ LoadHeapObject(reg, current_prototype);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003976
3977 // Check prototype maps up to the holder.
3978 while (!current_prototype.is_identical_to(holder)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003979 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
3980 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003981 current_prototype =
3982 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
3983 // Load next prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003984 __ LoadHeapObject(reg, current_prototype);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003985 }
3986
3987 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003988 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
3989 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003990}
3991
3992
ulan@chromium.org967e2702012-02-28 09:49:15 +00003993void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
3994 class DeferredAllocateObject: public LDeferredCode {
3995 public:
3996 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
3997 : LDeferredCode(codegen), instr_(instr) { }
3998 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
3999 virtual LInstruction* instr() { return instr_; }
4000 private:
4001 LAllocateObject* instr_;
4002 };
4003
4004 DeferredAllocateObject* deferred = new DeferredAllocateObject(this, instr);
4005
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004006 Register result = ToRegister(instr->result());
4007 Register scratch = ToRegister(instr->TempAt(0));
4008 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
4009 Handle<Map> initial_map(constructor->initial_map());
4010 int instance_size = initial_map->instance_size();
4011 ASSERT(initial_map->pre_allocated_property_fields() +
4012 initial_map->unused_property_fields() -
4013 initial_map->inobject_properties() == 0);
4014
4015 // Allocate memory for the object. The initial map might change when
4016 // the constructor's prototype changes, but instance size and property
4017 // counts remain unchanged (if slack tracking finished).
4018 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
4019 __ AllocateInNewSpace(instance_size,
4020 result,
4021 no_reg,
4022 scratch,
4023 deferred->entry(),
4024 TAG_OBJECT);
4025
4026 // Load the initial map.
4027 Register map = scratch;
4028 __ LoadHeapObject(scratch, constructor);
4029 __ movq(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
4030
4031 if (FLAG_debug_code) {
4032 __ AbortIfSmi(map);
4033 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
4034 Immediate(instance_size >> kPointerSizeLog2));
4035 __ Assert(equal, "Unexpected instance size");
4036 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
4037 Immediate(initial_map->pre_allocated_property_fields()));
4038 __ Assert(equal, "Unexpected pre-allocated property fields count");
4039 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
4040 Immediate(initial_map->unused_property_fields()));
4041 __ Assert(equal, "Unexpected unused property fields count");
4042 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
4043 Immediate(initial_map->inobject_properties()));
4044 __ Assert(equal, "Unexpected in-object property fields count");
4045 }
4046
4047 // Initialize map and fields of the newly allocated object.
4048 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
4049 __ movq(FieldOperand(result, JSObject::kMapOffset), map);
4050 __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
4051 __ movq(FieldOperand(result, JSObject::kElementsOffset), scratch);
4052 __ movq(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
4053 if (initial_map->inobject_properties() != 0) {
4054 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
4055 for (int i = 0; i < initial_map->inobject_properties(); i++) {
4056 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
4057 __ movq(FieldOperand(result, property_offset), scratch);
4058 }
4059 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00004060
4061 __ bind(deferred->exit());
4062}
4063
4064
4065void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
4066 Register result = ToRegister(instr->result());
4067 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
4068
4069 // TODO(3095996): Get rid of this. For now, we need to make the
4070 // result register contain a valid pointer because it is already
4071 // contained in the register pointer map.
4072 __ Set(result, 0);
4073
4074 PushSafepointRegistersScope scope(this);
4075 __ PushHeapObject(constructor);
4076 CallRuntimeFromDeferred(Runtime::kNewObject, 1, instr);
4077 __ StoreToSafepointRegisterSlot(result, rax);
4078}
4079
4080
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004081void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004082 Heap* heap = isolate()->heap();
4083 ElementsKind boilerplate_elements_kind =
4084 instr->hydrogen()->boilerplate_elements_kind();
4085
4086 // Deopt if the array literal boilerplate ElementsKind is of a type different
4087 // than the expected one. The check isn't necessary if the boilerplate has
4088 // already been converted to FAST_ELEMENTS.
4089 if (boilerplate_elements_kind != FAST_ELEMENTS) {
4090 __ LoadHeapObject(rax, instr->hydrogen()->boilerplate_object());
4091 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
4092 // Load the map's "bit field 2".
4093 __ movb(rbx, FieldOperand(rbx, Map::kBitField2Offset));
4094 // Retrieve elements_kind from bit field 2.
4095 __ and_(rbx, Immediate(Map::kElementsKindMask));
4096 __ cmpb(rbx, Immediate(boilerplate_elements_kind <<
4097 Map::kElementsKindShift));
4098 DeoptimizeIf(not_equal, instr->environment());
4099 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004100
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004101 // Set up the parameters to the stub/runtime call.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004102 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
4103 __ push(FieldOperand(rax, JSFunction::kLiteralsOffset));
4104 __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004105 // Boilerplate already exists, constant elements are never accessed.
4106 // Pass an empty fixed array.
4107 __ Push(Handle<FixedArray>(heap->empty_fixed_array()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004108
4109 // Pick the right runtime function or stub to call.
4110 int length = instr->hydrogen()->length();
4111 if (instr->hydrogen()->IsCopyOnWrite()) {
4112 ASSERT(instr->hydrogen()->depth() == 1);
4113 FastCloneShallowArrayStub::Mode mode =
4114 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
4115 FastCloneShallowArrayStub stub(mode, length);
4116 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4117 } else if (instr->hydrogen()->depth() > 1) {
4118 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
4119 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
4120 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
4121 } else {
4122 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004123 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
4124 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
4125 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004126 FastCloneShallowArrayStub stub(mode, length);
4127 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4128 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004129}
4130
4131
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004132void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
4133 Register result,
4134 Register source,
4135 int* offset) {
4136 ASSERT(!source.is(rcx));
4137 ASSERT(!result.is(rcx));
4138
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004139 // Only elements backing stores for non-COW arrays need to be copied.
4140 Handle<FixedArrayBase> elements(object->elements());
4141 bool has_elements = elements->length() > 0 &&
4142 elements->map() != isolate()->heap()->fixed_cow_array_map();
4143
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004144 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004145 // this object and its backing store.
4146 int object_offset = *offset;
4147 int object_size = object->map()->instance_size();
4148 int elements_offset = *offset + object_size;
4149 int elements_size = has_elements ? elements->Size() : 0;
4150 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004151
4152 // Copy object header.
4153 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004154 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004155 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004156 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004157 if (has_elements && i == JSObject::kElementsOffset) {
4158 __ lea(rcx, Operand(result, elements_offset));
4159 } else {
4160 __ movq(rcx, FieldOperand(source, i));
4161 }
4162 __ movq(FieldOperand(result, object_offset + i), rcx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004163 }
4164
4165 // Copy in-object properties.
4166 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004167 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004168 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
4169 if (value->IsJSObject()) {
4170 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4171 __ lea(rcx, Operand(result, *offset));
4172 __ movq(FieldOperand(result, total_offset), rcx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004173 __ LoadHeapObject(source, value_object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004174 EmitDeepCopy(value_object, result, source, offset);
4175 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004176 __ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004177 __ movq(FieldOperand(result, total_offset), rcx);
4178 } else {
4179 __ movq(rcx, value, RelocInfo::NONE);
4180 __ movq(FieldOperand(result, total_offset), rcx);
4181 }
4182 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004183
4184 // Copy elements backing store header.
4185 ASSERT(!has_elements || elements->IsFixedArray());
4186 if (has_elements) {
4187 __ LoadHeapObject(source, elements);
4188 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
4189 __ movq(rcx, FieldOperand(source, i));
4190 __ movq(FieldOperand(result, elements_offset + i), rcx);
4191 }
4192 }
4193
4194 // Copy elements backing store content.
4195 ASSERT(!has_elements || elements->IsFixedArray());
4196 int elements_length = has_elements ? elements->length() : 0;
4197 for (int i = 0; i < elements_length; i++) {
4198 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
4199 Handle<Object> value = JSObject::GetElement(object, i);
4200 if (value->IsJSObject()) {
4201 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4202 __ lea(rcx, Operand(result, *offset));
4203 __ movq(FieldOperand(result, total_offset), rcx);
4204 __ LoadHeapObject(source, value_object);
4205 EmitDeepCopy(value_object, result, source, offset);
4206 } else if (value->IsHeapObject()) {
4207 __ LoadHeapObject(rcx, Handle<HeapObject>::cast(value));
4208 __ movq(FieldOperand(result, total_offset), rcx);
4209 } else {
4210 __ movq(rcx, value, RelocInfo::NONE);
4211 __ movq(FieldOperand(result, total_offset), rcx);
4212 }
4213 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004214}
4215
4216
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004217void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004218 int size = instr->hydrogen()->total_size();
4219
4220 // Allocate all objects that are part of the literal in one big
4221 // allocation. This avoids multiple limit checks.
4222 Label allocated, runtime_allocate;
4223 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
4224 __ jmp(&allocated);
4225
4226 __ bind(&runtime_allocate);
4227 __ Push(Smi::FromInt(size));
4228 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
4229
4230 __ bind(&allocated);
4231 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004232 __ LoadHeapObject(rbx, instr->hydrogen()->boilerplate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004233 EmitDeepCopy(instr->hydrogen()->boilerplate(), rax, rbx, &offset);
4234 ASSERT_EQ(size, offset);
4235}
4236
4237
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004238void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004239 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004240 Handle<FixedArray> constant_properties =
4241 instr->hydrogen()->constant_properties();
4242
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004243 // Set up the parameters to the stub/runtime call.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004244 __ PushHeapObject(literals);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004245 __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004246 __ Push(constant_properties);
4247 int flags = instr->hydrogen()->fast_elements()
4248 ? ObjectLiteral::kFastElements
4249 : ObjectLiteral::kNoFlags;
4250 flags |= instr->hydrogen()->has_function()
4251 ? ObjectLiteral::kHasFunction
4252 : ObjectLiteral::kNoFlags;
4253 __ Push(Smi::FromInt(flags));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004254
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004255 // Pick the right runtime function or stub to call.
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004256 int properties_count = constant_properties->length() / 2;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004257 if (instr->hydrogen()->depth() > 1) {
4258 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004259 } else if (flags != ObjectLiteral::kFastElements ||
4260 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004261 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004262 } else {
4263 FastCloneShallowObjectStub stub(properties_count);
4264 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004265 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004266}
4267
4268
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004269void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
4270 ASSERT(ToRegister(instr->InputAt(0)).is(rax));
4271 __ push(rax);
4272 CallRuntime(Runtime::kToFastProperties, 1, instr);
4273}
4274
4275
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004276void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004277 Label materialized;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004278 // Registers will be used as follows:
4279 // rdi = JS function.
4280 // rcx = literals array.
4281 // rbx = regexp literal.
4282 // rax = regexp literal clone.
4283 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
4284 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
4285 int literal_offset = FixedArray::kHeaderSize +
4286 instr->hydrogen()->literal_index() * kPointerSize;
4287 __ movq(rbx, FieldOperand(rcx, literal_offset));
4288 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004289 __ j(not_equal, &materialized, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004290
4291 // Create regexp literal using runtime function
4292 // Result will be in rax.
4293 __ push(rcx);
4294 __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
4295 __ Push(instr->hydrogen()->pattern());
4296 __ Push(instr->hydrogen()->flags());
4297 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
4298 __ movq(rbx, rax);
4299
4300 __ bind(&materialized);
4301 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
4302 Label allocated, runtime_allocate;
4303 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
4304 __ jmp(&allocated);
4305
4306 __ bind(&runtime_allocate);
4307 __ push(rbx);
4308 __ Push(Smi::FromInt(size));
4309 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
4310 __ pop(rbx);
4311
4312 __ bind(&allocated);
4313 // Copy the content into the newly allocated memory.
4314 // (Unroll copy loop once for better throughput).
4315 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
4316 __ movq(rdx, FieldOperand(rbx, i));
4317 __ movq(rcx, FieldOperand(rbx, i + kPointerSize));
4318 __ movq(FieldOperand(rax, i), rdx);
4319 __ movq(FieldOperand(rax, i + kPointerSize), rcx);
4320 }
4321 if ((size % (2 * kPointerSize)) != 0) {
4322 __ movq(rdx, FieldOperand(rbx, size - kPointerSize));
4323 __ movq(FieldOperand(rax, size - kPointerSize), rdx);
4324 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004325}
4326
4327
4328void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004329 // Use the fast case closure allocation code that allocates in new
4330 // space for nested functions that don't need literals cloning.
4331 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
4332 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004333 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004334 FastNewClosureStub stub(shared_info->language_mode());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004335 __ Push(shared_info);
4336 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4337 } else {
4338 __ push(rsi);
4339 __ Push(shared_info);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004340 __ PushRoot(pretenure ?
4341 Heap::kTrueValueRootIndex :
4342 Heap::kFalseValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004343 CallRuntime(Runtime::kNewClosure, 3, instr);
4344 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004345}
4346
4347
4348void LCodeGen::DoTypeof(LTypeof* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004349 LOperand* input = instr->InputAt(0);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004350 EmitPushTaggedOperand(input);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004351 CallRuntime(Runtime::kTypeof, 1, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004352}
4353
4354
danno@chromium.org160a7b02011-04-18 15:51:38 +00004355void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
4356 ASSERT(!operand->IsDoubleRegister());
4357 if (operand->IsConstantOperand()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004358 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
4359 if (object->IsSmi()) {
4360 __ Push(Handle<Smi>::cast(object));
4361 } else {
4362 __ PushHeapObject(Handle<HeapObject>::cast(object));
4363 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004364 } else if (operand->IsRegister()) {
4365 __ push(ToRegister(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004366 } else {
danno@chromium.org160a7b02011-04-18 15:51:38 +00004367 __ push(ToOperand(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004368 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004369}
4370
4371
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004372void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004373 Register input = ToRegister(instr->InputAt(0));
4374 int true_block = chunk_->LookupDestination(instr->true_block_id());
4375 int false_block = chunk_->LookupDestination(instr->false_block_id());
4376 Label* true_label = chunk_->GetAssemblyLabel(true_block);
4377 Label* false_label = chunk_->GetAssemblyLabel(false_block);
4378
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004379 Condition final_branch_condition =
4380 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
4381 if (final_branch_condition != no_condition) {
4382 EmitBranch(true_block, false_block, final_branch_condition);
4383 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004384}
4385
4386
4387Condition LCodeGen::EmitTypeofIs(Label* true_label,
4388 Label* false_label,
4389 Register input,
4390 Handle<String> type_name) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004391 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 if (type_name->Equals(heap()->number_symbol())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004393 __ JumpIfSmi(input, true_label);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004394 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
4395 Heap::kHeapNumberMapRootIndex);
4396
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004397 final_branch_condition = equal;
4398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004399 } else if (type_name->Equals(heap()->string_symbol())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004400 __ JumpIfSmi(input, false_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004401 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
4402 __ j(above_equal, false_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004403 __ testb(FieldOperand(input, Map::kBitFieldOffset),
4404 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004405 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004407 } else if (type_name->Equals(heap()->boolean_symbol())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004408 __ CompareRoot(input, Heap::kTrueValueRootIndex);
4409 __ j(equal, true_label);
4410 __ CompareRoot(input, Heap::kFalseValueRootIndex);
4411 final_branch_condition = equal;
4412
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004413 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
4414 __ CompareRoot(input, Heap::kNullValueRootIndex);
4415 final_branch_condition = equal;
4416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004417 } else if (type_name->Equals(heap()->undefined_symbol())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004418 __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
4419 __ j(equal, true_label);
4420 __ JumpIfSmi(input, false_label);
4421 // Check for undetectable objects => true.
4422 __ movq(input, FieldOperand(input, HeapObject::kMapOffset));
4423 __ testb(FieldOperand(input, Map::kBitFieldOffset),
4424 Immediate(1 << Map::kIsUndetectable));
4425 final_branch_condition = not_zero;
4426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004428 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004429 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004430 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
4431 __ j(equal, true_label);
4432 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
4433 final_branch_condition = equal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004435 } else if (type_name->Equals(heap()->object_symbol())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004436 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004437 if (!FLAG_harmony_typeof) {
4438 __ CompareRoot(input, Heap::kNullValueRootIndex);
4439 __ j(equal, true_label);
4440 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004441 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004442 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004443 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4444 __ j(above, false_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004445 // Check for undetectable objects => false.
4446 __ testb(FieldOperand(input, Map::kBitFieldOffset),
4447 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004448 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004449
4450 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004451 __ jmp(false_label);
4452 }
4453
4454 return final_branch_condition;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004455}
4456
4457
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004458void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
4459 Register temp = ToRegister(instr->TempAt(0));
4460 int true_block = chunk_->LookupDestination(instr->true_block_id());
4461 int false_block = chunk_->LookupDestination(instr->false_block_id());
4462
4463 EmitIsConstructCall(temp);
4464 EmitBranch(true_block, false_block, equal);
4465}
4466
4467
4468void LCodeGen::EmitIsConstructCall(Register temp) {
4469 // Get the frame pointer for the calling frame.
4470 __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
4471
4472 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004473 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004474 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset),
4475 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004476 __ j(not_equal, &check_frame_marker, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004477 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset));
4478
4479 // Check the marker in the calling frame.
4480 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004481 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
4482 Smi::FromInt(StackFrame::CONSTRUCT));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004483}
4484
4485
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004486void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004487 // Ensure that we have enough space after the previous lazy-bailout
4488 // instruction for patching the code here.
4489 int current_pc = masm()->pc_offset();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004490 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
4491 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
4492 __ Nop(padding_size);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004493 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004494}
4495
4496
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004497void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004498 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
4499 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004500 ASSERT(instr->HasEnvironment());
4501 LEnvironment* env = instr->environment();
4502 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4503 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004504}
4505
4506
4507void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
4508 DeoptimizeIf(no_condition, instr->environment());
4509}
4510
4511
4512void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004513 LOperand* obj = instr->object();
4514 LOperand* key = instr->key();
danno@chromium.org160a7b02011-04-18 15:51:38 +00004515 EmitPushTaggedOperand(obj);
4516 EmitPushTaggedOperand(key);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004517 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4518 LPointerMap* pointers = instr->pointer_map();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004519 RecordPosition(pointers->position());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004520 // Create safepoint generator that will also ensure enough space in the
4521 // reloc info for patching in deoptimization (since this is invoking a
4522 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004523 SafepointGenerator safepoint_generator(
4524 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004525 __ Push(Smi::FromInt(strict_mode_flag()));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004526 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004527}
4528
4529
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004530void LCodeGen::DoIn(LIn* instr) {
4531 LOperand* obj = instr->object();
4532 LOperand* key = instr->key();
4533 EmitPushTaggedOperand(key);
4534 EmitPushTaggedOperand(obj);
4535 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4536 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004537 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004538 SafepointGenerator safepoint_generator(
4539 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004540 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004541}
4542
4543
ager@chromium.org04921a82011-06-27 13:21:41 +00004544void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004545 PushSafepointRegistersScope scope(this);
4546 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4547 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
4548 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0);
4549 ASSERT(instr->HasEnvironment());
4550 LEnvironment* env = instr->environment();
4551 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00004552}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004553
ager@chromium.org04921a82011-06-27 13:21:41 +00004554
4555void LCodeGen::DoStackCheck(LStackCheck* instr) {
4556 class DeferredStackCheck: public LDeferredCode {
4557 public:
4558 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
4559 : LDeferredCode(codegen), instr_(instr) { }
4560 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004561 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00004562 private:
4563 LStackCheck* instr_;
4564 };
4565
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004566 ASSERT(instr->HasEnvironment());
4567 LEnvironment* env = instr->environment();
4568 // There is no LLazyBailout instruction for stack-checks. We have to
4569 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00004570 if (instr->hydrogen()->is_function_entry()) {
4571 // Perform stack overflow check.
4572 Label done;
4573 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
4574 __ j(above_equal, &done, Label::kNear);
4575 StackCheckStub stub;
4576 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004577 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
4578 last_lazy_deopt_pc_ = masm()->pc_offset();
ager@chromium.org04921a82011-06-27 13:21:41 +00004579 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004580 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4581 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00004582 } else {
4583 ASSERT(instr->hydrogen()->is_backwards_branch());
4584 // Perform stack overflow check if this goto needs it before jumping.
4585 DeferredStackCheck* deferred_stack_check =
4586 new DeferredStackCheck(this, instr);
4587 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
4588 __ j(below, deferred_stack_check->entry());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004589 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
4590 last_lazy_deopt_pc_ = masm()->pc_offset();
ager@chromium.org04921a82011-06-27 13:21:41 +00004591 __ bind(instr->done_label());
4592 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004593 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4594 // Don't record a deoptimization index for the safepoint here.
4595 // This will be done explicitly when emitting call and the safepoint in
4596 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00004597 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004598}
4599
4600
4601void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004602 // This is a pseudo-instruction that ensures that the environment here is
4603 // properly registered for deoptimization and records the assembler's PC
4604 // offset.
4605 LEnvironment* environment = instr->environment();
4606 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
4607 instr->SpilledDoubleRegisterArray());
4608
4609 // If the environment were already registered, we would have no way of
4610 // backpatching it with the spill slot operands.
4611 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004612 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004613 ASSERT(osr_pc_offset_ == -1);
4614 osr_pc_offset_ = masm()->pc_offset();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004615}
4616
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004617
4618void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
4619 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4620 DeoptimizeIf(equal, instr->environment());
4621
4622 Register null_value = rdi;
4623 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
4624 __ cmpq(rax, null_value);
4625 DeoptimizeIf(equal, instr->environment());
4626
4627 Condition cc = masm()->CheckSmi(rax);
4628 DeoptimizeIf(cc, instr->environment());
4629
4630 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
4631 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
4632 DeoptimizeIf(below_equal, instr->environment());
4633
4634 Label use_cache, call_runtime;
4635 __ CheckEnumCache(null_value, &call_runtime);
4636
4637 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
4638 __ jmp(&use_cache, Label::kNear);
4639
4640 // Get the set of properties to enumerate.
4641 __ bind(&call_runtime);
4642 __ push(rax);
4643 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
4644
4645 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
4646 Heap::kMetaMapRootIndex);
4647 DeoptimizeIf(not_equal, instr->environment());
4648 __ bind(&use_cache);
4649}
4650
4651
4652void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
4653 Register map = ToRegister(instr->map());
4654 Register result = ToRegister(instr->result());
4655 __ LoadInstanceDescriptors(map, result);
4656 __ movq(result,
4657 FieldOperand(result, DescriptorArray::kEnumerationIndexOffset));
4658 __ movq(result,
4659 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
4660 Condition cc = masm()->CheckSmi(result);
4661 DeoptimizeIf(NegateCondition(cc), instr->environment());
4662}
4663
4664
4665void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
4666 Register object = ToRegister(instr->value());
4667 __ cmpq(ToRegister(instr->map()),
4668 FieldOperand(object, HeapObject::kMapOffset));
4669 DeoptimizeIf(not_equal, instr->environment());
4670}
4671
4672
4673void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
4674 Register object = ToRegister(instr->object());
4675 Register index = ToRegister(instr->index());
4676
4677 Label out_of_object, done;
4678 __ SmiToInteger32(index, index);
4679 __ cmpl(index, Immediate(0));
4680 __ j(less, &out_of_object);
4681 __ movq(object, FieldOperand(object,
4682 index,
4683 times_pointer_size,
4684 JSObject::kHeaderSize));
4685 __ jmp(&done, Label::kNear);
4686
4687 __ bind(&out_of_object);
4688 __ movq(object, FieldOperand(object, JSObject::kPropertiesOffset));
4689 __ negl(index);
4690 // Index is now equal to out of object property index plus 1.
4691 __ movq(object, FieldOperand(object,
4692 index,
4693 times_pointer_size,
4694 FixedArray::kHeaderSize - kPointerSize));
4695 __ bind(&done);
4696}
4697
4698
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004699#undef __
4700
4701} } // namespace v8::internal
4702
4703#endif // V8_TARGET_ARCH_X64