blob: fb2ff110351cb74dbf1a6d383bc537b41c4105ae [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
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
mads.s.ager31e71382008-08-13 09:32:07 +0000335 // Do tail-call to the runtime system.
336 ExternalReference load_callback_property =
337 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
338 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339}
340
341
342void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
343 JSObject* object,
344 JSObject* holder,
345 Register receiver,
346 Register scratch1,
347 Register scratch2,
348 Object* value,
349 Label* miss_label) {
350 // Check that the receiver isn't a smi.
351 __ test(receiver, Immediate(kSmiTagMask));
352 __ j(zero, miss_label, not_taken);
353
354 // Check that the maps haven't changed.
355 Register reg =
356 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
357
358 // Return the constant value.
359 __ mov(eax, Handle<Object>(value));
360 __ ret(0);
361}
362
363
364void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
365 JSObject* object,
366 JSObject* holder,
367 Register receiver,
368 Register name,
369 Register scratch1,
370 Register scratch2,
371 Label* miss_label) {
372 // Check that the receiver isn't a smi.
373 __ test(receiver, Immediate(kSmiTagMask));
374 __ j(zero, miss_label, not_taken);
375
376 // Check that the maps haven't changed.
377 Register reg =
378 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
379
380 // Push the arguments on the JS stack of the caller.
381 __ pop(scratch2); // remove return address
382 __ push(receiver); // receiver
383 __ push(reg); // holder
384 __ push(name); // name
385 __ push(scratch2); // restore return address
386
mads.s.ager31e71382008-08-13 09:32:07 +0000387 // Do tail-call to the runtime system.
388 ExternalReference load_ic_property =
389 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
390 __ TailCallRuntime(load_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391}
392
393
394void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
395 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
396 Code* code = NULL;
397 if (kind == Code::LOAD_IC) {
398 code = Builtins::builtin(Builtins::LoadIC_Miss);
399 } else {
400 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
401 }
402
403 Handle<Code> ic(code);
404 __ jmp(ic, code_target);
405}
406
407
408void StubCompiler::GenerateStoreField(MacroAssembler* masm,
409 JSObject* object,
410 int index,
411 Map* transition,
412 Register receiver_reg,
413 Register name_reg,
414 Register scratch,
415 Label* miss_label) {
416 // Check that the object isn't a smi.
417 __ test(receiver_reg, Immediate(kSmiTagMask));
418 __ j(zero, miss_label, not_taken);
419
420 // Check that the map of the object hasn't changed.
421 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
422 Immediate(Handle<Map>(object->map())));
423 __ j(not_equal, miss_label, not_taken);
424
425 // Perform global security token check if needed.
426 if (object->IsJSGlobalObject()) {
427 __ CheckAccessGlobal(receiver_reg, scratch, miss_label);
428 }
429
430 // Stub never generated for non-global objects that require access
431 // checks.
432 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
433
434 // Get the properties array (optimistically).
435 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
436
437 // Perform map transition for the receiver if necessary.
438 if (transition != NULL) {
439 // Update the map of the object; no write barrier updating is
440 // needed because the map is never in new space.
441 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
442 Immediate(Handle<Map>(transition)));
443 }
444
445 // Write to the properties array.
446 int offset = index * kPointerSize + Array::kHeaderSize;
447 __ mov(FieldOperand(scratch, offset), eax);
448
449 // Update the write barrier for the array address.
450 // Pass the value being stored in the now unused name_reg.
451 __ mov(name_reg, Operand(eax));
452 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
453
454 // Return the value (register eax).
455 __ ret(0);
456}
457
458
459#undef __
460
461#define __ masm()->
462
463
464// TODO(1241006): Avoid having lazy compile stubs specialized by the
465// number of arguments. It is not needed anymore.
466Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
467 HandleScope scope;
468
469 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000470 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471
472 // Push a copy of the function onto the stack.
473 __ push(edi);
474
475 __ push(edi); // function is also the parameter to the runtime call
476 __ CallRuntime(Runtime::kLazyCompile, 1);
477 __ pop(edi);
478
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000479 __ ExitInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000480
481 // Do a tail-call of the compiled function.
482 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
483 __ jmp(Operand(ecx));
484
485 return GetCodeWithFlags(flags);
486}
487
488
489Object* CallStubCompiler::CompileCallField(Object* object,
490 JSObject* holder,
491 int index) {
492 // ----------- S t a t e -------------
493 // -----------------------------------
494
495 HandleScope scope;
496 Label miss;
497
498 // Get the receiver from the stack.
499 const int argc = arguments().immediate();
500 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
501
502 // Check that the receiver isn't a smi.
503 __ test(edx, Immediate(kSmiTagMask));
504 __ j(zero, &miss, not_taken);
505
506 // Do the right check and compute the holder register.
507 Register reg =
508 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
509
510 // Get the properties array of the holder and get the function from the field.
511 int offset = index * kPointerSize + Array::kHeaderSize;
512 __ mov(edi, FieldOperand(reg, JSObject::kPropertiesOffset));
513 __ mov(edi, FieldOperand(edi, offset));
514
515 // Check that the function really is a function.
516 __ test(edi, Immediate(kSmiTagMask));
517 __ j(zero, &miss, not_taken);
518 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
519 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
520 __ cmp(ebx, JS_FUNCTION_TYPE);
521 __ j(not_equal, &miss, not_taken);
522
523 // Invoke the function.
524 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
525
526 // Handle call cache miss.
527 __ bind(&miss);
528 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
529 __ jmp(ic, code_target);
530
531 // Return the generated code.
532 return GetCode(FIELD);
533}
534
535
536Object* CallStubCompiler::CompileCallConstant(Object* object,
537 JSObject* holder,
538 JSFunction* function,
539 CheckType check) {
540 // ----------- S t a t e -------------
541 // -----------------------------------
542
543 HandleScope scope;
544 Label miss;
545
546 // Get the receiver from the stack.
547 const int argc = arguments().immediate();
548 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
549
550 // Check that the receiver isn't a smi.
551 if (check != NUMBER_CHECK) {
552 __ test(edx, Immediate(kSmiTagMask));
553 __ j(zero, &miss, not_taken);
554 }
555
556 switch (check) {
557 case RECEIVER_MAP_CHECK:
558 // Check that the maps haven't changed.
559 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
560 break;
561
562 case STRING_CHECK:
563 // Check that the object is a two-byte string or a symbol.
564 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
565 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
566 __ cmp(ecx, FIRST_NONSTRING_TYPE);
567 __ j(above_equal, &miss, not_taken);
568 // Check that the maps starting from the prototype haven't changed.
569 GenerateLoadGlobalFunctionPrototype(masm(),
570 Context::STRING_FUNCTION_INDEX,
571 ecx);
572 __ CheckMaps(JSObject::cast(object->GetPrototype()),
573 ecx, holder, ebx, edx, &miss);
574 break;
575
576 case NUMBER_CHECK: {
577 Label fast;
578 // Check that the object is a smi or a heap number.
579 __ test(edx, Immediate(kSmiTagMask));
580 __ j(zero, &fast, taken);
581 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
582 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
583 __ cmp(ecx, HEAP_NUMBER_TYPE);
584 __ j(not_equal, &miss, not_taken);
585 __ bind(&fast);
586 // Check that the maps starting from the prototype haven't changed.
587 GenerateLoadGlobalFunctionPrototype(masm(),
588 Context::NUMBER_FUNCTION_INDEX,
589 ecx);
590 __ CheckMaps(JSObject::cast(object->GetPrototype()),
591 ecx, holder, ebx, edx, &miss);
592 break;
593 }
594
595 case BOOLEAN_CHECK: {
596 Label fast;
597 // Check that the object is a boolean.
598 __ cmp(edx, Factory::true_value());
599 __ j(equal, &fast, taken);
600 __ cmp(edx, Factory::false_value());
601 __ j(not_equal, &miss, not_taken);
602 __ bind(&fast);
603 // Check that the maps starting from the prototype haven't changed.
604 GenerateLoadGlobalFunctionPrototype(masm(),
605 Context::BOOLEAN_FUNCTION_INDEX,
606 ecx);
607 __ CheckMaps(JSObject::cast(object->GetPrototype()),
608 ecx, holder, ebx, edx, &miss);
609 break;
610 }
611
612 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
613 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
614 // Make sure object->elements()->map() != Heap::dictionary_array_map()
615 // Get the elements array of the object.
616 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
617 // Check that the object is in fast mode (not dictionary).
618 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
619 Immediate(Factory::hash_table_map()));
620 __ j(equal, &miss, not_taken);
621 break;
622
623 default:
624 UNREACHABLE();
625 }
626
627 // Get the function and setup the context.
628 __ mov(Operand(edi), Immediate(Handle<JSFunction>(function)));
629 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
630
631 // Jump to the cached code (tail call).
632 Handle<Code> code(function->code());
633 ParameterCount expected(function->shared()->formal_parameter_count());
634 __ InvokeCode(code, expected, arguments(), code_target, JUMP_FUNCTION);
635
636 // Handle call cache miss.
637 __ bind(&miss);
638 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
639 __ jmp(ic, code_target);
640
641 // Return the generated code.
642 return GetCode(CONSTANT_FUNCTION);
643}
644
645
646Object* CallStubCompiler::CompileCallInterceptor(Object* object,
647 JSObject* holder,
648 String* name) {
649 // ----------- S t a t e -------------
650 // -----------------------------------
651
652 HandleScope scope;
653 Label miss;
654
655 // Get the number of arguments.
656 const int argc = arguments().immediate();
657
658 // Get the receiver from the stack.
659 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
660 // Check that the receiver isn't a smi.
661 __ test(edx, Immediate(kSmiTagMask));
662 __ j(zero, &miss, not_taken);
663
664 // Check that maps have not changed and compute the holder register.
665 Register reg =
666 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
667
668 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000669 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670
671 // Push arguments on the expression stack.
672 __ push(edx); // receiver
673 __ push(reg); // holder
674 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
675
676 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677 ExternalReference load_interceptor =
678 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000679 __ mov(Operand(eax), Immediate(3));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 __ mov(Operand(ebx), Immediate(load_interceptor));
681
682 CEntryStub stub;
683 __ CallStub(&stub);
684
685 // Move result to edi and restore receiver.
686 __ mov(Operand(edi), eax);
687 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
688
689 // Exit frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000690 __ ExitInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691
692 // Check that the function really is a function.
693 __ test(edi, Immediate(kSmiTagMask));
694 __ j(zero, &miss, not_taken);
695 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
696 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
697 __ cmp(ebx, JS_FUNCTION_TYPE);
698 __ j(not_equal, &miss, not_taken);
699
700 // Invoke the function.
701 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
702
703 // Handle load cache miss.
704 __ bind(&miss);
705 Handle<Code> ic = ComputeCallMiss(argc);
706 __ jmp(ic, code_target);
707
708 // Return the generated code.
709 return GetCode(INTERCEPTOR);
710}
711
712
713Object* StoreStubCompiler::CompileStoreField(JSObject* object,
714 int index,
715 Map* transition,
716 String* name) {
717 // ----------- S t a t e -------------
718 // -- eax : value
719 // -- ecx : name
720 // -- esp[0] : return address
721 // -- esp[4] : receiver
722 // -----------------------------------
723
724 HandleScope scope;
725 Label miss;
726
727 // Get the object from the stack.
728 __ mov(ebx, Operand(esp, 1 * kPointerSize));
729
730 // Generate store field code. Trashes the name register.
731 GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
732
733 // Handle store cache miss.
734 __ bind(&miss);
735 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
736 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
737 __ jmp(ic, code_target);
738
739 // Return the generated code.
740 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
741}
742
743
744Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
745 AccessorInfo* callback,
746 String* name) {
747 // ----------- S t a t e -------------
748 // -- eax : value
749 // -- ecx : name
750 // -- esp[0] : return address
751 // -- esp[4] : receiver
752 // -----------------------------------
753
754 HandleScope scope;
755 Label miss;
756
757 // Get the object from the stack.
758 __ mov(ebx, Operand(esp, 1 * kPointerSize));
759
760 // Check that the object isn't a smi.
761 __ test(ebx, Immediate(kSmiTagMask));
762 __ j(zero, &miss, not_taken);
763
764 // Check that the map of the object hasn't changed.
765 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
766 Immediate(Handle<Map>(object->map())));
767 __ j(not_equal, &miss, not_taken);
768
769 // Perform global security token check if needed.
770 if (object->IsJSGlobalObject()) {
771 __ CheckAccessGlobal(ebx, edx, &miss);
772 }
773
774 // Stub never generated for non-global objects that require access
775 // checks.
776 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
777
778 __ pop(ebx); // remove the return address
779 __ push(Operand(esp, 0)); // receiver
780 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
781 __ push(ecx); // name
782 __ push(eax); // value
783 __ push(ebx); // restore return address
784
mads.s.ager31e71382008-08-13 09:32:07 +0000785 // Do tail-call to the runtime system.
786 ExternalReference store_callback_property =
787 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
788 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789
790 // Handle store cache miss.
791 __ bind(&miss);
792 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
793 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
794 __ jmp(ic, code_target);
795
796 // Return the generated code.
797 return GetCode(CALLBACKS);
798}
799
800
801Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
802 String* name) {
803 // ----------- S t a t e -------------
804 // -- eax : value
805 // -- ecx : name
806 // -- esp[0] : return address
807 // -- esp[4] : receiver
808 // -----------------------------------
809
810 HandleScope scope;
811 Label miss;
812
813 // Get the object from the stack.
814 __ mov(ebx, Operand(esp, 1 * kPointerSize));
815
816 // Check that the object isn't a smi.
817 __ test(ebx, Immediate(kSmiTagMask));
818 __ j(zero, &miss, not_taken);
819
820 // Check that the map of the object hasn't changed.
821 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
822 Immediate(Handle<Map>(receiver->map())));
823 __ j(not_equal, &miss, not_taken);
824
825 // Perform global security token check if needed.
826 if (receiver->IsJSGlobalObject()) {
827 __ CheckAccessGlobal(ebx, edx, &miss);
828 }
829
830 // Stub never generated for non-global objects that require access
831 // checks.
832 ASSERT(receiver->IsJSGlobalObject() || !receiver->IsAccessCheckNeeded());
833
834 __ pop(ebx); // remove the return address
835 __ push(Operand(esp, 0)); // receiver
836 __ push(ecx); // name
837 __ push(eax); // value
838 __ push(ebx); // restore return address
839
mads.s.ager31e71382008-08-13 09:32:07 +0000840 // Do tail-call to the runtime system.
841 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000843 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844
845 // Handle store cache miss.
846 __ bind(&miss);
847 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
848 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
849 __ jmp(ic, code_target);
850
851 // Return the generated code.
852 return GetCode(INTERCEPTOR);
853}
854
855
856Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
857 int index,
858 Map* transition,
859 String* name) {
860 // ----------- S t a t e -------------
861 // -- eax : value
862 // -- esp[0] : return address
863 // -- esp[4] : key
864 // -- esp[8] : receiver
865 // -----------------------------------
866 HandleScope scope;
867 Label miss;
868
869 __ IncrementCounter(&Counters::keyed_store_field, 1);
870
871 // Get the name from the stack.
872 __ mov(ecx, Operand(esp, 1 * kPointerSize));
873 // Check that the name has not changed.
874 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
875 __ j(not_equal, &miss, not_taken);
876
877 // Get the object from the stack.
878 __ mov(ebx, Operand(esp, 2 * kPointerSize));
879
880 // Generate store field code. Trashes the name register.
881 GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
882
883 // Handle store cache miss.
884 __ bind(&miss);
885 __ DecrementCounter(&Counters::keyed_store_field, 1);
886 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
887 __ jmp(ic, code_target);
888
889 // Return the generated code.
890 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
891}
892
893
894Object* LoadStubCompiler::CompileLoadField(JSObject* object,
895 JSObject* holder,
896 int index) {
897 // ----------- S t a t e -------------
898 // -- ecx : name
899 // -- esp[0] : return address
900 // -- esp[4] : receiver
901 // -----------------------------------
902
903 HandleScope scope;
904 Label miss;
905
906 __ mov(eax, (Operand(esp, kPointerSize)));
907 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
908 __ bind(&miss);
909 GenerateLoadMiss(masm(), Code::LOAD_IC);
910
911 // Return the generated code.
912 return GetCode(FIELD);
913}
914
915
916Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
917 JSObject* holder,
918 AccessorInfo* callback) {
919 // ----------- S t a t e -------------
920 // -- ecx : name
921 // -- esp[0] : return address
922 // -- esp[4] : receiver
923 // -----------------------------------
924
925 HandleScope scope;
926 Label miss;
927
928 __ mov(eax, (Operand(esp, kPointerSize)));
929 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
930 edx, callback, &miss);
931 __ bind(&miss);
932 GenerateLoadMiss(masm(), Code::LOAD_IC);
933
934 // Return the generated code.
935 return GetCode(CALLBACKS);
936}
937
938
939Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
940 JSObject* holder,
941 Object* value) {
942 // ----------- S t a t e -------------
943 // -- ecx : name
944 // -- esp[0] : return address
945 // -- esp[4] : receiver
946 // -----------------------------------
947
948 HandleScope scope;
949 Label miss;
950
951 __ mov(eax, (Operand(esp, kPointerSize)));
952 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
953 __ bind(&miss);
954 GenerateLoadMiss(masm(), Code::LOAD_IC);
955
956 // Return the generated code.
957 return GetCode(CONSTANT_FUNCTION);
958}
959
960
961Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
962 JSObject* holder,
963 String* name) {
964 // ----------- S t a t e -------------
965 // -- ecx : name
966 // -- esp[0] : return address
967 // -- esp[4] : receiver
968 // -----------------------------------
969 HandleScope scope;
970 Label miss;
971
972 __ mov(eax, (Operand(esp, kPointerSize)));
973 GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
974 __ bind(&miss);
975 GenerateLoadMiss(masm(), Code::LOAD_IC);
976
977 // Return the generated code.
978 return GetCode(INTERCEPTOR);
979}
980
981
982Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
983 JSObject* receiver,
984 JSObject* holder,
985 int index) {
986 // ----------- S t a t e -------------
987 // -- esp[0] : return address
988 // -- esp[4] : name
989 // -- esp[8] : receiver
990 // -----------------------------------
991 HandleScope scope;
992 Label miss;
993
994 __ mov(eax, (Operand(esp, kPointerSize)));
995 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
996 __ IncrementCounter(&Counters::keyed_load_field, 1);
997
998 // Check that the name has not changed.
999 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1000 __ j(not_equal, &miss, not_taken);
1001
1002 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1003 __ bind(&miss);
1004 __ DecrementCounter(&Counters::keyed_load_field, 1);
1005 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1006
1007 // Return the generated code.
1008 return GetCode(FIELD);
1009}
1010
1011
1012Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1013 JSObject* receiver,
1014 JSObject* holder,
1015 AccessorInfo* callback) {
1016 // ----------- S t a t e -------------
1017 // -- esp[0] : return address
1018 // -- esp[4] : name
1019 // -- esp[8] : receiver
1020 // -----------------------------------
1021 HandleScope scope;
1022 Label miss;
1023
1024 __ mov(eax, (Operand(esp, kPointerSize)));
1025 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1026 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1027
1028 // Check that the name has not changed.
1029 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1030 __ j(not_equal, &miss, not_taken);
1031
1032 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1033 callback, &miss);
1034 __ bind(&miss);
1035 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1036 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1037
1038 // Return the generated code.
1039 return GetCode(CALLBACKS);
1040}
1041
1042
1043Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1044 JSObject* receiver,
1045 JSObject* holder,
1046 Object* value) {
1047 // ----------- S t a t e -------------
1048 // -- esp[0] : return address
1049 // -- esp[4] : name
1050 // -- esp[8] : receiver
1051 // -----------------------------------
1052 HandleScope scope;
1053 Label miss;
1054
1055 __ mov(eax, (Operand(esp, kPointerSize)));
1056 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1057 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1058
1059 // Check that the name has not changed.
1060 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1061 __ j(not_equal, &miss, not_taken);
1062
1063 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1064 __ bind(&miss);
1065 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1066 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1067
1068 // Return the generated code.
1069 return GetCode(CONSTANT_FUNCTION);
1070}
1071
1072
1073Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1074 JSObject* holder,
1075 String* name) {
1076 // ----------- S t a t e -------------
1077 // -- esp[0] : return address
1078 // -- esp[4] : name
1079 // -- esp[8] : receiver
1080 // -----------------------------------
1081 HandleScope scope;
1082 Label miss;
1083
1084 __ mov(eax, (Operand(esp, kPointerSize)));
1085 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1086 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1087
1088 // Check that the name has not changed.
1089 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1090 __ j(not_equal, &miss, not_taken);
1091
1092 GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
1093 __ bind(&miss);
1094 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1095 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1096
1097 // Return the generated code.
1098 return GetCode(INTERCEPTOR);
1099}
1100
1101
1102
1103
1104Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1105 // ----------- S t a t e -------------
1106 // -- esp[0] : return address
1107 // -- esp[4] : name
1108 // -- esp[8] : receiver
1109 // -----------------------------------
1110 HandleScope scope;
1111 Label miss;
1112
1113 __ mov(eax, (Operand(esp, kPointerSize)));
1114 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1115 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1116
1117 // Check that the name has not changed.
1118 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1119 __ j(not_equal, &miss, not_taken);
1120
1121 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1122 __ bind(&miss);
1123 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1124 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1125
1126 // Return the generated code.
1127 return GetCode(CALLBACKS);
1128}
1129
1130
1131Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
1132 // ----------- S t a t e -------------
1133 // -- esp[0] : return address
1134 // -- esp[4] : name
1135 // -- esp[8] : receiver
1136 // -----------------------------------
1137 HandleScope scope;
1138 Label miss;
1139
1140 __ mov(eax, (Operand(esp, kPointerSize)));
1141 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1142 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1143
1144 // Check that the name has not changed.
1145 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1146 __ j(not_equal, &miss, not_taken);
1147
1148 GenerateLoadShortStringLength(masm(), ecx, edx, &miss);
1149 __ bind(&miss);
1150 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1151 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1152
1153 // Return the generated code.
1154 return GetCode(CALLBACKS);
1155}
1156
1157
1158Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
1159 // ----------- S t a t e -------------
1160 // -- esp[0] : return address
1161 // -- esp[4] : name
1162 // -- esp[8] : receiver
1163 // -----------------------------------
1164 HandleScope scope;
1165 Label miss;
1166
1167 __ mov(eax, (Operand(esp, kPointerSize)));
1168 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1169 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1170
1171 // Check that the name has not changed.
1172 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1173 __ j(not_equal, &miss, not_taken);
1174
1175 GenerateLoadMediumStringLength(masm(), ecx, edx, &miss);
1176 __ bind(&miss);
1177 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1178 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1179
1180 // Return the generated code.
1181 return GetCode(CALLBACKS);
1182}
1183
1184
1185Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
1186 // ----------- S t a t e -------------
1187 // -- esp[0] : return address
1188 // -- esp[4] : name
1189 // -- esp[8] : receiver
1190 // -----------------------------------
1191 HandleScope scope;
1192 Label miss;
1193
1194 __ mov(eax, (Operand(esp, kPointerSize)));
1195 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1196 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1197
1198 // Check that the name has not changed.
1199 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1200 __ j(not_equal, &miss, not_taken);
1201
1202 GenerateLoadLongStringLength(masm(), ecx, edx, &miss);
1203 __ bind(&miss);
1204 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1205 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1206
1207 // Return the generated code.
1208 return GetCode(CALLBACKS);
1209}
1210
1211
1212Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1213 // ----------- S t a t e -------------
1214 // -- esp[0] : return address
1215 // -- esp[4] : name
1216 // -- esp[8] : receiver
1217 // -----------------------------------
1218 HandleScope scope;
1219 Label miss;
1220
1221 __ mov(eax, (Operand(esp, kPointerSize)));
1222 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1223 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1224
1225 // Check that the name has not changed.
1226 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1227 __ j(not_equal, &miss, not_taken);
1228
1229 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1230 __ bind(&miss);
1231 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1232 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1233
1234 // Return the generated code.
1235 return GetCode(CALLBACKS);
1236}
1237
1238
1239#undef __
1240
1241} } // namespace v8::internal