blob: 425c51dcae557e4670f5a44563198b495ceb7061 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-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
28#include "v8.h"
29
30#include "ic-inl.h"
31#include "codegen-inl.h"
32#include "stub-cache.h"
33
34namespace v8 {
35namespace internal {
36
37#define __ ACCESS_MASM(masm)
38
39
40static void ProbeTable(MacroAssembler* masm,
41 Code::Flags flags,
42 StubCache::Table table,
43 Register name,
44 Register offset,
45 Register extra) {
46 ExternalReference key_offset(SCTableReference::keyReference(table));
47 ExternalReference value_offset(SCTableReference::valueReference(table));
48
49 Label miss;
50
51 if (extra.is_valid()) {
52 // Get the code entry from the cache.
53 __ mov(extra, Operand::StaticArray(offset, times_2, value_offset));
54
55 // Check that the key in the entry matches the name.
56 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
57 __ j(not_equal, &miss, not_taken);
58
59 // Check that the flags match what we're looking for.
60 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
61 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
62 __ cmp(offset, flags);
63 __ j(not_equal, &miss);
64
65 // Jump to the first instruction in the code stub.
66 __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag));
67 __ jmp(Operand(extra));
68
69 __ bind(&miss);
70 } else {
71 // Save the offset on the stack.
72 __ push(offset);
73
74 // Check that the key in the entry matches the name.
75 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
76 __ j(not_equal, &miss, not_taken);
77
78 // Get the code entry from the cache.
79 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
80
81 // Check that the flags match what we're looking for.
82 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
83 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
84 __ cmp(offset, flags);
85 __ j(not_equal, &miss);
86
87 // Restore offset and re-load code entry from cache.
88 __ pop(offset);
89 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
90
91 // Jump to the first instruction in the code stub.
92 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
93 __ jmp(Operand(offset));
94
95 // Pop at miss.
96 __ bind(&miss);
97 __ pop(offset);
98 }
99}
100
101
102void StubCache::GenerateProbe(MacroAssembler* masm,
103 Code::Flags flags,
104 Register receiver,
105 Register name,
106 Register scratch,
107 Register extra) {
108 Label miss;
109
110 // Make sure that code is valid. The shifting code relies on the
111 // entry size being 8.
112 ASSERT(sizeof(Entry) == 8);
113
114 // Make sure the flags does not name a specific type.
115 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
116
117 // Make sure that there are no register conflicts.
118 ASSERT(!scratch.is(receiver));
119 ASSERT(!scratch.is(name));
120 ASSERT(!extra.is(receiver));
121 ASSERT(!extra.is(name));
122 ASSERT(!extra.is(scratch));
123
124 // Check that the receiver isn't a smi.
125 __ test(receiver, Immediate(kSmiTagMask));
126 __ j(zero, &miss, not_taken);
127
128 // Get the map of the receiver and compute the hash.
Steve Blockd0582a62009-12-15 09:54:21 +0000129 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000130 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
131 __ xor_(scratch, flags);
132 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
133
134 // Probe the primary table.
135 ProbeTable(masm, flags, kPrimary, name, scratch, extra);
136
137 // Primary miss: Compute hash for secondary probe.
Steve Blockd0582a62009-12-15 09:54:21 +0000138 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000139 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
140 __ xor_(scratch, flags);
141 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
142 __ sub(scratch, Operand(name));
143 __ add(Operand(scratch), Immediate(flags));
144 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
145
146 // Probe the secondary table.
147 ProbeTable(masm, flags, kSecondary, name, scratch, extra);
148
149 // Cache miss: Fall-through and let caller handle the miss by
150 // entering the runtime system.
151 __ bind(&miss);
152}
153
154
155template <typename Pushable>
156static void PushInterceptorArguments(MacroAssembler* masm,
157 Register receiver,
158 Register holder,
159 Pushable name,
160 JSObject* holder_obj) {
161 __ push(receiver);
162 __ push(holder);
163 __ push(name);
164 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
165 __ mov(receiver, Immediate(Handle<Object>(interceptor)));
166 __ push(receiver);
167 __ push(FieldOperand(receiver, InterceptorInfo::kDataOffset));
168}
169
170
171void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
172 int index,
173 Register prototype) {
174 // Load the global or builtins object from the current context.
175 __ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
176 // Load the global context from the global or builtins object.
177 __ mov(prototype,
178 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
179 // Load the function from the global context.
180 __ mov(prototype, Operand(prototype, Context::SlotOffset(index)));
181 // Load the initial map. The global functions all have initial maps.
182 __ mov(prototype,
183 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
184 // Load the prototype from the initial map.
185 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
186}
187
188
189void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
190 Register receiver,
191 Register scratch,
192 Label* miss_label) {
193 // Check that the receiver isn't a smi.
194 __ test(receiver, Immediate(kSmiTagMask));
195 __ j(zero, miss_label, not_taken);
196
197 // Check that the object is a JS array.
198 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
199 __ j(not_equal, miss_label, not_taken);
200
201 // Load length directly from the JS array.
202 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
203 __ ret(0);
204}
205
206
207// Generate code to check if an object is a string. If the object is
208// a string, the map's instance type is left in the scratch register.
209static void GenerateStringCheck(MacroAssembler* masm,
210 Register receiver,
211 Register scratch,
212 Label* smi,
213 Label* non_string_object) {
214 // Check that the object isn't a smi.
215 __ test(receiver, Immediate(kSmiTagMask));
216 __ j(zero, smi, not_taken);
217
218 // Check that the object is a string.
219 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
220 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
221 ASSERT(kNotStringTag != 0);
222 __ test(scratch, Immediate(kNotStringTag));
223 __ j(not_zero, non_string_object, not_taken);
224}
225
226
227void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
228 Register receiver,
229 Register scratch,
230 Label* miss) {
231 Label load_length, check_wrapper;
232
233 // Check if the object is a string leaving the instance type in the
234 // scratch register.
235 GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
236
Steve Blockd0582a62009-12-15 09:54:21 +0000237 // Load length from the string and convert to a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 __ bind(&load_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000239 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 __ shl(eax, kSmiTagSize);
241 __ ret(0);
242
243 // Check if the object is a JSValue wrapper.
244 __ bind(&check_wrapper);
245 __ cmp(scratch, JS_VALUE_TYPE);
246 __ j(not_equal, miss, not_taken);
247
248 // Check if the wrapped value is a string and load the length
249 // directly if it is.
250 __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
251 GenerateStringCheck(masm, receiver, scratch, miss, miss);
252 __ jmp(&load_length);
253}
254
255
256void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
257 Register receiver,
258 Register scratch1,
259 Register scratch2,
260 Label* miss_label) {
261 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
262 __ mov(eax, Operand(scratch1));
263 __ ret(0);
264}
265
266
267// Load a fast property out of a holder object (src). In-object properties
268// are loaded directly otherwise the property is loaded from the properties
269// fixed array.
270void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
271 Register dst, Register src,
272 JSObject* holder, int index) {
273 // Adjust for the number of properties stored in the holder.
274 index -= holder->map()->inobject_properties();
275 if (index < 0) {
276 // Get the property straight out of the holder.
277 int offset = holder->map()->instance_size() + (index * kPointerSize);
278 __ mov(dst, FieldOperand(src, offset));
279 } else {
280 // Calculate the offset into the properties array.
281 int offset = index * kPointerSize + FixedArray::kHeaderSize;
282 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
283 __ mov(dst, FieldOperand(dst, offset));
284 }
285}
286
287
288template <class Pushable>
289static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
290 Register receiver,
291 Register holder,
292 Pushable name,
293 JSObject* holder_obj) {
294 PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
295
296 ExternalReference ref =
297 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly));
298 __ mov(eax, Immediate(5));
299 __ mov(ebx, Immediate(ref));
300
301 CEntryStub stub(1);
302 __ CallStub(&stub);
303}
304
305
306template <class Compiler>
307static void CompileLoadInterceptor(Compiler* compiler,
308 StubCompiler* stub_compiler,
309 MacroAssembler* masm,
310 JSObject* object,
311 JSObject* holder,
312 String* name,
313 LookupResult* lookup,
314 Register receiver,
315 Register scratch1,
316 Register scratch2,
317 Label* miss) {
318 ASSERT(holder->HasNamedInterceptor());
319 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
320
321 // Check that the receiver isn't a smi.
322 __ test(receiver, Immediate(kSmiTagMask));
323 __ j(zero, miss, not_taken);
324
325 // Check that the maps haven't changed.
326 Register reg =
327 stub_compiler->CheckPrototypes(object, receiver, holder,
328 scratch1, scratch2, name, miss);
329
330 if (lookup->IsValid() && lookup->IsCacheable()) {
331 compiler->CompileCacheable(masm,
332 stub_compiler,
333 receiver,
334 reg,
335 scratch1,
336 scratch2,
337 holder,
338 lookup,
339 name,
340 miss);
341 } else {
342 compiler->CompileRegular(masm,
343 receiver,
344 reg,
345 scratch2,
346 holder,
347 miss);
348 }
349}
350
351
352static void LookupPostInterceptor(JSObject* holder,
353 String* name,
354 LookupResult* lookup) {
355 holder->LocalLookupRealNamedProperty(name, lookup);
356 if (lookup->IsNotFound()) {
357 Object* proto = holder->GetPrototype();
358 if (proto != Heap::null_value()) {
359 proto->Lookup(name, lookup);
360 }
361 }
362}
363
364
365class LoadInterceptorCompiler BASE_EMBEDDED {
366 public:
367 explicit LoadInterceptorCompiler(Register name) : name_(name) {}
368
369 void CompileCacheable(MacroAssembler* masm,
370 StubCompiler* stub_compiler,
371 Register receiver,
372 Register holder,
373 Register scratch1,
374 Register scratch2,
375 JSObject* holder_obj,
376 LookupResult* lookup,
377 String* name,
378 Label* miss_label) {
379 AccessorInfo* callback = 0;
380 bool optimize = false;
381 // So far the most popular follow ups for interceptor loads are FIELD
382 // and CALLBACKS, so inline only them, other cases may be added
383 // later.
384 if (lookup->type() == FIELD) {
385 optimize = true;
386 } else if (lookup->type() == CALLBACKS) {
387 Object* callback_object = lookup->GetCallbackObject();
388 if (callback_object->IsAccessorInfo()) {
389 callback = AccessorInfo::cast(callback_object);
390 optimize = callback->getter() != NULL;
391 }
392 }
393
394 if (!optimize) {
395 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
396 return;
397 }
398
399 // Note: starting a frame here makes GC aware of pointers pushed below.
400 __ EnterInternalFrame();
401
402 if (lookup->type() == CALLBACKS) {
403 __ push(receiver);
404 }
405 __ push(holder);
406 __ push(name_);
407
408 CompileCallLoadPropertyWithInterceptor(masm,
409 receiver,
410 holder,
411 name_,
412 holder_obj);
413
414 Label interceptor_failed;
415 __ cmp(eax, Factory::no_interceptor_result_sentinel());
416 __ j(equal, &interceptor_failed);
417 __ LeaveInternalFrame();
418 __ ret(0);
419
420 __ bind(&interceptor_failed);
421 __ pop(name_);
422 __ pop(holder);
423 if (lookup->type() == CALLBACKS) {
424 __ pop(receiver);
425 }
426
427 __ LeaveInternalFrame();
428
429 if (lookup->type() == FIELD) {
430 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
431 lookup->holder(), scratch1,
432 scratch2,
433 name,
434 miss_label);
435 stub_compiler->GenerateFastPropertyLoad(masm, eax,
436 holder, lookup->holder(),
437 lookup->GetFieldIndex());
438 __ ret(0);
439 } else {
440 ASSERT(lookup->type() == CALLBACKS);
441 ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
442 ASSERT(callback != NULL);
443 ASSERT(callback->getter() != NULL);
444
445 Label cleanup;
446 __ pop(scratch2);
447 __ push(receiver);
448 __ push(scratch2);
449
450 holder = stub_compiler->CheckPrototypes(holder_obj, holder,
451 lookup->holder(), scratch1,
452 scratch2,
453 name,
454 &cleanup);
455
456 __ pop(scratch2); // save old return address
457 __ push(holder);
458 __ mov(holder, Immediate(Handle<AccessorInfo>(callback)));
459 __ push(holder);
460 __ push(FieldOperand(holder, AccessorInfo::kDataOffset));
461 __ push(name_);
462 __ push(scratch2); // restore old return address
463
464 ExternalReference ref =
465 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
466 __ TailCallRuntime(ref, 5, 1);
467
468 __ bind(&cleanup);
469 __ pop(scratch1);
470 __ pop(scratch2);
471 __ push(scratch1);
472 }
473 }
474
475
476 void CompileRegular(MacroAssembler* masm,
477 Register receiver,
478 Register holder,
479 Register scratch,
480 JSObject* holder_obj,
481 Label* miss_label) {
482 __ pop(scratch); // save old return address
483 PushInterceptorArguments(masm, receiver, holder, name_, holder_obj);
484 __ push(scratch); // restore old return address
485
486 ExternalReference ref = ExternalReference(
487 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
488 __ TailCallRuntime(ref, 5, 1);
489 }
490
491 private:
492 Register name_;
493};
494
495
496class CallInterceptorCompiler BASE_EMBEDDED {
497 public:
498 explicit CallInterceptorCompiler(const ParameterCount& arguments)
499 : arguments_(arguments), argc_(arguments.immediate()) {}
500
501 void CompileCacheable(MacroAssembler* masm,
502 StubCompiler* stub_compiler,
503 Register receiver,
504 Register holder,
505 Register scratch1,
506 Register scratch2,
507 JSObject* holder_obj,
508 LookupResult* lookup,
509 String* name,
510 Label* miss_label) {
511 JSFunction* function = 0;
512 bool optimize = false;
513 // So far the most popular case for failed interceptor is
514 // CONSTANT_FUNCTION sitting below.
515 if (lookup->type() == CONSTANT_FUNCTION) {
516 function = lookup->GetConstantFunction();
517 // JSArray holder is a special case for call constant function
518 // (see the corresponding code).
519 if (function->is_compiled() && !holder_obj->IsJSArray()) {
520 optimize = true;
521 }
522 }
523
524 if (!optimize) {
525 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
526 return;
527 }
528
529 __ EnterInternalFrame();
530 __ push(holder); // save the holder
531
532 CompileCallLoadPropertyWithInterceptor(
533 masm,
534 receiver,
535 holder,
536 // Under EnterInternalFrame this refers to name.
537 Operand(ebp, (argc_ + 3) * kPointerSize),
538 holder_obj);
539
540 __ pop(receiver); // restore holder
541 __ LeaveInternalFrame();
542
543 __ cmp(eax, Factory::no_interceptor_result_sentinel());
544 Label invoke;
545 __ j(not_equal, &invoke);
546
547 stub_compiler->CheckPrototypes(holder_obj, receiver,
548 lookup->holder(), scratch1,
549 scratch2,
550 name,
551 miss_label);
552 if (lookup->holder()->IsGlobalObject()) {
553 __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize));
554 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
555 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx);
556 }
557
558 ASSERT(function->is_compiled());
559 // Get the function and setup the context.
560 __ mov(edi, Immediate(Handle<JSFunction>(function)));
561 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
562
563 // Jump to the cached code (tail call).
564 ASSERT(function->is_compiled());
565 Handle<Code> code(function->code());
566 ParameterCount expected(function->shared()->formal_parameter_count());
567 __ InvokeCode(code, expected, arguments_,
568 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
569
570 __ bind(&invoke);
571 }
572
573 void CompileRegular(MacroAssembler* masm,
574 Register receiver,
575 Register holder,
576 Register scratch,
577 JSObject* holder_obj,
578 Label* miss_label) {
579 __ EnterInternalFrame();
580
581 PushInterceptorArguments(masm,
582 receiver,
583 holder,
584 Operand(ebp, (argc_ + 3) * kPointerSize),
585 holder_obj);
586
587 ExternalReference ref = ExternalReference(
588 IC_Utility(IC::kLoadPropertyWithInterceptorForCall));
589 __ mov(eax, Immediate(5));
590 __ mov(ebx, Immediate(ref));
591
592 CEntryStub stub(1);
593 __ CallStub(&stub);
594
595 __ LeaveInternalFrame();
596 }
597
598 private:
599 const ParameterCount& arguments_;
600 int argc_;
601};
602
603
604void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
605 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
606 Code* code = NULL;
607 if (kind == Code::LOAD_IC) {
608 code = Builtins::builtin(Builtins::LoadIC_Miss);
609 } else {
610 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
611 }
612
613 Handle<Code> ic(code);
614 __ jmp(ic, RelocInfo::CODE_TARGET);
615}
616
617
618void StubCompiler::GenerateStoreField(MacroAssembler* masm,
619 Builtins::Name storage_extend,
620 JSObject* object,
621 int index,
622 Map* transition,
623 Register receiver_reg,
624 Register name_reg,
625 Register scratch,
626 Label* miss_label) {
627 // Check that the object isn't a smi.
628 __ test(receiver_reg, Immediate(kSmiTagMask));
629 __ j(zero, miss_label, not_taken);
630
631 // Check that the map of the object hasn't changed.
632 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
633 Immediate(Handle<Map>(object->map())));
634 __ j(not_equal, miss_label, not_taken);
635
636 // Perform global security token check if needed.
637 if (object->IsJSGlobalProxy()) {
638 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
639 }
640
641 // Stub never generated for non-global objects that require access
642 // checks.
643 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
644
645 // Perform map transition for the receiver if necessary.
646 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
647 // The properties must be extended before we can store the value.
648 // We jump to a runtime call that extends the properties array.
649 __ mov(ecx, Immediate(Handle<Map>(transition)));
650 Handle<Code> ic(Builtins::builtin(storage_extend));
651 __ jmp(ic, RelocInfo::CODE_TARGET);
652 return;
653 }
654
655 if (transition != NULL) {
656 // Update the map of the object; no write barrier updating is
657 // needed because the map is never in new space.
658 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
659 Immediate(Handle<Map>(transition)));
660 }
661
662 // Adjust for the number of properties stored in the object. Even in the
663 // face of a transition we can use the old map here because the size of the
664 // object and the number of in-object properties is not going to change.
665 index -= object->map()->inobject_properties();
666
667 if (index < 0) {
668 // Set the property straight into the object.
669 int offset = object->map()->instance_size() + (index * kPointerSize);
670 __ mov(FieldOperand(receiver_reg, offset), eax);
671
672 // Update the write barrier for the array address.
673 // Pass the value being stored in the now unused name_reg.
674 __ mov(name_reg, Operand(eax));
675 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
676 } else {
677 // Write to the properties array.
678 int offset = index * kPointerSize + FixedArray::kHeaderSize;
679 // Get the properties array (optimistically).
680 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
681 __ mov(FieldOperand(scratch, offset), eax);
682
683 // Update the write barrier for the array address.
684 // Pass the value being stored in the now unused name_reg.
685 __ mov(name_reg, Operand(eax));
686 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
687 }
688
689 // Return the value (register eax).
690 __ ret(0);
691}
692
693
694#undef __
695#define __ ACCESS_MASM(masm())
696
697
698Register StubCompiler::CheckPrototypes(JSObject* object,
699 Register object_reg,
700 JSObject* holder,
701 Register holder_reg,
702 Register scratch,
703 String* name,
704 Label* miss) {
705 // Check that the maps haven't changed.
706 Register result =
707 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
708
709 // If we've skipped any global objects, it's not enough to verify
710 // that their maps haven't changed.
711 while (object != holder) {
712 if (object->IsGlobalObject()) {
713 GlobalObject* global = GlobalObject::cast(object);
714 Object* probe = global->EnsurePropertyCell(name);
715 if (probe->IsFailure()) {
716 set_failure(Failure::cast(probe));
717 return result;
718 }
719 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
720 ASSERT(cell->value()->IsTheHole());
721 __ mov(scratch, Immediate(Handle<Object>(cell)));
722 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
723 Immediate(Factory::the_hole_value()));
724 __ j(not_equal, miss, not_taken);
725 }
726 object = JSObject::cast(object->GetPrototype());
727 }
728
729 // Return the register containin the holder.
730 return result;
731}
732
733
734void StubCompiler::GenerateLoadField(JSObject* object,
735 JSObject* holder,
736 Register receiver,
737 Register scratch1,
738 Register scratch2,
739 int index,
740 String* name,
741 Label* miss) {
742 // Check that the receiver isn't a smi.
743 __ test(receiver, Immediate(kSmiTagMask));
744 __ j(zero, miss, not_taken);
745
746 // Check the prototype chain.
747 Register reg =
748 CheckPrototypes(object, receiver, holder,
749 scratch1, scratch2, name, miss);
750
751 // Get the value from the properties.
752 GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
753 __ ret(0);
754}
755
756
757void StubCompiler::GenerateLoadCallback(JSObject* object,
758 JSObject* holder,
759 Register receiver,
760 Register name_reg,
761 Register scratch1,
762 Register scratch2,
763 AccessorInfo* callback,
764 String* name,
765 Label* miss) {
766 // Check that the receiver isn't a smi.
767 __ test(receiver, Immediate(kSmiTagMask));
768 __ j(zero, miss, not_taken);
769
770 // Check that the maps haven't changed.
771 Register reg =
772 CheckPrototypes(object, receiver, holder,
773 scratch1, scratch2, name, miss);
774
Steve Blockd0582a62009-12-15 09:54:21 +0000775 Handle<AccessorInfo> callback_handle(callback);
776
777 Register other = reg.is(scratch1) ? scratch2 : scratch1;
778 __ EnterInternalFrame();
779 __ PushHandleScope(other);
780 // Push the stack address where the list of arguments ends
781 __ mov(other, esp);
782 __ sub(Operand(other), Immediate(2 * kPointerSize));
783 __ push(other);
Steve Blocka7e24c12009-10-30 11:49:00 +0000784 __ push(receiver); // receiver
785 __ push(reg); // holder
Steve Blockd0582a62009-12-15 09:54:21 +0000786 __ mov(other, Immediate(callback_handle));
787 __ push(other);
788 __ push(FieldOperand(other, AccessorInfo::kDataOffset)); // data
Steve Blocka7e24c12009-10-30 11:49:00 +0000789 __ push(name_reg); // name
Steve Blockd0582a62009-12-15 09:54:21 +0000790 // Save a pointer to where we pushed the arguments pointer.
791 // This will be passed as the const Arguments& to the C++ callback.
792 __ mov(eax, esp);
793 __ add(Operand(eax), Immediate(5 * kPointerSize));
794 __ mov(ebx, esp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000795
Steve Blockd0582a62009-12-15 09:54:21 +0000796 // Do call through the api.
797 ASSERT_EQ(6, ApiGetterEntryStub::kStackSpace);
798 Address getter_address = v8::ToCData<Address>(callback->getter());
799 ApiFunction fun(getter_address);
800 ApiGetterEntryStub stub(callback_handle, &fun);
801 __ CallStub(&stub);
802
803 // We need to avoid using eax since that now holds the result.
804 Register tmp = other.is(eax) ? reg : other;
805 __ PopHandleScope(eax, tmp);
806 __ LeaveInternalFrame();
807
808 __ ret(0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000809}
810
811
812void StubCompiler::GenerateLoadConstant(JSObject* object,
813 JSObject* holder,
814 Register receiver,
815 Register scratch1,
816 Register scratch2,
817 Object* value,
818 String* name,
819 Label* miss) {
820 // Check that the receiver isn't a smi.
821 __ test(receiver, Immediate(kSmiTagMask));
822 __ j(zero, miss, not_taken);
823
824 // Check that the maps haven't changed.
825 Register reg =
826 CheckPrototypes(object, receiver, holder,
827 scratch1, scratch2, name, miss);
828
829 // Return the constant value.
830 __ mov(eax, Handle<Object>(value));
831 __ ret(0);
832}
833
834
835void StubCompiler::GenerateLoadInterceptor(JSObject* object,
836 JSObject* holder,
837 LookupResult* lookup,
838 Register receiver,
839 Register name_reg,
840 Register scratch1,
841 Register scratch2,
842 String* name,
843 Label* miss) {
844 LoadInterceptorCompiler compiler(name_reg);
845 CompileLoadInterceptor(&compiler,
846 this,
847 masm(),
848 object,
849 holder,
850 name,
851 lookup,
852 receiver,
853 scratch1,
854 scratch2,
855 miss);
856}
857
858
859// TODO(1241006): Avoid having lazy compile stubs specialized by the
860// number of arguments. It is not needed anymore.
861Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
862 // Enter an internal frame.
863 __ EnterInternalFrame();
864
865 // Push a copy of the function onto the stack.
866 __ push(edi);
867
868 __ push(edi); // function is also the parameter to the runtime call
869 __ CallRuntime(Runtime::kLazyCompile, 1);
870 __ pop(edi);
871
872 // Tear down temporary frame.
873 __ LeaveInternalFrame();
874
875 // Do a tail-call of the compiled function.
876 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
877 __ jmp(Operand(ecx));
878
879 return GetCodeWithFlags(flags, "LazyCompileStub");
880}
881
882
883Object* CallStubCompiler::CompileCallField(Object* object,
884 JSObject* holder,
885 int index,
886 String* name) {
887 // ----------- S t a t e -------------
888 // -----------------------------------
889 Label miss;
890
891 // Get the receiver from the stack.
892 const int argc = arguments().immediate();
893 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
894
895 // Check that the receiver isn't a smi.
896 __ test(edx, Immediate(kSmiTagMask));
897 __ j(zero, &miss, not_taken);
898
899 // Do the right check and compute the holder register.
900 Register reg =
901 CheckPrototypes(JSObject::cast(object), edx, holder,
902 ebx, ecx, name, &miss);
903
904 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
905
906 // Check that the function really is a function.
907 __ test(edi, Immediate(kSmiTagMask));
908 __ j(zero, &miss, not_taken);
909 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
910 __ j(not_equal, &miss, not_taken);
911
912 // Patch the receiver on the stack with the global proxy if
913 // necessary.
914 if (object->IsGlobalObject()) {
915 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
916 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
917 }
918
919 // Invoke the function.
920 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
921
922 // Handle call cache miss.
923 __ bind(&miss);
924 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
925 __ jmp(ic, RelocInfo::CODE_TARGET);
926
927 // Return the generated code.
928 return GetCode(FIELD, name);
929}
930
931
932Object* CallStubCompiler::CompileCallConstant(Object* object,
933 JSObject* holder,
934 JSFunction* function,
935 String* name,
936 CheckType check) {
937 // ----------- S t a t e -------------
938 // -----------------------------------
939 Label miss;
940
941 // Get the receiver from the stack.
942 const int argc = arguments().immediate();
943 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
944
945 // Check that the receiver isn't a smi.
946 if (check != NUMBER_CHECK) {
947 __ test(edx, Immediate(kSmiTagMask));
948 __ j(zero, &miss, not_taken);
949 }
950
951 // Make sure that it's okay not to patch the on stack receiver
952 // unless we're doing a receiver map check.
953 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
954
955 switch (check) {
956 case RECEIVER_MAP_CHECK:
957 // Check that the maps haven't changed.
958 CheckPrototypes(JSObject::cast(object), edx, holder,
959 ebx, ecx, name, &miss);
960
961 // Patch the receiver on the stack with the global proxy if
962 // necessary.
963 if (object->IsGlobalObject()) {
964 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
965 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
966 }
967 break;
968
969 case STRING_CHECK:
970 // Check that the object is a two-byte string or a symbol.
971 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
972 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
973 __ cmp(ecx, FIRST_NONSTRING_TYPE);
974 __ j(above_equal, &miss, not_taken);
975 // Check that the maps starting from the prototype haven't changed.
976 GenerateLoadGlobalFunctionPrototype(masm(),
977 Context::STRING_FUNCTION_INDEX,
978 ecx);
979 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
980 ebx, edx, name, &miss);
981 break;
982
983 case NUMBER_CHECK: {
984 Label fast;
985 // Check that the object is a smi or a heap number.
986 __ test(edx, Immediate(kSmiTagMask));
987 __ j(zero, &fast, taken);
988 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
989 __ j(not_equal, &miss, not_taken);
990 __ bind(&fast);
991 // Check that the maps starting from the prototype haven't changed.
992 GenerateLoadGlobalFunctionPrototype(masm(),
993 Context::NUMBER_FUNCTION_INDEX,
994 ecx);
995 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
996 ebx, edx, name, &miss);
997 break;
998 }
999
1000 case BOOLEAN_CHECK: {
1001 Label fast;
1002 // Check that the object is a boolean.
1003 __ cmp(edx, Factory::true_value());
1004 __ j(equal, &fast, taken);
1005 __ cmp(edx, Factory::false_value());
1006 __ j(not_equal, &miss, not_taken);
1007 __ bind(&fast);
1008 // Check that the maps starting from the prototype haven't changed.
1009 GenerateLoadGlobalFunctionPrototype(masm(),
1010 Context::BOOLEAN_FUNCTION_INDEX,
1011 ecx);
1012 CheckPrototypes(JSObject::cast(object->GetPrototype()), ecx, holder,
1013 ebx, edx, name, &miss);
1014 break;
1015 }
1016
1017 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
1018 CheckPrototypes(JSObject::cast(object), edx, holder,
1019 ebx, ecx, name, &miss);
1020 // Make sure object->HasFastElements().
1021 // Get the elements array of the object.
1022 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
1023 // Check that the object is in fast mode (not dictionary).
1024 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1025 Immediate(Factory::fixed_array_map()));
1026 __ j(not_equal, &miss, not_taken);
1027 break;
1028
1029 default:
1030 UNREACHABLE();
1031 }
1032
1033 // Get the function and setup the context.
1034 __ mov(edi, Immediate(Handle<JSFunction>(function)));
1035 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1036
1037 // Jump to the cached code (tail call).
1038 ASSERT(function->is_compiled());
1039 Handle<Code> code(function->code());
1040 ParameterCount expected(function->shared()->formal_parameter_count());
1041 __ InvokeCode(code, expected, arguments(),
1042 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1043
1044 // Handle call cache miss.
1045 __ bind(&miss);
1046 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1047 __ jmp(ic, RelocInfo::CODE_TARGET);
1048
1049 // Return the generated code.
1050 String* function_name = NULL;
1051 if (function->shared()->name()->IsString()) {
1052 function_name = String::cast(function->shared()->name());
1053 }
1054 return GetCode(CONSTANT_FUNCTION, function_name);
1055}
1056
1057
1058Object* CallStubCompiler::CompileCallInterceptor(Object* object,
1059 JSObject* holder,
1060 String* name) {
1061 // ----------- S t a t e -------------
1062 // -----------------------------------
1063 Label miss;
1064
1065 // Get the number of arguments.
1066 const int argc = arguments().immediate();
1067
1068 LookupResult lookup;
1069 LookupPostInterceptor(holder, name, &lookup);
1070
1071 // Get the receiver from the stack.
1072 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1073
1074 CallInterceptorCompiler compiler(arguments());
1075 CompileLoadInterceptor(&compiler,
1076 this,
1077 masm(),
1078 JSObject::cast(object),
1079 holder,
1080 name,
1081 &lookup,
1082 edx,
1083 ebx,
1084 ecx,
1085 &miss);
1086
1087 // Restore receiver.
1088 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1089
1090 // Check that the function really is a function.
1091 __ test(eax, Immediate(kSmiTagMask));
1092 __ j(zero, &miss, not_taken);
1093 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
1094 __ j(not_equal, &miss, not_taken);
1095
1096 // Patch the receiver on the stack with the global proxy if
1097 // necessary.
1098 if (object->IsGlobalObject()) {
1099 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1100 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1101 }
1102
1103 // Invoke the function.
1104 __ mov(edi, eax);
1105 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
1106
1107 // Handle load cache miss.
1108 __ bind(&miss);
1109 Handle<Code> ic = ComputeCallMiss(argc);
1110 __ jmp(ic, RelocInfo::CODE_TARGET);
1111
1112 // Return the generated code.
1113 return GetCode(INTERCEPTOR, name);
1114}
1115
1116
1117Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
1118 GlobalObject* holder,
1119 JSGlobalPropertyCell* cell,
1120 JSFunction* function,
1121 String* name) {
1122 // ----------- S t a t e -------------
1123 // -----------------------------------
1124 Label miss;
1125
1126 // Get the number of arguments.
1127 const int argc = arguments().immediate();
1128
1129 // Get the receiver from the stack.
1130 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1131
1132 // If the object is the holder then we know that it's a global
1133 // object which can only happen for contextual calls. In this case,
1134 // the receiver cannot be a smi.
1135 if (object != holder) {
1136 __ test(edx, Immediate(kSmiTagMask));
1137 __ j(zero, &miss, not_taken);
1138 }
1139
1140 // Check that the maps haven't changed.
1141 CheckPrototypes(object, edx, holder, ebx, ecx, name, &miss);
1142
1143 // Get the value from the cell.
1144 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1145 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1146
1147 // Check that the cell contains the same function.
1148 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
1149 __ j(not_equal, &miss, not_taken);
1150
1151 // Patch the receiver on the stack with the global proxy.
1152 if (object->IsGlobalObject()) {
1153 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1154 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1155 }
1156
1157 // Setup the context (function already in edi).
1158 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1159
1160 // Jump to the cached code (tail call).
1161 __ IncrementCounter(&Counters::call_global_inline, 1);
1162 ASSERT(function->is_compiled());
1163 Handle<Code> code(function->code());
1164 ParameterCount expected(function->shared()->formal_parameter_count());
1165 __ InvokeCode(code, expected, arguments(),
1166 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
1167
1168 // Handle call cache miss.
1169 __ bind(&miss);
1170 __ IncrementCounter(&Counters::call_global_inline_miss, 1);
1171 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
1172 __ jmp(ic, RelocInfo::CODE_TARGET);
1173
1174 // Return the generated code.
1175 return GetCode(NORMAL, name);
1176}
1177
1178
1179Object* StoreStubCompiler::CompileStoreField(JSObject* object,
1180 int index,
1181 Map* transition,
1182 String* name) {
1183 // ----------- S t a t e -------------
1184 // -- eax : value
1185 // -- ecx : name
1186 // -- esp[0] : return address
1187 // -- esp[4] : receiver
1188 // -----------------------------------
1189 Label miss;
1190
1191 // Get the object from the stack.
1192 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1193
1194 // Generate store field code. Trashes the name register.
1195 GenerateStoreField(masm(),
1196 Builtins::StoreIC_ExtendStorage,
1197 object,
1198 index,
1199 transition,
1200 ebx, ecx, edx,
1201 &miss);
1202
1203 // Handle store cache miss.
1204 __ bind(&miss);
1205 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
1206 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1207 __ jmp(ic, RelocInfo::CODE_TARGET);
1208
1209 // Return the generated code.
1210 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1211}
1212
1213
1214Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
1215 AccessorInfo* callback,
1216 String* name) {
1217 // ----------- S t a t e -------------
1218 // -- eax : value
1219 // -- ecx : name
1220 // -- esp[0] : return address
1221 // -- esp[4] : receiver
1222 // -----------------------------------
1223 Label miss;
1224
1225 // Get the object from the stack.
1226 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1227
1228 // Check that the object isn't a smi.
1229 __ test(ebx, Immediate(kSmiTagMask));
1230 __ j(zero, &miss, not_taken);
1231
1232 // Check that the map of the object hasn't changed.
1233 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1234 Immediate(Handle<Map>(object->map())));
1235 __ j(not_equal, &miss, not_taken);
1236
1237 // Perform global security token check if needed.
1238 if (object->IsJSGlobalProxy()) {
1239 __ CheckAccessGlobalProxy(ebx, edx, &miss);
1240 }
1241
1242 // Stub never generated for non-global objects that require access
1243 // checks.
1244 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
1245
1246 __ pop(ebx); // remove the return address
1247 __ push(Operand(esp, 0)); // receiver
1248 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
1249 __ push(ecx); // name
1250 __ push(eax); // value
1251 __ push(ebx); // restore return address
1252
1253 // Do tail-call to the runtime system.
1254 ExternalReference store_callback_property =
1255 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
1256 __ TailCallRuntime(store_callback_property, 4, 1);
1257
1258 // Handle store cache miss.
1259 __ bind(&miss);
1260 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
1261 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1262 __ jmp(ic, RelocInfo::CODE_TARGET);
1263
1264 // Return the generated code.
1265 return GetCode(CALLBACKS, name);
1266}
1267
1268
1269Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
1270 String* name) {
1271 // ----------- S t a t e -------------
1272 // -- eax : value
1273 // -- ecx : name
1274 // -- esp[0] : return address
1275 // -- esp[4] : receiver
1276 // -----------------------------------
1277 Label miss;
1278
1279 // Get the object from the stack.
1280 __ mov(ebx, Operand(esp, 1 * kPointerSize));
1281
1282 // Check that the object isn't a smi.
1283 __ test(ebx, Immediate(kSmiTagMask));
1284 __ j(zero, &miss, not_taken);
1285
1286 // Check that the map of the object hasn't changed.
1287 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1288 Immediate(Handle<Map>(receiver->map())));
1289 __ j(not_equal, &miss, not_taken);
1290
1291 // Perform global security token check if needed.
1292 if (receiver->IsJSGlobalProxy()) {
1293 __ CheckAccessGlobalProxy(ebx, edx, &miss);
1294 }
1295
1296 // Stub never generated for non-global objects that require access
1297 // checks.
1298 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
1299
1300 __ pop(ebx); // remove the return address
1301 __ push(Operand(esp, 0)); // receiver
1302 __ push(ecx); // name
1303 __ push(eax); // value
1304 __ push(ebx); // restore return address
1305
1306 // Do tail-call to the runtime system.
1307 ExternalReference store_ic_property =
1308 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
1309 __ TailCallRuntime(store_ic_property, 3, 1);
1310
1311 // Handle store cache miss.
1312 __ bind(&miss);
1313 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
1314 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1315 __ jmp(ic, RelocInfo::CODE_TARGET);
1316
1317 // Return the generated code.
1318 return GetCode(INTERCEPTOR, name);
1319}
1320
1321
1322Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
1323 JSGlobalPropertyCell* cell,
1324 String* name) {
1325 // ----------- S t a t e -------------
1326 // -- eax : value
1327 // -- ecx : name
1328 // -- esp[0] : return address
1329 // -- esp[4] : receiver
1330 // -----------------------------------
1331 Label miss;
1332
1333 // Check that the map of the global has not changed.
1334 __ mov(ebx, Operand(esp, kPointerSize));
1335 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1336 Immediate(Handle<Map>(object->map())));
1337 __ j(not_equal, &miss, not_taken);
1338
1339 // Store the value in the cell.
1340 __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1341 __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
1342
1343 // Return the value (register eax).
1344 __ IncrementCounter(&Counters::named_store_global_inline, 1);
1345 __ ret(0);
1346
1347 // Handle store cache miss.
1348 __ bind(&miss);
1349 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
1350 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
1351 __ jmp(ic, RelocInfo::CODE_TARGET);
1352
1353 // Return the generated code.
1354 return GetCode(NORMAL, name);
1355}
1356
1357
1358Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1359 int index,
1360 Map* transition,
1361 String* name) {
1362 // ----------- S t a t e -------------
1363 // -- eax : value
1364 // -- esp[0] : return address
1365 // -- esp[4] : key
1366 // -- esp[8] : receiver
1367 // -----------------------------------
1368 Label miss;
1369
1370 __ IncrementCounter(&Counters::keyed_store_field, 1);
1371
1372 // Get the name from the stack.
1373 __ mov(ecx, Operand(esp, 1 * kPointerSize));
1374 // Check that the name has not changed.
1375 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
1376 __ j(not_equal, &miss, not_taken);
1377
1378 // Get the object from the stack.
1379 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1380
1381 // Generate store field code. Trashes the name register.
1382 GenerateStoreField(masm(),
1383 Builtins::KeyedStoreIC_ExtendStorage,
1384 object,
1385 index,
1386 transition,
1387 ebx, ecx, edx,
1388 &miss);
1389
1390 // Handle store cache miss.
1391 __ bind(&miss);
1392 __ DecrementCounter(&Counters::keyed_store_field, 1);
1393 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1394 __ jmp(ic, RelocInfo::CODE_TARGET);
1395
1396 // Return the generated code.
1397 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
1398}
1399
1400
1401
1402Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1403 JSObject* holder,
1404 int index,
1405 String* name) {
1406 // ----------- S t a t e -------------
1407 // -- ecx : name
1408 // -- esp[0] : return address
1409 // -- esp[4] : receiver
1410 // -----------------------------------
1411 Label miss;
1412
1413 __ mov(eax, Operand(esp, kPointerSize));
1414 GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
1415 __ bind(&miss);
1416 GenerateLoadMiss(masm(), Code::LOAD_IC);
1417
1418 // Return the generated code.
1419 return GetCode(FIELD, name);
1420}
1421
1422
1423Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
1424 JSObject* holder,
1425 AccessorInfo* callback,
1426 String* name) {
1427 // ----------- S t a t e -------------
1428 // -- ecx : name
1429 // -- esp[0] : return address
1430 // -- esp[4] : receiver
1431 // -----------------------------------
1432 Label miss;
1433
1434 __ mov(eax, Operand(esp, kPointerSize));
1435 GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
1436 callback, name, &miss);
1437 __ bind(&miss);
1438 GenerateLoadMiss(masm(), Code::LOAD_IC);
1439
1440 // Return the generated code.
1441 return GetCode(CALLBACKS, name);
1442}
1443
1444
1445Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1446 JSObject* holder,
1447 Object* value,
1448 String* name) {
1449 // ----------- S t a t e -------------
1450 // -- ecx : name
1451 // -- esp[0] : return address
1452 // -- esp[4] : receiver
1453 // -----------------------------------
1454 Label miss;
1455
1456 __ mov(eax, Operand(esp, kPointerSize));
1457 GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
1458 __ bind(&miss);
1459 GenerateLoadMiss(masm(), Code::LOAD_IC);
1460
1461 // Return the generated code.
1462 return GetCode(CONSTANT_FUNCTION, name);
1463}
1464
1465
1466Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1467 JSObject* holder,
1468 String* name) {
1469 // ----------- S t a t e -------------
1470 // -- ecx : name
1471 // -- esp[0] : return address
1472 // -- esp[4] : receiver
1473 // -----------------------------------
1474 Label miss;
1475
1476 LookupResult lookup;
1477 LookupPostInterceptor(holder, name, &lookup);
1478
1479 __ mov(eax, Operand(esp, kPointerSize));
1480 // TODO(368): Compile in the whole chain: all the interceptors in
1481 // prototypes and ultimate answer.
1482 GenerateLoadInterceptor(receiver,
1483 holder,
1484 &lookup,
1485 eax,
1486 ecx,
1487 edx,
1488 ebx,
1489 name,
1490 &miss);
1491
1492 __ bind(&miss);
1493 GenerateLoadMiss(masm(), Code::LOAD_IC);
1494
1495 // Return the generated code.
1496 return GetCode(INTERCEPTOR, name);
1497}
1498
1499
1500Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1501 GlobalObject* holder,
1502 JSGlobalPropertyCell* cell,
1503 String* name,
1504 bool is_dont_delete) {
1505 // ----------- S t a t e -------------
1506 // -- ecx : name
1507 // -- esp[0] : return address
1508 // -- esp[4] : receiver
1509 // -----------------------------------
1510 Label miss;
1511
1512 // Get the receiver from the stack.
1513 __ mov(eax, Operand(esp, kPointerSize));
1514
1515 // If the object is the holder then we know that it's a global
1516 // object which can only happen for contextual loads. In this case,
1517 // the receiver cannot be a smi.
1518 if (object != holder) {
1519 __ test(eax, Immediate(kSmiTagMask));
1520 __ j(zero, &miss, not_taken);
1521 }
1522
1523 // Check that the maps haven't changed.
1524 CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
1525
1526 // Get the value from the cell.
1527 __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1528 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
1529
1530 // Check for deleted property if property can actually be deleted.
1531 if (!is_dont_delete) {
1532 __ cmp(eax, Factory::the_hole_value());
1533 __ j(equal, &miss, not_taken);
1534 } else if (FLAG_debug_code) {
1535 __ cmp(eax, Factory::the_hole_value());
1536 __ Check(not_equal, "DontDelete cells can't contain the hole");
1537 }
1538
1539 __ IncrementCounter(&Counters::named_load_global_inline, 1);
1540 __ ret(0);
1541
1542 __ bind(&miss);
1543 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
1544 GenerateLoadMiss(masm(), Code::LOAD_IC);
1545
1546 // Return the generated code.
1547 return GetCode(NORMAL, name);
1548}
1549
1550
1551Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1552 JSObject* receiver,
1553 JSObject* holder,
1554 int index) {
1555 // ----------- S t a t e -------------
1556 // -- esp[0] : return address
1557 // -- esp[4] : name
1558 // -- esp[8] : receiver
1559 // -----------------------------------
1560 Label miss;
1561
1562 __ mov(eax, Operand(esp, kPointerSize));
1563 __ mov(ecx, Operand(esp, 2 * kPointerSize));
1564 __ IncrementCounter(&Counters::keyed_load_field, 1);
1565
1566 // Check that the name has not changed.
1567 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1568 __ j(not_equal, &miss, not_taken);
1569
1570 GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss);
1571
1572 __ bind(&miss);
1573 __ DecrementCounter(&Counters::keyed_load_field, 1);
1574 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1575
1576 // Return the generated code.
1577 return GetCode(FIELD, name);
1578}
1579
1580
1581Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1582 JSObject* receiver,
1583 JSObject* holder,
1584 AccessorInfo* callback) {
1585 // ----------- S t a t e -------------
1586 // -- esp[0] : return address
1587 // -- esp[4] : name
1588 // -- esp[8] : receiver
1589 // -----------------------------------
1590 Label miss;
1591
1592 __ mov(eax, Operand(esp, kPointerSize));
1593 __ mov(ecx, Operand(esp, 2 * kPointerSize));
1594 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1595
1596 // Check that the name has not changed.
1597 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1598 __ j(not_equal, &miss, not_taken);
1599
1600 GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx,
1601 callback, name, &miss);
1602 __ bind(&miss);
1603 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1604 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1605
1606 // Return the generated code.
1607 return GetCode(CALLBACKS, name);
1608}
1609
1610
1611Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1612 JSObject* receiver,
1613 JSObject* holder,
1614 Object* value) {
1615 // ----------- S t a t e -------------
1616 // -- esp[0] : return address
1617 // -- esp[4] : name
1618 // -- esp[8] : receiver
1619 // -----------------------------------
1620 Label miss;
1621
1622 __ mov(eax, Operand(esp, kPointerSize));
1623 __ mov(ecx, Operand(esp, 2 * kPointerSize));
1624 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1625
1626 // Check that the name has not changed.
1627 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1628 __ j(not_equal, &miss, not_taken);
1629
1630 GenerateLoadConstant(receiver, holder, ecx, ebx, edx,
1631 value, name, &miss);
1632 __ bind(&miss);
1633 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1634 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1635
1636 // Return the generated code.
1637 return GetCode(CONSTANT_FUNCTION, name);
1638}
1639
1640
1641Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1642 JSObject* holder,
1643 String* name) {
1644 // ----------- S t a t e -------------
1645 // -- esp[0] : return address
1646 // -- esp[4] : name
1647 // -- esp[8] : receiver
1648 // -----------------------------------
1649 Label miss;
1650
1651 __ mov(eax, Operand(esp, kPointerSize));
1652 __ mov(ecx, Operand(esp, 2 * kPointerSize));
1653 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1654
1655 // Check that the name has not changed.
1656 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1657 __ j(not_equal, &miss, not_taken);
1658
1659 LookupResult lookup;
1660 LookupPostInterceptor(holder, name, &lookup);
1661 GenerateLoadInterceptor(receiver,
1662 holder,
1663 &lookup,
1664 ecx,
1665 eax,
1666 edx,
1667 ebx,
1668 name,
1669 &miss);
1670 __ bind(&miss);
1671 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1672 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1673
1674 // Return the generated code.
1675 return GetCode(INTERCEPTOR, name);
1676}
1677
1678
1679
1680
1681Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1682 // ----------- S t a t e -------------
1683 // -- esp[0] : return address
1684 // -- esp[4] : name
1685 // -- esp[8] : receiver
1686 // -----------------------------------
1687 Label miss;
1688
1689 __ mov(eax, Operand(esp, kPointerSize));
1690 __ mov(ecx, Operand(esp, 2 * kPointerSize));
1691 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1692
1693 // Check that the name has not changed.
1694 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1695 __ j(not_equal, &miss, not_taken);
1696
1697 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1698 __ bind(&miss);
1699 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1700 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1701
1702 // Return the generated code.
1703 return GetCode(CALLBACKS, name);
1704}
1705
1706
1707Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
1708 // ----------- S t a t e -------------
1709 // -- esp[0] : return address
1710 // -- esp[4] : name
1711 // -- esp[8] : receiver
1712 // -----------------------------------
1713 Label miss;
1714
1715 __ mov(eax, Operand(esp, kPointerSize));
1716 __ mov(ecx, Operand(esp, 2 * kPointerSize));
1717 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1718
1719 // Check that the name has not changed.
1720 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1721 __ j(not_equal, &miss, not_taken);
1722
1723 GenerateLoadStringLength(masm(), ecx, edx, &miss);
1724 __ bind(&miss);
1725 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1726 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1727
1728 // Return the generated code.
1729 return GetCode(CALLBACKS, name);
1730}
1731
1732
1733Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1734 // ----------- S t a t e -------------
1735 // -- esp[0] : return address
1736 // -- esp[4] : name
1737 // -- esp[8] : receiver
1738 // -----------------------------------
1739 Label miss;
1740
1741 __ mov(eax, Operand(esp, kPointerSize));
1742 __ mov(ecx, Operand(esp, 2 * kPointerSize));
1743 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1744
1745 // Check that the name has not changed.
1746 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1747 __ j(not_equal, &miss, not_taken);
1748
1749 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1750 __ bind(&miss);
1751 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1752 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1753
1754 // Return the generated code.
1755 return GetCode(CALLBACKS, name);
1756}
1757
1758
1759// Specialized stub for constructing objects from functions which only have only
1760// simple assignments of the form this.x = ...; in their body.
1761Object* ConstructStubCompiler::CompileConstructStub(
1762 SharedFunctionInfo* shared) {
1763 // ----------- S t a t e -------------
1764 // -- eax : argc
1765 // -- edi : constructor
1766 // -- esp[0] : return address
1767 // -- esp[4] : last argument
1768 // -----------------------------------
1769 Label generic_stub_call;
1770#ifdef ENABLE_DEBUGGER_SUPPORT
1771 // Check to see whether there are any break points in the function code. If
1772 // there are jump to the generic constructor stub which calls the actual
1773 // code for the function thereby hitting the break points.
1774 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1775 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset));
1776 __ cmp(ebx, Factory::undefined_value());
1777 __ j(not_equal, &generic_stub_call, not_taken);
1778#endif
1779
1780 // Load the initial map and verify that it is in fact a map.
1781 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1782 // Will both indicate a NULL and a Smi.
1783 __ test(ebx, Immediate(kSmiTagMask));
1784 __ j(zero, &generic_stub_call);
1785 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1786 __ j(not_equal, &generic_stub_call);
1787
1788#ifdef DEBUG
1789 // Cannot construct functions this way.
1790 // edi: constructor
1791 // ebx: initial map
1792 __ CmpInstanceType(ebx, JS_FUNCTION_TYPE);
1793 __ Assert(not_equal, "Function constructed by construct stub.");
1794#endif
1795
1796 // Now allocate the JSObject on the heap by moving the new space allocation
1797 // top forward.
1798 // edi: constructor
1799 // ebx: initial map
1800 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
1801 __ shl(ecx, kPointerSizeLog2);
1802 __ AllocateInNewSpace(ecx,
1803 edx,
1804 ecx,
1805 no_reg,
1806 &generic_stub_call,
1807 NO_ALLOCATION_FLAGS);
1808
1809 // Allocated the JSObject, now initialize the fields and add the heap tag.
1810 // ebx: initial map
1811 // edx: JSObject (untagged)
1812 __ mov(Operand(edx, JSObject::kMapOffset), ebx);
1813 __ mov(ebx, Factory::empty_fixed_array());
1814 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx);
1815 __ mov(Operand(edx, JSObject::kElementsOffset), ebx);
1816
1817 // Push the allocated object to the stack. This is the object that will be
1818 // returned (after it is tagged).
1819 __ push(edx);
1820
1821 // eax: argc
1822 // edx: JSObject (untagged)
1823 // Load the address of the first in-object property into edx.
1824 __ lea(edx, Operand(edx, JSObject::kHeaderSize));
1825 // Calculate the location of the first argument. The stack contains the
1826 // allocated object and the return address on top of the argc arguments.
1827 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize));
1828
1829 // Use edi for holding undefined which is used in several places below.
1830 __ mov(edi, Factory::undefined_value());
1831
1832 // eax: argc
1833 // ecx: first argument
1834 // edx: first in-object property of the JSObject
1835 // edi: undefined
1836 // Fill the initialized properties with a constant value or a passed argument
1837 // depending on the this.x = ...; assignment in the function.
1838 for (int i = 0; i < shared->this_property_assignments_count(); i++) {
1839 if (shared->IsThisPropertyAssignmentArgument(i)) {
1840 Label not_passed;
1841 // Set the property to undefined.
1842 __ mov(Operand(edx, i * kPointerSize), edi);
1843 // Check if the argument assigned to the property is actually passed.
1844 int arg_number = shared->GetThisPropertyAssignmentArgument(i);
1845 __ cmp(eax, arg_number);
1846 __ j(below_equal, &not_passed);
1847 // Argument passed - find it on the stack.
1848 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize));
1849 __ mov(Operand(edx, i * kPointerSize), ebx);
1850 __ bind(&not_passed);
1851 } else {
1852 // Set the property to the constant value.
1853 Handle<Object> constant(shared->GetThisPropertyAssignmentConstant(i));
1854 __ mov(Operand(edx, i * kPointerSize), Immediate(constant));
1855 }
1856 }
1857
1858 // Fill the unused in-object property fields with undefined.
1859 for (int i = shared->this_property_assignments_count();
1860 i < shared->CalculateInObjectProperties();
1861 i++) {
1862 __ mov(Operand(edx, i * kPointerSize), edi);
1863 }
1864
1865 // Move argc to ebx and retrieve and tag the JSObject to return.
1866 __ mov(ebx, eax);
1867 __ pop(eax);
1868 __ or_(Operand(eax), Immediate(kHeapObjectTag));
1869
1870 // Remove caller arguments and receiver from the stack and return.
1871 __ pop(ecx);
1872 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1873 __ push(ecx);
1874 __ IncrementCounter(&Counters::constructed_objects, 1);
1875 __ IncrementCounter(&Counters::constructed_objects_stub, 1);
1876 __ ret(0);
1877
1878 // Jump to the generic stub in case the specialized code cannot handle the
1879 // construction.
1880 __ bind(&generic_stub_call);
1881 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1882 Handle<Code> generic_construct_stub(code);
1883 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1884
1885 // Return the generated code.
1886 return GetCode();
1887}
1888
1889
1890#undef __
1891
1892} } // namespace v8::internal