blob: a46f8d92bf7bb074fd5a090aa624c8daf13524ca [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_IA32
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000034#include "cpu-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "debug.h"
machenbach@chromium.orged29eb22013-10-31 13:30:00 +000036#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "runtime.h"
38#include "serialize.h"
39
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000043// -------------------------------------------------------------------------
44// MacroAssembler implementation.
45
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000046MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
47 : Assembler(arg_isolate, buffer, size),
kasper.lund7276f142008-07-30 08:49:36 +000048 generating_stub_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000049 allow_stub_calls_(true),
50 has_frame_(false) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000051 if (isolate() != NULL) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000052 // TODO(titzer): should we just use a null handle here instead?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000053 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
54 isolate());
55 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056}
57
58
machenbach@chromium.org935a7792013-11-12 09:05:18 +000059void MacroAssembler::Load(Register dst, const Operand& src, Representation r) {
60 ASSERT(!r.IsDouble());
61 if (r.IsInteger8()) {
62 movsx_b(dst, src);
63 } else if (r.IsUInteger8()) {
64 movzx_b(dst, src);
65 } else if (r.IsInteger16()) {
66 movsx_w(dst, src);
67 } else if (r.IsUInteger16()) {
68 movzx_w(dst, src);
69 } else {
70 mov(dst, src);
71 }
72}
73
74
75void MacroAssembler::Store(Register src, const Operand& dst, Representation r) {
76 ASSERT(!r.IsDouble());
77 if (r.IsInteger8() || r.IsUInteger8()) {
78 mov_b(dst, src);
79 } else if (r.IsInteger16() || r.IsUInteger16()) {
80 mov_w(dst, src);
81 } else {
82 mov(dst, src);
83 }
84}
85
86
danno@chromium.org59400602013-08-13 17:09:37 +000087void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
88 if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) {
89 Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
90 mov(destination, value);
91 return;
92 }
93 ExternalReference roots_array_start =
94 ExternalReference::roots_array_start(isolate());
95 mov(destination, Immediate(index));
96 mov(destination, Operand::StaticArray(destination,
97 times_pointer_size,
98 roots_array_start));
99}
100
101
102void MacroAssembler::StoreRoot(Register source,
103 Register scratch,
104 Heap::RootListIndex index) {
105 ASSERT(Heap::RootCanBeWrittenAfterInitialization(index));
106 ExternalReference roots_array_start =
107 ExternalReference::roots_array_start(isolate());
108 mov(scratch, Immediate(index));
109 mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
110 source);
111}
112
113
114void MacroAssembler::CompareRoot(Register with,
115 Register scratch,
116 Heap::RootListIndex index) {
117 ExternalReference roots_array_start =
118 ExternalReference::roots_array_start(isolate());
119 mov(scratch, Immediate(index));
120 cmp(with, Operand::StaticArray(scratch,
121 times_pointer_size,
122 roots_array_start));
123}
124
125
126void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
127 ASSERT(isolate()->heap()->RootCanBeTreatedAsConstant(index));
128 Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
129 cmp(with, value);
130}
131
132
133void MacroAssembler::CompareRoot(const Operand& with,
134 Heap::RootListIndex index) {
135 ASSERT(isolate()->heap()->RootCanBeTreatedAsConstant(index));
136 Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
137 cmp(with, value);
138}
139
140
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000141void MacroAssembler::InNewSpace(
142 Register object,
143 Register scratch,
144 Condition cc,
145 Label* condition_met,
146 Label::Distance condition_met_distance) {
147 ASSERT(cc == equal || cc == not_equal);
148 if (scratch.is(object)) {
149 and_(scratch, Immediate(~Page::kPageAlignmentMask));
150 } else {
151 mov(scratch, Immediate(~Page::kPageAlignmentMask));
152 and_(scratch, object);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000153 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000154 // Check that we can use a test_b.
155 ASSERT(MemoryChunk::IN_FROM_SPACE < 8);
156 ASSERT(MemoryChunk::IN_TO_SPACE < 8);
157 int mask = (1 << MemoryChunk::IN_FROM_SPACE)
158 | (1 << MemoryChunk::IN_TO_SPACE);
159 // If non-zero, the page belongs to new-space.
160 test_b(Operand(scratch, MemoryChunk::kFlagsOffset),
161 static_cast<uint8_t>(mask));
162 j(cc, condition_met, condition_met_distance);
163}
ager@chromium.orgac091b72010-05-05 07:34:42 +0000164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000166void MacroAssembler::RememberedSetHelper(
167 Register object, // Only used for debug checks.
168 Register addr,
169 Register scratch,
170 SaveFPRegsMode save_fp,
171 MacroAssembler::RememberedSetFinalAction and_then) {
172 Label done;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000173 if (emit_debug_code()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000174 Label ok;
175 JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear);
176 int3();
177 bind(&ok);
178 }
179 // Load store buffer top.
180 ExternalReference store_buffer =
181 ExternalReference::store_buffer_top(isolate());
182 mov(scratch, Operand::StaticVariable(store_buffer));
183 // Store pointer to buffer.
184 mov(Operand(scratch, 0), addr);
185 // Increment buffer top.
186 add(scratch, Immediate(kPointerSize));
187 // Write back new top of buffer.
188 mov(Operand::StaticVariable(store_buffer), scratch);
189 // Call stub on end of buffer.
190 // Check for end of buffer.
191 test(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit));
192 if (and_then == kReturnAtEnd) {
193 Label buffer_overflowed;
194 j(not_equal, &buffer_overflowed, Label::kNear);
195 ret(0);
196 bind(&buffer_overflowed);
197 } else {
198 ASSERT(and_then == kFallThroughAtEnd);
199 j(equal, &done, Label::kNear);
200 }
201 StoreBufferOverflowStub store_buffer_overflow =
202 StoreBufferOverflowStub(save_fp);
203 CallStub(&store_buffer_overflow);
204 if (and_then == kReturnAtEnd) {
205 ret(0);
206 } else {
207 ASSERT(and_then == kFallThroughAtEnd);
208 bind(&done);
209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210}
211
212
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000213void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
214 XMMRegister scratch_reg,
215 Register result_reg) {
216 Label done;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000217 Label conv_failure;
218 pxor(scratch_reg, scratch_reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000219 cvtsd2si(result_reg, input_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000220 test(result_reg, Immediate(0xFFFFFF00));
221 j(zero, &done, Label::kNear);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000222 cmp(result_reg, Immediate(0x80000000));
223 j(equal, &conv_failure, Label::kNear);
224 mov(result_reg, Immediate(0));
225 setcc(above, result_reg);
226 sub(result_reg, Immediate(1));
227 and_(result_reg, Immediate(255));
228 jmp(&done, Label::kNear);
229 bind(&conv_failure);
230 Set(result_reg, Immediate(0));
231 ucomisd(input_reg, scratch_reg);
232 j(below, &done, Label::kNear);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000233 Set(result_reg, Immediate(255));
234 bind(&done);
235}
236
237
238void MacroAssembler::ClampUint8(Register reg) {
239 Label done;
240 test(reg, Immediate(0xFFFFFF00));
241 j(zero, &done, Label::kNear);
242 setcc(negative, reg); // 1 if negative, 0 if positive.
243 dec_b(reg); // 0 if negative, 255 if positive.
244 bind(&done);
245}
246
247
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000248void MacroAssembler::SlowTruncateToI(Register result_reg,
249 Register input_reg,
250 int offset) {
251 DoubleToIStub stub(input_reg, result_reg, offset, true);
252 call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
253}
254
255
256void MacroAssembler::TruncateDoubleToI(Register result_reg,
257 XMMRegister input_reg) {
258 Label done;
259 cvttsd2si(result_reg, Operand(input_reg));
260 cmp(result_reg, 0x80000000u);
261 j(not_equal, &done, Label::kNear);
262
263 sub(esp, Immediate(kDoubleSize));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000264 movsd(MemOperand(esp, 0), input_reg);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000265 SlowTruncateToI(result_reg, esp, 0);
266 add(esp, Immediate(kDoubleSize));
267 bind(&done);
268}
269
270
271void MacroAssembler::TruncateX87TOSToI(Register result_reg) {
272 sub(esp, Immediate(kDoubleSize));
273 fst_d(MemOperand(esp, 0));
274 SlowTruncateToI(result_reg, esp, 0);
275 add(esp, Immediate(kDoubleSize));
276}
277
278
279void MacroAssembler::X87TOSToI(Register result_reg,
280 MinusZeroMode minus_zero_mode,
281 Label* conversion_failed,
282 Label::Distance dst) {
283 Label done;
284 sub(esp, Immediate(kPointerSize));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000285 fld(0);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000286 fist_s(MemOperand(esp, 0));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000287 fild_s(MemOperand(esp, 0));
288 pop(result_reg);
289 FCmp();
290 j(not_equal, conversion_failed, dst);
291 j(parity_even, conversion_failed, dst);
292 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
293 test(result_reg, Operand(result_reg));
294 j(not_zero, &done, Label::kNear);
295 // To check for minus zero, we load the value again as float, and check
296 // if that is still 0.
297 sub(esp, Immediate(kPointerSize));
298 fst_s(MemOperand(esp, 0));
299 pop(result_reg);
300 test(result_reg, Operand(result_reg));
301 j(not_zero, conversion_failed, dst);
302 }
303 bind(&done);
304}
305
306
307void MacroAssembler::DoubleToI(Register result_reg,
308 XMMRegister input_reg,
309 XMMRegister scratch,
310 MinusZeroMode minus_zero_mode,
311 Label* conversion_failed,
312 Label::Distance dst) {
313 ASSERT(!input_reg.is(scratch));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000314 cvttsd2si(result_reg, Operand(input_reg));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000315 Cvtsi2sd(scratch, Operand(result_reg));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000316 ucomisd(scratch, input_reg);
317 j(not_equal, conversion_failed, dst);
318 j(parity_even, conversion_failed, dst); // NaN.
319 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000320 Label done;
321 // The integer converted back is equal to the original. We
322 // only have to test if we got -0 as an input.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000323 test(result_reg, Operand(result_reg));
324 j(not_zero, &done, Label::kNear);
325 movmskpd(result_reg, input_reg);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000326 // Bit 0 contains the sign of the double in input_reg.
327 // If input was positive, we are ok and return 0, otherwise
328 // jump to conversion_failed.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000329 and_(result_reg, 1);
330 j(not_zero, conversion_failed, dst);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000331 bind(&done);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000332 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000333}
334
335
336void MacroAssembler::TruncateHeapNumberToI(Register result_reg,
337 Register input_reg) {
338 Label done, slow_case;
339
340 if (CpuFeatures::IsSupported(SSE3)) {
341 CpuFeatureScope scope(this, SSE3);
342 Label convert;
343 // Use more powerful conversion when sse3 is available.
344 // Load x87 register with heap number.
345 fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
346 // Get exponent alone and check for too-big exponent.
347 mov(result_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
348 and_(result_reg, HeapNumber::kExponentMask);
349 const uint32_t kTooBigExponent =
350 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
351 cmp(Operand(result_reg), Immediate(kTooBigExponent));
352 j(greater_equal, &slow_case, Label::kNear);
353
354 // Reserve space for 64 bit answer.
355 sub(Operand(esp), Immediate(kDoubleSize));
356 // Do conversion, which cannot fail because we checked the exponent.
357 fisttp_d(Operand(esp, 0));
358 mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
359 add(Operand(esp), Immediate(kDoubleSize));
360 jmp(&done, Label::kNear);
361
362 // Slow case.
363 bind(&slow_case);
364 if (input_reg.is(result_reg)) {
365 // Input is clobbered. Restore number from fpu stack
366 sub(Operand(esp), Immediate(kDoubleSize));
367 fstp_d(Operand(esp, 0));
368 SlowTruncateToI(result_reg, esp, 0);
369 add(esp, Immediate(kDoubleSize));
370 } else {
371 fstp(0);
372 SlowTruncateToI(result_reg, input_reg);
373 }
374 } else if (CpuFeatures::IsSupported(SSE2)) {
375 CpuFeatureScope scope(this, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000376 movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000377 cvttsd2si(result_reg, Operand(xmm0));
378 cmp(result_reg, 0x80000000u);
379 j(not_equal, &done, Label::kNear);
380 // Check if the input was 0x8000000 (kMinInt).
381 // If no, then we got an overflow and we deoptimize.
382 ExternalReference min_int = ExternalReference::address_of_min_int();
383 ucomisd(xmm0, Operand::StaticVariable(min_int));
384 j(not_equal, &slow_case, Label::kNear);
385 j(parity_even, &slow_case, Label::kNear); // NaN.
386 jmp(&done, Label::kNear);
387
388 // Slow case.
389 bind(&slow_case);
390 if (input_reg.is(result_reg)) {
391 // Input is clobbered. Restore number from double scratch.
392 sub(esp, Immediate(kDoubleSize));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000393 movsd(MemOperand(esp, 0), xmm0);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000394 SlowTruncateToI(result_reg, esp, 0);
395 add(esp, Immediate(kDoubleSize));
396 } else {
397 SlowTruncateToI(result_reg, input_reg);
398 }
399 } else {
400 SlowTruncateToI(result_reg, input_reg);
401 }
402 bind(&done);
403}
404
405
406void MacroAssembler::TaggedToI(Register result_reg,
407 Register input_reg,
408 XMMRegister temp,
409 MinusZeroMode minus_zero_mode,
410 Label* lost_precision) {
411 Label done;
412 ASSERT(!temp.is(xmm0));
413
414 cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
415 isolate()->factory()->heap_number_map());
416 j(not_equal, lost_precision, Label::kNear);
417
418 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
419 ASSERT(!temp.is(no_xmm_reg));
420 CpuFeatureScope scope(this, SSE2);
421
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000422 movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000423 cvttsd2si(result_reg, Operand(xmm0));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000424 Cvtsi2sd(temp, Operand(result_reg));
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000425 ucomisd(xmm0, temp);
426 RecordComment("Deferred TaggedToI: lost precision");
427 j(not_equal, lost_precision, Label::kNear);
428 RecordComment("Deferred TaggedToI: NaN");
429 j(parity_even, lost_precision, Label::kNear);
430 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
431 test(result_reg, Operand(result_reg));
432 j(not_zero, &done, Label::kNear);
433 movmskpd(result_reg, xmm0);
434 and_(result_reg, 1);
435 RecordComment("Deferred TaggedToI: minus zero");
436 j(not_zero, lost_precision, Label::kNear);
437 }
438 } else {
439 // TODO(olivf) Converting a number on the fpu is actually quite slow. We
440 // should first try a fast conversion and then bailout to this slow case.
441 Label lost_precision_pop, zero_check;
442 Label* lost_precision_int = (minus_zero_mode == FAIL_ON_MINUS_ZERO)
443 ? &lost_precision_pop : lost_precision;
444 sub(esp, Immediate(kPointerSize));
445 fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
446 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) fld(0);
447 fist_s(MemOperand(esp, 0));
448 fild_s(MemOperand(esp, 0));
449 FCmp();
450 pop(result_reg);
451 j(not_equal, lost_precision_int, Label::kNear);
452 j(parity_even, lost_precision_int, Label::kNear); // NaN.
453 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
454 test(result_reg, Operand(result_reg));
455 j(zero, &zero_check, Label::kNear);
456 fstp(0);
457 jmp(&done, Label::kNear);
458 bind(&zero_check);
459 // To check for minus zero, we load the value again as float, and check
460 // if that is still 0.
461 sub(esp, Immediate(kPointerSize));
462 fstp_s(Operand(esp, 0));
463 pop(result_reg);
464 test(result_reg, Operand(result_reg));
465 j(zero, &done, Label::kNear);
466 jmp(lost_precision, Label::kNear);
467
468 bind(&lost_precision_pop);
469 fstp(0);
470 jmp(lost_precision, Label::kNear);
471 }
472 }
473 bind(&done);
474}
475
476
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000477void MacroAssembler::LoadUint32(XMMRegister dst,
478 Register src,
479 XMMRegister scratch) {
480 Label done;
481 cmp(src, Immediate(0));
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000482 ExternalReference uint32_bias =
483 ExternalReference::address_of_uint32_bias();
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000484 movsd(scratch, Operand::StaticVariable(uint32_bias));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000485 Cvtsi2sd(dst, src);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000486 j(not_sign, &done, Label::kNear);
487 addsd(dst, scratch);
488 bind(&done);
489}
490
491
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000492void MacroAssembler::LoadUint32NoSSE2(Register src) {
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000493 Label done;
494 push(src);
495 fild_s(Operand(esp, 0));
496 cmp(src, Immediate(0));
497 j(not_sign, &done, Label::kNear);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000498 ExternalReference uint32_bias =
499 ExternalReference::address_of_uint32_bias();
500 fld_d(Operand::StaticVariable(uint32_bias));
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000501 faddp(1);
502 bind(&done);
503 add(esp, Immediate(kPointerSize));
504}
505
506
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000507void MacroAssembler::RecordWriteArray(Register object,
508 Register value,
509 Register index,
510 SaveFPRegsMode save_fp,
511 RememberedSetAction remembered_set_action,
512 SmiCheck smi_check) {
513 // First, check if a write barrier is even needed. The tests below
514 // catch stores of Smis.
515 Label done;
516
517 // Skip barrier if writing a smi.
518 if (smi_check == INLINE_SMI_CHECK) {
519 ASSERT_EQ(0, kSmiTag);
520 test(value, Immediate(kSmiTagMask));
521 j(zero, &done);
522 }
523
524 // Array access: calculate the destination address in the same manner as
525 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
526 // into an array of words.
527 Register dst = index;
528 lea(dst, Operand(object, index, times_half_pointer_size,
529 FixedArray::kHeaderSize - kHeapObjectTag));
530
531 RecordWrite(
532 object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
533
534 bind(&done);
535
536 // Clobber clobbered input registers when running with the debug-code flag
537 // turned on to provoke errors.
538 if (emit_debug_code()) {
539 mov(value, Immediate(BitCast<int32_t>(kZapValue)));
540 mov(index, Immediate(BitCast<int32_t>(kZapValue)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000541 }
542}
543
544
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000545void MacroAssembler::RecordWriteField(
546 Register object,
547 int offset,
548 Register value,
549 Register dst,
550 SaveFPRegsMode save_fp,
551 RememberedSetAction remembered_set_action,
552 SmiCheck smi_check) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000553 // First, check if a write barrier is even needed. The tests below
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000554 // catch stores of Smis.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000555 Label done;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000557 // Skip barrier if writing a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000558 if (smi_check == INLINE_SMI_CHECK) {
559 JumpIfSmi(value, &done, Label::kNear);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000561
562 // Although the object register is tagged, the offset is relative to the start
563 // of the object, so so offset must be a multiple of kPointerSize.
564 ASSERT(IsAligned(offset, kPointerSize));
565
566 lea(dst, FieldOperand(object, offset));
567 if (emit_debug_code()) {
568 Label ok;
569 test_b(dst, (1 << kPointerSizeLog2) - 1);
570 j(zero, &ok, Label::kNear);
571 int3();
572 bind(&ok);
573 }
574
575 RecordWrite(
576 object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577
578 bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000579
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000580 // Clobber clobbered input registers when running with the debug-code flag
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000581 // turned on to provoke errors.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000582 if (emit_debug_code()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000583 mov(value, Immediate(BitCast<int32_t>(kZapValue)));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000584 mov(dst, Immediate(BitCast<int32_t>(kZapValue)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000586}
587
588
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000589void MacroAssembler::RecordWriteForMap(
590 Register object,
591 Handle<Map> map,
592 Register scratch1,
593 Register scratch2,
594 SaveFPRegsMode save_fp) {
595 Label done;
596
597 Register address = scratch1;
598 Register value = scratch2;
599 if (emit_debug_code()) {
600 Label ok;
601 lea(address, FieldOperand(object, HeapObject::kMapOffset));
602 test_b(address, (1 << kPointerSizeLog2) - 1);
603 j(zero, &ok, Label::kNear);
604 int3();
605 bind(&ok);
606 }
607
608 ASSERT(!object.is(value));
609 ASSERT(!object.is(address));
610 ASSERT(!value.is(address));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000611 AssertNotSmi(object);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000612
613 if (!FLAG_incremental_marking) {
614 return;
615 }
616
617 // A single check of the map's pages interesting flag suffices, since it is
618 // only set during incremental collection, and then it's also guaranteed that
619 // the from object's page's interesting flag is also set. This optimization
620 // relies on the fact that maps can never be in new space.
621 ASSERT(!isolate()->heap()->InNewSpace(*map));
622 CheckPageFlagForMap(map,
623 MemoryChunk::kPointersToHereAreInterestingMask,
624 zero,
625 &done,
626 Label::kNear);
627
628 // Delay the initialization of |address| and |value| for the stub until it's
629 // known that the will be needed. Up until this point their values are not
630 // needed since they are embedded in the operands of instructions that need
631 // them.
632 lea(address, FieldOperand(object, HeapObject::kMapOffset));
633 mov(value, Immediate(map));
634 RecordWriteStub stub(object, value, address, OMIT_REMEMBERED_SET, save_fp);
635 CallStub(&stub);
636
637 bind(&done);
638
639 // Clobber clobbered input registers when running with the debug-code flag
640 // turned on to provoke errors.
641 if (emit_debug_code()) {
642 mov(value, Immediate(BitCast<int32_t>(kZapValue)));
643 mov(scratch1, Immediate(BitCast<int32_t>(kZapValue)));
644 mov(scratch2, Immediate(BitCast<int32_t>(kZapValue)));
645 }
646}
647
648
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000649void MacroAssembler::RecordWrite(Register object,
650 Register address,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000651 Register value,
652 SaveFPRegsMode fp_mode,
653 RememberedSetAction remembered_set_action,
654 SmiCheck smi_check) {
655 ASSERT(!object.is(value));
656 ASSERT(!object.is(address));
657 ASSERT(!value.is(address));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000658 AssertNotSmi(object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000659
660 if (remembered_set_action == OMIT_REMEMBERED_SET &&
661 !FLAG_incremental_marking) {
662 return;
663 }
664
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000665 if (emit_debug_code()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000666 Label ok;
667 cmp(value, Operand(address, 0));
668 j(equal, &ok, Label::kNear);
669 int3();
670 bind(&ok);
671 }
672
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000673 // First, check if a write barrier is even needed. The tests below
674 // catch stores of Smis and stores into young gen.
675 Label done;
676
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000677 if (smi_check == INLINE_SMI_CHECK) {
678 // Skip barrier if writing a smi.
679 JumpIfSmi(value, &done, Label::kNear);
680 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000681
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000682 CheckPageFlag(value,
683 value, // Used as scratch.
684 MemoryChunk::kPointersToHereAreInterestingMask,
685 zero,
686 &done,
687 Label::kNear);
688 CheckPageFlag(object,
689 value, // Used as scratch.
690 MemoryChunk::kPointersFromHereAreInterestingMask,
691 zero,
692 &done,
693 Label::kNear);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000694
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695 RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode);
696 CallStub(&stub);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000697
698 bind(&done);
699
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000700 // Clobber clobbered registers when running with the debug-code flag
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000701 // turned on to provoke errors.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000702 if (emit_debug_code()) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000703 mov(address, Immediate(BitCast<int32_t>(kZapValue)));
704 mov(value, Immediate(BitCast<int32_t>(kZapValue)));
705 }
706}
707
708
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000709#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5c838252010-02-19 08:53:10 +0000710void MacroAssembler::DebugBreak() {
711 Set(eax, Immediate(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak, isolate())));
ager@chromium.org5c838252010-02-19 08:53:10 +0000713 CEntryStub ces(1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000714 call(ces.GetCode(isolate()), RelocInfo::DEBUG_BREAK);
ager@chromium.org5c838252010-02-19 08:53:10 +0000715}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000716#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000718
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000719void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) {
720 xorps(dst, dst);
721 cvtsi2sd(dst, src);
722}
723
724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725void MacroAssembler::Set(Register dst, const Immediate& x) {
726 if (x.is_zero()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000727 xor_(dst, dst); // Shorter than mov.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728 } else {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000729 mov(dst, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 }
731}
732
733
734void MacroAssembler::Set(const Operand& dst, const Immediate& x) {
735 mov(dst, x);
736}
737
738
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000739bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
740 static const int kMaxImmediateBits = 17;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000741 if (!RelocInfo::IsNone(x.rmode_)) return false;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000742 return !is_intn(x.x_, kMaxImmediateBits);
743}
744
745
746void MacroAssembler::SafeSet(Register dst, const Immediate& x) {
747 if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
748 Set(dst, Immediate(x.x_ ^ jit_cookie()));
749 xor_(dst, jit_cookie());
750 } else {
751 Set(dst, x);
752 }
753}
754
755
756void MacroAssembler::SafePush(const Immediate& x) {
757 if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
758 push(Immediate(x.x_ ^ jit_cookie()));
759 xor_(Operand(esp, 0), Immediate(jit_cookie()));
760 } else {
761 push(x);
762 }
763}
764
765
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000766void MacroAssembler::CmpObjectType(Register heap_object,
767 InstanceType type,
768 Register map) {
769 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
770 CmpInstanceType(map, type);
771}
772
773
774void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
775 cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
776 static_cast<int8_t>(type));
777}
778
779
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000780void MacroAssembler::CheckFastElements(Register map,
781 Label* fail,
782 Label::Distance distance) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000783 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
784 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
785 STATIC_ASSERT(FAST_ELEMENTS == 2);
786 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000787 cmpb(FieldOperand(map, Map::kBitField2Offset),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000788 Map::kMaximumBitField2FastHoleyElementValue);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000789 j(above, fail, distance);
790}
791
792
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000793void MacroAssembler::CheckFastObjectElements(Register map,
794 Label* fail,
795 Label::Distance distance) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000796 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
797 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
798 STATIC_ASSERT(FAST_ELEMENTS == 2);
799 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 cmpb(FieldOperand(map, Map::kBitField2Offset),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000801 Map::kMaximumBitField2FastHoleySmiElementValue);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000802 j(below_equal, fail, distance);
803 cmpb(FieldOperand(map, Map::kBitField2Offset),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000804 Map::kMaximumBitField2FastHoleyElementValue);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000805 j(above, fail, distance);
806}
807
808
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000809void MacroAssembler::CheckFastSmiElements(Register map,
810 Label* fail,
811 Label::Distance distance) {
812 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
813 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000814 cmpb(FieldOperand(map, Map::kBitField2Offset),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000815 Map::kMaximumBitField2FastHoleySmiElementValue);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000816 j(above, fail, distance);
817}
818
819
820void MacroAssembler::StoreNumberToDoubleElements(
821 Register maybe_number,
822 Register elements,
823 Register key,
824 Register scratch1,
825 XMMRegister scratch2,
826 Label* fail,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000827 bool specialize_for_processor,
828 int elements_offset) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000829 Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value;
830 JumpIfSmi(maybe_number, &smi_value, Label::kNear);
831
832 CheckMap(maybe_number,
833 isolate()->factory()->heap_number_map(),
834 fail,
835 DONT_DO_SMI_CHECK);
836
837 // Double value, canonicalize NaN.
838 uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
839 cmp(FieldOperand(maybe_number, offset),
840 Immediate(kNaNOrInfinityLowerBoundUpper32));
841 j(greater_equal, &maybe_nan, Label::kNear);
842
843 bind(&not_nan);
844 ExternalReference canonical_nan_reference =
845 ExternalReference::address_of_canonical_non_hole_nan();
846 if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000847 CpuFeatureScope use_sse2(this, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000848 movsd(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000849 bind(&have_double_value);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000850 movsd(FieldOperand(elements, key, times_4,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000851 FixedDoubleArray::kHeaderSize - elements_offset),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000852 scratch2);
853 } else {
854 fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset));
855 bind(&have_double_value);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000856 fstp_d(FieldOperand(elements, key, times_4,
857 FixedDoubleArray::kHeaderSize - elements_offset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000858 }
859 jmp(&done);
860
861 bind(&maybe_nan);
862 // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
863 // it's an Infinity, and the non-NaN code path applies.
864 j(greater, &is_nan, Label::kNear);
865 cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0));
866 j(zero, &not_nan);
867 bind(&is_nan);
868 if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000869 CpuFeatureScope use_sse2(this, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000870 movsd(scratch2, Operand::StaticVariable(canonical_nan_reference));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000871 } else {
872 fld_d(Operand::StaticVariable(canonical_nan_reference));
873 }
874 jmp(&have_double_value, Label::kNear);
875
876 bind(&smi_value);
877 // Value is a smi. Convert to a double and store.
878 // Preserve original value.
879 mov(scratch1, maybe_number);
880 SmiUntag(scratch1);
881 if (CpuFeatures::IsSupported(SSE2) && specialize_for_processor) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000882 CpuFeatureScope fscope(this, SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000883 Cvtsi2sd(scratch2, scratch1);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000884 movsd(FieldOperand(elements, key, times_4,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000885 FixedDoubleArray::kHeaderSize - elements_offset),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000886 scratch2);
887 } else {
888 push(scratch1);
889 fild_s(Operand(esp, 0));
890 pop(scratch1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000891 fstp_d(FieldOperand(elements, key, times_4,
892 FixedDoubleArray::kHeaderSize - elements_offset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000893 }
894 bind(&done);
895}
896
897
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000898void MacroAssembler::CompareMap(Register obj, Handle<Map> map) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000899 cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000900}
901
902
ager@chromium.org5c838252010-02-19 08:53:10 +0000903void MacroAssembler::CheckMap(Register obj,
904 Handle<Map> map,
905 Label* fail,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000906 SmiCheckType smi_check_type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000907 if (smi_check_type == DO_SMI_CHECK) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000908 JumpIfSmi(obj, fail);
ager@chromium.org5c838252010-02-19 08:53:10 +0000909 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000910
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000911 CompareMap(obj, map);
ager@chromium.org5c838252010-02-19 08:53:10 +0000912 j(not_equal, fail);
913}
914
915
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000916void MacroAssembler::DispatchMap(Register obj,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000917 Register unused,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000918 Handle<Map> map,
919 Handle<Code> success,
920 SmiCheckType smi_check_type) {
921 Label fail;
ager@chromium.org560b07b2011-05-23 16:33:44 +0000922 if (smi_check_type == DO_SMI_CHECK) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000923 JumpIfSmi(obj, &fail);
924 }
925 cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
926 j(equal, success);
927
928 bind(&fail);
929}
930
931
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000932Condition MacroAssembler::IsObjectStringType(Register heap_object,
933 Register map,
934 Register instance_type) {
935 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
936 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000937 STATIC_ASSERT(kNotStringTag != 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000938 test(instance_type, Immediate(kIsNotStringMask));
939 return zero;
940}
941
942
ulan@chromium.org750145a2013-03-07 15:14:13 +0000943Condition MacroAssembler::IsObjectNameType(Register heap_object,
944 Register map,
945 Register instance_type) {
946 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
947 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
948 cmpb(instance_type, static_cast<uint8_t>(LAST_NAME_TYPE));
949 return below_equal;
950}
951
952
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000953void MacroAssembler::IsObjectJSObjectType(Register heap_object,
954 Register map,
955 Register scratch,
956 Label* fail) {
957 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
958 IsInstanceJSObjectType(map, scratch, fail);
959}
960
961
962void MacroAssembler::IsInstanceJSObjectType(Register map,
963 Register scratch,
964 Label* fail) {
965 movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000966 sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000967 cmp(scratch,
968 LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000969 j(above, fail);
970}
971
972
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973void MacroAssembler::FCmp() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000974 if (CpuFeatures::IsSupported(CMOV)) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000975 fucomip();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000976 fstp(0);
ager@chromium.org3811b432009-10-28 14:53:37 +0000977 } else {
978 fucompp();
979 push(eax);
980 fnstsw_ax();
981 sahf();
982 pop(eax);
983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000987void MacroAssembler::AssertNumber(Register object) {
988 if (emit_debug_code()) {
989 Label ok;
990 JumpIfSmi(object, &ok);
991 cmp(FieldOperand(object, HeapObject::kMapOffset),
992 isolate()->factory()->heap_number_map());
danno@chromium.org59400602013-08-13 17:09:37 +0000993 Check(equal, kOperandNotANumber);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000994 bind(&ok);
995 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000996}
997
998
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000999void MacroAssembler::AssertSmi(Register object) {
1000 if (emit_debug_code()) {
1001 test(object, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001002 Check(equal, kOperandIsNotASmi);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001003 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001004}
1005
1006
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001007void MacroAssembler::AssertString(Register object) {
1008 if (emit_debug_code()) {
1009 test(object, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001010 Check(not_equal, kOperandIsASmiAndNotAString);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001011 push(object);
1012 mov(object, FieldOperand(object, HeapObject::kMapOffset));
1013 CmpInstanceType(object, FIRST_NONSTRING_TYPE);
1014 pop(object);
danno@chromium.org59400602013-08-13 17:09:37 +00001015 Check(below, kOperandIsNotAString);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001016 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001017}
1018
1019
ulan@chromium.org750145a2013-03-07 15:14:13 +00001020void MacroAssembler::AssertName(Register object) {
1021 if (emit_debug_code()) {
1022 test(object, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001023 Check(not_equal, kOperandIsASmiAndNotAName);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001024 push(object);
1025 mov(object, FieldOperand(object, HeapObject::kMapOffset));
1026 CmpInstanceType(object, LAST_NAME_TYPE);
1027 pop(object);
danno@chromium.org59400602013-08-13 17:09:37 +00001028 Check(below_equal, kOperandIsNotAName);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001029 }
1030}
1031
1032
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001033void MacroAssembler::AssertNotSmi(Register object) {
1034 if (emit_debug_code()) {
1035 test(object, Immediate(kSmiTagMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001036 Check(not_equal, kOperandIsASmi);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001037 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001038}
1039
1040
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001041void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
1042 if (frame_mode == BUILD_STUB_FRAME) {
1043 push(ebp); // Caller's frame pointer.
1044 mov(ebp, esp);
1045 push(esi); // Callee's context.
1046 push(Immediate(Smi::FromInt(StackFrame::STUB)));
1047 } else {
1048 PredictableCodeSizeScope predictible_code_size_scope(this,
1049 kNoCodeAgeSequenceLength);
machenbach@chromium.orged29eb22013-10-31 13:30:00 +00001050 if (isolate()->IsCodePreAgingActive()) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001051 // Pre-age the code.
1052 call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
1053 RelocInfo::CODE_AGE_SEQUENCE);
1054 Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength);
1055 } else {
1056 push(ebp); // Caller's frame pointer.
1057 mov(ebp, esp);
1058 push(esi); // Callee's context.
1059 push(edi); // Callee's JS function.
1060 }
1061 }
1062}
1063
1064
ager@chromium.org7c537e22008-10-16 08:43:32 +00001065void MacroAssembler::EnterFrame(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066 push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001067 mov(ebp, esp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068 push(esi);
1069 push(Immediate(Smi::FromInt(type)));
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001070 push(Immediate(CodeObject()));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001071 if (emit_debug_code()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001072 cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
danno@chromium.org59400602013-08-13 17:09:37 +00001073 Check(not_equal, kCodeObjectNotProperlyPatched);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001074 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075}
1076
1077
ager@chromium.org7c537e22008-10-16 08:43:32 +00001078void MacroAssembler::LeaveFrame(StackFrame::Type type) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001079 if (emit_debug_code()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
1081 Immediate(Smi::FromInt(type)));
danno@chromium.org59400602013-08-13 17:09:37 +00001082 Check(equal, kStackFrameTypesMustMatch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083 }
1084 leave();
1085}
1086
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001087
1088void MacroAssembler::EnterExitFramePrologue() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001089 // Set up the frame structure on the stack.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001090 ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
ager@chromium.org236ad962008-09-25 09:45:57 +00001091 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
1092 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
1093 push(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001094 mov(ebp, esp);
ager@chromium.org236ad962008-09-25 09:45:57 +00001095
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001096 // Reserve room for entry stack pointer and push the code object.
ager@chromium.org236ad962008-09-25 09:45:57 +00001097 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
ager@chromium.org5c838252010-02-19 08:53:10 +00001098 push(Immediate(0)); // Saved entry sp, patched before call.
1099 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
ager@chromium.org236ad962008-09-25 09:45:57 +00001100
1101 // Save the frame pointer and the context in top.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001102 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 isolate());
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001104 ExternalReference context_address(Isolate::kContextAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 isolate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001106 mov(Operand::StaticVariable(c_entry_fp_address), ebp);
1107 mov(Operand::StaticVariable(context_address), esi);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001108}
ager@chromium.org236ad962008-09-25 09:45:57 +00001109
ager@chromium.org236ad962008-09-25 09:45:57 +00001110
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001111void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
1112 // Optionally save all XMM registers.
1113 if (save_doubles) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001114 CpuFeatureScope scope(this, SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001115 int space = XMMRegister::kNumRegisters * kDoubleSize + argc * kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001116 sub(esp, Immediate(space));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001117 const int offset = -2 * kPointerSize;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001118 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
1119 XMMRegister reg = XMMRegister::from_code(i);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001120 movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001121 }
1122 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001123 sub(esp, Immediate(argc * kPointerSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001124 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001125
1126 // Get the required frame alignment for the OS.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001127 const int kFrameAlignment = OS::ActivationFrameAlignment();
ager@chromium.org236ad962008-09-25 09:45:57 +00001128 if (kFrameAlignment > 0) {
1129 ASSERT(IsPowerOf2(kFrameAlignment));
1130 and_(esp, -kFrameAlignment);
1131 }
1132
1133 // Patch the saved entry sp.
1134 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
1135}
1136
1137
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001138void MacroAssembler::EnterExitFrame(bool save_doubles) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001139 EnterExitFramePrologue();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001140
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001141 // Set up argc and argv in callee-saved registers.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001142 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001143 mov(edi, eax);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001144 lea(esi, Operand(ebp, eax, times_4, offset));
1145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001146 // Reserve space for argc, argv and isolate.
1147 EnterExitFrameEpilogue(3, save_doubles);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001148}
1149
1150
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001151void MacroAssembler::EnterApiExitFrame(int argc) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001152 EnterExitFramePrologue();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001153 EnterExitFrameEpilogue(argc, false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001154}
1155
1156
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001157void MacroAssembler::LeaveExitFrame(bool save_doubles) {
1158 // Optionally restore all XMM registers.
1159 if (save_doubles) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001160 CpuFeatureScope scope(this, SSE2);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001161 const int offset = -2 * kPointerSize;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001162 for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
1163 XMMRegister reg = XMMRegister::from_code(i);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00001164 movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001165 }
1166 }
1167
ager@chromium.org236ad962008-09-25 09:45:57 +00001168 // Get the return address from the stack and restore the frame pointer.
1169 mov(ecx, Operand(ebp, 1 * kPointerSize));
1170 mov(ebp, Operand(ebp, 0 * kPointerSize));
1171
1172 // Pop the arguments and the receiver from the caller stack.
1173 lea(esp, Operand(esi, 1 * kPointerSize));
1174
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001175 // Push the return address to get ready to return.
1176 push(ecx);
1177
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001178 LeaveExitFrameEpilogue(true);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001179}
1180
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001181
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001182void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001183 // Restore current context from top and clear it in debug mode.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001184 ExternalReference context_address(Isolate::kContextAddress, isolate());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001185 if (restore_context) {
1186 mov(esi, Operand::StaticVariable(context_address));
1187 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001188#ifdef DEBUG
1189 mov(Operand::StaticVariable(context_address), Immediate(0));
1190#endif
ager@chromium.org236ad962008-09-25 09:45:57 +00001191
ager@chromium.org236ad962008-09-25 09:45:57 +00001192 // Clear the top frame.
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001193 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 isolate());
ager@chromium.org236ad962008-09-25 09:45:57 +00001195 mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
1196}
1197
1198
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001199void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001200 mov(esp, ebp);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001201 pop(ebp);
1202
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001203 LeaveExitFrameEpilogue(restore_context);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001204}
1205
1206
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001207void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001208 int handler_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001209 // Adjust this code if not the case.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001210 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1211 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001212 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1213 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1214 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1215 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
1216
1217 // We will build up the handler from the bottom by pushing on the stack.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001218 // First push the frame pointer and context.
1219 if (kind == StackHandler::JS_ENTRY) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001220 // The frame pointer does not point to a JS frame so we save NULL for
1221 // ebp. We expect the code throwing an exception to check ebp before
1222 // dereferencing it to restore the context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001223 push(Immediate(0)); // NULL frame pointer.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001224 push(Immediate(Smi::FromInt(0))); // No context.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001225 } else {
1226 push(ebp);
1227 push(esi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001229 // Push the state and the code object.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001230 unsigned state =
1231 StackHandler::IndexField::encode(handler_index) |
1232 StackHandler::KindField::encode(kind);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001233 push(Immediate(state));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001234 Push(CodeObject());
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001235
1236 // Link the current handler as the next handler.
1237 ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1238 push(Operand::StaticVariable(handler_address));
1239 // Set this new handler as the current one.
1240 mov(Operand::StaticVariable(handler_address), esp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241}
1242
1243
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001244void MacroAssembler::PopTryHandler() {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001245 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001246 ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1247 pop(Operand::StaticVariable(handler_address));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001248 add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001249}
1250
1251
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001252void MacroAssembler::JumpToHandlerEntry() {
1253 // Compute the handler entry address and jump to it. The handler table is
1254 // a fixed array of (smi-tagged) code offsets.
1255 // eax = exception, edi = code object, edx = state.
1256 mov(ebx, FieldOperand(edi, Code::kHandlerTableOffset));
1257 shr(edx, StackHandler::kKindWidth);
1258 mov(edx, FieldOperand(ebx, edx, times_4, FixedArray::kHeaderSize));
1259 SmiUntag(edx);
1260 lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
1261 jmp(edi);
1262}
1263
1264
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001265void MacroAssembler::Throw(Register value) {
1266 // Adjust this code if not the case.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001267 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1268 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001269 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1270 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1271 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1272 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
1273
1274 // The exception is expected in eax.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001275 if (!value.is(eax)) {
1276 mov(eax, value);
1277 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001278 // Drop the stack pointer to the top of the top handler.
1279 ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001280 mov(esp, Operand::StaticVariable(handler_address));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001281 // Restore the next handler.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001282 pop(Operand::StaticVariable(handler_address));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001283
1284 // Remove the code object and state, compute the handler address in edi.
1285 pop(edi); // Code object.
1286 pop(edx); // Index and state.
1287
1288 // Restore the context and frame pointer.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001289 pop(esi); // Context.
1290 pop(ebp); // Frame pointer.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001291
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001292 // If the handler is a JS frame, restore the context to the frame.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001293 // (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
1294 // ebp or esi.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001295 Label skip;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001296 test(esi, esi);
1297 j(zero, &skip, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001298 mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001299 bind(&skip);
1300
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001301 JumpToHandlerEntry();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001302}
1303
1304
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001305void MacroAssembler::ThrowUncatchable(Register value) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001306 // Adjust this code if not the case.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001307 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1308 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001309 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1310 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1311 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1312 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001313
danno@chromium.orgc612e022011-11-10 11:38:15 +00001314 // The exception is expected in eax.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001315 if (!value.is(eax)) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001316 mov(eax, value);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001317 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001318 // Drop the stack pointer to the top of the top stack handler.
1319 ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1320 mov(esp, Operand::StaticVariable(handler_address));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001321
danno@chromium.orgc612e022011-11-10 11:38:15 +00001322 // Unwind the handlers until the top ENTRY handler is found.
1323 Label fetch_next, check_kind;
1324 jmp(&check_kind, Label::kNear);
1325 bind(&fetch_next);
1326 mov(esp, Operand(esp, StackHandlerConstants::kNextOffset));
1327
1328 bind(&check_kind);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001329 STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001330 test(Operand(esp, StackHandlerConstants::kStateOffset),
1331 Immediate(StackHandler::KindField::kMask));
1332 j(not_zero, &fetch_next);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001333
1334 // Set the top handler address to next handler past the top ENTRY handler.
1335 pop(Operand::StaticVariable(handler_address));
1336
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001337 // Remove the code object and state, compute the handler address in edi.
1338 pop(edi); // Code object.
1339 pop(edx); // Index and state.
1340
1341 // Clear the context pointer and frame pointer (0 was saved in the handler).
danno@chromium.orgc612e022011-11-10 11:38:15 +00001342 pop(esi);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001343 pop(ebp);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001344
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00001345 JumpToHandlerEntry();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001346}
1347
1348
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001349void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001350 Register scratch1,
1351 Register scratch2,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001352 Label* miss) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001353 Label same_contexts;
1354
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001355 ASSERT(!holder_reg.is(scratch1));
1356 ASSERT(!holder_reg.is(scratch2));
1357 ASSERT(!scratch1.is(scratch2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001359 // Load current lexical context from the stack frame.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001360 mov(scratch1, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001361
1362 // When generating debug code, make sure the lexical context is set.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001363 if (emit_debug_code()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001364 cmp(scratch1, Immediate(0));
danno@chromium.org59400602013-08-13 17:09:37 +00001365 Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001367 // Load the native context of the current context.
1368 int offset =
1369 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001370 mov(scratch1, FieldOperand(scratch1, offset));
1371 mov(scratch1, FieldOperand(scratch1, GlobalObject::kNativeContextOffset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001372
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001373 // Check the context is a native context.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001374 if (emit_debug_code()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001375 // Read the first word and compare to native_context_map.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001376 cmp(FieldOperand(scratch1, HeapObject::kMapOffset),
1377 isolate()->factory()->native_context_map());
danno@chromium.org59400602013-08-13 17:09:37 +00001378 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001379 }
1380
1381 // Check if both contexts are the same.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001382 cmp(scratch1, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001383 j(equal, &same_contexts);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001384
1385 // Compare security tokens, save holder_reg on the stack so we can use it
1386 // as a temporary register.
1387 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388 // Check that the security token in the calling global object is
1389 // compatible with the security token in the receiving global
1390 // object.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001391 mov(scratch2,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001392 FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001393
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001394 // Check the context is a native context.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001395 if (emit_debug_code()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001396 cmp(scratch2, isolate()->factory()->null_value());
danno@chromium.org59400602013-08-13 17:09:37 +00001397 Check(not_equal, kJSGlobalProxyContextShouldNotBeNull);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001398
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001399 // Read the first word and compare to native_context_map(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001400 cmp(FieldOperand(scratch2, HeapObject::kMapOffset),
1401 isolate()->factory()->native_context_map());
danno@chromium.org59400602013-08-13 17:09:37 +00001402 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001403 }
1404
1405 int token_offset = Context::kHeaderSize +
1406 Context::SECURITY_TOKEN_INDEX * kPointerSize;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001407 mov(scratch1, FieldOperand(scratch1, token_offset));
1408 cmp(scratch1, FieldOperand(scratch2, token_offset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001409 j(not_equal, miss);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001410
1411 bind(&same_contexts);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412}
1413
1414
machenbach@chromium.orgea468882013-11-18 08:53:19 +00001415// Compute the hash code from the untagged key. This must be kept in sync with
1416// ComputeIntegerHash in utils.h and KeyedLoadGenericElementStub in
1417// code-stub-hydrogen.cc
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001418//
1419// Note: r0 will contain hash code
1420void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
1421 // Xor original key with a seed.
1422 if (Serializer::enabled()) {
1423 ExternalReference roots_array_start =
1424 ExternalReference::roots_array_start(isolate());
1425 mov(scratch, Immediate(Heap::kHashSeedRootIndex));
1426 mov(scratch,
1427 Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
1428 SmiUntag(scratch);
1429 xor_(r0, scratch);
1430 } else {
1431 int32_t seed = isolate()->heap()->HashSeed();
1432 xor_(r0, Immediate(seed));
1433 }
1434
1435 // hash = ~hash + (hash << 15);
1436 mov(scratch, r0);
1437 not_(r0);
1438 shl(scratch, 15);
1439 add(r0, scratch);
1440 // hash = hash ^ (hash >> 12);
1441 mov(scratch, r0);
1442 shr(scratch, 12);
1443 xor_(r0, scratch);
1444 // hash = hash + (hash << 2);
1445 lea(r0, Operand(r0, r0, times_4, 0));
1446 // hash = hash ^ (hash >> 4);
1447 mov(scratch, r0);
1448 shr(scratch, 4);
1449 xor_(r0, scratch);
1450 // hash = hash * 2057;
1451 imul(r0, r0, 2057);
1452 // hash = hash ^ (hash >> 16);
1453 mov(scratch, r0);
1454 shr(scratch, 16);
1455 xor_(r0, scratch);
1456}
1457
1458
1459
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001460void MacroAssembler::LoadFromNumberDictionary(Label* miss,
1461 Register elements,
1462 Register key,
1463 Register r0,
1464 Register r1,
1465 Register r2,
1466 Register result) {
1467 // Register use:
1468 //
1469 // elements - holds the slow-case elements of the receiver and is unchanged.
1470 //
1471 // key - holds the smi key on entry and is unchanged.
1472 //
1473 // Scratch registers:
1474 //
1475 // r0 - holds the untagged key on entry and holds the hash once computed.
1476 //
1477 // r1 - used to hold the capacity mask of the dictionary
1478 //
1479 // r2 - used for the index into the dictionary.
1480 //
1481 // result - holds the result on exit if the load succeeds and we fall through.
1482
1483 Label done;
1484
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001485 GetNumberHash(r0, r1);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001486
1487 // Compute capacity mask.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001488 mov(r1, FieldOperand(elements, SeededNumberDictionary::kCapacityOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001489 shr(r1, kSmiTagSize); // convert smi to int
1490 dec(r1);
1491
1492 // Generate an unrolled loop that performs a few probes before giving up.
machenbach@chromium.orgea468882013-11-18 08:53:19 +00001493 for (int i = 0; i < kNumberDictionaryProbes; i++) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001494 // Use r2 for index calculations and keep the hash intact in r0.
1495 mov(r2, r0);
1496 // Compute the masked index: (hash + i + i * i) & mask.
1497 if (i > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001498 add(r2, Immediate(SeededNumberDictionary::GetProbeOffset(i)));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001499 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 and_(r2, r1);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001501
1502 // Scale the index by multiplying by the entry size.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001503 ASSERT(SeededNumberDictionary::kEntrySize == 3);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001504 lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
1505
1506 // Check if the key matches.
1507 cmp(key, FieldOperand(elements,
1508 r2,
1509 times_pointer_size,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001510 SeededNumberDictionary::kElementsStartOffset));
machenbach@chromium.orgea468882013-11-18 08:53:19 +00001511 if (i != (kNumberDictionaryProbes - 1)) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001512 j(equal, &done);
1513 } else {
1514 j(not_equal, miss);
1515 }
1516 }
1517
1518 bind(&done);
1519 // Check that the value is a normal propety.
1520 const int kDetailsOffset =
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001521 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001522 ASSERT_EQ(NORMAL, 0);
1523 test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001524 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001525 j(not_zero, miss);
1526
1527 // Get the value at the masked, scaled index.
1528 const int kValueOffset =
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001529 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001530 mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
1531}
1532
1533
ager@chromium.orga1645e22009-09-09 19:27:10 +00001534void MacroAssembler::LoadAllocationTopHelper(Register result,
ager@chromium.orga1645e22009-09-09 19:27:10 +00001535 Register scratch,
1536 AllocationFlags flags) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001537 ExternalReference allocation_top =
1538 AllocationUtils::GetAllocationTopReference(isolate(), flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001539
1540 // Just return if allocation top is already known.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001541 if ((flags & RESULT_CONTAINS_TOP) != 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001542 // No use of scratch if allocation top is provided.
1543 ASSERT(scratch.is(no_reg));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001544#ifdef DEBUG
1545 // Assert that result actually contains top on entry.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001546 cmp(result, Operand::StaticVariable(allocation_top));
danno@chromium.org59400602013-08-13 17:09:37 +00001547 Check(equal, kUnexpectedAllocationTop);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001548#endif
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001549 return;
1550 }
1551
1552 // Move address of new object to result. Use scratch register if available.
1553 if (scratch.is(no_reg)) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001554 mov(result, Operand::StaticVariable(allocation_top));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001555 } else {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001556 mov(scratch, Immediate(allocation_top));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001557 mov(result, Operand(scratch, 0));
1558 }
1559}
1560
1561
1562void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001563 Register scratch,
1564 AllocationFlags flags) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001565 if (emit_debug_code()) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001566 test(result_end, Immediate(kObjectAlignmentMask));
danno@chromium.org59400602013-08-13 17:09:37 +00001567 Check(zero, kUnalignedAllocationInNewSpace);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001568 }
1569
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001570 ExternalReference allocation_top =
1571 AllocationUtils::GetAllocationTopReference(isolate(), flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001572
1573 // Update new top. Use scratch if available.
1574 if (scratch.is(no_reg)) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001575 mov(Operand::StaticVariable(allocation_top), result_end);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001576 } else {
1577 mov(Operand(scratch, 0), result_end);
1578 }
1579}
1580
ager@chromium.orga1645e22009-09-09 19:27:10 +00001581
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001582void MacroAssembler::Allocate(int object_size,
1583 Register result,
1584 Register result_end,
1585 Register scratch,
1586 Label* gc_required,
1587 AllocationFlags flags) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001588 ASSERT((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00001589 ASSERT(object_size <= Page::kMaxNonCodeHeapObjectSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001590 if (!FLAG_inline_new) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001591 if (emit_debug_code()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001592 // Trash the registers to simulate an allocation failure.
1593 mov(result, Immediate(0x7091));
1594 if (result_end.is_valid()) {
1595 mov(result_end, Immediate(0x7191));
1596 }
1597 if (scratch.is_valid()) {
1598 mov(scratch, Immediate(0x7291));
1599 }
1600 }
1601 jmp(gc_required);
1602 return;
1603 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001604 ASSERT(!result.is(result_end));
1605
1606 // Load address of new object into result.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001607 LoadAllocationTopHelper(result, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001608
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001609 ExternalReference allocation_limit =
1610 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1611
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001612 // Align the next allocation. Storing the filler map without checking top is
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001613 // safe in new-space because the limit of the heap is aligned there.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001614 if ((flags & DOUBLE_ALIGNMENT) != 0) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001615 ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001616 ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
1617 Label aligned;
1618 test(result, Immediate(kDoubleAlignmentMask));
1619 j(zero, &aligned, Label::kNear);
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001620 if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
1621 cmp(result, Operand::StaticVariable(allocation_limit));
1622 j(above_equal, gc_required);
1623 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001624 mov(Operand(result, 0),
1625 Immediate(isolate()->factory()->one_pointer_filler_map()));
1626 add(result, Immediate(kDoubleSize / 2));
1627 bind(&aligned);
1628 }
1629
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001630 // Calculate new top and bail out if space is exhausted.
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001631 Register top_reg = result_end.is_valid() ? result_end : result;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001632 if (!top_reg.is(result)) {
1633 mov(top_reg, result);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001634 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001635 add(top_reg, Immediate(object_size));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001636 j(carry, gc_required);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001637 cmp(top_reg, Operand::StaticVariable(allocation_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001638 j(above, gc_required);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001639
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001640 // Update allocation top.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001641 UpdateAllocationTopHelper(top_reg, scratch, flags);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001642
1643 // Tag result if requested.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001644 bool tag_result = (flags & TAG_OBJECT) != 0;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001645 if (top_reg.is(result)) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001646 if (tag_result) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001647 sub(result, Immediate(object_size - kHeapObjectTag));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001648 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 sub(result, Immediate(object_size));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001650 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001651 } else if (tag_result) {
1652 ASSERT(kHeapObjectTag == 1);
1653 inc(result);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001654 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001655}
1656
1657
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001658void MacroAssembler::Allocate(int header_size,
1659 ScaleFactor element_size,
1660 Register element_count,
1661 RegisterValueType element_count_type,
1662 Register result,
1663 Register result_end,
1664 Register scratch,
1665 Label* gc_required,
1666 AllocationFlags flags) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001667 ASSERT((flags & SIZE_IN_WORDS) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668 if (!FLAG_inline_new) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001669 if (emit_debug_code()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001670 // Trash the registers to simulate an allocation failure.
1671 mov(result, Immediate(0x7091));
1672 mov(result_end, Immediate(0x7191));
1673 if (scratch.is_valid()) {
1674 mov(scratch, Immediate(0x7291));
1675 }
1676 // Register element_count is not modified by the function.
1677 }
1678 jmp(gc_required);
1679 return;
1680 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001681 ASSERT(!result.is(result_end));
1682
1683 // Load address of new object into result.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001684 LoadAllocationTopHelper(result, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001685
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001686 ExternalReference allocation_limit =
1687 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1688
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001689 // Align the next allocation. Storing the filler map without checking top is
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001690 // safe in new-space because the limit of the heap is aligned there.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001691 if ((flags & DOUBLE_ALIGNMENT) != 0) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001692 ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001693 ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
1694 Label aligned;
1695 test(result, Immediate(kDoubleAlignmentMask));
1696 j(zero, &aligned, Label::kNear);
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001697 if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
1698 cmp(result, Operand::StaticVariable(allocation_limit));
1699 j(above_equal, gc_required);
1700 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001701 mov(Operand(result, 0),
1702 Immediate(isolate()->factory()->one_pointer_filler_map()));
1703 add(result, Immediate(kDoubleSize / 2));
1704 bind(&aligned);
1705 }
1706
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001707 // Calculate new top and bail out if space is exhausted.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001708 // We assume that element_count*element_size + header_size does not
1709 // overflow.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001710 if (element_count_type == REGISTER_VALUE_IS_SMI) {
1711 STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1);
1712 STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2);
1713 STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4);
1714 ASSERT(element_size >= times_2);
1715 ASSERT(kSmiTagSize == 1);
1716 element_size = static_cast<ScaleFactor>(element_size - 1);
1717 } else {
1718 ASSERT(element_count_type == REGISTER_VALUE_IS_INT32);
1719 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001720 lea(result_end, Operand(element_count, element_size, header_size));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001721 add(result_end, result);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001722 j(carry, gc_required);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001723 cmp(result_end, Operand::StaticVariable(allocation_limit));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001724 j(above, gc_required);
1725
ager@chromium.orga1645e22009-09-09 19:27:10 +00001726 if ((flags & TAG_OBJECT) != 0) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001727 ASSERT(kHeapObjectTag == 1);
1728 inc(result);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001729 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001730
1731 // Update allocation top.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001732 UpdateAllocationTopHelper(result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001733}
1734
1735
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001736void MacroAssembler::Allocate(Register object_size,
1737 Register result,
1738 Register result_end,
1739 Register scratch,
1740 Label* gc_required,
1741 AllocationFlags flags) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001742 ASSERT((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 if (!FLAG_inline_new) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001744 if (emit_debug_code()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001745 // Trash the registers to simulate an allocation failure.
1746 mov(result, Immediate(0x7091));
1747 mov(result_end, Immediate(0x7191));
1748 if (scratch.is_valid()) {
1749 mov(scratch, Immediate(0x7291));
1750 }
1751 // object_size is left unchanged by this function.
1752 }
1753 jmp(gc_required);
1754 return;
1755 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001756 ASSERT(!result.is(result_end));
1757
1758 // Load address of new object into result.
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001759 LoadAllocationTopHelper(result, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001760
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001761 ExternalReference allocation_limit =
1762 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1763
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001764 // Align the next allocation. Storing the filler map without checking top is
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001765 // safe in new-space because the limit of the heap is aligned there.
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001766 if ((flags & DOUBLE_ALIGNMENT) != 0) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001767 ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001768 ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
1769 Label aligned;
1770 test(result, Immediate(kDoubleAlignmentMask));
1771 j(zero, &aligned, Label::kNear);
mstarzinger@chromium.orgf6fe1182013-08-19 18:11:56 +00001772 if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
1773 cmp(result, Operand::StaticVariable(allocation_limit));
1774 j(above_equal, gc_required);
1775 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001776 mov(Operand(result, 0),
1777 Immediate(isolate()->factory()->one_pointer_filler_map()));
1778 add(result, Immediate(kDoubleSize / 2));
1779 bind(&aligned);
1780 }
1781
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001782 // Calculate new top and bail out if space is exhausted.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001783 if (!object_size.is(result_end)) {
1784 mov(result_end, object_size);
1785 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001786 add(result_end, result);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001787 j(carry, gc_required);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001788 cmp(result_end, Operand::StaticVariable(allocation_limit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001789 j(above, gc_required);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001790
ager@chromium.orga1645e22009-09-09 19:27:10 +00001791 // Tag result if requested.
1792 if ((flags & TAG_OBJECT) != 0) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001793 ASSERT(kHeapObjectTag == 1);
1794 inc(result);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001795 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001796
1797 // Update allocation top.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001798 UpdateAllocationTopHelper(result_end, scratch, flags);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001799}
1800
1801
1802void MacroAssembler::UndoAllocationInNewSpace(Register object) {
1803 ExternalReference new_space_allocation_top =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 ExternalReference::new_space_allocation_top_address(isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001805
1806 // Make sure the object has no tag before resetting top.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 and_(object, Immediate(~kHeapObjectTagMask));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001808#ifdef DEBUG
1809 cmp(object, Operand::StaticVariable(new_space_allocation_top));
danno@chromium.org59400602013-08-13 17:09:37 +00001810 Check(below, kUndoAllocationOfNonAllocatedMemory);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001811#endif
1812 mov(Operand::StaticVariable(new_space_allocation_top), object);
1813}
1814
1815
ager@chromium.org3811b432009-10-28 14:53:37 +00001816void MacroAssembler::AllocateHeapNumber(Register result,
1817 Register scratch1,
1818 Register scratch2,
1819 Label* gc_required) {
1820 // Allocate heap number in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001821 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
1822 TAG_OBJECT);
ager@chromium.org3811b432009-10-28 14:53:37 +00001823
1824 // Set the map.
1825 mov(FieldOperand(result, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001826 Immediate(isolate()->factory()->heap_number_map()));
ager@chromium.org3811b432009-10-28 14:53:37 +00001827}
1828
1829
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001830void MacroAssembler::AllocateTwoByteString(Register result,
1831 Register length,
1832 Register scratch1,
1833 Register scratch2,
1834 Register scratch3,
1835 Label* gc_required) {
1836 // Calculate the number of bytes needed for the characters in the string while
1837 // observing object alignment.
1838 ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001839 ASSERT(kShortSize == 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001840 // scratch1 = length * 2 + kObjectAlignmentMask.
1841 lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001842 and_(scratch1, Immediate(~kObjectAlignmentMask));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001843
1844 // Allocate two byte string in new space.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001845 Allocate(SeqTwoByteString::kHeaderSize,
1846 times_1,
1847 scratch1,
1848 REGISTER_VALUE_IS_INT32,
1849 result,
1850 scratch2,
1851 scratch3,
1852 gc_required,
1853 TAG_OBJECT);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001854
1855 // Set the map, length and hash field.
1856 mov(FieldOperand(result, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001857 Immediate(isolate()->factory()->string_map()));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001858 mov(scratch1, length);
1859 SmiTag(scratch1);
1860 mov(FieldOperand(result, String::kLengthOffset), scratch1);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001861 mov(FieldOperand(result, String::kHashFieldOffset),
1862 Immediate(String::kEmptyHashField));
1863}
1864
1865
1866void MacroAssembler::AllocateAsciiString(Register result,
1867 Register length,
1868 Register scratch1,
1869 Register scratch2,
1870 Register scratch3,
1871 Label* gc_required) {
1872 // Calculate the number of bytes needed for the characters in the string while
1873 // observing object alignment.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001874 ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001875 mov(scratch1, length);
1876 ASSERT(kCharSize == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001877 add(scratch1, Immediate(kObjectAlignmentMask));
1878 and_(scratch1, Immediate(~kObjectAlignmentMask));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001879
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001880 // Allocate ASCII string in new space.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001881 Allocate(SeqOneByteString::kHeaderSize,
1882 times_1,
1883 scratch1,
1884 REGISTER_VALUE_IS_INT32,
1885 result,
1886 scratch2,
1887 scratch3,
1888 gc_required,
1889 TAG_OBJECT);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001890
1891 // Set the map, length and hash field.
1892 mov(FieldOperand(result, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001893 Immediate(isolate()->factory()->ascii_string_map()));
ager@chromium.orgac091b72010-05-05 07:34:42 +00001894 mov(scratch1, length);
1895 SmiTag(scratch1);
1896 mov(FieldOperand(result, String::kLengthOffset), scratch1);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001897 mov(FieldOperand(result, String::kHashFieldOffset),
1898 Immediate(String::kEmptyHashField));
1899}
1900
1901
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +00001902void MacroAssembler::AllocateAsciiString(Register result,
1903 int length,
1904 Register scratch1,
1905 Register scratch2,
1906 Label* gc_required) {
1907 ASSERT(length > 0);
1908
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001909 // Allocate ASCII string in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001910 Allocate(SeqOneByteString::SizeFor(length), result, scratch1, scratch2,
1911 gc_required, TAG_OBJECT);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +00001912
1913 // Set the map, length and hash field.
1914 mov(FieldOperand(result, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001915 Immediate(isolate()->factory()->ascii_string_map()));
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +00001916 mov(FieldOperand(result, String::kLengthOffset),
1917 Immediate(Smi::FromInt(length)));
1918 mov(FieldOperand(result, String::kHashFieldOffset),
1919 Immediate(String::kEmptyHashField));
1920}
1921
1922
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001923void MacroAssembler::AllocateTwoByteConsString(Register result,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001924 Register scratch1,
1925 Register scratch2,
1926 Label* gc_required) {
1927 // Allocate heap number in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001928 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
1929 TAG_OBJECT);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001930
1931 // Set the map. The other fields are left uninitialized.
1932 mov(FieldOperand(result, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001933 Immediate(isolate()->factory()->cons_string_map()));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001934}
1935
1936
1937void MacroAssembler::AllocateAsciiConsString(Register result,
1938 Register scratch1,
1939 Register scratch2,
1940 Label* gc_required) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001941 Label allocate_new_space, install_map;
1942 AllocationFlags flags = TAG_OBJECT;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001943
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001944 ExternalReference high_promotion_mode = ExternalReference::
1945 new_space_high_promotion_mode_active_address(isolate());
1946
1947 test(Operand::StaticVariable(high_promotion_mode), Immediate(1));
1948 j(zero, &allocate_new_space);
1949
1950 Allocate(ConsString::kSize,
1951 result,
1952 scratch1,
1953 scratch2,
1954 gc_required,
1955 static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE));
1956 jmp(&install_map);
1957
1958 bind(&allocate_new_space);
1959 Allocate(ConsString::kSize,
1960 result,
1961 scratch1,
1962 scratch2,
1963 gc_required,
1964 flags);
1965
1966 bind(&install_map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001967 // Set the map. The other fields are left uninitialized.
1968 mov(FieldOperand(result, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001969 Immediate(isolate()->factory()->cons_ascii_string_map()));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001970}
1971
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001972
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001973void MacroAssembler::AllocateTwoByteSlicedString(Register result,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001974 Register scratch1,
1975 Register scratch2,
1976 Label* gc_required) {
1977 // Allocate heap number in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001978 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1979 TAG_OBJECT);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001980
1981 // Set the map. The other fields are left uninitialized.
1982 mov(FieldOperand(result, HeapObject::kMapOffset),
1983 Immediate(isolate()->factory()->sliced_string_map()));
1984}
1985
1986
1987void MacroAssembler::AllocateAsciiSlicedString(Register result,
1988 Register scratch1,
1989 Register scratch2,
1990 Label* gc_required) {
1991 // Allocate heap number in new space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001992 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1993 TAG_OBJECT);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001994
1995 // Set the map. The other fields are left uninitialized.
1996 mov(FieldOperand(result, HeapObject::kMapOffset),
1997 Immediate(isolate()->factory()->sliced_ascii_string_map()));
1998}
1999
2000
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002001// Copy memory, byte-by-byte, from source to destination. Not optimized for
2002// long or aligned copies. The contents of scratch and length are destroyed.
2003// Source and destination are incremented by length.
2004// Many variants of movsb, loop unrolling, word moves, and indexed operands
2005// have been tried here already, and this is fastest.
2006// A simpler loop is faster on small copies, but 30% slower on large ones.
2007// The cld() instruction must have been emitted, to set the direction flag(),
2008// before calling this function.
2009void MacroAssembler::CopyBytes(Register source,
2010 Register destination,
2011 Register length,
2012 Register scratch) {
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002013 Label short_loop, len4, len8, len12, done, short_string;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002014 ASSERT(source.is(esi));
2015 ASSERT(destination.is(edi));
2016 ASSERT(length.is(ecx));
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002017 cmp(length, Immediate(4));
2018 j(below, &short_string, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002019
2020 // Because source is 4-byte aligned in our uses of this function,
2021 // we keep source aligned for the rep_movs call by copying the odd bytes
2022 // at the end of the ranges.
2023 mov(scratch, Operand(source, length, times_1, -4));
2024 mov(Operand(destination, length, times_1, -4), scratch);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002025
2026 cmp(length, Immediate(8));
2027 j(below_equal, &len4, Label::kNear);
2028 cmp(length, Immediate(12));
2029 j(below_equal, &len8, Label::kNear);
2030 cmp(length, Immediate(16));
2031 j(below_equal, &len12, Label::kNear);
2032
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002033 mov(scratch, ecx);
2034 shr(ecx, 2);
2035 rep_movs();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002036 and_(scratch, Immediate(0x3));
2037 add(destination, scratch);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002038 jmp(&done, Label::kNear);
2039
2040 bind(&len12);
2041 mov(scratch, Operand(source, 8));
2042 mov(Operand(destination, 8), scratch);
2043 bind(&len8);
2044 mov(scratch, Operand(source, 4));
2045 mov(Operand(destination, 4), scratch);
2046 bind(&len4);
2047 mov(scratch, Operand(source, 0));
2048 mov(Operand(destination, 0), scratch);
2049 add(destination, length);
2050 jmp(&done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002051
2052 bind(&short_string);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002053 test(length, length);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002054 j(zero, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002055
2056 bind(&short_loop);
2057 mov_b(scratch, Operand(source, 0));
2058 mov_b(Operand(destination, 0), scratch);
2059 inc(source);
2060 inc(destination);
2061 dec(length);
2062 j(not_zero, &short_loop);
2063
2064 bind(&done);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002065}
2066
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002067
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002068void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
2069 Register end_offset,
2070 Register filler) {
2071 Label loop, entry;
2072 jmp(&entry);
2073 bind(&loop);
2074 mov(Operand(start_offset, 0), filler);
2075 add(start_offset, Immediate(kPointerSize));
2076 bind(&entry);
2077 cmp(start_offset, end_offset);
2078 j(less, &loop);
2079}
2080
2081
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002082void MacroAssembler::BooleanBitTest(Register object,
2083 int field_offset,
2084 int bit_index) {
2085 bit_index += kSmiTagSize + kSmiShiftSize;
2086 ASSERT(IsPowerOf2(kBitsPerByte));
2087 int byte_index = bit_index / kBitsPerByte;
2088 int byte_bit_index = bit_index & (kBitsPerByte - 1);
2089 test_b(FieldOperand(object, field_offset + byte_index),
2090 static_cast<byte>(1 << byte_bit_index));
2091}
2092
2093
2094
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002095void MacroAssembler::NegativeZeroTest(Register result,
2096 Register op,
2097 Label* then_label) {
2098 Label ok;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002099 test(result, result);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002100 j(not_zero, &ok);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002101 test(op, op);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002102 j(sign, then_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002103 bind(&ok);
2104}
2105
2106
2107void MacroAssembler::NegativeZeroTest(Register result,
2108 Register op1,
2109 Register op2,
2110 Register scratch,
2111 Label* then_label) {
2112 Label ok;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002113 test(result, result);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002114 j(not_zero, &ok);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002115 mov(scratch, op1);
2116 or_(scratch, op2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002117 j(sign, then_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002118 bind(&ok);
2119}
2120
2121
ager@chromium.org7c537e22008-10-16 08:43:32 +00002122void MacroAssembler::TryGetFunctionPrototype(Register function,
2123 Register result,
2124 Register scratch,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002125 Label* miss,
2126 bool miss_on_bound_function) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002127 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002128 JumpIfSmi(function, miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002129
2130 // Check that the function really is a function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002131 CmpObjectType(function, JS_FUNCTION_TYPE, result);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002132 j(not_equal, miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002133
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002134 if (miss_on_bound_function) {
2135 // If a bound function, go to miss label.
2136 mov(scratch,
2137 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2138 BooleanBitTest(scratch, SharedFunctionInfo::kCompilerHintsOffset,
2139 SharedFunctionInfo::kBoundFunction);
2140 j(not_zero, miss);
2141 }
2142
ager@chromium.org7c537e22008-10-16 08:43:32 +00002143 // Make sure that the function has an instance prototype.
2144 Label non_instance;
2145 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
2146 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002147 j(not_zero, &non_instance);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002148
2149 // Get the prototype or initial map from the function.
2150 mov(result,
2151 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2152
2153 // If the prototype or initial map is the hole, don't return it and
2154 // simply miss the cache instead. This will allow us to allocate a
2155 // prototype object on-demand in the runtime system.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002156 cmp(result, Immediate(isolate()->factory()->the_hole_value()));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002157 j(equal, miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002158
2159 // If the function does not have an initial map, we're done.
2160 Label done;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002161 CmpObjectType(result, MAP_TYPE, scratch);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002162 j(not_equal, &done);
2163
2164 // Get the prototype from the initial map.
2165 mov(result, FieldOperand(result, Map::kPrototypeOffset));
2166 jmp(&done);
2167
2168 // Non-instance prototype: Fetch prototype from constructor field
2169 // in initial map.
2170 bind(&non_instance);
2171 mov(result, FieldOperand(result, Map::kConstructorOffset));
2172
2173 // All done.
2174 bind(&done);
2175}
2176
2177
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002178void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002179 ASSERT(AllowThisStubCall(stub)); // Calls are not allowed in some stubs.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002180 call(stub->GetCode(isolate()), RelocInfo::CODE_TARGET, ast_id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181}
2182
2183
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002184void MacroAssembler::TailCallStub(CodeStub* stub) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002185 ASSERT(allow_stub_calls_ ||
2186 stub->CompilingCallsToThisStubIsGCSafe(isolate()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002187 jmp(stub->GetCode(isolate()), RelocInfo::CODE_TARGET);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002188}
2189
2190
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002191void MacroAssembler::StubReturn(int argc) {
2192 ASSERT(argc >= 1 && generating_stub());
2193 ret((argc - 1) * kPointerSize);
2194}
2195
2196
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002197bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
2198 if (!has_frame_ && stub->SometimesSetsUpAFrame()) return false;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002199 return allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe(isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002200}
2201
2202
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002203void MacroAssembler::IllegalOperation(int num_arguments) {
2204 if (num_arguments > 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002205 add(esp, Immediate(num_arguments * kPointerSize));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002206 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002207 mov(eax, Immediate(isolate()->factory()->undefined_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208}
2209
2210
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002211void MacroAssembler::IndexFromHash(Register hash, Register index) {
2212 // The assert checks that the constants for the maximum number of digits
2213 // for an array index cached in the hash field and the number of bits
2214 // reserved for it does not conflict.
2215 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
2216 (1 << String::kArrayIndexValueBits));
2217 // We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
2218 // the low kHashShift bits.
2219 and_(hash, String::kArrayIndexValueMask);
2220 STATIC_ASSERT(String::kHashShift >= kSmiTagSize && kSmiTag == 0);
2221 if (String::kHashShift > kSmiTagSize) {
2222 shr(hash, String::kHashShift - kSmiTagSize);
2223 }
2224 if (!index.is(hash)) {
2225 mov(index, hash);
2226 }
2227}
2228
2229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002230void MacroAssembler::CallRuntime(const Runtime::Function* f,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002231 int num_arguments,
2232 SaveFPRegsMode save_doubles) {
mads.s.ager31e71382008-08-13 09:32:07 +00002233 // If the expected number of arguments of the runtime function is
2234 // constant, we check that the actual number of arguments match the
2235 // expectation.
2236 if (f->nargs >= 0 && f->nargs != num_arguments) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002237 IllegalOperation(num_arguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002238 return;
2239 }
2240
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002241 // TODO(1236192): Most runtime routines don't need the number of
2242 // arguments passed in because it is constant. At some point we
2243 // should remove this need and make the runtime routine entry code
2244 // smarter.
2245 Set(eax, Immediate(num_arguments));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 mov(ebx, Immediate(ExternalReference(f, isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002247 CEntryStub ces(1, CpuFeatures::IsSupported(SSE2) ? save_doubles
2248 : kDontSaveFPRegs);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002249 CallStub(&ces);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250}
2251
2252
whesse@chromium.orge90029b2010-08-02 11:52:17 +00002253void MacroAssembler::CallExternalReference(ExternalReference ref,
2254 int num_arguments) {
2255 mov(eax, Immediate(num_arguments));
2256 mov(ebx, Immediate(ref));
2257
2258 CEntryStub stub(1);
2259 CallStub(&stub);
2260}
2261
2262
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002263void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
2264 int num_arguments,
2265 int result_size) {
mads.s.ager31e71382008-08-13 09:32:07 +00002266 // TODO(1236192): Most runtime routines don't need the number of
2267 // arguments passed in because it is constant. At some point we
2268 // should remove this need and make the runtime routine entry code
2269 // smarter.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002270 Set(eax, Immediate(num_arguments));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002271 JumpToExternalReference(ext);
2272}
2273
2274
2275void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
2276 int num_arguments,
2277 int result_size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002278 TailCallExternalReference(ExternalReference(fid, isolate()),
2279 num_arguments,
2280 result_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281}
2282
2283
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002284Operand ApiParameterOperand(int index) {
2285 return Operand(esp, index * kPointerSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002286}
2287
2288
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002289void MacroAssembler::PrepareCallApiFunction(int argc) {
2290 EnterApiExitFrame(argc);
2291 if (emit_debug_code()) {
2292 mov(esi, Immediate(BitCast<int32_t>(kZapValue)));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002293 }
2294}
2295
2296
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002297void MacroAssembler::CallApiFunctionAndReturn(
2298 Address function_address,
2299 Address thunk_address,
2300 Operand thunk_last_arg,
2301 int stack_space,
2302 Operand return_value_operand,
2303 Operand* context_restore_operand) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002304 ExternalReference next_address =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002305 ExternalReference::handle_scope_next_address(isolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002306 ExternalReference limit_address =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002307 ExternalReference::handle_scope_limit_address(isolate());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002308 ExternalReference level_address =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002309 ExternalReference::handle_scope_level_address(isolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002310
lrn@chromium.org303ada72010-10-27 09:33:13 +00002311 // Allocate HandleScope in callee-save registers.
2312 mov(ebx, Operand::StaticVariable(next_address));
2313 mov(edi, Operand::StaticVariable(limit_address));
2314 add(Operand::StaticVariable(level_address), Immediate(1));
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002315
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002316 if (FLAG_log_timer_events) {
2317 FrameScope frame(this, StackFrame::MANUAL);
2318 PushSafepointRegisters();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002319 PrepareCallCFunction(1, eax);
2320 mov(Operand(esp, 0),
2321 Immediate(ExternalReference::isolate_address(isolate())));
2322 CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002323 PopSafepointRegisters();
2324 }
2325
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002326
2327 Label profiler_disabled;
2328 Label end_profiler_check;
2329 bool* is_profiling_flag =
2330 isolate()->cpu_profiler()->is_profiling_address();
2331 STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
2332 mov(eax, Immediate(reinterpret_cast<Address>(is_profiling_flag)));
2333 cmpb(Operand(eax, 0), 0);
2334 j(zero, &profiler_disabled);
2335
2336 // Additional parameter is the address of the actual getter function.
2337 mov(thunk_last_arg, Immediate(function_address));
2338 // Call the api function.
2339 call(thunk_address, RelocInfo::RUNTIME_ENTRY);
2340 jmp(&end_profiler_check);
2341
2342 bind(&profiler_disabled);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002343 // Call the api function.
2344 call(function_address, RelocInfo::RUNTIME_ENTRY);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002345 bind(&end_profiler_check);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002346
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002347 if (FLAG_log_timer_events) {
2348 FrameScope frame(this, StackFrame::MANUAL);
2349 PushSafepointRegisters();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002350 PrepareCallCFunction(1, eax);
2351 mov(Operand(esp, 0),
2352 Immediate(ExternalReference::isolate_address(isolate())));
2353 CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002354 PopSafepointRegisters();
2355 }
2356
lrn@chromium.org303ada72010-10-27 09:33:13 +00002357 Label prologue;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002358 // Load the value from ReturnValue
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002359 mov(eax, return_value_operand);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002360
lrn@chromium.org303ada72010-10-27 09:33:13 +00002361 Label promote_scheduled_exception;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002362 Label exception_handled;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002363 Label delete_allocated_handles;
2364 Label leave_exit_frame;
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00002365
lrn@chromium.org303ada72010-10-27 09:33:13 +00002366 bind(&prologue);
2367 // No more valid handles (the result handle was the last one). Restore
2368 // previous handle scope.
2369 mov(Operand::StaticVariable(next_address), ebx);
2370 sub(Operand::StaticVariable(level_address), Immediate(1));
danno@chromium.org59400602013-08-13 17:09:37 +00002371 Assert(above_equal, kInvalidHandleScopeLevel);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002372 cmp(edi, Operand::StaticVariable(limit_address));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002373 j(not_equal, &delete_allocated_handles);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002374 bind(&leave_exit_frame);
kmillikin@chromium.org2d5475f2009-12-20 18:15:52 +00002375
lrn@chromium.org303ada72010-10-27 09:33:13 +00002376 // Check if the function scheduled an exception.
2377 ExternalReference scheduled_exception_address =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002378 ExternalReference::scheduled_exception_address(isolate());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002379 cmp(Operand::StaticVariable(scheduled_exception_address),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002380 Immediate(isolate()->factory()->the_hole_value()));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002381 j(not_equal, &promote_scheduled_exception);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002382 bind(&exception_handled);
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00002383
2384#if ENABLE_EXTRA_CHECKS
2385 // Check if the function returned a valid JavaScript value.
2386 Label ok;
2387 Register return_value = eax;
2388 Register map = ecx;
2389
2390 JumpIfSmi(return_value, &ok, Label::kNear);
2391 mov(map, FieldOperand(return_value, HeapObject::kMapOffset));
2392
2393 CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2394 j(below, &ok, Label::kNear);
2395
2396 CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2397 j(above_equal, &ok, Label::kNear);
2398
2399 cmp(map, isolate()->factory()->heap_number_map());
2400 j(equal, &ok, Label::kNear);
2401
2402 cmp(return_value, isolate()->factory()->undefined_value());
2403 j(equal, &ok, Label::kNear);
2404
2405 cmp(return_value, isolate()->factory()->true_value());
2406 j(equal, &ok, Label::kNear);
2407
2408 cmp(return_value, isolate()->factory()->false_value());
2409 j(equal, &ok, Label::kNear);
2410
2411 cmp(return_value, isolate()->factory()->null_value());
2412 j(equal, &ok, Label::kNear);
2413
danno@chromium.org59400602013-08-13 17:09:37 +00002414 Abort(kAPICallReturnedInvalidObject);
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00002415
2416 bind(&ok);
2417#endif
2418
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002419 bool restore_context = context_restore_operand != NULL;
2420 if (restore_context) {
2421 mov(esi, *context_restore_operand);
2422 }
2423 LeaveApiExitFrame(!restore_context);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002424 ret(stack_space * kPointerSize);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002425
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00002426 bind(&promote_scheduled_exception);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002427 {
2428 FrameScope frame(this, StackFrame::INTERNAL);
2429 CallRuntime(Runtime::kPromoteScheduledException, 0);
2430 }
2431 jmp(&exception_handled);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00002432
lrn@chromium.org303ada72010-10-27 09:33:13 +00002433 // HandleScope limit has changed. Delete allocated extensions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002434 ExternalReference delete_extensions =
2435 ExternalReference::delete_handle_scope_extensions(isolate());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002436 bind(&delete_allocated_handles);
2437 mov(Operand::StaticVariable(limit_address), edi);
2438 mov(edi, eax);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002439 mov(Operand(esp, 0),
2440 Immediate(ExternalReference::isolate_address(isolate())));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002441 mov(eax, Immediate(delete_extensions));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002442 call(eax);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002443 mov(eax, edi);
2444 jmp(&leave_exit_frame);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002445}
2446
2447
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002448void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002449 // Set the entry point and jump to the C entry runtime stub.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002450 mov(ebx, Immediate(ext));
ager@chromium.orga1645e22009-09-09 19:27:10 +00002451 CEntryStub ces(1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002452 jmp(ces.GetCode(isolate()), RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002453}
2454
2455
danno@chromium.org40cb8782011-05-25 07:58:50 +00002456void MacroAssembler::SetCallKind(Register dst, CallKind call_kind) {
2457 // This macro takes the dst register to make the code more readable
2458 // at the call sites. However, the dst register has to be ecx to
2459 // follow the calling convention which requires the call type to be
2460 // in ecx.
2461 ASSERT(dst.is(ecx));
2462 if (call_kind == CALL_AS_FUNCTION) {
2463 // Set to some non-zero smi by updating the least significant
2464 // byte.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002465 mov_b(dst, 1 << kSmiTagSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002466 } else {
2467 // Set to smi zero by clearing the register.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002468 xor_(dst, dst);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002469 }
2470}
2471
2472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002473void MacroAssembler::InvokePrologue(const ParameterCount& expected,
2474 const ParameterCount& actual,
2475 Handle<Code> code_constant,
2476 const Operand& code_operand,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002477 Label* done,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002478 bool* definitely_mismatches,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002479 InvokeFlag flag,
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002480 Label::Distance done_near,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002481 const CallWrapper& call_wrapper,
2482 CallKind call_kind) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483 bool definitely_matches = false;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002484 *definitely_mismatches = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002485 Label invoke;
2486 if (expected.is_immediate()) {
2487 ASSERT(actual.is_immediate());
2488 if (expected.immediate() == actual.immediate()) {
2489 definitely_matches = true;
2490 } else {
2491 mov(eax, actual.immediate());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002492 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
2493 if (expected.immediate() == sentinel) {
2494 // Don't worry about adapting arguments for builtins that
2495 // don't want that done. Skip adaption code by making it look
2496 // like we have a match between expected and actual number of
2497 // arguments.
2498 definitely_matches = true;
2499 } else {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002500 *definitely_mismatches = true;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002501 mov(ebx, expected.immediate());
2502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002503 }
2504 } else {
2505 if (actual.is_immediate()) {
2506 // Expected is in register, actual is immediate. This is the
2507 // case when we invoke function values without going through the
2508 // IC mechanism.
2509 cmp(expected.reg(), actual.immediate());
2510 j(equal, &invoke);
2511 ASSERT(expected.reg().is(ebx));
2512 mov(eax, actual.immediate());
2513 } else if (!expected.reg().is(actual.reg())) {
2514 // Both expected and actual are in (different) registers. This
2515 // is the case when we invoke functions using call and apply.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002516 cmp(expected.reg(), actual.reg());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002517 j(equal, &invoke);
2518 ASSERT(actual.reg().is(eax));
2519 ASSERT(expected.reg().is(ebx));
2520 }
2521 }
2522
2523 if (!definitely_matches) {
2524 Handle<Code> adaptor =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002525 isolate()->builtins()->ArgumentsAdaptorTrampoline();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002526 if (!code_constant.is_null()) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002527 mov(edx, Immediate(code_constant));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002528 add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002529 } else if (!code_operand.is_reg(edx)) {
2530 mov(edx, code_operand);
2531 }
2532
2533 if (flag == CALL_FUNCTION) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002534 call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002535 SetCallKind(ecx, call_kind);
ager@chromium.org236ad962008-09-25 09:45:57 +00002536 call(adaptor, RelocInfo::CODE_TARGET);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002537 call_wrapper.AfterCall();
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002538 if (!*definitely_mismatches) {
2539 jmp(done, done_near);
2540 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002541 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002542 SetCallKind(ecx, call_kind);
ager@chromium.org236ad962008-09-25 09:45:57 +00002543 jmp(adaptor, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002544 }
2545 bind(&invoke);
2546 }
2547}
2548
2549
2550void MacroAssembler::InvokeCode(const Operand& code,
2551 const ParameterCount& expected,
2552 const ParameterCount& actual,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002553 InvokeFlag flag,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002554 const CallWrapper& call_wrapper,
2555 CallKind call_kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002556 // You can't call a function without a valid frame.
2557 ASSERT(flag == JUMP_FUNCTION || has_frame());
2558
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002559 Label done;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002560 bool definitely_mismatches = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002561 InvokePrologue(expected, actual, Handle<Code>::null(), code,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002562 &done, &definitely_mismatches, flag, Label::kNear,
2563 call_wrapper, call_kind);
2564 if (!definitely_mismatches) {
2565 if (flag == CALL_FUNCTION) {
2566 call_wrapper.BeforeCall(CallSize(code));
2567 SetCallKind(ecx, call_kind);
2568 call(code);
2569 call_wrapper.AfterCall();
2570 } else {
2571 ASSERT(flag == JUMP_FUNCTION);
2572 SetCallKind(ecx, call_kind);
2573 jmp(code);
2574 }
2575 bind(&done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002577}
2578
2579
2580void MacroAssembler::InvokeCode(Handle<Code> code,
2581 const ParameterCount& expected,
2582 const ParameterCount& actual,
ager@chromium.org236ad962008-09-25 09:45:57 +00002583 RelocInfo::Mode rmode,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002584 InvokeFlag flag,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002585 const CallWrapper& call_wrapper,
2586 CallKind call_kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002587 // You can't call a function without a valid frame.
2588 ASSERT(flag == JUMP_FUNCTION || has_frame());
2589
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002590 Label done;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002591 Operand dummy(eax, 0);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002592 bool definitely_mismatches = false;
2593 InvokePrologue(expected, actual, code, dummy, &done, &definitely_mismatches,
2594 flag, Label::kNear, call_wrapper, call_kind);
2595 if (!definitely_mismatches) {
2596 if (flag == CALL_FUNCTION) {
2597 call_wrapper.BeforeCall(CallSize(code, rmode));
2598 SetCallKind(ecx, call_kind);
2599 call(code, rmode);
2600 call_wrapper.AfterCall();
2601 } else {
2602 ASSERT(flag == JUMP_FUNCTION);
2603 SetCallKind(ecx, call_kind);
2604 jmp(code, rmode);
2605 }
2606 bind(&done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002607 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608}
2609
2610
2611void MacroAssembler::InvokeFunction(Register fun,
2612 const ParameterCount& actual,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002613 InvokeFlag flag,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002614 const CallWrapper& call_wrapper,
2615 CallKind call_kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002616 // You can't call a function without a valid frame.
2617 ASSERT(flag == JUMP_FUNCTION || has_frame());
2618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619 ASSERT(fun.is(edi));
2620 mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2621 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2622 mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002623 SmiUntag(ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002624
2625 ParameterCount expected(ebx);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00002626 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
danno@chromium.org40cb8782011-05-25 07:58:50 +00002627 expected, actual, flag, call_wrapper, call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002628}
2629
2630
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002631void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002632 const ParameterCount& expected,
ager@chromium.org5c838252010-02-19 08:53:10 +00002633 const ParameterCount& actual,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002634 InvokeFlag flag,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002635 const CallWrapper& call_wrapper,
2636 CallKind call_kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002637 // You can't call a function without a valid frame.
2638 ASSERT(flag == JUMP_FUNCTION || has_frame());
2639
ager@chromium.org5c838252010-02-19 08:53:10 +00002640 // Get the function and setup the context.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002641 LoadHeapObject(edi, function);
ager@chromium.org5c838252010-02-19 08:53:10 +00002642 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002643
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002644 // We call indirectly through the code field in the function to
2645 // allow recompilation to take effect without changing any of the
2646 // call sites.
2647 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2648 expected, actual, flag, call_wrapper, call_kind);
ager@chromium.org5c838252010-02-19 08:53:10 +00002649}
2650
2651
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002652void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
2653 InvokeFlag flag,
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002654 const CallWrapper& call_wrapper) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002655 // You can't call a builtin without a valid frame.
2656 ASSERT(flag == JUMP_FUNCTION || has_frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002657
2658 // Rely on the assertion to check that the number of provided
2659 // arguments match the expected number of arguments. Fake a
2660 // parameter count to avoid emitting code to do the check.
2661 ParameterCount expected(0);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00002662 GetBuiltinFunction(edi, id);
2663 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002664 expected, expected, flag, call_wrapper, CALL_AS_METHOD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002665}
2666
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002667
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00002668void MacroAssembler::GetBuiltinFunction(Register target,
2669 Builtins::JavaScript id) {
2670 // Load the JavaScript builtin function from the builtins object.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002671 mov(target, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00002672 mov(target, FieldOperand(target, GlobalObject::kBuiltinsOffset));
2673 mov(target, FieldOperand(target,
2674 JSBuiltinsObject::OffsetOfFunctionWithId(id)));
2675}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002677
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002678void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002679 ASSERT(!target.is(edi));
ager@chromium.org5c838252010-02-19 08:53:10 +00002680 // Load the JavaScript builtin function from the builtins object.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00002681 GetBuiltinFunction(edi, id);
2682 // Load the code entry point from the function into the target register.
2683 mov(target, FieldOperand(edi, JSFunction::kCodeEntryOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002684}
2685
2686
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002687void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2688 if (context_chain_length > 0) {
2689 // Move up the chain of contexts to the context containing the slot.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002690 mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX)));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002691 for (int i = 1; i < context_chain_length; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002692 mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002693 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002694 } else {
2695 // Slot is in the current function context. Move it into the
2696 // destination register in case we store into it (the write barrier
2697 // cannot be allowed to destroy the context in esi).
2698 mov(dst, esi);
2699 }
2700
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002701 // We should not have found a with context by walking the context chain
2702 // (i.e., the static scope chain and runtime context chain do not agree).
2703 // A variable occurring in such a scope should have slot type LOOKUP and
2704 // not CONTEXT.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002705 if (emit_debug_code()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002706 cmp(FieldOperand(dst, HeapObject::kMapOffset),
2707 isolate()->factory()->with_context_map());
danno@chromium.org59400602013-08-13 17:09:37 +00002708 Check(not_equal, kVariableResolvedToWithContext);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002709 }
2710}
2711
2712
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00002713void MacroAssembler::LoadTransitionedArrayMapConditional(
2714 ElementsKind expected_kind,
2715 ElementsKind transitioned_kind,
2716 Register map_in_out,
2717 Register scratch,
2718 Label* no_map_match) {
2719 // Load the global or builtins object from the current context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002720 mov(scratch, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2721 mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00002722
2723 // Check that the function's map is the same as the expected cached map.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002724 mov(scratch, Operand(scratch,
2725 Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
2726
2727 size_t offset = expected_kind * kPointerSize +
2728 FixedArrayBase::kHeaderSize;
2729 cmp(map_in_out, FieldOperand(scratch, offset));
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00002730 j(not_equal, no_map_match);
2731
2732 // Use the transitioned cached map.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002733 offset = transitioned_kind * kPointerSize +
2734 FixedArrayBase::kHeaderSize;
2735 mov(map_in_out, FieldOperand(scratch, offset));
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00002736}
2737
2738
2739void MacroAssembler::LoadInitialArrayMap(
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002740 Register function_in, Register scratch,
2741 Register map_out, bool can_have_holes) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002742 ASSERT(!function_in.is(map_out));
2743 Label done;
2744 mov(map_out, FieldOperand(function_in,
2745 JSFunction::kPrototypeOrInitialMapOffset));
2746 if (!FLAG_smi_only_arrays) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002747 ElementsKind kind = can_have_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
2748 LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
2749 kind,
2750 map_out,
2751 scratch,
2752 &done);
2753 } else if (can_have_holes) {
2754 LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
2755 FAST_HOLEY_SMI_ELEMENTS,
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00002756 map_out,
2757 scratch,
2758 &done);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002759 }
2760 bind(&done);
2761}
2762
2763
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002764void MacroAssembler::LoadGlobalContext(Register global_context) {
2765 // Load the global or builtins object from the current context.
2766 mov(global_context,
2767 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2768 // Load the native context from the global or builtins object.
2769 mov(global_context,
2770 FieldOperand(global_context, GlobalObject::kNativeContextOffset));
2771}
2772
2773
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002774void MacroAssembler::LoadGlobalFunction(int index, Register function) {
2775 // Load the global or builtins object from the current context.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002776 mov(function,
2777 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2778 // Load the native context from the global or builtins object.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002779 mov(function,
2780 FieldOperand(function, GlobalObject::kNativeContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002781 // Load the function from the native context.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002782 mov(function, Operand(function, Context::SlotOffset(index)));
2783}
2784
2785
2786void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2787 Register map) {
2788 // Load the initial map. The global functions all have initial maps.
2789 mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002790 if (emit_debug_code()) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002791 Label ok, fail;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002792 CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002793 jmp(&ok);
2794 bind(&fail);
danno@chromium.org59400602013-08-13 17:09:37 +00002795 Abort(kGlobalFunctionsMustHaveInitialMap);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002796 bind(&ok);
2797 }
2798}
2799
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002800
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002801// Store the value in register src in the safepoint register stack
2802// slot for register dst.
2803void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) {
2804 mov(SafepointRegisterSlot(dst), src);
2805}
2806
2807
2808void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) {
2809 mov(SafepointRegisterSlot(dst), src);
2810}
2811
2812
2813void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
2814 mov(dst, SafepointRegisterSlot(src));
2815}
2816
2817
2818Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
2819 return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
2820}
2821
2822
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002823int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
2824 // The registers are pushed starting with the lowest encoding,
2825 // which means that lowest encodings are furthest away from
2826 // the stack pointer.
2827 ASSERT(reg_code >= 0 && reg_code < kNumSafepointRegisters);
2828 return kNumSafepointRegisters - reg_code - 1;
2829}
2830
2831
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002832void MacroAssembler::LoadHeapObject(Register result,
2833 Handle<HeapObject> object) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002834 AllowDeferredHandleDereference embedding_raw_address;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002835 if (isolate()->heap()->InNewSpace(*object)) {
danno@chromium.org41728482013-06-12 22:31:22 +00002836 Handle<Cell> cell = isolate()->factory()->NewCell(object);
2837 mov(result, Operand::ForCell(cell));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002838 } else {
2839 mov(result, object);
2840 }
2841}
2842
2843
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002844void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002845 AllowDeferredHandleDereference using_raw_address;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002846 if (isolate()->heap()->InNewSpace(*object)) {
danno@chromium.org41728482013-06-12 22:31:22 +00002847 Handle<Cell> cell = isolate()->factory()->NewCell(object);
2848 cmp(reg, Operand::ForCell(cell));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002849 } else {
2850 cmp(reg, object);
2851 }
2852}
2853
2854
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002855void MacroAssembler::PushHeapObject(Handle<HeapObject> object) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002856 AllowDeferredHandleDereference using_raw_address;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002857 if (isolate()->heap()->InNewSpace(*object)) {
danno@chromium.org41728482013-06-12 22:31:22 +00002858 Handle<Cell> cell = isolate()->factory()->NewCell(object);
2859 push(Operand::ForCell(cell));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002860 } else {
2861 Push(object);
2862 }
2863}
2864
2865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002866void MacroAssembler::Ret() {
2867 ret(0);
2868}
2869
2870
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002871void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
2872 if (is_uint16(bytes_dropped)) {
2873 ret(bytes_dropped);
2874 } else {
2875 pop(scratch);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002876 add(esp, Immediate(bytes_dropped));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002877 push(scratch);
2878 ret(0);
2879 }
2880}
2881
2882
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002883void MacroAssembler::VerifyX87StackDepth(uint32_t depth) {
2884 // Make sure the floating point stack is either empty or has depth items.
2885 ASSERT(depth <= 7);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002886 // This is very expensive.
2887 ASSERT(FLAG_debug_code && FLAG_enable_slow_asserts);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002888
2889 // The top-of-stack (tos) is 7 if there is one item pushed.
2890 int tos = (8 - depth) % 8;
2891 const int kTopMask = 0x3800;
2892 push(eax);
2893 fwait();
2894 fnstsw_ax();
2895 and_(eax, kTopMask);
2896 shr(eax, 11);
2897 cmp(eax, Immediate(tos));
danno@chromium.org59400602013-08-13 17:09:37 +00002898 Check(equal, kUnexpectedFPUStackDepthAfterInstruction);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002899 fnclex();
2900 pop(eax);
2901}
2902
2903
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002904void MacroAssembler::Drop(int stack_elements) {
2905 if (stack_elements > 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002906 add(esp, Immediate(stack_elements * kPointerSize));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00002907 }
2908}
2909
2910
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002911void MacroAssembler::Move(Register dst, Register src) {
2912 if (!dst.is(src)) {
2913 mov(dst, src);
2914 }
2915}
2916
2917
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002918void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
2919 if (FLAG_native_code_counters && counter->Enabled()) {
2920 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
2921 }
2922}
2923
2924
2925void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
2926 ASSERT(value > 0);
2927 if (FLAG_native_code_counters && counter->Enabled()) {
2928 Operand operand = Operand::StaticVariable(ExternalReference(counter));
2929 if (value == 1) {
2930 inc(operand);
2931 } else {
2932 add(operand, Immediate(value));
2933 }
2934 }
2935}
2936
2937
2938void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
2939 ASSERT(value > 0);
2940 if (FLAG_native_code_counters && counter->Enabled()) {
2941 Operand operand = Operand::StaticVariable(ExternalReference(counter));
2942 if (value == 1) {
2943 dec(operand);
2944 } else {
2945 sub(operand, Immediate(value));
2946 }
2947 }
2948}
2949
2950
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002951void MacroAssembler::IncrementCounter(Condition cc,
2952 StatsCounter* counter,
2953 int value) {
2954 ASSERT(value > 0);
2955 if (FLAG_native_code_counters && counter->Enabled()) {
2956 Label skip;
2957 j(NegateCondition(cc), &skip);
2958 pushfd();
2959 IncrementCounter(counter, value);
2960 popfd();
2961 bind(&skip);
2962 }
2963}
2964
2965
2966void MacroAssembler::DecrementCounter(Condition cc,
2967 StatsCounter* counter,
2968 int value) {
2969 ASSERT(value > 0);
2970 if (FLAG_native_code_counters && counter->Enabled()) {
2971 Label skip;
2972 j(NegateCondition(cc), &skip);
2973 pushfd();
2974 DecrementCounter(counter, value);
2975 popfd();
2976 bind(&skip);
2977 }
2978}
2979
2980
danno@chromium.org59400602013-08-13 17:09:37 +00002981void MacroAssembler::Assert(Condition cc, BailoutReason reason) {
2982 if (emit_debug_code()) Check(cc, reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002983}
2984
2985
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002986void MacroAssembler::AssertFastElements(Register elements) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002987 if (emit_debug_code()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002988 Factory* factory = isolate()->factory();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002989 Label ok;
2990 cmp(FieldOperand(elements, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002991 Immediate(factory->fixed_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002992 j(equal, &ok);
2993 cmp(FieldOperand(elements, HeapObject::kMapOffset),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002994 Immediate(factory->fixed_double_array_map()));
2995 j(equal, &ok);
2996 cmp(FieldOperand(elements, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002997 Immediate(factory->fixed_cow_array_map()));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002998 j(equal, &ok);
danno@chromium.org59400602013-08-13 17:09:37 +00002999 Abort(kJSObjectWithFastElementsMapHasSlowElements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00003000 bind(&ok);
3001 }
3002}
3003
3004
danno@chromium.org59400602013-08-13 17:09:37 +00003005void MacroAssembler::Check(Condition cc, BailoutReason reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003006 Label L;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003007 j(cc, &L);
danno@chromium.org59400602013-08-13 17:09:37 +00003008 Abort(reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009 // will not return here
3010 bind(&L);
3011}
3012
3013
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003014void MacroAssembler::CheckStackAlignment() {
3015 int frame_alignment = OS::ActivationFrameAlignment();
3016 int frame_alignment_mask = frame_alignment - 1;
3017 if (frame_alignment > kPointerSize) {
3018 ASSERT(IsPowerOf2(frame_alignment));
3019 Label alignment_as_expected;
3020 test(esp, Immediate(frame_alignment_mask));
3021 j(zero, &alignment_as_expected);
3022 // Abort if stack is not aligned.
3023 int3();
3024 bind(&alignment_as_expected);
3025 }
3026}
3027
3028
danno@chromium.org59400602013-08-13 17:09:37 +00003029void MacroAssembler::Abort(BailoutReason reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003030 // We want to pass the msg string like a smi to avoid GC
3031 // problems, however msg is not guaranteed to be aligned
3032 // properly. Instead, we pass an aligned pointer that is
ager@chromium.org32912102009-01-16 10:38:43 +00003033 // a proper v8 smi, but also pass the alignment difference
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034 // from the real pointer as a smi.
danno@chromium.org59400602013-08-13 17:09:37 +00003035 const char* msg = GetBailoutReason(reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003036 intptr_t p1 = reinterpret_cast<intptr_t>(msg);
3037 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
3038 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
3039#ifdef DEBUG
3040 if (msg != NULL) {
3041 RecordComment("Abort message: ");
3042 RecordComment(msg);
3043 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003044
3045 if (FLAG_trap_on_abort) {
3046 int3();
3047 return;
3048 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049#endif
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003051 push(eax);
3052 push(Immediate(p0));
3053 push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0))));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003054 // Disable stub call restrictions to always allow calls to abort.
3055 if (!has_frame_) {
3056 // We don't actually want to generate a pile of code for this, so just
3057 // claim there is a stack frame, without generating one.
3058 FrameScope scope(this, StackFrame::NONE);
3059 CallRuntime(Runtime::kAbort, 2);
3060 } else {
3061 CallRuntime(Runtime::kAbort, 2);
3062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003063 // will not return here
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003064 int3();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003065}
3066
3067
danno@chromium.org40cb8782011-05-25 07:58:50 +00003068void MacroAssembler::LoadInstanceDescriptors(Register map,
3069 Register descriptors) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003070 mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003071}
3072
3073
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003074void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
3075 mov(dst, FieldOperand(map, Map::kBitField3Offset));
3076 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
3077}
3078
3079
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003080void MacroAssembler::LoadPowerOf2(XMMRegister dst,
3081 Register scratch,
3082 int power) {
3083 ASSERT(is_uintn(power + HeapNumber::kExponentBias,
3084 HeapNumber::kExponentBits));
3085 mov(scratch, Immediate(power + HeapNumber::kExponentBias));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003086 movd(dst, scratch);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003087 psllq(dst, HeapNumber::kMantissaBits);
3088}
3089
3090
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003091void MacroAssembler::LookupNumberStringCache(Register object,
3092 Register result,
3093 Register scratch1,
3094 Register scratch2,
3095 Label* not_found) {
3096 // Use of registers. Register result is used as a temporary.
3097 Register number_string_cache = result;
3098 Register mask = scratch1;
3099 Register scratch = scratch2;
3100
3101 // Load the number string cache.
3102 LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
3103 // Make the hash mask from the length of the number string cache. It
3104 // contains two elements (number and string) for each cache entry.
3105 mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
3106 shr(mask, kSmiTagSize + 1); // Untag length and divide it by two.
3107 sub(mask, Immediate(1)); // Make mask.
3108
3109 // Calculate the entry in the number string cache. The hash value in the
3110 // number string cache for smis is just the smi value, and the hash for
3111 // doubles is the xor of the upper and lower words. See
3112 // Heap::GetNumberStringCache.
3113 Label smi_hash_calculated;
3114 Label load_result_from_cache;
3115 Label not_smi;
3116 STATIC_ASSERT(kSmiTag == 0);
3117 JumpIfNotSmi(object, &not_smi, Label::kNear);
3118 mov(scratch, object);
3119 SmiUntag(scratch);
3120 jmp(&smi_hash_calculated, Label::kNear);
3121 bind(&not_smi);
3122 cmp(FieldOperand(object, HeapObject::kMapOffset),
3123 isolate()->factory()->heap_number_map());
3124 j(not_equal, not_found);
3125 STATIC_ASSERT(8 == kDoubleSize);
3126 mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
3127 xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
3128 // Object is heap number and hash is now in scratch. Calculate cache index.
3129 and_(scratch, mask);
3130 Register index = scratch;
3131 Register probe = mask;
3132 mov(probe,
3133 FieldOperand(number_string_cache,
3134 index,
3135 times_twice_pointer_size,
3136 FixedArray::kHeaderSize));
3137 JumpIfSmi(probe, not_found);
3138 if (CpuFeatures::IsSupported(SSE2)) {
3139 CpuFeatureScope fscope(this, SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003140 movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003141 ucomisd(xmm0, FieldOperand(probe, HeapNumber::kValueOffset));
3142 } else {
3143 fld_d(FieldOperand(object, HeapNumber::kValueOffset));
3144 fld_d(FieldOperand(probe, HeapNumber::kValueOffset));
3145 FCmp();
3146 }
3147 j(parity_even, not_found); // Bail out if NaN is involved.
3148 j(not_equal, not_found); // The cache did not contain this value.
3149 jmp(&load_result_from_cache, Label::kNear);
3150
3151 bind(&smi_hash_calculated);
3152 // Object is smi and hash is now in scratch. Calculate cache index.
3153 and_(scratch, mask);
3154 // Check if the entry is the smi we are looking for.
3155 cmp(object,
3156 FieldOperand(number_string_cache,
3157 index,
3158 times_twice_pointer_size,
3159 FixedArray::kHeaderSize));
3160 j(not_equal, not_found);
3161
3162 // Get the result from the cache.
3163 bind(&load_result_from_cache);
3164 mov(result,
3165 FieldOperand(number_string_cache,
3166 index,
3167 times_twice_pointer_size,
3168 FixedArray::kHeaderSize + kPointerSize));
3169 IncrementCounter(isolate()->counters()->number_to_string_native(), 1);
3170}
3171
3172
ager@chromium.org5c838252010-02-19 08:53:10 +00003173void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(
3174 Register instance_type,
3175 Register scratch,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00003176 Label* failure) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003177 if (!scratch.is(instance_type)) {
3178 mov(scratch, instance_type);
3179 }
3180 and_(scratch,
3181 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003182 cmp(scratch, kStringTag | kSeqStringTag | kOneByteStringTag);
ager@chromium.org5c838252010-02-19 08:53:10 +00003183 j(not_equal, failure);
3184}
3185
3186
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003187void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
3188 Register object2,
3189 Register scratch1,
3190 Register scratch2,
3191 Label* failure) {
3192 // Check that both objects are not smis.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003193 STATIC_ASSERT(kSmiTag == 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003194 mov(scratch1, object1);
3195 and_(scratch1, object2);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003196 JumpIfSmi(scratch1, failure);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003197
3198 // Load instance type for both strings.
3199 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
3200 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
3201 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
3202 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
3203
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003204 // Check that both are flat ASCII strings.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00003205 const int kFlatAsciiStringMask =
3206 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00003207 const int kFlatAsciiStringTag =
3208 kStringTag | kOneByteStringTag | kSeqStringTag;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003209 // Interleave bits from both instance types and compare them in one check.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00003210 ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003211 and_(scratch1, kFlatAsciiStringMask);
3212 and_(scratch2, kFlatAsciiStringMask);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00003213 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
3214 cmp(scratch1, kFlatAsciiStringTag | (kFlatAsciiStringTag << 3));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003215 j(not_equal, failure);
3216}
3217
3218
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003219void MacroAssembler::JumpIfNotUniqueName(Operand operand,
3220 Label* not_unique_name,
3221 Label::Distance distance) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003222 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
3223 Label succeed;
3224 test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
3225 j(zero, &succeed);
3226 cmpb(operand, static_cast<uint8_t>(SYMBOL_TYPE));
3227 j(not_equal, not_unique_name, distance);
3228
3229 bind(&succeed);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003230}
3231
3232
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003233void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003234 int frame_alignment = OS::ActivationFrameAlignment();
3235 if (frame_alignment != 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003236 // Make stack end at alignment and make room for num_arguments words
3237 // and the original value of esp.
3238 mov(scratch, esp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003239 sub(esp, Immediate((num_arguments + 1) * kPointerSize));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003240 ASSERT(IsPowerOf2(frame_alignment));
3241 and_(esp, -frame_alignment);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003242 mov(Operand(esp, num_arguments * kPointerSize), scratch);
3243 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003244 sub(esp, Immediate(num_arguments * kPointerSize));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003245 }
3246}
3247
3248
3249void MacroAssembler::CallCFunction(ExternalReference function,
3250 int num_arguments) {
3251 // Trashing eax is ok as it will be the return value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003252 mov(eax, Immediate(function));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003253 CallCFunction(eax, num_arguments);
3254}
3255
3256
3257void MacroAssembler::CallCFunction(Register function,
3258 int num_arguments) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003259 ASSERT(has_frame());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003260 // Check stack alignment.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003261 if (emit_debug_code()) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003262 CheckStackAlignment();
3263 }
3264
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003265 call(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003266 if (OS::ActivationFrameAlignment() != 0) {
3267 mov(esp, Operand(esp, num_arguments * kPointerSize));
3268 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003269 add(esp, Immediate(num_arguments * kPointerSize));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003270 }
3271}
3272
3273
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003274bool AreAliased(Register r1, Register r2, Register r3, Register r4) {
3275 if (r1.is(r2)) return true;
3276 if (r1.is(r3)) return true;
3277 if (r1.is(r4)) return true;
3278 if (r2.is(r3)) return true;
3279 if (r2.is(r4)) return true;
3280 if (r3.is(r4)) return true;
3281 return false;
3282}
3283
3284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003285CodePatcher::CodePatcher(byte* address, int size)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003286 : address_(address),
3287 size_(size),
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003288 masm_(NULL, address, size + Assembler::kGap) {
ager@chromium.org32912102009-01-16 10:38:43 +00003289 // Create a new macro assembler pointing to the address of the code to patch.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003290 // The size is adjusted with kGap on order for the assembler to generate size
3291 // bytes of instructions without failing with buffer size constraints.
3292 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3293}
3294
3295
3296CodePatcher::~CodePatcher() {
3297 // Indicate that code has changed.
3298 CPU::FlushICache(address_, size_);
3299
3300 // Check that the code was patched as expected.
3301 ASSERT(masm_.pc_ == address_ + size_);
3302 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3303}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003304
3305
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003306void MacroAssembler::CheckPageFlag(
3307 Register object,
3308 Register scratch,
3309 int mask,
3310 Condition cc,
3311 Label* condition_met,
3312 Label::Distance condition_met_distance) {
3313 ASSERT(cc == zero || cc == not_zero);
3314 if (scratch.is(object)) {
3315 and_(scratch, Immediate(~Page::kPageAlignmentMask));
3316 } else {
3317 mov(scratch, Immediate(~Page::kPageAlignmentMask));
3318 and_(scratch, object);
3319 }
3320 if (mask < (1 << kBitsPerByte)) {
3321 test_b(Operand(scratch, MemoryChunk::kFlagsOffset),
3322 static_cast<uint8_t>(mask));
3323 } else {
3324 test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
3325 }
3326 j(cc, condition_met, condition_met_distance);
3327}
3328
3329
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003330void MacroAssembler::CheckPageFlagForMap(
3331 Handle<Map> map,
3332 int mask,
3333 Condition cc,
3334 Label* condition_met,
3335 Label::Distance condition_met_distance) {
3336 ASSERT(cc == zero || cc == not_zero);
3337 Page* page = Page::FromAddress(map->address());
3338 ExternalReference reference(ExternalReference::page_flags(page));
3339 // The inlined static address check of the page's flags relies
3340 // on maps never being compacted.
3341 ASSERT(!isolate()->heap()->mark_compact_collector()->
3342 IsOnEvacuationCandidate(*map));
3343 if (mask < (1 << kBitsPerByte)) {
3344 test_b(Operand::StaticVariable(reference), static_cast<uint8_t>(mask));
3345 } else {
3346 test(Operand::StaticVariable(reference), Immediate(mask));
3347 }
3348 j(cc, condition_met, condition_met_distance);
3349}
3350
3351
danno@chromium.orgf005df62013-04-30 16:36:45 +00003352void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
3353 Register scratch,
3354 Label* if_deprecated) {
3355 if (map->CanBeDeprecated()) {
3356 mov(scratch, map);
3357 mov(scratch, FieldOperand(scratch, Map::kBitField3Offset));
3358 and_(scratch, Immediate(Smi::FromInt(Map::Deprecated::kMask)));
3359 j(not_zero, if_deprecated);
3360 }
3361}
3362
3363
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003364void MacroAssembler::JumpIfBlack(Register object,
3365 Register scratch0,
3366 Register scratch1,
3367 Label* on_black,
3368 Label::Distance on_black_near) {
3369 HasColor(object, scratch0, scratch1,
3370 on_black, on_black_near,
3371 1, 0); // kBlackBitPattern.
3372 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
3373}
3374
3375
3376void MacroAssembler::HasColor(Register object,
3377 Register bitmap_scratch,
3378 Register mask_scratch,
3379 Label* has_color,
3380 Label::Distance has_color_distance,
3381 int first_bit,
3382 int second_bit) {
3383 ASSERT(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
3384
3385 GetMarkBits(object, bitmap_scratch, mask_scratch);
3386
3387 Label other_color, word_boundary;
3388 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3389 j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear);
3390 add(mask_scratch, mask_scratch); // Shift left 1 by adding.
3391 j(zero, &word_boundary, Label::kNear);
3392 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3393 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
3394 jmp(&other_color, Label::kNear);
3395
3396 bind(&word_boundary);
3397 test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), 1);
3398
3399 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
3400 bind(&other_color);
3401}
3402
3403
3404void MacroAssembler::GetMarkBits(Register addr_reg,
3405 Register bitmap_reg,
3406 Register mask_reg) {
3407 ASSERT(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx));
3408 mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask));
3409 and_(bitmap_reg, addr_reg);
3410 mov(ecx, addr_reg);
3411 int shift =
3412 Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
3413 shr(ecx, shift);
3414 and_(ecx,
3415 (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
3416
3417 add(bitmap_reg, ecx);
3418 mov(ecx, addr_reg);
3419 shr(ecx, kPointerSizeLog2);
3420 and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
3421 mov(mask_reg, Immediate(1));
3422 shl_cl(mask_reg);
3423}
3424
3425
3426void MacroAssembler::EnsureNotWhite(
3427 Register value,
3428 Register bitmap_scratch,
3429 Register mask_scratch,
3430 Label* value_is_white_and_not_data,
3431 Label::Distance distance) {
3432 ASSERT(!AreAliased(value, bitmap_scratch, mask_scratch, ecx));
3433 GetMarkBits(value, bitmap_scratch, mask_scratch);
3434
3435 // If the value is black or grey we don't need to do anything.
3436 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0);
3437 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
3438 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0);
3439 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
3440
3441 Label done;
3442
3443 // Since both black and grey have a 1 in the first position and white does
3444 // not have a 1 there we only need to check one bit.
3445 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3446 j(not_zero, &done, Label::kNear);
3447
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003448 if (emit_debug_code()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003449 // Check for impossible bit pattern.
3450 Label ok;
3451 push(mask_scratch);
3452 // shl. May overflow making the check conservative.
3453 add(mask_scratch, mask_scratch);
3454 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3455 j(zero, &ok, Label::kNear);
3456 int3();
3457 bind(&ok);
3458 pop(mask_scratch);
3459 }
3460
3461 // Value is white. We check whether it is data that doesn't need scanning.
3462 // Currently only checks for HeapNumber and non-cons strings.
3463 Register map = ecx; // Holds map while checking type.
3464 Register length = ecx; // Holds length of object after checking type.
3465 Label not_heap_number;
3466 Label is_data_object;
3467
3468 // Check for heap-number
3469 mov(map, FieldOperand(value, HeapObject::kMapOffset));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003470 cmp(map, isolate()->factory()->heap_number_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003471 j(not_equal, &not_heap_number, Label::kNear);
3472 mov(length, Immediate(HeapNumber::kSize));
3473 jmp(&is_data_object, Label::kNear);
3474
3475 bind(&not_heap_number);
3476 // Check for strings.
3477 ASSERT(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
3478 ASSERT(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
3479 // If it's a string and it's not a cons string then it's an object containing
3480 // no GC pointers.
3481 Register instance_type = ecx;
3482 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
3483 test_b(instance_type, kIsIndirectStringMask | kIsNotStringMask);
3484 j(not_zero, value_is_white_and_not_data);
3485 // It's a non-indirect (non-cons and non-slice) string.
3486 // If it's external, the length is just ExternalString::kSize.
3487 // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
3488 Label not_external;
3489 // External strings are the only ones with the kExternalStringTag bit
3490 // set.
3491 ASSERT_EQ(0, kSeqStringTag & kExternalStringTag);
3492 ASSERT_EQ(0, kConsStringTag & kExternalStringTag);
3493 test_b(instance_type, kExternalStringTag);
3494 j(zero, &not_external, Label::kNear);
3495 mov(length, Immediate(ExternalString::kSize));
3496 jmp(&is_data_object, Label::kNear);
3497
3498 bind(&not_external);
3499 // Sequential string, either ASCII or UC16.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003500 ASSERT(kOneByteStringTag == 0x04);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003501 and_(length, Immediate(kStringEncodingMask));
3502 xor_(length, Immediate(kStringEncodingMask));
3503 add(length, Immediate(0x04));
3504 // Value now either 4 (if ASCII) or 8 (if UC16), i.e., char-size shifted
3505 // by 2. If we multiply the string length as smi by this, it still
3506 // won't overflow a 32-bit value.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003507 ASSERT_EQ(SeqOneByteString::kMaxSize, SeqTwoByteString::kMaxSize);
3508 ASSERT(SeqOneByteString::kMaxSize <=
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003509 static_cast<int>(0xffffffffu >> (2 + kSmiTagSize)));
3510 imul(length, FieldOperand(value, String::kLengthOffset));
3511 shr(length, 2 + kSmiTagSize + kSmiShiftSize);
3512 add(length, Immediate(SeqString::kHeaderSize + kObjectAlignmentMask));
3513 and_(length, Immediate(~kObjectAlignmentMask));
3514
3515 bind(&is_data_object);
3516 // Value is a data object, and it is white. Mark it black. Since we know
3517 // that the object is white we can make it black by flipping one bit.
3518 or_(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch);
3519
3520 and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask));
3521 add(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset),
3522 length);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003523 if (emit_debug_code()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003524 mov(length, Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
3525 cmp(length, Operand(bitmap_scratch, MemoryChunk::kSizeOffset));
danno@chromium.org59400602013-08-13 17:09:37 +00003526 Check(less_equal, kLiveBytesCountOverflowChunkSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003527 }
3528
3529 bind(&done);
3530}
3531
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003532
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003533void MacroAssembler::EnumLength(Register dst, Register map) {
3534 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
3535 mov(dst, FieldOperand(map, Map::kBitField3Offset));
3536 and_(dst, Immediate(Smi::FromInt(Map::EnumLengthBits::kMask)));
3537}
3538
3539
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003540void MacroAssembler::CheckEnumCache(Label* call_runtime) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003541 Label next, start;
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003542 mov(ecx, eax);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003543
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003544 // Check if the enum length field is properly initialized, indicating that
3545 // there is an enum cache.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003546 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003547
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003548 EnumLength(edx, ebx);
3549 cmp(edx, Immediate(Smi::FromInt(Map::kInvalidEnumCache)));
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003550 j(equal, call_runtime);
3551
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003552 jmp(&start);
3553
3554 bind(&next);
3555 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003556
3557 // For all objects but the receiver, check that the cache is empty.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003558 EnumLength(edx, ebx);
3559 cmp(edx, Immediate(Smi::FromInt(0)));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003560 j(not_equal, call_runtime);
3561
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003562 bind(&start);
3563
3564 // Check that there are no elements. Register rcx contains the current JS
3565 // object we've reached through the prototype chain.
3566 mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
3567 cmp(ecx, isolate()->factory()->empty_fixed_array());
3568 j(not_equal, call_runtime);
3569
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00003570 mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
3571 cmp(ecx, isolate()->factory()->null_value());
3572 j(not_equal, &next);
3573}
3574
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003575
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003576void MacroAssembler::TestJSArrayForAllocationMemento(
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003577 Register receiver_reg,
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00003578 Register scratch_reg,
3579 Label* no_memento_found) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003580 ExternalReference new_space_start =
3581 ExternalReference::new_space_start(isolate());
3582 ExternalReference new_space_allocation_top =
3583 ExternalReference::new_space_allocation_top_address(isolate());
3584
3585 lea(scratch_reg, Operand(receiver_reg,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003586 JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003587 cmp(scratch_reg, Immediate(new_space_start));
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00003588 j(less, no_memento_found);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003589 cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00003590 j(greater, no_memento_found);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003591 cmp(MemOperand(scratch_reg, -AllocationMemento::kSize),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003592 Immediate(isolate()->factory()->allocation_memento_map()));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003593}
3594
3595
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003596void MacroAssembler::JumpIfDictionaryInPrototypeChain(
3597 Register object,
3598 Register scratch0,
3599 Register scratch1,
3600 Label* found) {
3601 ASSERT(!scratch1.is(scratch0));
3602 Factory* factory = isolate()->factory();
3603 Register current = scratch0;
3604 Label loop_again;
3605
3606 // scratch contained elements pointer.
3607 mov(current, object);
3608
3609 // Loop based on the map going up the prototype chain.
3610 bind(&loop_again);
3611 mov(current, FieldOperand(current, HeapObject::kMapOffset));
3612 mov(scratch1, FieldOperand(current, Map::kBitField2Offset));
3613 and_(scratch1, Map::kElementsKindMask);
3614 shr(scratch1, Map::kElementsKindShift);
3615 cmp(scratch1, Immediate(DICTIONARY_ELEMENTS));
3616 j(equal, found);
3617 mov(current, FieldOperand(current, Map::kPrototypeOffset));
3618 cmp(current, Immediate(factory->null_value()));
3619 j(not_equal, &loop_again);
3620}
3621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003623
3624#endif // V8_TARGET_ARCH_IA32