blob: a0ef7d851485944e23e7662fafd07677e0c6681c [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001// Copyright 2006-2008 Google Inc. 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 { namespace internal {
35
36#define __ masm->
37
38
39static void ProbeTable(MacroAssembler* masm,
40 Code::Flags flags,
41 StubCache::Table table,
42 Register name,
43 Register offset) {
44 ExternalReference key_offset(SCTableReference::keyReference(table));
45 ExternalReference value_offset(SCTableReference::valueReference(table));
46
47 Label miss;
48
49 // Save the offset on the stack.
50 __ push(offset);
51
52 // Check that the key in the entry matches the name.
53 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
54 __ j(not_equal, &miss, not_taken);
55
56 // Get the code entry from the cache.
57 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
58
59 // Check that the flags match what we're looking for.
60 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
61 __ and_(offset, ~Code::kFlagsTypeMask);
62 __ cmp(offset, flags);
63 __ j(not_equal, &miss);
64
65 // Restore offset and re-load code entry from cache.
66 __ pop(offset);
67 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
68
69 // Jump to the first instruction in the code stub.
70 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
71 __ jmp(Operand(offset));
72
73 // Miss: Restore offset and fall through.
74 __ bind(&miss);
75 __ pop(offset);
76}
77
78
79void StubCache::GenerateProbe(MacroAssembler* masm,
80 Code::Flags flags,
81 Register receiver,
82 Register name,
83 Register scratch) {
84 Label miss;
85
86 // Make sure that code is valid. The shifting code relies on the
87 // entry size being 8.
88 ASSERT(sizeof(Entry) == 8);
89
90 // Make sure the flags does not name a specific type.
91 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
92
93 // Make sure that there are no register conflicts.
94 ASSERT(!scratch.is(receiver));
95 ASSERT(!scratch.is(name));
96
97 // Check that the receiver isn't a smi.
98 __ test(receiver, Immediate(kSmiTagMask));
99 __ j(zero, &miss, not_taken);
100
101 // Get the map of the receiver and compute the hash.
102 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
103 __ add(scratch, FieldOperand(name, String::kLengthOffset));
104 __ xor_(scratch, flags);
105 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
106
107 // Probe the primary table.
108 ProbeTable(masm, flags, kPrimary, name, scratch);
109
110 // Primary miss: Compute hash for secondary probe.
111 __ sub(scratch, Operand(name));
112 __ add(Operand(scratch), Immediate(flags));
113 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
114
115 // Probe the secondary table.
116 ProbeTable(masm, flags, kSecondary, name, scratch);
117
118 // Cache miss: Fall-through and let caller handle the miss by
119 // entering the runtime system.
120 __ bind(&miss);
121}
122
123
124void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
125 int index,
126 Register prototype) {
127 // Load the global or builtins object from the current context.
128 __ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
129 // Load the global context from the global or builtins object.
130 __ mov(prototype,
131 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
132 // Load the function from the global context.
133 __ mov(prototype, Operand(prototype, Context::SlotOffset(index)));
134 // Load the initial map. The global functions all have initial maps.
135 __ mov(prototype,
136 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
137 // Load the prototype from the initial map.
138 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
139}
140
141
142void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
143 Register receiver,
144 Register scratch,
145 Label* miss_label) {
146 // Check that the receiver isn't a smi.
147 __ test(receiver, Immediate(kSmiTagMask));
148 __ j(zero, miss_label, not_taken);
149
150 // Check that the object is a JS array.
151 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
152 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
153 __ cmp(scratch, JS_ARRAY_TYPE);
154 __ j(not_equal, miss_label, not_taken);
155
156 // Load length directly from the JS array.
157 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
158 __ ret(0);
159}
160
161
162void StubCompiler::GenerateLoadShortStringLength(MacroAssembler* masm,
163 Register receiver,
164 Register scratch,
165 Label* miss_label) {
166 // Check that the receiver isn't a smi.
167 __ test(receiver, Immediate(kSmiTagMask));
168 __ j(zero, miss_label, not_taken);
169
170 // Check that the object is a short string.
171 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
172 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
173 __ and_(scratch, kIsNotStringMask | kStringSizeMask);
174 __ cmp(scratch, kStringTag | kShortStringTag);
175 __ j(not_equal, miss_label, not_taken);
176
177 // Load length directly from the string.
178 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
179 __ shr(eax, String::kShortLengthShift);
180 __ shl(eax, kSmiTagSize);
181 __ ret(0);
182}
183
184void StubCompiler::GenerateLoadMediumStringLength(MacroAssembler* masm,
185 Register receiver,
186 Register scratch,
187 Label* miss_label) {
188 // Check that the receiver isn't a smi.
189 __ test(receiver, Immediate(kSmiTagMask));
190 __ j(zero, miss_label, not_taken);
191
192 // Check that the object is a short string.
193 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
194 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
195 __ and_(scratch, kIsNotStringMask | kStringSizeMask);
196 __ cmp(scratch, kStringTag | kMediumStringTag);
197 __ j(not_equal, miss_label, not_taken);
198
199 // Load length directly from the string.
200 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
201 __ shr(eax, String::kMediumLengthShift);
202 __ shl(eax, kSmiTagSize);
203 __ ret(0);
204}
205
206
207void StubCompiler::GenerateLoadLongStringLength(MacroAssembler* masm,
208 Register receiver,
209 Register scratch,
210 Label* miss_label) {
211 // Check that the receiver isn't a smi.
212 __ test(receiver, Immediate(kSmiTagMask));
213 __ j(zero, miss_label, not_taken);
214
215 // Check that the object is a short string.
216 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
217 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
218 __ and_(scratch, kIsNotStringMask | kStringSizeMask);
219 __ cmp(scratch, kStringTag | kLongStringTag);
220 __ j(not_equal, miss_label, not_taken);
221
222 // Load length directly from the string.
223 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
224 __ shr(eax, String::kLongLengthShift);
225 __ shl(eax, kSmiTagSize);
226 __ ret(0);
227}
228
229
230void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
231 Register receiver,
232 Register scratch1,
233 Register scratch2,
234 Label* miss_label) {
235 // Check that the receiver isn't a smi.
236 __ test(receiver, Immediate(kSmiTagMask));
237 __ j(zero, miss_label, not_taken);
238
239 // Check that the receiver is a function.
240 __ mov(scratch1, FieldOperand(receiver, HeapObject::kMapOffset));
241 __ movzx_b(scratch2, FieldOperand(scratch1, Map::kInstanceTypeOffset));
242 __ cmp(scratch2, JS_FUNCTION_TYPE);
243 __ j(not_equal, miss_label, not_taken);
244
245 // Make sure that the function has an instance prototype.
246 Label non_instance;
247 __ movzx_b(scratch2, FieldOperand(scratch1, Map::kBitFieldOffset));
248 __ test(scratch2, Immediate(1 << Map::kHasNonInstancePrototype));
249 __ j(not_zero, &non_instance, not_taken);
250
251 // Get the prototype or initial map from the function.
252 __ mov(scratch1,
253 FieldOperand(receiver, JSFunction::kPrototypeOrInitialMapOffset));
254
255 // If the prototype or initial map is the hole, don't return it and
256 // simply miss the cache instead. This will allow us to allocate a
257 // prototype object on-demand in the runtime system.
258 __ cmp(Operand(scratch1), Immediate(Factory::the_hole_value()));
259 __ j(equal, miss_label, not_taken);
260 __ mov(eax, Operand(scratch1));
261
262 // If the function does not have an initial map, we're done.
263 Label done;
264 __ mov(scratch1, FieldOperand(eax, HeapObject::kMapOffset));
265 __ movzx_b(scratch2, FieldOperand(scratch1, Map::kInstanceTypeOffset));
266 __ cmp(scratch2, MAP_TYPE);
267 __ j(not_equal, &done);
268
269 // Get the prototype from the initial map.
270 __ mov(eax, FieldOperand(eax, Map::kPrototypeOffset));
271
272 // All done: Return the prototype.
273 __ bind(&done);
274 __ ret(0);
275
276 // Non-instance prototype: Fetch prototype from constructor field
277 // in initial map.
278 __ bind(&non_instance);
279 __ mov(eax, FieldOperand(scratch1, Map::kConstructorOffset));
280 __ ret(0);
281}
282
283
284void StubCompiler::GenerateLoadField(MacroAssembler* masm,
285 JSObject* object,
286 JSObject* holder,
287 Register receiver,
288 Register scratch1,
289 Register scratch2,
290 int index,
291 Label* miss_label) {
292 // Check that the receiver isn't a smi.
293 __ test(receiver, Immediate(kSmiTagMask));
294 __ j(zero, miss_label, not_taken);
295
296 // Check that the maps haven't changed.
297 Register reg =
298 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
299
300 // Get the properties array of the holder.
301 __ mov(scratch1, FieldOperand(reg, JSObject::kPropertiesOffset));
302
303 // Return the value from the properties array.
304 int offset = index * kPointerSize + Array::kHeaderSize;
305 __ mov(eax, FieldOperand(scratch1, offset));
306 __ ret(0);
307}
308
309
310void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
311 JSObject* object,
312 JSObject* holder,
313 Register receiver,
314 Register name,
315 Register scratch1,
316 Register scratch2,
317 AccessorInfo* callback,
318 Label* miss_label) {
319 // Check that the receiver isn't a smi.
320 __ test(receiver, Immediate(kSmiTagMask));
321 __ j(zero, miss_label, not_taken);
322
323 // Check that the maps haven't changed.
324 Register reg =
325 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
326
327 // Push the arguments on the JS stack of the caller.
328 __ pop(scratch2); // remove return address
329 __ push(receiver); // receiver
330 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
331 __ push(name); // name
332 __ push(reg); // holder
333 __ push(scratch2); // restore return address
334
335 // Do tail-call to the C builtin.
336 __ mov(eax, 3); // not counting receiver
337 __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kLoadCallbackProperty)));
338}
339
340
341void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
342 JSObject* object,
343 JSObject* holder,
344 Register receiver,
345 Register scratch1,
346 Register scratch2,
347 Object* value,
348 Label* miss_label) {
349 // Check that the receiver isn't a smi.
350 __ test(receiver, Immediate(kSmiTagMask));
351 __ j(zero, miss_label, not_taken);
352
353 // Check that the maps haven't changed.
354 Register reg =
355 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
356
357 // Return the constant value.
358 __ mov(eax, Handle<Object>(value));
359 __ ret(0);
360}
361
362
363void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
364 JSObject* object,
365 JSObject* holder,
366 Register receiver,
367 Register name,
368 Register scratch1,
369 Register scratch2,
370 Label* miss_label) {
371 // Check that the receiver isn't a smi.
372 __ test(receiver, Immediate(kSmiTagMask));
373 __ j(zero, miss_label, not_taken);
374
375 // Check that the maps haven't changed.
376 Register reg =
377 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
378
379 // Push the arguments on the JS stack of the caller.
380 __ pop(scratch2); // remove return address
381 __ push(receiver); // receiver
382 __ push(reg); // holder
383 __ push(name); // name
384 __ push(scratch2); // restore return address
385
386 // Do tail-call to the C builtin.
387 __ mov(eax, 2); // not counting receiver
388 __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)));
389}
390
391
392void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
393 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
394 Code* code = NULL;
395 if (kind == Code::LOAD_IC) {
396 code = Builtins::builtin(Builtins::LoadIC_Miss);
397 } else {
398 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
399 }
400
401 Handle<Code> ic(code);
402 __ jmp(ic, code_target);
403}
404
405
406void StubCompiler::GenerateStoreField(MacroAssembler* masm,
407 JSObject* object,
408 int index,
409 Map* transition,
410 Register receiver_reg,
411 Register name_reg,
412 Register scratch,
413 Label* miss_label) {
414 // Check that the object isn't a smi.
415 __ test(receiver_reg, Immediate(kSmiTagMask));
416 __ j(zero, miss_label, not_taken);
417
418 // Check that the map of the object hasn't changed.
419 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
420 Immediate(Handle<Map>(object->map())));
421 __ j(not_equal, miss_label, not_taken);
422
423 // Perform global security token check if needed.
424 if (object->IsJSGlobalObject()) {
425 __ CheckAccessGlobal(receiver_reg, scratch, miss_label);
426 }
427
428 // Stub never generated for non-global objects that require access
429 // checks.
430 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
431
432 // Get the properties array (optimistically).
433 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
434
435 // Perform map transition for the receiver if necessary.
436 if (transition != NULL) {
437 // Update the map of the object; no write barrier updating is
438 // needed because the map is never in new space.
439 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
440 Immediate(Handle<Map>(transition)));
441 }
442
443 // Write to the properties array.
444 int offset = index * kPointerSize + Array::kHeaderSize;
445 __ mov(FieldOperand(scratch, offset), eax);
446
447 // Update the write barrier for the array address.
448 // Pass the value being stored in the now unused name_reg.
449 __ mov(name_reg, Operand(eax));
450 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
451
452 // Return the value (register eax).
453 __ ret(0);
454}
455
456
457#undef __
458
459#define __ masm()->
460
461
462// TODO(1241006): Avoid having lazy compile stubs specialized by the
463// number of arguments. It is not needed anymore.
464Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
465 HandleScope scope;
466
467 // Enter an internal frame.
468 __ EnterFrame(StackFrame::INTERNAL);
469
470 // Push a copy of the function onto the stack.
471 __ push(edi);
472
473 __ push(edi); // function is also the parameter to the runtime call
474 __ CallRuntime(Runtime::kLazyCompile, 1);
475 __ pop(edi);
476
477 __ ExitFrame(StackFrame::INTERNAL);
478
479 // Do a tail-call of the compiled function.
480 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
481 __ jmp(Operand(ecx));
482
483 return GetCodeWithFlags(flags);
484}
485
486
487Object* CallStubCompiler::CompileCallField(Object* object,
488 JSObject* holder,
489 int index) {
490 // ----------- S t a t e -------------
491 // -----------------------------------
492
493 HandleScope scope;
494 Label miss;
495
496 // Get the receiver from the stack.
497 const int argc = arguments().immediate();
498 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
499
500 // Check that the receiver isn't a smi.
501 __ test(edx, Immediate(kSmiTagMask));
502 __ j(zero, &miss, not_taken);
503
504 // Do the right check and compute the holder register.
505 Register reg =
506 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
507
508 // Get the properties array of the holder and get the function from the field.
509 int offset = index * kPointerSize + Array::kHeaderSize;
510 __ mov(edi, FieldOperand(reg, JSObject::kPropertiesOffset));
511 __ mov(edi, FieldOperand(edi, offset));
512
513 // Check that the function really is a function.
514 __ test(edi, Immediate(kSmiTagMask));
515 __ j(zero, &miss, not_taken);
516 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
517 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
518 __ cmp(ebx, JS_FUNCTION_TYPE);
519 __ j(not_equal, &miss, not_taken);
520
521 // Invoke the function.
522 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
523
524 // Handle call cache miss.
525 __ bind(&miss);
526 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
527 __ jmp(ic, code_target);
528
529 // Return the generated code.
530 return GetCode(FIELD);
531}
532
533
534Object* CallStubCompiler::CompileCallConstant(Object* object,
535 JSObject* holder,
536 JSFunction* function,
537 CheckType check) {
538 // ----------- S t a t e -------------
539 // -----------------------------------
540
541 HandleScope scope;
542 Label miss;
543
544 // Get the receiver from the stack.
545 const int argc = arguments().immediate();
546 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
547
548 // Check that the receiver isn't a smi.
549 if (check != NUMBER_CHECK) {
550 __ test(edx, Immediate(kSmiTagMask));
551 __ j(zero, &miss, not_taken);
552 }
553
554 switch (check) {
555 case RECEIVER_MAP_CHECK:
556 // Check that the maps haven't changed.
557 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
558 break;
559
560 case STRING_CHECK:
561 // Check that the object is a two-byte string or a symbol.
562 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
563 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
564 __ cmp(ecx, FIRST_NONSTRING_TYPE);
565 __ j(above_equal, &miss, not_taken);
566 // Check that the maps starting from the prototype haven't changed.
567 GenerateLoadGlobalFunctionPrototype(masm(),
568 Context::STRING_FUNCTION_INDEX,
569 ecx);
570 __ CheckMaps(JSObject::cast(object->GetPrototype()),
571 ecx, holder, ebx, edx, &miss);
572 break;
573
574 case NUMBER_CHECK: {
575 Label fast;
576 // Check that the object is a smi or a heap number.
577 __ test(edx, Immediate(kSmiTagMask));
578 __ j(zero, &fast, taken);
579 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
580 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
581 __ cmp(ecx, HEAP_NUMBER_TYPE);
582 __ j(not_equal, &miss, not_taken);
583 __ bind(&fast);
584 // Check that the maps starting from the prototype haven't changed.
585 GenerateLoadGlobalFunctionPrototype(masm(),
586 Context::NUMBER_FUNCTION_INDEX,
587 ecx);
588 __ CheckMaps(JSObject::cast(object->GetPrototype()),
589 ecx, holder, ebx, edx, &miss);
590 break;
591 }
592
593 case BOOLEAN_CHECK: {
594 Label fast;
595 // Check that the object is a boolean.
596 __ cmp(edx, Factory::true_value());
597 __ j(equal, &fast, taken);
598 __ cmp(edx, Factory::false_value());
599 __ j(not_equal, &miss, not_taken);
600 __ bind(&fast);
601 // Check that the maps starting from the prototype haven't changed.
602 GenerateLoadGlobalFunctionPrototype(masm(),
603 Context::BOOLEAN_FUNCTION_INDEX,
604 ecx);
605 __ CheckMaps(JSObject::cast(object->GetPrototype()),
606 ecx, holder, ebx, edx, &miss);
607 break;
608 }
609
610 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
611 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
612 // Make sure object->elements()->map() != Heap::dictionary_array_map()
613 // Get the elements array of the object.
614 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
615 // Check that the object is in fast mode (not dictionary).
616 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
617 Immediate(Factory::hash_table_map()));
618 __ j(equal, &miss, not_taken);
619 break;
620
621 default:
622 UNREACHABLE();
623 }
624
625 // Get the function and setup the context.
626 __ mov(Operand(edi), Immediate(Handle<JSFunction>(function)));
627 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
628
629 // Jump to the cached code (tail call).
630 Handle<Code> code(function->code());
631 ParameterCount expected(function->shared()->formal_parameter_count());
632 __ InvokeCode(code, expected, arguments(), code_target, JUMP_FUNCTION);
633
634 // Handle call cache miss.
635 __ bind(&miss);
636 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
637 __ jmp(ic, code_target);
638
639 // Return the generated code.
640 return GetCode(CONSTANT_FUNCTION);
641}
642
643
644Object* CallStubCompiler::CompileCallInterceptor(Object* object,
645 JSObject* holder,
646 String* name) {
647 // ----------- S t a t e -------------
648 // -----------------------------------
649
650 HandleScope scope;
651 Label miss;
652
653 // Get the number of arguments.
654 const int argc = arguments().immediate();
655
656 // Get the receiver from the stack.
657 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
658 // Check that the receiver isn't a smi.
659 __ test(edx, Immediate(kSmiTagMask));
660 __ j(zero, &miss, not_taken);
661
662 // Check that maps have not changed and compute the holder register.
663 Register reg =
664 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
665
666 // Enter an internal frame.
667 __ EnterFrame(StackFrame::INTERNAL);
668
669 // Push arguments on the expression stack.
670 __ push(edx); // receiver
671 __ push(reg); // holder
672 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
673
674 // Perform call.
675 __ mov(Operand(eax), Immediate(2)); // 2 arguments w/o receiver
676 ExternalReference load_interceptor =
677 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
678 __ mov(Operand(ebx), Immediate(load_interceptor));
679
680 CEntryStub stub;
681 __ CallStub(&stub);
682
683 // Move result to edi and restore receiver.
684 __ mov(Operand(edi), eax);
685 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
686
687 // Exit frame.
688 __ ExitFrame(StackFrame::INTERNAL);
689
690 // Check that the function really is a function.
691 __ test(edi, Immediate(kSmiTagMask));
692 __ j(zero, &miss, not_taken);
693 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
694 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
695 __ cmp(ebx, JS_FUNCTION_TYPE);
696 __ j(not_equal, &miss, not_taken);
697
698 // Invoke the function.
699 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
700
701 // Handle load cache miss.
702 __ bind(&miss);
703 Handle<Code> ic = ComputeCallMiss(argc);
704 __ jmp(ic, code_target);
705
706 // Return the generated code.
707 return GetCode(INTERCEPTOR);
708}
709
710
711Object* StoreStubCompiler::CompileStoreField(JSObject* object,
712 int index,
713 Map* transition,
714 String* name) {
715 // ----------- S t a t e -------------
716 // -- eax : value
717 // -- ecx : name
718 // -- esp[0] : return address
719 // -- esp[4] : receiver
720 // -----------------------------------
721
722 HandleScope scope;
723 Label miss;
724
725 // Get the object from the stack.
726 __ mov(ebx, Operand(esp, 1 * kPointerSize));
727
728 // Generate store field code. Trashes the name register.
729 GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
730
731 // Handle store cache miss.
732 __ bind(&miss);
733 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
734 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
735 __ jmp(ic, code_target);
736
737 // Return the generated code.
738 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
739}
740
741
742Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
743 AccessorInfo* callback,
744 String* name) {
745 // ----------- S t a t e -------------
746 // -- eax : value
747 // -- ecx : name
748 // -- esp[0] : return address
749 // -- esp[4] : receiver
750 // -----------------------------------
751
752 HandleScope scope;
753 Label miss;
754
755 // Get the object from the stack.
756 __ mov(ebx, Operand(esp, 1 * kPointerSize));
757
758 // Check that the object isn't a smi.
759 __ test(ebx, Immediate(kSmiTagMask));
760 __ j(zero, &miss, not_taken);
761
762 // Check that the map of the object hasn't changed.
763 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
764 Immediate(Handle<Map>(object->map())));
765 __ j(not_equal, &miss, not_taken);
766
767 // Perform global security token check if needed.
768 if (object->IsJSGlobalObject()) {
769 __ CheckAccessGlobal(ebx, edx, &miss);
770 }
771
772 // Stub never generated for non-global objects that require access
773 // checks.
774 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
775
776 __ pop(ebx); // remove the return address
777 __ push(Operand(esp, 0)); // receiver
778 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
779 __ push(ecx); // name
780 __ push(eax); // value
781 __ push(ebx); // restore return address
782
783 // Do tail-call to the C builtin.
784 __ mov(eax, 3); // not counting receiver
785 __ JumpToBuiltin(ExternalReference(IC_Utility(IC::kStoreCallbackProperty)));
786
787 // Handle store cache miss.
788 __ bind(&miss);
789 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
790 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
791 __ jmp(ic, code_target);
792
793 // Return the generated code.
794 return GetCode(CALLBACKS);
795}
796
797
798Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
799 String* name) {
800 // ----------- S t a t e -------------
801 // -- eax : value
802 // -- ecx : name
803 // -- esp[0] : return address
804 // -- esp[4] : receiver
805 // -----------------------------------
806
807 HandleScope scope;
808 Label miss;
809
810 // Get the object from the stack.
811 __ mov(ebx, Operand(esp, 1 * kPointerSize));
812
813 // Check that the object isn't a smi.
814 __ test(ebx, Immediate(kSmiTagMask));
815 __ j(zero, &miss, not_taken);
816
817 // Check that the map of the object hasn't changed.
818 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
819 Immediate(Handle<Map>(receiver->map())));
820 __ j(not_equal, &miss, not_taken);
821
822 // Perform global security token check if needed.
823 if (receiver->IsJSGlobalObject()) {
824 __ CheckAccessGlobal(ebx, edx, &miss);
825 }
826
827 // Stub never generated for non-global objects that require access
828 // checks.
829 ASSERT(receiver->IsJSGlobalObject() || !receiver->IsAccessCheckNeeded());
830
831 __ pop(ebx); // remove the return address
832 __ push(Operand(esp, 0)); // receiver
833 __ push(ecx); // name
834 __ push(eax); // value
835 __ push(ebx); // restore return address
836
837 // Do tail-call to the C builtin.
838 __ mov(eax, 2); // not counting receiver
839 ExternalReference store_interceptor =
840 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
841 __ JumpToBuiltin(store_interceptor);
842
843 // Handle store cache miss.
844 __ bind(&miss);
845 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
846 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
847 __ jmp(ic, code_target);
848
849 // Return the generated code.
850 return GetCode(INTERCEPTOR);
851}
852
853
854Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
855 int index,
856 Map* transition,
857 String* name) {
858 // ----------- S t a t e -------------
859 // -- eax : value
860 // -- esp[0] : return address
861 // -- esp[4] : key
862 // -- esp[8] : receiver
863 // -----------------------------------
864 HandleScope scope;
865 Label miss;
866
867 __ IncrementCounter(&Counters::keyed_store_field, 1);
868
869 // Get the name from the stack.
870 __ mov(ecx, Operand(esp, 1 * kPointerSize));
871 // Check that the name has not changed.
872 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
873 __ j(not_equal, &miss, not_taken);
874
875 // Get the object from the stack.
876 __ mov(ebx, Operand(esp, 2 * kPointerSize));
877
878 // Generate store field code. Trashes the name register.
879 GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
880
881 // Handle store cache miss.
882 __ bind(&miss);
883 __ DecrementCounter(&Counters::keyed_store_field, 1);
884 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
885 __ jmp(ic, code_target);
886
887 // Return the generated code.
888 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
889}
890
891
892Object* LoadStubCompiler::CompileLoadField(JSObject* object,
893 JSObject* holder,
894 int index) {
895 // ----------- S t a t e -------------
896 // -- ecx : name
897 // -- esp[0] : return address
898 // -- esp[4] : receiver
899 // -----------------------------------
900
901 HandleScope scope;
902 Label miss;
903
904 __ mov(eax, (Operand(esp, kPointerSize)));
905 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
906 __ bind(&miss);
907 GenerateLoadMiss(masm(), Code::LOAD_IC);
908
909 // Return the generated code.
910 return GetCode(FIELD);
911}
912
913
914Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
915 JSObject* holder,
916 AccessorInfo* callback) {
917 // ----------- S t a t e -------------
918 // -- ecx : name
919 // -- esp[0] : return address
920 // -- esp[4] : receiver
921 // -----------------------------------
922
923 HandleScope scope;
924 Label miss;
925
926 __ mov(eax, (Operand(esp, kPointerSize)));
927 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
928 edx, callback, &miss);
929 __ bind(&miss);
930 GenerateLoadMiss(masm(), Code::LOAD_IC);
931
932 // Return the generated code.
933 return GetCode(CALLBACKS);
934}
935
936
937Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
938 JSObject* holder,
939 Object* value) {
940 // ----------- S t a t e -------------
941 // -- ecx : name
942 // -- esp[0] : return address
943 // -- esp[4] : receiver
944 // -----------------------------------
945
946 HandleScope scope;
947 Label miss;
948
949 __ mov(eax, (Operand(esp, kPointerSize)));
950 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
951 __ bind(&miss);
952 GenerateLoadMiss(masm(), Code::LOAD_IC);
953
954 // Return the generated code.
955 return GetCode(CONSTANT_FUNCTION);
956}
957
958
959Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
960 JSObject* holder,
961 String* name) {
962 // ----------- S t a t e -------------
963 // -- ecx : name
964 // -- esp[0] : return address
965 // -- esp[4] : receiver
966 // -----------------------------------
967 HandleScope scope;
968 Label miss;
969
970 __ mov(eax, (Operand(esp, kPointerSize)));
971 GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
972 __ bind(&miss);
973 GenerateLoadMiss(masm(), Code::LOAD_IC);
974
975 // Return the generated code.
976 return GetCode(INTERCEPTOR);
977}
978
979
980Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
981 JSObject* receiver,
982 JSObject* holder,
983 int index) {
984 // ----------- S t a t e -------------
985 // -- esp[0] : return address
986 // -- esp[4] : name
987 // -- esp[8] : receiver
988 // -----------------------------------
989 HandleScope scope;
990 Label miss;
991
992 __ mov(eax, (Operand(esp, kPointerSize)));
993 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
994 __ IncrementCounter(&Counters::keyed_load_field, 1);
995
996 // Check that the name has not changed.
997 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
998 __ j(not_equal, &miss, not_taken);
999
1000 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1001 __ bind(&miss);
1002 __ DecrementCounter(&Counters::keyed_load_field, 1);
1003 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1004
1005 // Return the generated code.
1006 return GetCode(FIELD);
1007}
1008
1009
1010Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1011 JSObject* receiver,
1012 JSObject* holder,
1013 AccessorInfo* callback) {
1014 // ----------- S t a t e -------------
1015 // -- esp[0] : return address
1016 // -- esp[4] : name
1017 // -- esp[8] : receiver
1018 // -----------------------------------
1019 HandleScope scope;
1020 Label miss;
1021
1022 __ mov(eax, (Operand(esp, kPointerSize)));
1023 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1024 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1025
1026 // Check that the name has not changed.
1027 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1028 __ j(not_equal, &miss, not_taken);
1029
1030 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1031 callback, &miss);
1032 __ bind(&miss);
1033 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1034 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1035
1036 // Return the generated code.
1037 return GetCode(CALLBACKS);
1038}
1039
1040
1041Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1042 JSObject* receiver,
1043 JSObject* holder,
1044 Object* value) {
1045 // ----------- S t a t e -------------
1046 // -- esp[0] : return address
1047 // -- esp[4] : name
1048 // -- esp[8] : receiver
1049 // -----------------------------------
1050 HandleScope scope;
1051 Label miss;
1052
1053 __ mov(eax, (Operand(esp, kPointerSize)));
1054 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1055 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1056
1057 // Check that the name has not changed.
1058 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1059 __ j(not_equal, &miss, not_taken);
1060
1061 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1062 __ bind(&miss);
1063 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1064 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1065
1066 // Return the generated code.
1067 return GetCode(CONSTANT_FUNCTION);
1068}
1069
1070
1071Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1072 JSObject* holder,
1073 String* name) {
1074 // ----------- S t a t e -------------
1075 // -- esp[0] : return address
1076 // -- esp[4] : name
1077 // -- esp[8] : receiver
1078 // -----------------------------------
1079 HandleScope scope;
1080 Label miss;
1081
1082 __ mov(eax, (Operand(esp, kPointerSize)));
1083 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1084 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1085
1086 // Check that the name has not changed.
1087 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1088 __ j(not_equal, &miss, not_taken);
1089
1090 GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
1091 __ bind(&miss);
1092 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1093 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1094
1095 // Return the generated code.
1096 return GetCode(INTERCEPTOR);
1097}
1098
1099
1100
1101
1102Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1103 // ----------- S t a t e -------------
1104 // -- esp[0] : return address
1105 // -- esp[4] : name
1106 // -- esp[8] : receiver
1107 // -----------------------------------
1108 HandleScope scope;
1109 Label miss;
1110
1111 __ mov(eax, (Operand(esp, kPointerSize)));
1112 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1113 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1114
1115 // Check that the name has not changed.
1116 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1117 __ j(not_equal, &miss, not_taken);
1118
1119 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1120 __ bind(&miss);
1121 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1122 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1123
1124 // Return the generated code.
1125 return GetCode(CALLBACKS);
1126}
1127
1128
1129Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
1130 // ----------- S t a t e -------------
1131 // -- esp[0] : return address
1132 // -- esp[4] : name
1133 // -- esp[8] : receiver
1134 // -----------------------------------
1135 HandleScope scope;
1136 Label miss;
1137
1138 __ mov(eax, (Operand(esp, kPointerSize)));
1139 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1140 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1141
1142 // Check that the name has not changed.
1143 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1144 __ j(not_equal, &miss, not_taken);
1145
1146 GenerateLoadShortStringLength(masm(), ecx, edx, &miss);
1147 __ bind(&miss);
1148 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1149 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1150
1151 // Return the generated code.
1152 return GetCode(CALLBACKS);
1153}
1154
1155
1156Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
1157 // ----------- S t a t e -------------
1158 // -- esp[0] : return address
1159 // -- esp[4] : name
1160 // -- esp[8] : receiver
1161 // -----------------------------------
1162 HandleScope scope;
1163 Label miss;
1164
1165 __ mov(eax, (Operand(esp, kPointerSize)));
1166 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1167 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1168
1169 // Check that the name has not changed.
1170 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1171 __ j(not_equal, &miss, not_taken);
1172
1173 GenerateLoadMediumStringLength(masm(), ecx, edx, &miss);
1174 __ bind(&miss);
1175 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1176 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1177
1178 // Return the generated code.
1179 return GetCode(CALLBACKS);
1180}
1181
1182
1183Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
1184 // ----------- S t a t e -------------
1185 // -- esp[0] : return address
1186 // -- esp[4] : name
1187 // -- esp[8] : receiver
1188 // -----------------------------------
1189 HandleScope scope;
1190 Label miss;
1191
1192 __ mov(eax, (Operand(esp, kPointerSize)));
1193 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1194 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1195
1196 // Check that the name has not changed.
1197 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1198 __ j(not_equal, &miss, not_taken);
1199
1200 GenerateLoadLongStringLength(masm(), ecx, edx, &miss);
1201 __ bind(&miss);
1202 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1203 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1204
1205 // Return the generated code.
1206 return GetCode(CALLBACKS);
1207}
1208
1209
1210Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1211 // ----------- S t a t e -------------
1212 // -- esp[0] : return address
1213 // -- esp[4] : name
1214 // -- esp[8] : receiver
1215 // -----------------------------------
1216 HandleScope scope;
1217 Label miss;
1218
1219 __ mov(eax, (Operand(esp, kPointerSize)));
1220 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1221 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1222
1223 // Check that the name has not changed.
1224 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1225 __ j(not_equal, &miss, not_taken);
1226
1227 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1228 __ bind(&miss);
1229 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1230 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1231
1232 // Return the generated code.
1233 return GetCode(CALLBACKS);
1234}
1235
1236
1237#undef __
1238
1239} } // namespace v8::internal