blob: 5e39cb62c5e9088ab4be1f878191c0fab1449859 [file] [log] [blame]
ager@chromium.org5ec48922009-05-05 07:25:34 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
kasperl@chromium.org71affb52009-05-26 05:44:31 +000028#include "v8.h"
29
30#include "bootstrapper.h"
31#include "codegen-inl.h"
ager@chromium.orgeadaf222009-06-16 09:43:10 +000032#include "assembler-x64.h"
ager@chromium.orge2902be2009-06-08 12:21:35 +000033#include "macro-assembler-x64.h"
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000034#include "serialize.h"
ager@chromium.orgeadaf222009-06-16 09:43:10 +000035#include "debug.h"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036
37namespace v8 {
38namespace internal {
39
40MacroAssembler::MacroAssembler(void* buffer, int size)
41 : Assembler(buffer, size),
42 unresolved_(0),
43 generating_stub_(false),
44 allow_stub_calls_(true),
45 code_object_(Heap::undefined_value()) {
46}
47
ager@chromium.orge2902be2009-06-08 12:21:35 +000048
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +000049
50static void RecordWriteHelper(MacroAssembler* masm,
51 Register object,
52 Register addr,
53 Register scratch) {
54 Label fast;
55
56 // Compute the page address from the heap object pointer, leave it
57 // in 'object'.
58 ASSERT(is_int32(~Page::kPageAlignmentMask));
59 masm->and_(object,
60 Immediate(static_cast<int32_t>(~Page::kPageAlignmentMask)));
61
62 // Compute the bit addr in the remembered set, leave it in "addr".
63 masm->subq(addr, object);
64 masm->shr(addr, Immediate(kPointerSizeLog2));
65
66 // If the bit offset lies beyond the normal remembered set range, it is in
67 // the extra remembered set area of a large object.
68 masm->cmpq(addr, Immediate(Page::kPageSize / kPointerSize));
69 masm->j(less, &fast);
70
71 // Adjust 'addr' to be relative to the start of the extra remembered set
72 // and the page address in 'object' to be the address of the extra
73 // remembered set.
74 masm->subq(addr, Immediate(Page::kPageSize / kPointerSize));
75 // Load the array length into 'scratch'.
76 masm->movl(scratch,
77 Operand(object,
78 Page::kObjectStartOffset + FixedArray::kLengthOffset));
79 // Extra remembered set starts right after FixedArray.
80 // Add the page header, array header, and array body size
81 // (length * pointer size) to the page address to find the extra remembered
82 // set start.
83 masm->lea(object,
84 Operand(object, scratch, times_pointer_size,
85 Page::kObjectStartOffset + FixedArray::kHeaderSize));
86
87 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
88 // to limit code size. We should probably evaluate this decision by
89 // measuring the performance of an equivalent implementation using
90 // "simpler" instructions
91 masm->bind(&fast);
92 masm->bts(Operand(object, Page::kRSetOffset), addr);
93}
94
95
96class RecordWriteStub : public CodeStub {
97 public:
98 RecordWriteStub(Register object, Register addr, Register scratch)
99 : object_(object), addr_(addr), scratch_(scratch) { }
100
101 void Generate(MacroAssembler* masm);
102
103 private:
104 Register object_;
105 Register addr_;
106 Register scratch_;
107
108#ifdef DEBUG
109 void Print() {
110 PrintF("RecordWriteStub (object reg %d), (addr reg %d), (scratch reg %d)\n",
111 object_.code(), addr_.code(), scratch_.code());
112 }
113#endif
114
115 // Minor key encoding in 12 bits of three registers (object, address and
116 // scratch) OOOOAAAASSSS.
117 class ScratchBits: public BitField<uint32_t, 0, 4> {};
118 class AddressBits: public BitField<uint32_t, 4, 4> {};
119 class ObjectBits: public BitField<uint32_t, 8, 4> {};
120
121 Major MajorKey() { return RecordWrite; }
122
123 int MinorKey() {
124 // Encode the registers.
125 return ObjectBits::encode(object_.code()) |
126 AddressBits::encode(addr_.code()) |
127 ScratchBits::encode(scratch_.code());
128 }
129};
130
131
132void RecordWriteStub::Generate(MacroAssembler* masm) {
133 RecordWriteHelper(masm, object_, addr_, scratch_);
134 masm->ret(0);
135}
136
137
138// Set the remembered set bit for [object+offset].
139// object is the object being stored into, value is the object being stored.
140// If offset is zero, then the scratch register contains the array index into
141// the elements array represented as a Smi.
142// All registers are clobbered by the operation.
143void MacroAssembler::RecordWrite(Register object,
144 int offset,
145 Register value,
146 Register scratch) {
147 // First, check if a remembered set write is even needed. The tests below
148 // catch stores of Smis and stores into young gen (which does not have space
149 // for the remembered set bits.
150 Label done;
151
152 // Test that the object address is not in the new space. We cannot
153 // set remembered set bits in the new space.
154 movq(value, object);
155 ASSERT(is_int32(static_cast<int64_t>(Heap::NewSpaceMask())));
156 and_(value, Immediate(static_cast<int32_t>(Heap::NewSpaceMask())));
157 movq(kScratchRegister, ExternalReference::new_space_start());
158 cmpq(value, kScratchRegister);
159 j(equal, &done);
160
161 if ((offset > 0) && (offset < Page::kMaxHeapObjectSize)) {
162 // Compute the bit offset in the remembered set, leave it in 'value'.
163 lea(value, Operand(object, offset));
164 ASSERT(is_int32(Page::kPageAlignmentMask));
165 and_(value, Immediate(static_cast<int32_t>(Page::kPageAlignmentMask)));
166 shr(value, Immediate(kObjectAlignmentBits));
167
168 // Compute the page address from the heap object pointer, leave it in
169 // 'object' (immediate value is sign extended).
170 and_(object, Immediate(~Page::kPageAlignmentMask));
171
172 // NOTE: For now, we use the bit-test-and-set (bts) x86 instruction
173 // to limit code size. We should probably evaluate this decision by
174 // measuring the performance of an equivalent implementation using
175 // "simpler" instructions
176 bts(Operand(object, Page::kRSetOffset), value);
177 } else {
178 Register dst = scratch;
179 if (offset != 0) {
180 lea(dst, Operand(object, offset));
181 } else {
182 // array access: calculate the destination address in the same manner as
183 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 4 to get an offset
184 // into an array of words.
185 lea(dst, Operand(object, dst, times_half_pointer_size,
186 FixedArray::kHeaderSize - kHeapObjectTag));
187 }
188 // If we are already generating a shared stub, not inlining the
189 // record write code isn't going to save us any memory.
190 if (generating_stub()) {
191 RecordWriteHelper(this, object, dst, value);
192 } else {
193 RecordWriteStub stub(object, dst, value);
194 CallStub(&stub);
195 }
196 }
197
198 bind(&done);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000199}
200
201
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000202void MacroAssembler::Assert(Condition cc, const char* msg) {
203 if (FLAG_debug_code) Check(cc, msg);
204}
205
206
207void MacroAssembler::Check(Condition cc, const char* msg) {
208 Label L;
209 j(cc, &L);
210 Abort(msg);
211 // will not return here
212 bind(&L);
213}
214
215
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000216void MacroAssembler::NegativeZeroTest(Register result,
217 Register op,
218 Label* then_label) {
219 Label ok;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000220 testl(result, result);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000221 j(not_zero, &ok);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000222 testl(op, op);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000223 j(sign, then_label);
224 bind(&ok);
225}
226
227
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000228void MacroAssembler::Abort(const char* msg) {
229 // We want to pass the msg string like a smi to avoid GC
230 // problems, however msg is not guaranteed to be aligned
231 // properly. Instead, we pass an aligned pointer that is
232 // a proper v8 smi, but also pass the alignment difference
233 // from the real pointer as a smi.
234 intptr_t p1 = reinterpret_cast<intptr_t>(msg);
235 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
236 // Note: p0 might not be a valid Smi *value*, but it has a valid Smi tag.
237 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
238#ifdef DEBUG
239 if (msg != NULL) {
240 RecordComment("Abort message: ");
241 RecordComment(msg);
242 }
243#endif
244 push(rax);
245 movq(kScratchRegister, p0, RelocInfo::NONE);
246 push(kScratchRegister);
247 movq(kScratchRegister,
248 reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0)),
249 RelocInfo::NONE);
250 push(kScratchRegister);
251 CallRuntime(Runtime::kAbort, 2);
252 // will not return here
253}
254
255
256void MacroAssembler::CallStub(CodeStub* stub) {
257 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
258 movq(kScratchRegister, stub->GetCode(), RelocInfo::CODE_TARGET);
259 call(kScratchRegister);
260}
261
262
263void MacroAssembler::StubReturn(int argc) {
264 ASSERT(argc >= 1 && generating_stub());
265 ret((argc - 1) * kPointerSize);
266}
267
268
269void MacroAssembler::IllegalOperation(int num_arguments) {
270 if (num_arguments > 0) {
271 addq(rsp, Immediate(num_arguments * kPointerSize));
272 }
273 movq(rax, Factory::undefined_value(), RelocInfo::EMBEDDED_OBJECT);
274}
275
276
277void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
278 CallRuntime(Runtime::FunctionForId(id), num_arguments);
279}
280
281
282void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
283 // If the expected number of arguments of the runtime function is
284 // constant, we check that the actual number of arguments match the
285 // expectation.
286 if (f->nargs >= 0 && f->nargs != num_arguments) {
287 IllegalOperation(num_arguments);
288 return;
289 }
290
291 Runtime::FunctionId function_id =
292 static_cast<Runtime::FunctionId>(f->stub_id);
293 RuntimeStub stub(function_id, num_arguments);
294 CallStub(&stub);
295}
296
297
298void MacroAssembler::TailCallRuntime(ExternalReference const& ext,
299 int num_arguments) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000300 // ----------- S t a t e -------------
301 // -- rsp[0] : return address
302 // -- rsp[8] : argument num_arguments - 1
303 // ...
304 // -- rsp[8 * num_arguments] : argument 0 (receiver)
305 // -----------------------------------
306
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000307 // TODO(1236192): Most runtime routines don't need the number of
308 // arguments passed in because it is constant. At some point we
309 // should remove this need and make the runtime routine entry code
310 // smarter.
311 movq(rax, Immediate(num_arguments));
312 JumpToBuiltin(ext);
313}
314
315
316void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) {
317 // Set the entry point and jump to the C entry runtime stub.
318 movq(rbx, ext);
319 CEntryStub ces;
320 movq(kScratchRegister, ces.GetCode(), RelocInfo::CODE_TARGET);
321 jmp(kScratchRegister);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000322}
323
ager@chromium.orge2902be2009-06-08 12:21:35 +0000324
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000325void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
326 bool resolved;
327 Handle<Code> code = ResolveBuiltin(id, &resolved);
328
329 const char* name = Builtins::GetName(id);
330 int argc = Builtins::GetArgumentsCount(id);
331
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000332 movq(target, code, RelocInfo::EMBEDDED_OBJECT);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000333 if (!resolved) {
334 uint32_t flags =
335 Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
336 Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
337 Bootstrapper::FixupFlagsUseCodeObject::encode(true);
338 Unresolved entry = { pc_offset() - sizeof(intptr_t), flags, name };
339 unresolved_.Add(entry);
340 }
341 addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
342}
343
344
345Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
346 bool* resolved) {
347 // Move the builtin function into the temporary function slot by
348 // reading it from the builtins object. NOTE: We should be able to
349 // reduce this to two instructions by putting the function table in
350 // the global object instead of the "builtins" object and by using a
351 // real register for the function.
352 movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
353 movq(rdx, FieldOperand(rdx, GlobalObject::kBuiltinsOffset));
354 int builtins_offset =
355 JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
356 movq(rdi, FieldOperand(rdx, builtins_offset));
357
358
359 return Builtins::GetCode(id, resolved);
360}
361
362
ager@chromium.orge2902be2009-06-08 12:21:35 +0000363void MacroAssembler::Set(Register dst, int64_t x) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000364 if (x == 0) {
365 xor_(dst, dst);
366 } else if (is_int32(x)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000367 movq(dst, Immediate(x));
368 } else if (is_uint32(x)) {
369 movl(dst, Immediate(x));
370 } else {
371 movq(dst, x, RelocInfo::NONE);
372 }
373}
374
375
376void MacroAssembler::Set(const Operand& dst, int64_t x) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000377 if (x == 0) {
378 xor_(kScratchRegister, kScratchRegister);
379 movq(dst, kScratchRegister);
380 } else if (is_int32(x)) {
381 movq(dst, Immediate(x));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000382 } else if (is_uint32(x)) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000383 movl(dst, Immediate(x));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000384 } else {
385 movq(kScratchRegister, x, RelocInfo::NONE);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000386 movq(dst, kScratchRegister);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000387 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000388}
389
390
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000391bool MacroAssembler::IsUnsafeSmi(Smi* value) {
392 return false;
393}
394
395void MacroAssembler::LoadUnsafeSmi(Register dst, Smi* source) {
396 UNIMPLEMENTED();
397}
398
399
400void MacroAssembler::Move(Register dst, Handle<Object> source) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000401 ASSERT(!source->IsFailure());
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000402 if (source->IsSmi()) {
403 if (IsUnsafeSmi(source)) {
404 LoadUnsafeSmi(dst, source);
405 } else {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000406 int32_t smi = static_cast<int32_t>(reinterpret_cast<intptr_t>(*source));
407 movq(dst, Immediate(smi));
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000408 }
409 } else {
410 movq(dst, source, RelocInfo::EMBEDDED_OBJECT);
411 }
412}
413
414
415void MacroAssembler::Move(const Operand& dst, Handle<Object> source) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000416 if (source->IsSmi()) {
417 int32_t smi = static_cast<int32_t>(reinterpret_cast<intptr_t>(*source));
418 movq(dst, Immediate(smi));
419 } else {
420 movq(kScratchRegister, source, RelocInfo::EMBEDDED_OBJECT);
421 movq(dst, kScratchRegister);
422 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000423}
424
425
426void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
427 Move(kScratchRegister, source);
428 cmpq(dst, kScratchRegister);
429}
430
431
ager@chromium.org3e875802009-06-29 08:26:34 +0000432void MacroAssembler::Cmp(const Operand& dst, Handle<Object> source) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000433 if (source->IsSmi()) {
434 if (IsUnsafeSmi(source)) {
435 LoadUnsafeSmi(kScratchRegister, source);
436 cmpl(dst, kScratchRegister);
437 } else {
438 // For smi-comparison, it suffices to compare the low 32 bits.
439 int32_t smi = static_cast<int32_t>(reinterpret_cast<intptr_t>(*source));
440 cmpl(dst, Immediate(smi));
441 }
442 } else {
443 ASSERT(source->IsHeapObject());
444 movq(kScratchRegister, source, RelocInfo::EMBEDDED_OBJECT);
445 cmpq(dst, kScratchRegister);
446 }
ager@chromium.org3e875802009-06-29 08:26:34 +0000447}
448
449
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000450void MacroAssembler::Push(Handle<Object> source) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000451 if (source->IsSmi()) {
452 if (IsUnsafeSmi(source)) {
453 LoadUnsafeSmi(kScratchRegister, source);
454 push(kScratchRegister);
455 } else {
456 int32_t smi = static_cast<int32_t>(reinterpret_cast<intptr_t>(*source));
457 push(Immediate(smi));
458 }
459 } else {
460 ASSERT(source->IsHeapObject());
461 movq(kScratchRegister, source, RelocInfo::EMBEDDED_OBJECT);
462 push(kScratchRegister);
463 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000464}
465
466
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000467void MacroAssembler::Push(Smi* source) {
468 if (IsUnsafeSmi(source)) {
469 LoadUnsafeSmi(kScratchRegister, source);
470 push(kScratchRegister);
471 } else {
472 int32_t smi = static_cast<int32_t>(reinterpret_cast<intptr_t>(source));
473 push(Immediate(smi));
474 }
475}
476
477
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000478void MacroAssembler::Jump(ExternalReference ext) {
479 movq(kScratchRegister, ext);
480 jmp(kScratchRegister);
481}
482
483
484void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) {
485 movq(kScratchRegister, destination, rmode);
486 jmp(kScratchRegister);
487}
488
489
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000490void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
491 WriteRecordedPositions();
492 ASSERT(RelocInfo::IsCodeTarget(rmode));
493 movq(kScratchRegister, code_object, rmode);
ager@chromium.org3e875802009-06-29 08:26:34 +0000494#ifdef DEBUG
495 Label target;
496 bind(&target);
497#endif
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000498 jmp(kScratchRegister);
ager@chromium.org3e875802009-06-29 08:26:34 +0000499#ifdef DEBUG
500 ASSERT_EQ(kTargetAddrToReturnAddrDist,
501 SizeOfCodeGeneratedSince(&target) + kPointerSize);
502#endif
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000503}
504
505
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000506void MacroAssembler::Call(ExternalReference ext) {
507 movq(kScratchRegister, ext);
508 call(kScratchRegister);
509}
510
511
512void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
513 movq(kScratchRegister, destination, rmode);
514 call(kScratchRegister);
515}
516
517
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000518void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
519 WriteRecordedPositions();
520 ASSERT(RelocInfo::IsCodeTarget(rmode));
521 movq(kScratchRegister, code_object, rmode);
522#ifdef DEBUG
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000523 // Patch target is kPointer size bytes *before* target label.
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000524 Label target;
525 bind(&target);
526#endif
527 call(kScratchRegister);
528#ifdef DEBUG
529 ASSERT_EQ(kTargetAddrToReturnAddrDist,
530 SizeOfCodeGeneratedSince(&target) + kPointerSize);
531#endif
532}
533
534
ager@chromium.orge2902be2009-06-08 12:21:35 +0000535void MacroAssembler::PushTryHandler(CodeLocation try_location,
536 HandlerType type) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000537 // Adjust this code if not the case.
538 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
539
540 // The pc (return address) is already on TOS. This code pushes state,
541 // frame pointer and current handler. Check that they are expected
542 // next on the stack, in that order.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000543 ASSERT_EQ(StackHandlerConstants::kStateOffset,
544 StackHandlerConstants::kPCOffset - kPointerSize);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000545 ASSERT_EQ(StackHandlerConstants::kFPOffset,
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000546 StackHandlerConstants::kStateOffset - kPointerSize);
547 ASSERT_EQ(StackHandlerConstants::kNextOffset,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000548 StackHandlerConstants::kFPOffset - kPointerSize);
549
550 if (try_location == IN_JAVASCRIPT) {
551 if (type == TRY_CATCH_HANDLER) {
552 push(Immediate(StackHandler::TRY_CATCH));
553 } else {
554 push(Immediate(StackHandler::TRY_FINALLY));
555 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000556 push(rbp);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000557 } else {
558 ASSERT(try_location == IN_JS_ENTRY);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000559 // The frame pointer does not point to a JS frame so we save NULL
560 // for rbp. We expect the code throwing an exception to check rbp
561 // before dereferencing it to restore the context.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000562 push(Immediate(StackHandler::ENTRY));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000563 push(Immediate(0)); // NULL frame pointer.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000564 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000565 // Save the current handler.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000566 movq(kScratchRegister, ExternalReference(Top::k_handler_address));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000567 push(Operand(kScratchRegister, 0));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000568 // Link this handler.
569 movq(Operand(kScratchRegister, 0), rsp);
570}
571
572
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000573void MacroAssembler::Ret() {
574 ret(0);
575}
576
577
ager@chromium.org3e875802009-06-29 08:26:34 +0000578void MacroAssembler::FCmp() {
579 fcompp();
580 push(rax);
581 fnstsw_ax();
582 // TODO(X64): Check that sahf is safe to use, using CPUProbe.
583 sahf();
584 pop(rax);
585}
586
587
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000588void MacroAssembler::CmpObjectType(Register heap_object,
589 InstanceType type,
590 Register map) {
591 movq(map, FieldOperand(heap_object, HeapObject::kMapOffset));
592 CmpInstanceType(map, type);
593}
594
595
596void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
597 cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
598 Immediate(static_cast<int8_t>(type)));
599}
600
601
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000602void MacroAssembler::TryGetFunctionPrototype(Register function,
603 Register result,
604 Label* miss) {
605 // Check that the receiver isn't a smi.
606 testl(function, Immediate(kSmiTagMask));
607 j(zero, miss);
608
609 // Check that the function really is a function.
610 CmpObjectType(function, JS_FUNCTION_TYPE, result);
611 j(not_equal, miss);
612
613 // Make sure that the function has an instance prototype.
614 Label non_instance;
615 testb(FieldOperand(result, Map::kBitFieldOffset),
616 Immediate(1 << Map::kHasNonInstancePrototype));
617 j(not_zero, &non_instance);
618
619 // Get the prototype or initial map from the function.
620 movq(result,
621 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
622
623 // If the prototype or initial map is the hole, don't return it and
624 // simply miss the cache instead. This will allow us to allocate a
625 // prototype object on-demand in the runtime system.
626 Cmp(result, Factory::the_hole_value());
627 j(equal, miss);
628
629 // If the function does not have an initial map, we're done.
630 Label done;
631 CmpObjectType(result, MAP_TYPE, kScratchRegister);
632 j(not_equal, &done);
633
634 // Get the prototype from the initial map.
635 movq(result, FieldOperand(result, Map::kPrototypeOffset));
636 jmp(&done);
637
638 // Non-instance prototype: Fetch prototype from constructor field
639 // in initial map.
640 bind(&non_instance);
641 movq(result, FieldOperand(result, Map::kConstructorOffset));
642
643 // All done.
644 bind(&done);
645}
646
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000647
648void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
649 if (FLAG_native_code_counters && counter->Enabled()) {
650 movq(kScratchRegister, ExternalReference(counter));
651 movl(Operand(kScratchRegister, 0), Immediate(value));
652 }
653}
654
655
656void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
657 ASSERT(value > 0);
658 if (FLAG_native_code_counters && counter->Enabled()) {
659 movq(kScratchRegister, ExternalReference(counter));
660 Operand operand(kScratchRegister, 0);
661 if (value == 1) {
662 incl(operand);
663 } else {
664 addl(operand, Immediate(value));
665 }
666 }
667}
668
669
670void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
671 ASSERT(value > 0);
672 if (FLAG_native_code_counters && counter->Enabled()) {
673 movq(kScratchRegister, ExternalReference(counter));
674 Operand operand(kScratchRegister, 0);
675 if (value == 1) {
676 decl(operand);
677 } else {
678 subl(operand, Immediate(value));
679 }
680 }
681}
682
683
684#ifdef ENABLE_DEBUGGER_SUPPORT
685
686void MacroAssembler::PushRegistersFromMemory(RegList regs) {
687 ASSERT((regs & ~kJSCallerSaved) == 0);
688 // Push the content of the memory location to the stack.
689 for (int i = 0; i < kNumJSCallerSaved; i++) {
690 int r = JSCallerSavedCode(i);
691 if ((regs & (1 << r)) != 0) {
692 ExternalReference reg_addr =
693 ExternalReference(Debug_Address::Register(i));
694 movq(kScratchRegister, reg_addr);
695 push(Operand(kScratchRegister, 0));
696 }
697 }
698}
699
700void MacroAssembler::SaveRegistersToMemory(RegList regs) {
701 ASSERT((regs & ~kJSCallerSaved) == 0);
702 // Copy the content of registers to memory location.
703 for (int i = 0; i < kNumJSCallerSaved; i++) {
704 int r = JSCallerSavedCode(i);
705 if ((regs & (1 << r)) != 0) {
706 Register reg = { r };
707 ExternalReference reg_addr =
708 ExternalReference(Debug_Address::Register(i));
709 movq(kScratchRegister, reg_addr);
710 movq(Operand(kScratchRegister, 0), reg);
711 }
712 }
713}
714
715
716void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
717 ASSERT((regs & ~kJSCallerSaved) == 0);
718 // Copy the content of memory location to registers.
719 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
720 int r = JSCallerSavedCode(i);
721 if ((regs & (1 << r)) != 0) {
722 Register reg = { r };
723 ExternalReference reg_addr =
724 ExternalReference(Debug_Address::Register(i));
725 movq(kScratchRegister, reg_addr);
726 movq(reg, Operand(kScratchRegister, 0));
727 }
728 }
729}
730
731
732void MacroAssembler::PopRegistersToMemory(RegList regs) {
733 ASSERT((regs & ~kJSCallerSaved) == 0);
734 // Pop the content from the stack to the memory location.
735 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
736 int r = JSCallerSavedCode(i);
737 if ((regs & (1 << r)) != 0) {
738 ExternalReference reg_addr =
739 ExternalReference(Debug_Address::Register(i));
740 movq(kScratchRegister, reg_addr);
741 pop(Operand(kScratchRegister, 0));
742 }
743 }
744}
745
746
747void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
748 Register scratch,
749 RegList regs) {
750 ASSERT(!scratch.is(kScratchRegister));
751 ASSERT(!base.is(kScratchRegister));
752 ASSERT(!base.is(scratch));
753 ASSERT((regs & ~kJSCallerSaved) == 0);
754 // Copy the content of the stack to the memory location and adjust base.
755 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
756 int r = JSCallerSavedCode(i);
757 if ((regs & (1 << r)) != 0) {
758 movq(scratch, Operand(base, 0));
759 ExternalReference reg_addr =
760 ExternalReference(Debug_Address::Register(i));
761 movq(kScratchRegister, reg_addr);
762 movq(Operand(kScratchRegister, 0), scratch);
763 lea(base, Operand(base, kPointerSize));
764 }
765 }
766}
767
768#endif // ENABLE_DEBUGGER_SUPPORT
769
770
ager@chromium.org3e875802009-06-29 08:26:34 +0000771void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
772 bool resolved;
773 Handle<Code> code = ResolveBuiltin(id, &resolved);
774
775 // Calls are not allowed in some stubs.
776 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
777
778 // Rely on the assertion to check that the number of provided
779 // arguments match the expected number of arguments. Fake a
780 // parameter count to avoid emitting code to do the check.
781 ParameterCount expected(0);
782 InvokeCode(Handle<Code>(code), expected, expected,
783 RelocInfo::CODE_TARGET, flag);
784
785 const char* name = Builtins::GetName(id);
786 int argc = Builtins::GetArgumentsCount(id);
787 // The target address for the jump is stored as an immediate at offset
788 // kInvokeCodeAddressOffset.
789 if (!resolved) {
790 uint32_t flags =
791 Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000792 Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
ager@chromium.org3e875802009-06-29 08:26:34 +0000793 Bootstrapper::FixupFlagsUseCodeObject::encode(false);
794 Unresolved entry =
795 { pc_offset() - kTargetAddrToReturnAddrDist, flags, name };
796 unresolved_.Add(entry);
797 }
798}
799
800
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000801void MacroAssembler::InvokePrologue(const ParameterCount& expected,
802 const ParameterCount& actual,
803 Handle<Code> code_constant,
804 Register code_register,
805 Label* done,
806 InvokeFlag flag) {
807 bool definitely_matches = false;
808 Label invoke;
809 if (expected.is_immediate()) {
810 ASSERT(actual.is_immediate());
811 if (expected.immediate() == actual.immediate()) {
812 definitely_matches = true;
813 } else {
814 movq(rax, Immediate(actual.immediate()));
815 if (expected.immediate() ==
816 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
817 // Don't worry about adapting arguments for built-ins that
818 // don't want that done. Skip adaption code by making it look
819 // like we have a match between expected and actual number of
820 // arguments.
821 definitely_matches = true;
822 } else {
823 movq(rbx, Immediate(expected.immediate()));
824 }
825 }
826 } else {
827 if (actual.is_immediate()) {
828 // Expected is in register, actual is immediate. This is the
829 // case when we invoke function values without going through the
830 // IC mechanism.
831 cmpq(expected.reg(), Immediate(actual.immediate()));
832 j(equal, &invoke);
833 ASSERT(expected.reg().is(rbx));
834 movq(rax, Immediate(actual.immediate()));
835 } else if (!expected.reg().is(actual.reg())) {
836 // Both expected and actual are in (different) registers. This
837 // is the case when we invoke functions using call and apply.
838 cmpq(expected.reg(), actual.reg());
839 j(equal, &invoke);
840 ASSERT(actual.reg().is(rax));
841 ASSERT(expected.reg().is(rbx));
842 }
843 }
844
845 if (!definitely_matches) {
846 Handle<Code> adaptor =
847 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
848 if (!code_constant.is_null()) {
849 movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
850 addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
851 } else if (!code_register.is(rdx)) {
852 movq(rdx, code_register);
853 }
854
855 movq(kScratchRegister, adaptor, RelocInfo::CODE_TARGET);
856 if (flag == CALL_FUNCTION) {
857 call(kScratchRegister);
858 jmp(done);
859 } else {
860 jmp(kScratchRegister);
861 }
862 bind(&invoke);
863 }
864}
865
866
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000867void MacroAssembler::InvokeCode(Register code,
868 const ParameterCount& expected,
869 const ParameterCount& actual,
870 InvokeFlag flag) {
871 Label done;
872 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
873 if (flag == CALL_FUNCTION) {
874 call(code);
875 } else {
876 ASSERT(flag == JUMP_FUNCTION);
877 jmp(code);
878 }
879 bind(&done);
880}
881
882
883void MacroAssembler::InvokeCode(Handle<Code> code,
884 const ParameterCount& expected,
885 const ParameterCount& actual,
886 RelocInfo::Mode rmode,
887 InvokeFlag flag) {
888 Label done;
889 Register dummy = rax;
890 InvokePrologue(expected, actual, code, dummy, &done, flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000891 if (flag == CALL_FUNCTION) {
ager@chromium.org3e875802009-06-29 08:26:34 +0000892 Call(code, rmode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000893 } else {
894 ASSERT(flag == JUMP_FUNCTION);
ager@chromium.org3e875802009-06-29 08:26:34 +0000895 Jump(code, rmode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000896 }
897 bind(&done);
898}
899
900
901void MacroAssembler::InvokeFunction(Register function,
902 const ParameterCount& actual,
903 InvokeFlag flag) {
904 ASSERT(function.is(rdi));
905 movq(rdx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
906 movq(rsi, FieldOperand(function, JSFunction::kContextOffset));
ager@chromium.org3e875802009-06-29 08:26:34 +0000907 movsxlq(rbx,
908 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000909 movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000910 // Advances rdx to the end of the Code object header, to the start of
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000911 // the executable code.
912 lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
913
914 ParameterCount expected(rbx);
915 InvokeCode(rdx, expected, actual, flag);
916}
917
918
919void MacroAssembler::EnterFrame(StackFrame::Type type) {
920 push(rbp);
921 movq(rbp, rsp);
922 push(rsi); // Context.
923 push(Immediate(Smi::FromInt(type)));
924 movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
925 push(kScratchRegister);
926 if (FLAG_debug_code) {
927 movq(kScratchRegister,
928 Factory::undefined_value(),
929 RelocInfo::EMBEDDED_OBJECT);
930 cmpq(Operand(rsp, 0), kScratchRegister);
931 Check(not_equal, "code object not properly patched");
932 }
933}
934
935
936void MacroAssembler::LeaveFrame(StackFrame::Type type) {
937 if (FLAG_debug_code) {
938 movq(kScratchRegister, Immediate(Smi::FromInt(type)));
939 cmpq(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister);
940 Check(equal, "stack frame types must match");
941 }
942 movq(rsp, rbp);
943 pop(rbp);
944}
945
946
947
948void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
949 ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
950
951 // Setup the frame structure on the stack.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000952 // All constants are relative to the frame pointer of the exit frame.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000953 ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
954 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
955 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
956 push(rbp);
957 movq(rbp, rsp);
958
959 // Reserve room for entry stack pointer and push the debug marker.
960 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
961 push(Immediate(0)); // saved entry sp, patched before call
962 push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0));
963
964 // Save the frame pointer and the context in top.
965 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
966 ExternalReference context_address(Top::k_context_address);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000967 movq(r14, rax); // Backup rax before we use it.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000968
969 movq(rax, rbp);
970 store_rax(c_entry_fp_address);
971 movq(rax, rsi);
972 store_rax(context_address);
973
974 // Setup argv in callee-saved register r15. It is reused in LeaveExitFrame,
975 // so it must be retained across the C-call.
976 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000977 lea(r15, Operand(rbp, r14, times_pointer_size, offset));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000978
979#ifdef ENABLE_DEBUGGER_SUPPORT
980 // Save the state of all registers to the stack from the memory
981 // location. This is needed to allow nested break points.
982 if (type == StackFrame::EXIT_DEBUG) {
983 // TODO(1243899): This should be symmetric to
984 // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
985 // correct here, but computed for the other call. Very error
986 // prone! FIX THIS. Actually there are deeper problems with
987 // register saving than this asymmetry (see the bug report
988 // associated with this issue).
989 PushRegistersFromMemory(kJSCallerSaved);
990 }
991#endif
992
993 // Reserve space for two arguments: argc and argv
994 subq(rsp, Immediate(2 * kPointerSize));
995
996 // Get the required frame alignment for the OS.
997 static const int kFrameAlignment = OS::ActivationFrameAlignment();
998 if (kFrameAlignment > 0) {
999 ASSERT(IsPowerOf2(kFrameAlignment));
1000 movq(kScratchRegister, Immediate(-kFrameAlignment));
1001 and_(rsp, kScratchRegister);
1002 }
1003
1004 // Patch the saved entry sp.
1005 movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp);
1006}
1007
1008
1009void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
1010 // Registers:
1011 // r15 : argv
1012#ifdef ENABLE_DEBUGGER_SUPPORT
1013 // Restore the memory copy of the registers by digging them out from
1014 // the stack. This is needed to allow nested break points.
1015 if (type == StackFrame::EXIT_DEBUG) {
1016 // It's okay to clobber register ebx below because we don't need
1017 // the function pointer after this.
1018 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
1019 int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
1020 lea(rbx, Operand(rbp, kOffset));
1021 CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved);
1022 }
1023#endif
1024
1025 // Get the return address from the stack and restore the frame pointer.
1026 movq(rcx, Operand(rbp, 1 * kPointerSize));
1027 movq(rbp, Operand(rbp, 0 * kPointerSize));
1028
1029 // Pop the arguments and the receiver from the caller stack.
1030 lea(rsp, Operand(r15, 1 * kPointerSize));
1031
1032 // Restore current context from top and clear it in debug mode.
1033 ExternalReference context_address(Top::k_context_address);
1034 movq(kScratchRegister, context_address);
1035 movq(rsi, Operand(kScratchRegister, 0));
1036#ifdef DEBUG
1037 movq(Operand(kScratchRegister, 0), Immediate(0));
1038#endif
1039
1040 // Push the return address to get ready to return.
1041 push(rcx);
1042
1043 // Clear the top frame.
1044 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
1045 movq(kScratchRegister, c_entry_fp_address);
1046 movq(Operand(kScratchRegister, 0), Immediate(0));
1047}
1048
1049
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001050Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
1051 JSObject* holder, Register holder_reg,
1052 Register scratch,
1053 Label* miss) {
1054 // Make sure there's no overlap between scratch and the other
1055 // registers.
1056 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
1057
1058 // Keep track of the current object in register reg. On the first
1059 // iteration, reg is an alias for object_reg, on later iterations,
1060 // it is an alias for holder_reg.
1061 Register reg = object_reg;
1062 int depth = 1;
1063
1064 // Check the maps in the prototype chain.
1065 // Traverse the prototype chain from the object and do map checks.
1066 while (object != holder) {
1067 depth++;
1068
1069 // Only global objects and objects that do not require access
1070 // checks are allowed in stubs.
1071 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1072
1073 JSObject* prototype = JSObject::cast(object->GetPrototype());
1074 if (Heap::InNewSpace(prototype)) {
1075 // Get the map of the current object.
1076 movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1077 Cmp(scratch, Handle<Map>(object->map()));
1078 // Branch on the result of the map check.
1079 j(not_equal, miss);
1080 // Check access rights to the global object. This has to happen
1081 // after the map check so that we know that the object is
1082 // actually a global object.
1083 if (object->IsJSGlobalProxy()) {
1084 CheckAccessGlobalProxy(reg, scratch, miss);
1085
1086 // Restore scratch register to be the map of the object.
1087 // We load the prototype from the map in the scratch register.
1088 movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1089 }
1090 // The prototype is in new space; we cannot store a reference
1091 // to it in the code. Load it from the map.
1092 reg = holder_reg; // from now the object is in holder_reg
1093 movq(reg, FieldOperand(scratch, Map::kPrototypeOffset));
1094
1095 } else {
1096 // Check the map of the current object.
1097 Cmp(FieldOperand(reg, HeapObject::kMapOffset),
1098 Handle<Map>(object->map()));
1099 // Branch on the result of the map check.
1100 j(not_equal, miss);
1101 // Check access rights to the global object. This has to happen
1102 // after the map check so that we know that the object is
1103 // actually a global object.
1104 if (object->IsJSGlobalProxy()) {
1105 CheckAccessGlobalProxy(reg, scratch, miss);
1106 }
1107 // The prototype is in old space; load it directly.
1108 reg = holder_reg; // from now the object is in holder_reg
1109 Move(reg, Handle<JSObject>(prototype));
1110 }
1111
1112 // Go to the next object in the prototype chain.
1113 object = prototype;
1114 }
1115
1116 // Check the holder map.
1117 Cmp(FieldOperand(reg, HeapObject::kMapOffset),
1118 Handle<Map>(holder->map()));
1119 j(not_equal, miss);
1120
1121 // Log the check depth.
1122 LOG(IntEvent("check-maps-depth", depth));
1123
1124 // Perform security check for access to the global object and return
1125 // the holder register.
1126 ASSERT(object == holder);
1127 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1128 if (object->IsJSGlobalProxy()) {
1129 CheckAccessGlobalProxy(reg, scratch, miss);
1130 }
1131 return reg;
1132}
1133
1134
1135
1136
1137void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
1138 Register scratch,
1139 Label* miss) {
1140 Label same_contexts;
1141
1142 ASSERT(!holder_reg.is(scratch));
1143 ASSERT(!scratch.is(kScratchRegister));
1144 // Load current lexical context from the stack frame.
1145 movq(scratch, Operand(rbp, StandardFrameConstants::kContextOffset));
1146
1147 // When generating debug code, make sure the lexical context is set.
1148 if (FLAG_debug_code) {
1149 cmpq(scratch, Immediate(0));
1150 Check(not_equal, "we should not have an empty lexical context");
1151 }
1152 // Load the global context of the current context.
1153 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
1154 movq(scratch, FieldOperand(scratch, offset));
1155 movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
1156
1157 // Check the context is a global context.
1158 if (FLAG_debug_code) {
1159 Cmp(FieldOperand(scratch, HeapObject::kMapOffset),
1160 Factory::global_context_map());
1161 Check(equal, "JSGlobalObject::global_context should be a global context.");
1162 }
1163
1164 // Check if both contexts are the same.
1165 cmpq(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
1166 j(equal, &same_contexts);
1167
1168 // Compare security tokens.
1169 // Check that the security token in the calling global object is
1170 // compatible with the security token in the receiving global
1171 // object.
1172
1173 // Check the context is a global context.
1174 if (FLAG_debug_code) {
1175 // Preserve original value of holder_reg.
1176 push(holder_reg);
1177 movq(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
1178 Cmp(holder_reg, Factory::null_value());
1179 Check(not_equal, "JSGlobalProxy::context() should not be null.");
1180
1181 // Read the first word and compare to global_context_map(),
1182 movq(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
1183 Cmp(holder_reg, Factory::global_context_map());
1184 Check(equal, "JSGlobalObject::global_context should be a global context.");
1185 pop(holder_reg);
1186 }
1187
1188 movq(kScratchRegister,
1189 FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
1190 int token_offset = Context::kHeaderSize +
1191 Context::SECURITY_TOKEN_INDEX * kPointerSize;
1192 movq(scratch, FieldOperand(scratch, token_offset));
1193 cmpq(scratch, FieldOperand(kScratchRegister, token_offset));
1194 j(not_equal, miss);
1195
1196 bind(&same_contexts);
1197}
1198
1199
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001200} } // namespace v8::internal