blob: 220035bb36e5faac85612e1e9b5491c9a6b6de70 [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);
ager@chromium.org236ad962008-09-25 09:45:57 +0000404 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405}
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
ager@chromium.org236ad962008-09-25 09:45:57 +0000479 __ LeaveInternalFrame();
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());
ager@chromium.org236ad962008-09-25 09:45:57 +0000529 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530
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());
ager@chromium.org236ad962008-09-25 09:45:57 +0000634 __ InvokeCode(code, expected, arguments(),
635 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636
637 // Handle call cache miss.
638 __ bind(&miss);
639 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000640 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641
642 // Return the generated code.
643 return GetCode(CONSTANT_FUNCTION);
644}
645
646
647Object* CallStubCompiler::CompileCallInterceptor(Object* object,
648 JSObject* holder,
649 String* name) {
650 // ----------- S t a t e -------------
651 // -----------------------------------
652
653 HandleScope scope;
654 Label miss;
655
656 // Get the number of arguments.
657 const int argc = arguments().immediate();
658
659 // Get the receiver from the stack.
660 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
661 // Check that the receiver isn't a smi.
662 __ test(edx, Immediate(kSmiTagMask));
663 __ j(zero, &miss, not_taken);
664
665 // Check that maps have not changed and compute the holder register.
666 Register reg =
667 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
668
669 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000670 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671
672 // Push arguments on the expression stack.
673 __ push(edx); // receiver
674 __ push(reg); // holder
675 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
676
677 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000678 ExternalReference load_interceptor =
679 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000680 __ mov(Operand(eax), Immediate(3));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681 __ mov(Operand(ebx), Immediate(load_interceptor));
682
683 CEntryStub stub;
684 __ CallStub(&stub);
685
686 // Move result to edi and restore receiver.
687 __ mov(Operand(edi), eax);
688 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
689
690 // Exit frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000691 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000692
693 // Check that the function really is a function.
694 __ test(edi, Immediate(kSmiTagMask));
695 __ j(zero, &miss, not_taken);
696 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
697 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
698 __ cmp(ebx, JS_FUNCTION_TYPE);
699 __ j(not_equal, &miss, not_taken);
700
701 // Invoke the function.
702 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
703
704 // Handle load cache miss.
705 __ bind(&miss);
706 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000707 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708
709 // Return the generated code.
710 return GetCode(INTERCEPTOR);
711}
712
713
714Object* StoreStubCompiler::CompileStoreField(JSObject* object,
715 int index,
716 Map* transition,
717 String* name) {
718 // ----------- S t a t e -------------
719 // -- eax : value
720 // -- ecx : name
721 // -- esp[0] : return address
722 // -- esp[4] : receiver
723 // -----------------------------------
724
725 HandleScope scope;
726 Label miss;
727
728 // Get the object from the stack.
729 __ mov(ebx, Operand(esp, 1 * kPointerSize));
730
731 // Generate store field code. Trashes the name register.
732 GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
733
734 // Handle store cache miss.
735 __ bind(&miss);
736 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
737 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000738 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739
740 // Return the generated code.
741 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
742}
743
744
745Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
746 AccessorInfo* callback,
747 String* name) {
748 // ----------- S t a t e -------------
749 // -- eax : value
750 // -- ecx : name
751 // -- esp[0] : return address
752 // -- esp[4] : receiver
753 // -----------------------------------
754
755 HandleScope scope;
756 Label miss;
757
758 // Get the object from the stack.
759 __ mov(ebx, Operand(esp, 1 * kPointerSize));
760
761 // Check that the object isn't a smi.
762 __ test(ebx, Immediate(kSmiTagMask));
763 __ j(zero, &miss, not_taken);
764
765 // Check that the map of the object hasn't changed.
766 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
767 Immediate(Handle<Map>(object->map())));
768 __ j(not_equal, &miss, not_taken);
769
770 // Perform global security token check if needed.
771 if (object->IsJSGlobalObject()) {
772 __ CheckAccessGlobal(ebx, edx, &miss);
773 }
774
775 // Stub never generated for non-global objects that require access
776 // checks.
777 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
778
779 __ pop(ebx); // remove the return address
780 __ push(Operand(esp, 0)); // receiver
781 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
782 __ push(ecx); // name
783 __ push(eax); // value
784 __ push(ebx); // restore return address
785
mads.s.ager31e71382008-08-13 09:32:07 +0000786 // Do tail-call to the runtime system.
787 ExternalReference store_callback_property =
788 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
789 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000790
791 // Handle store cache miss.
792 __ bind(&miss);
793 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
794 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000795 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796
797 // Return the generated code.
798 return GetCode(CALLBACKS);
799}
800
801
802Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
803 String* name) {
804 // ----------- S t a t e -------------
805 // -- eax : value
806 // -- ecx : name
807 // -- esp[0] : return address
808 // -- esp[4] : receiver
809 // -----------------------------------
810
811 HandleScope scope;
812 Label miss;
813
814 // Get the object from the stack.
815 __ mov(ebx, Operand(esp, 1 * kPointerSize));
816
817 // Check that the object isn't a smi.
818 __ test(ebx, Immediate(kSmiTagMask));
819 __ j(zero, &miss, not_taken);
820
821 // Check that the map of the object hasn't changed.
822 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
823 Immediate(Handle<Map>(receiver->map())));
824 __ j(not_equal, &miss, not_taken);
825
826 // Perform global security token check if needed.
827 if (receiver->IsJSGlobalObject()) {
828 __ CheckAccessGlobal(ebx, edx, &miss);
829 }
830
831 // Stub never generated for non-global objects that require access
832 // checks.
833 ASSERT(receiver->IsJSGlobalObject() || !receiver->IsAccessCheckNeeded());
834
835 __ pop(ebx); // remove the return address
836 __ push(Operand(esp, 0)); // receiver
837 __ push(ecx); // name
838 __ push(eax); // value
839 __ push(ebx); // restore return address
840
mads.s.ager31e71382008-08-13 09:32:07 +0000841 // Do tail-call to the runtime system.
842 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000843 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000844 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845
846 // Handle store cache miss.
847 __ bind(&miss);
848 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
849 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000850 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851
852 // Return the generated code.
853 return GetCode(INTERCEPTOR);
854}
855
856
857Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
858 int index,
859 Map* transition,
860 String* name) {
861 // ----------- S t a t e -------------
862 // -- eax : value
863 // -- esp[0] : return address
864 // -- esp[4] : key
865 // -- esp[8] : receiver
866 // -----------------------------------
867 HandleScope scope;
868 Label miss;
869
870 __ IncrementCounter(&Counters::keyed_store_field, 1);
871
872 // Get the name from the stack.
873 __ mov(ecx, Operand(esp, 1 * kPointerSize));
874 // Check that the name has not changed.
875 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
876 __ j(not_equal, &miss, not_taken);
877
878 // Get the object from the stack.
879 __ mov(ebx, Operand(esp, 2 * kPointerSize));
880
881 // Generate store field code. Trashes the name register.
882 GenerateStoreField(masm(), object, index, transition, ebx, ecx, edx, &miss);
883
884 // Handle store cache miss.
885 __ bind(&miss);
886 __ DecrementCounter(&Counters::keyed_store_field, 1);
887 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000888 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889
890 // Return the generated code.
891 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
892}
893
894
895Object* LoadStubCompiler::CompileLoadField(JSObject* object,
896 JSObject* holder,
897 int index) {
898 // ----------- S t a t e -------------
899 // -- ecx : name
900 // -- esp[0] : return address
901 // -- esp[4] : receiver
902 // -----------------------------------
903
904 HandleScope scope;
905 Label miss;
906
907 __ mov(eax, (Operand(esp, kPointerSize)));
908 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
909 __ bind(&miss);
910 GenerateLoadMiss(masm(), Code::LOAD_IC);
911
912 // Return the generated code.
913 return GetCode(FIELD);
914}
915
916
917Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
918 JSObject* holder,
919 AccessorInfo* callback) {
920 // ----------- S t a t e -------------
921 // -- ecx : name
922 // -- esp[0] : return address
923 // -- esp[4] : receiver
924 // -----------------------------------
925
926 HandleScope scope;
927 Label miss;
928
929 __ mov(eax, (Operand(esp, kPointerSize)));
930 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
931 edx, callback, &miss);
932 __ bind(&miss);
933 GenerateLoadMiss(masm(), Code::LOAD_IC);
934
935 // Return the generated code.
936 return GetCode(CALLBACKS);
937}
938
939
940Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
941 JSObject* holder,
942 Object* value) {
943 // ----------- S t a t e -------------
944 // -- ecx : name
945 // -- esp[0] : return address
946 // -- esp[4] : receiver
947 // -----------------------------------
948
949 HandleScope scope;
950 Label miss;
951
952 __ mov(eax, (Operand(esp, kPointerSize)));
953 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
954 __ bind(&miss);
955 GenerateLoadMiss(masm(), Code::LOAD_IC);
956
957 // Return the generated code.
958 return GetCode(CONSTANT_FUNCTION);
959}
960
961
962Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
963 JSObject* holder,
964 String* name) {
965 // ----------- S t a t e -------------
966 // -- ecx : name
967 // -- esp[0] : return address
968 // -- esp[4] : receiver
969 // -----------------------------------
970 HandleScope scope;
971 Label miss;
972
973 __ mov(eax, (Operand(esp, kPointerSize)));
974 GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
975 __ bind(&miss);
976 GenerateLoadMiss(masm(), Code::LOAD_IC);
977
978 // Return the generated code.
979 return GetCode(INTERCEPTOR);
980}
981
982
983Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
984 JSObject* receiver,
985 JSObject* holder,
986 int index) {
987 // ----------- S t a t e -------------
988 // -- esp[0] : return address
989 // -- esp[4] : name
990 // -- esp[8] : receiver
991 // -----------------------------------
992 HandleScope scope;
993 Label miss;
994
995 __ mov(eax, (Operand(esp, kPointerSize)));
996 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
997 __ IncrementCounter(&Counters::keyed_load_field, 1);
998
999 // Check that the name has not changed.
1000 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1001 __ j(not_equal, &miss, not_taken);
1002
1003 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1004 __ bind(&miss);
1005 __ DecrementCounter(&Counters::keyed_load_field, 1);
1006 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1007
1008 // Return the generated code.
1009 return GetCode(FIELD);
1010}
1011
1012
1013Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1014 JSObject* receiver,
1015 JSObject* holder,
1016 AccessorInfo* callback) {
1017 // ----------- S t a t e -------------
1018 // -- esp[0] : return address
1019 // -- esp[4] : name
1020 // -- esp[8] : receiver
1021 // -----------------------------------
1022 HandleScope scope;
1023 Label miss;
1024
1025 __ mov(eax, (Operand(esp, kPointerSize)));
1026 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1027 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1028
1029 // Check that the name has not changed.
1030 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1031 __ j(not_equal, &miss, not_taken);
1032
1033 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1034 callback, &miss);
1035 __ bind(&miss);
1036 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1037 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1038
1039 // Return the generated code.
1040 return GetCode(CALLBACKS);
1041}
1042
1043
1044Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1045 JSObject* receiver,
1046 JSObject* holder,
1047 Object* value) {
1048 // ----------- S t a t e -------------
1049 // -- esp[0] : return address
1050 // -- esp[4] : name
1051 // -- esp[8] : receiver
1052 // -----------------------------------
1053 HandleScope scope;
1054 Label miss;
1055
1056 __ mov(eax, (Operand(esp, kPointerSize)));
1057 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1058 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1059
1060 // Check that the name has not changed.
1061 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1062 __ j(not_equal, &miss, not_taken);
1063
1064 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1065 __ bind(&miss);
1066 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1067 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1068
1069 // Return the generated code.
1070 return GetCode(CONSTANT_FUNCTION);
1071}
1072
1073
1074Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1075 JSObject* holder,
1076 String* name) {
1077 // ----------- S t a t e -------------
1078 // -- esp[0] : return address
1079 // -- esp[4] : name
1080 // -- esp[8] : receiver
1081 // -----------------------------------
1082 HandleScope scope;
1083 Label miss;
1084
1085 __ mov(eax, (Operand(esp, kPointerSize)));
1086 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1087 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1088
1089 // Check that the name has not changed.
1090 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1091 __ j(not_equal, &miss, not_taken);
1092
1093 GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
1094 __ bind(&miss);
1095 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1096 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1097
1098 // Return the generated code.
1099 return GetCode(INTERCEPTOR);
1100}
1101
1102
1103
1104
1105Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1106 // ----------- S t a t e -------------
1107 // -- esp[0] : return address
1108 // -- esp[4] : name
1109 // -- esp[8] : receiver
1110 // -----------------------------------
1111 HandleScope scope;
1112 Label miss;
1113
1114 __ mov(eax, (Operand(esp, kPointerSize)));
1115 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1116 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1117
1118 // Check that the name has not changed.
1119 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1120 __ j(not_equal, &miss, not_taken);
1121
1122 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1123 __ bind(&miss);
1124 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1125 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1126
1127 // Return the generated code.
1128 return GetCode(CALLBACKS);
1129}
1130
1131
1132Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
1133 // ----------- S t a t e -------------
1134 // -- esp[0] : return address
1135 // -- esp[4] : name
1136 // -- esp[8] : receiver
1137 // -----------------------------------
1138 HandleScope scope;
1139 Label miss;
1140
1141 __ mov(eax, (Operand(esp, kPointerSize)));
1142 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1143 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1144
1145 // Check that the name has not changed.
1146 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1147 __ j(not_equal, &miss, not_taken);
1148
1149 GenerateLoadShortStringLength(masm(), ecx, edx, &miss);
1150 __ bind(&miss);
1151 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1152 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1153
1154 // Return the generated code.
1155 return GetCode(CALLBACKS);
1156}
1157
1158
1159Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
1160 // ----------- S t a t e -------------
1161 // -- esp[0] : return address
1162 // -- esp[4] : name
1163 // -- esp[8] : receiver
1164 // -----------------------------------
1165 HandleScope scope;
1166 Label miss;
1167
1168 __ mov(eax, (Operand(esp, kPointerSize)));
1169 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1170 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1171
1172 // Check that the name has not changed.
1173 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1174 __ j(not_equal, &miss, not_taken);
1175
1176 GenerateLoadMediumStringLength(masm(), ecx, edx, &miss);
1177 __ bind(&miss);
1178 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1179 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1180
1181 // Return the generated code.
1182 return GetCode(CALLBACKS);
1183}
1184
1185
1186Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
1187 // ----------- S t a t e -------------
1188 // -- esp[0] : return address
1189 // -- esp[4] : name
1190 // -- esp[8] : receiver
1191 // -----------------------------------
1192 HandleScope scope;
1193 Label miss;
1194
1195 __ mov(eax, (Operand(esp, kPointerSize)));
1196 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1197 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1198
1199 // Check that the name has not changed.
1200 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1201 __ j(not_equal, &miss, not_taken);
1202
1203 GenerateLoadLongStringLength(masm(), ecx, edx, &miss);
1204 __ bind(&miss);
1205 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1206 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1207
1208 // Return the generated code.
1209 return GetCode(CALLBACKS);
1210}
1211
1212
1213Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1214 // ----------- S t a t e -------------
1215 // -- esp[0] : return address
1216 // -- esp[4] : name
1217 // -- esp[8] : receiver
1218 // -----------------------------------
1219 HandleScope scope;
1220 Label miss;
1221
1222 __ mov(eax, (Operand(esp, kPointerSize)));
1223 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1224 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1225
1226 // Check that the name has not changed.
1227 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1228 __ j(not_equal, &miss, not_taken);
1229
1230 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1231 __ bind(&miss);
1232 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1233 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1234
1235 // Return the generated code.
1236 return GetCode(CALLBACKS);
1237}
1238
1239
1240#undef __
1241
1242} } // namespace v8::internal