blob: f59ed57a26ff3be46eca7d77a9ebaeef26ba35b5 [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.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000102 __ mov(scratch, FieldOperand(name, String::kLengthOffset));
103 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104 __ 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
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000162// Generate code to check if an object is a string. If the object is
163// a string, the map's instance type is left in the scratch register.
164static void GenerateStringCheck(MacroAssembler* masm,
165 Register receiver,
166 Register scratch,
167 Label* smi,
168 Label* non_string_object) {
169 // Check that the object isn't a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000170 __ test(receiver, Immediate(kSmiTagMask));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000171 __ j(zero, smi, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000173 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
175 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000176 ASSERT(kNotStringTag != 0);
177 __ test(scratch, Immediate(kNotStringTag));
178 __ j(not_zero, non_string_object, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179}
180
181
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000182void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
183 Register receiver,
184 Register scratch,
185 Label* miss) {
186 Label load_length, check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000188 // Check if the object is a string.
189 GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190
191 // Load length directly from the string.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000192 __ bind(&load_length);
193 __ and_(scratch, kStringSizeMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000195 // ecx is also the receiver.
196 __ lea(ecx, Operand(scratch, String::kLongLengthShift));
197 __ shr(eax); // ecx is implicit shift register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198 __ shl(eax, kSmiTagSize);
199 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000200
201 // Check if the object is a JSValue wrapper.
202 __ bind(&check_wrapper);
203 __ cmp(receiver, JS_VALUE_TYPE);
204 __ j(not_equal, miss, not_taken);
205
206 // Check if the wrapped value is a string and load the length
207 // directly if it is.
208 __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
209 GenerateStringCheck(masm, receiver, scratch, miss, miss);
210 __ jmp(&load_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211}
212
213
214void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
215 Register receiver,
216 Register scratch1,
217 Register scratch2,
218 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000219 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 __ mov(eax, Operand(scratch1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000222}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000223
ager@chromium.org7c537e22008-10-16 08:43:32 +0000224
225// Load a fast property out of a holder object (src). In-object properties
226// are loaded directly otherwise the property is loaded from the properties
227// fixed array.
228void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
229 Register dst, Register src,
230 JSObject* holder, int index) {
231 // Adjust for the number of properties stored in the holder.
232 index -= holder->map()->inobject_properties();
233 if (index < 0) {
234 // Get the property straight out of the holder.
235 int offset = holder->map()->instance_size() + (index * kPointerSize);
236 __ mov(dst, FieldOperand(src, offset));
237 } else {
238 // Calculate the offset into the properties array.
239 int offset = index * kPointerSize + Array::kHeaderSize;
240 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
241 __ mov(dst, FieldOperand(dst, offset));
242 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000243}
244
245
246void StubCompiler::GenerateLoadField(MacroAssembler* masm,
247 JSObject* object,
248 JSObject* holder,
249 Register receiver,
250 Register scratch1,
251 Register scratch2,
252 int index,
253 Label* miss_label) {
254 // Check that the receiver isn't a smi.
255 __ test(receiver, Immediate(kSmiTagMask));
256 __ j(zero, miss_label, not_taken);
257
258 // Check that the maps haven't changed.
259 Register reg =
260 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
261
ager@chromium.org7c537e22008-10-16 08:43:32 +0000262 // Get the value from the properties.
263 GenerateFastPropertyLoad(masm, eax, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264 __ ret(0);
265}
266
267
268void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
269 JSObject* object,
270 JSObject* holder,
271 Register receiver,
272 Register name,
273 Register scratch1,
274 Register scratch2,
275 AccessorInfo* callback,
276 Label* miss_label) {
277 // Check that the receiver isn't a smi.
278 __ test(receiver, Immediate(kSmiTagMask));
279 __ j(zero, miss_label, not_taken);
280
281 // Check that the maps haven't changed.
282 Register reg =
283 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
284
285 // Push the arguments on the JS stack of the caller.
286 __ pop(scratch2); // remove return address
287 __ push(receiver); // receiver
288 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
289 __ push(name); // name
290 __ push(reg); // holder
291 __ push(scratch2); // restore return address
292
mads.s.ager31e71382008-08-13 09:32:07 +0000293 // Do tail-call to the runtime system.
294 ExternalReference load_callback_property =
295 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
296 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297}
298
299
300void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
301 JSObject* object,
302 JSObject* holder,
303 Register receiver,
304 Register scratch1,
305 Register scratch2,
306 Object* value,
307 Label* miss_label) {
308 // Check that the receiver isn't a smi.
309 __ test(receiver, Immediate(kSmiTagMask));
310 __ j(zero, miss_label, not_taken);
311
312 // Check that the maps haven't changed.
313 Register reg =
314 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
315
316 // Return the constant value.
317 __ mov(eax, Handle<Object>(value));
318 __ ret(0);
319}
320
321
322void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
323 JSObject* object,
324 JSObject* holder,
325 Register receiver,
326 Register name,
327 Register scratch1,
328 Register scratch2,
329 Label* miss_label) {
330 // Check that the receiver isn't a smi.
331 __ test(receiver, Immediate(kSmiTagMask));
332 __ j(zero, miss_label, not_taken);
333
334 // Check that the maps haven't changed.
335 Register reg =
336 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
337
338 // Push the arguments on the JS stack of the caller.
339 __ pop(scratch2); // remove return address
340 __ push(receiver); // receiver
341 __ push(reg); // holder
342 __ push(name); // name
343 __ push(scratch2); // restore return address
344
mads.s.ager31e71382008-08-13 09:32:07 +0000345 // Do tail-call to the runtime system.
346 ExternalReference load_ic_property =
347 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
348 __ TailCallRuntime(load_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349}
350
351
352void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
353 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
354 Code* code = NULL;
355 if (kind == Code::LOAD_IC) {
356 code = Builtins::builtin(Builtins::LoadIC_Miss);
357 } else {
358 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
359 }
360
361 Handle<Code> ic(code);
ager@chromium.org236ad962008-09-25 09:45:57 +0000362 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363}
364
365
366void StubCompiler::GenerateStoreField(MacroAssembler* masm,
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000367 Builtins::Name storage_extend,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 JSObject* object,
369 int index,
370 Map* transition,
371 Register receiver_reg,
372 Register name_reg,
373 Register scratch,
374 Label* miss_label) {
375 // Check that the object isn't a smi.
376 __ test(receiver_reg, Immediate(kSmiTagMask));
377 __ j(zero, miss_label, not_taken);
378
379 // Check that the map of the object hasn't changed.
380 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
381 Immediate(Handle<Map>(object->map())));
382 __ j(not_equal, miss_label, not_taken);
383
384 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000385 if (object->IsJSGlobalProxy()) {
386 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387 }
388
389 // Stub never generated for non-global objects that require access
390 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000391 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000393 // Perform map transition for the receiver if necessary.
394 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
395 // The properties must be extended before we can store the value.
396 // We jump to a runtime call that extends the propeties array.
397 __ mov(Operand(ecx), Immediate(Handle<Map>(transition)));
398 Handle<Code> ic(Builtins::builtin(storage_extend));
399 __ jmp(ic, RelocInfo::CODE_TARGET);
400 return;
401 }
402
ager@chromium.org7c537e22008-10-16 08:43:32 +0000403 // Adjust for the number of properties stored in the object. Even in the
404 // face of a transition we can use the old map here because the size of the
405 // object and the number of in-object properties is not going to change.
406 index -= object->map()->inobject_properties();
407
408 if (index >= 0) {
409 // Get the properties array (optimistically).
410 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
411 }
412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 if (transition != NULL) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000414 // Update the map of the object; no write barrier updating is
415 // needed because the map is never in new space.
416 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
417 Immediate(Handle<Map>(transition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000418 }
419
ager@chromium.org7c537e22008-10-16 08:43:32 +0000420 if (index < 0) {
421 // Set the property straight into the object.
422 int offset = object->map()->instance_size() + (index * kPointerSize);
423 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424
ager@chromium.org7c537e22008-10-16 08:43:32 +0000425 // Update the write barrier for the array address.
426 // Pass the value being stored in the now unused name_reg.
427 __ mov(name_reg, Operand(eax));
428 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
429 } else {
430 // Write to the properties array.
431 int offset = index * kPointerSize + Array::kHeaderSize;
432 __ mov(FieldOperand(scratch, offset), eax);
433
434 // Update the write barrier for the array address.
435 // Pass the value being stored in the now unused name_reg.
436 __ mov(name_reg, Operand(eax));
437 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
438 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439
440 // Return the value (register eax).
441 __ ret(0);
442}
443
444
445#undef __
446
447#define __ masm()->
448
449
450// TODO(1241006): Avoid having lazy compile stubs specialized by the
451// number of arguments. It is not needed anymore.
452Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
453 HandleScope scope;
454
455 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000456 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000457
458 // Push a copy of the function onto the stack.
459 __ push(edi);
460
461 __ push(edi); // function is also the parameter to the runtime call
462 __ CallRuntime(Runtime::kLazyCompile, 1);
463 __ pop(edi);
464
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000465 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000466 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467
468 // Do a tail-call of the compiled function.
469 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
470 __ jmp(Operand(ecx));
471
472 return GetCodeWithFlags(flags);
473}
474
475
476Object* CallStubCompiler::CompileCallField(Object* object,
477 JSObject* holder,
478 int index) {
479 // ----------- S t a t e -------------
480 // -----------------------------------
481
482 HandleScope scope;
483 Label miss;
484
485 // Get the receiver from the stack.
486 const int argc = arguments().immediate();
487 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
488
489 // Check that the receiver isn't a smi.
490 __ test(edx, Immediate(kSmiTagMask));
491 __ j(zero, &miss, not_taken);
492
493 // Do the right check and compute the holder register.
494 Register reg =
495 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
496
ager@chromium.org7c537e22008-10-16 08:43:32 +0000497 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498
499 // Check that the function really is a function.
500 __ test(edi, Immediate(kSmiTagMask));
501 __ j(zero, &miss, not_taken);
502 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
503 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
504 __ cmp(ebx, JS_FUNCTION_TYPE);
505 __ j(not_equal, &miss, not_taken);
506
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000507 // Patch the receiver on the stack with the global proxy if
508 // necessary.
509 if (object->IsGlobalObject()) {
510 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
511 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
512 }
513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514 // Invoke the function.
515 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
516
517 // Handle call cache miss.
518 __ bind(&miss);
519 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000520 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521
522 // Return the generated code.
523 return GetCode(FIELD);
524}
525
526
527Object* CallStubCompiler::CompileCallConstant(Object* object,
528 JSObject* holder,
529 JSFunction* function,
530 CheckType check) {
531 // ----------- S t a t e -------------
532 // -----------------------------------
533
534 HandleScope scope;
535 Label miss;
536
537 // Get the receiver from the stack.
538 const int argc = arguments().immediate();
539 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
540
541 // Check that the receiver isn't a smi.
542 if (check != NUMBER_CHECK) {
543 __ test(edx, Immediate(kSmiTagMask));
544 __ j(zero, &miss, not_taken);
545 }
546
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000547 // Make sure that it's okay not to patch the on stack receiver
548 // unless we're doing a receiver map check.
549 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 switch (check) {
552 case RECEIVER_MAP_CHECK:
553 // Check that the maps haven't changed.
554 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000555
556 // Patch the receiver on the stack with the global proxy if
557 // necessary.
558 if (object->IsGlobalObject()) {
559 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
560 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 break;
563
564 case STRING_CHECK:
565 // Check that the object is a two-byte string or a symbol.
566 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
567 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
568 __ cmp(ecx, FIRST_NONSTRING_TYPE);
569 __ j(above_equal, &miss, not_taken);
570 // Check that the maps starting from the prototype haven't changed.
571 GenerateLoadGlobalFunctionPrototype(masm(),
572 Context::STRING_FUNCTION_INDEX,
573 ecx);
574 __ CheckMaps(JSObject::cast(object->GetPrototype()),
575 ecx, holder, ebx, edx, &miss);
576 break;
577
578 case NUMBER_CHECK: {
579 Label fast;
580 // Check that the object is a smi or a heap number.
581 __ test(edx, Immediate(kSmiTagMask));
582 __ j(zero, &fast, taken);
583 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
584 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
585 __ cmp(ecx, HEAP_NUMBER_TYPE);
586 __ j(not_equal, &miss, not_taken);
587 __ bind(&fast);
588 // Check that the maps starting from the prototype haven't changed.
589 GenerateLoadGlobalFunctionPrototype(masm(),
590 Context::NUMBER_FUNCTION_INDEX,
591 ecx);
592 __ CheckMaps(JSObject::cast(object->GetPrototype()),
593 ecx, holder, ebx, edx, &miss);
594 break;
595 }
596
597 case BOOLEAN_CHECK: {
598 Label fast;
599 // Check that the object is a boolean.
600 __ cmp(edx, Factory::true_value());
601 __ j(equal, &fast, taken);
602 __ cmp(edx, Factory::false_value());
603 __ j(not_equal, &miss, not_taken);
604 __ bind(&fast);
605 // Check that the maps starting from the prototype haven't changed.
606 GenerateLoadGlobalFunctionPrototype(masm(),
607 Context::BOOLEAN_FUNCTION_INDEX,
608 ecx);
609 __ CheckMaps(JSObject::cast(object->GetPrototype()),
610 ecx, holder, ebx, edx, &miss);
611 break;
612 }
613
614 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
615 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
616 // Make sure object->elements()->map() != Heap::dictionary_array_map()
617 // Get the elements array of the object.
618 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
619 // Check that the object is in fast mode (not dictionary).
620 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
621 Immediate(Factory::hash_table_map()));
622 __ j(equal, &miss, not_taken);
623 break;
624
625 default:
626 UNREACHABLE();
627 }
628
629 // Get the function and setup the context.
630 __ mov(Operand(edi), Immediate(Handle<JSFunction>(function)));
631 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
632
633 // Jump to the cached code (tail call).
634 Handle<Code> code(function->code());
635 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000636 __ InvokeCode(code, expected, arguments(),
637 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638
639 // Handle call cache miss.
640 __ bind(&miss);
641 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000642 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643
644 // Return the generated code.
645 return GetCode(CONSTANT_FUNCTION);
646}
647
648
649Object* CallStubCompiler::CompileCallInterceptor(Object* object,
650 JSObject* holder,
651 String* name) {
652 // ----------- S t a t e -------------
653 // -----------------------------------
654
655 HandleScope scope;
656 Label miss;
657
658 // Get the number of arguments.
659 const int argc = arguments().immediate();
660
661 // Get the receiver from the stack.
662 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664 // Check that the receiver isn't a smi.
665 __ test(edx, Immediate(kSmiTagMask));
666 __ j(zero, &miss, not_taken);
667
668 // Check that maps have not changed and compute the holder register.
669 Register reg =
670 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
671
672 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000673 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674
675 // Push arguments on the expression stack.
676 __ push(edx); // receiver
677 __ push(reg); // holder
678 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
679
680 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681 ExternalReference load_interceptor =
682 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000683 __ mov(Operand(eax), Immediate(3));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684 __ mov(Operand(ebx), Immediate(load_interceptor));
685
686 CEntryStub stub;
687 __ CallStub(&stub);
688
689 // Move result to edi and restore receiver.
690 __ mov(Operand(edi), eax);
691 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
692
693 // Exit frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000694 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695
696 // Check that the function really is a function.
697 __ test(edi, Immediate(kSmiTagMask));
698 __ j(zero, &miss, not_taken);
699 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
700 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
701 __ cmp(ebx, JS_FUNCTION_TYPE);
702 __ j(not_equal, &miss, not_taken);
703
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000704 // Patch the receiver on the stack with the global proxy if
705 // necessary.
706 if (object->IsGlobalObject()) {
707 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
708 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
709 }
710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711 // Invoke the function.
712 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
713
714 // Handle load cache miss.
715 __ bind(&miss);
716 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000717 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718
719 // Return the generated code.
720 return GetCode(INTERCEPTOR);
721}
722
723
724Object* StoreStubCompiler::CompileStoreField(JSObject* object,
725 int index,
726 Map* transition,
727 String* name) {
728 // ----------- S t a t e -------------
729 // -- eax : value
730 // -- ecx : name
731 // -- esp[0] : return address
732 // -- esp[4] : receiver
733 // -----------------------------------
734
735 HandleScope scope;
736 Label miss;
737
738 // Get the object from the stack.
739 __ mov(ebx, Operand(esp, 1 * kPointerSize));
740
741 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000742 GenerateStoreField(masm(),
743 Builtins::StoreIC_ExtendStorage,
744 object,
745 index,
746 transition,
747 ebx, ecx, edx,
748 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000749
750 // Handle store cache miss.
751 __ bind(&miss);
752 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
753 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000754 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000755
756 // Return the generated code.
757 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
758}
759
760
761Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
762 AccessorInfo* callback,
763 String* name) {
764 // ----------- S t a t e -------------
765 // -- eax : value
766 // -- ecx : name
767 // -- esp[0] : return address
768 // -- esp[4] : receiver
769 // -----------------------------------
770
771 HandleScope scope;
772 Label miss;
773
774 // Get the object from the stack.
775 __ mov(ebx, Operand(esp, 1 * kPointerSize));
776
777 // Check that the object isn't a smi.
778 __ test(ebx, Immediate(kSmiTagMask));
779 __ j(zero, &miss, not_taken);
780
781 // Check that the map of the object hasn't changed.
782 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
783 Immediate(Handle<Map>(object->map())));
784 __ j(not_equal, &miss, not_taken);
785
786 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000787 if (object->IsJSGlobalProxy()) {
788 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789 }
790
791 // Stub never generated for non-global objects that require access
792 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000793 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000794
795 __ pop(ebx); // remove the return address
796 __ push(Operand(esp, 0)); // receiver
797 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
798 __ push(ecx); // name
799 __ push(eax); // value
800 __ push(ebx); // restore return address
801
mads.s.ager31e71382008-08-13 09:32:07 +0000802 // Do tail-call to the runtime system.
803 ExternalReference store_callback_property =
804 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
805 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806
807 // Handle store cache miss.
808 __ bind(&miss);
809 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
810 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000811 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812
813 // Return the generated code.
814 return GetCode(CALLBACKS);
815}
816
817
818Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
819 String* name) {
820 // ----------- S t a t e -------------
821 // -- eax : value
822 // -- ecx : name
823 // -- esp[0] : return address
824 // -- esp[4] : receiver
825 // -----------------------------------
826
827 HandleScope scope;
828 Label miss;
829
830 // Get the object from the stack.
831 __ mov(ebx, Operand(esp, 1 * kPointerSize));
832
833 // Check that the object isn't a smi.
834 __ test(ebx, Immediate(kSmiTagMask));
835 __ j(zero, &miss, not_taken);
836
837 // Check that the map of the object hasn't changed.
838 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
839 Immediate(Handle<Map>(receiver->map())));
840 __ j(not_equal, &miss, not_taken);
841
842 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000843 if (receiver->IsJSGlobalProxy()) {
844 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 }
846
847 // Stub never generated for non-global objects that require access
848 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000849 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850
851 __ pop(ebx); // remove the return address
852 __ push(Operand(esp, 0)); // receiver
853 __ push(ecx); // name
854 __ push(eax); // value
855 __ push(ebx); // restore return address
856
mads.s.ager31e71382008-08-13 09:32:07 +0000857 // Do tail-call to the runtime system.
858 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000860 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861
862 // Handle store cache miss.
863 __ bind(&miss);
864 __ mov(Operand(ecx), Immediate(Handle<String>(name))); // restore name
865 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000866 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867
868 // Return the generated code.
869 return GetCode(INTERCEPTOR);
870}
871
872
873Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
874 int index,
875 Map* transition,
876 String* name) {
877 // ----------- S t a t e -------------
878 // -- eax : value
879 // -- esp[0] : return address
880 // -- esp[4] : key
881 // -- esp[8] : receiver
882 // -----------------------------------
883 HandleScope scope;
884 Label miss;
885
886 __ IncrementCounter(&Counters::keyed_store_field, 1);
887
888 // Get the name from the stack.
889 __ mov(ecx, Operand(esp, 1 * kPointerSize));
890 // Check that the name has not changed.
891 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
892 __ j(not_equal, &miss, not_taken);
893
894 // Get the object from the stack.
895 __ mov(ebx, Operand(esp, 2 * kPointerSize));
896
897 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000898 GenerateStoreField(masm(),
899 Builtins::KeyedStoreIC_ExtendStorage,
900 object,
901 index,
902 transition,
903 ebx, ecx, edx,
904 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905
906 // Handle store cache miss.
907 __ bind(&miss);
908 __ DecrementCounter(&Counters::keyed_store_field, 1);
909 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000910 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911
912 // Return the generated code.
913 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
914}
915
916
917Object* LoadStubCompiler::CompileLoadField(JSObject* object,
918 JSObject* holder,
919 int index) {
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 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
931 __ bind(&miss);
932 GenerateLoadMiss(masm(), Code::LOAD_IC);
933
934 // Return the generated code.
935 return GetCode(FIELD);
936}
937
938
939Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
940 JSObject* holder,
941 AccessorInfo* callback) {
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 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
953 edx, callback, &miss);
954 __ bind(&miss);
955 GenerateLoadMiss(masm(), Code::LOAD_IC);
956
957 // Return the generated code.
958 return GetCode(CALLBACKS);
959}
960
961
962Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
963 JSObject* holder,
964 Object* value) {
965 // ----------- S t a t e -------------
966 // -- ecx : name
967 // -- esp[0] : return address
968 // -- esp[4] : receiver
969 // -----------------------------------
970
971 HandleScope scope;
972 Label miss;
973
974 __ mov(eax, (Operand(esp, kPointerSize)));
975 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
976 __ bind(&miss);
977 GenerateLoadMiss(masm(), Code::LOAD_IC);
978
979 // Return the generated code.
980 return GetCode(CONSTANT_FUNCTION);
981}
982
983
984Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
985 JSObject* holder,
986 String* name) {
987 // ----------- S t a t e -------------
988 // -- ecx : name
989 // -- esp[0] : return address
990 // -- esp[4] : receiver
991 // -----------------------------------
992 HandleScope scope;
993 Label miss;
994
995 __ mov(eax, (Operand(esp, kPointerSize)));
996 GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
997 __ bind(&miss);
998 GenerateLoadMiss(masm(), Code::LOAD_IC);
999
1000 // Return the generated code.
1001 return GetCode(INTERCEPTOR);
1002}
1003
1004
1005Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1006 JSObject* receiver,
1007 JSObject* holder,
1008 int index) {
1009 // ----------- S t a t e -------------
1010 // -- esp[0] : return address
1011 // -- esp[4] : name
1012 // -- esp[8] : receiver
1013 // -----------------------------------
1014 HandleScope scope;
1015 Label miss;
1016
1017 __ mov(eax, (Operand(esp, kPointerSize)));
1018 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1019 __ IncrementCounter(&Counters::keyed_load_field, 1);
1020
1021 // Check that the name has not changed.
1022 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1023 __ j(not_equal, &miss, not_taken);
1024
1025 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1026 __ bind(&miss);
1027 __ DecrementCounter(&Counters::keyed_load_field, 1);
1028 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1029
1030 // Return the generated code.
1031 return GetCode(FIELD);
1032}
1033
1034
1035Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1036 JSObject* receiver,
1037 JSObject* holder,
1038 AccessorInfo* callback) {
1039 // ----------- S t a t e -------------
1040 // -- esp[0] : return address
1041 // -- esp[4] : name
1042 // -- esp[8] : receiver
1043 // -----------------------------------
1044 HandleScope scope;
1045 Label miss;
1046
1047 __ mov(eax, (Operand(esp, kPointerSize)));
1048 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1049 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1050
1051 // Check that the name has not changed.
1052 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1053 __ j(not_equal, &miss, not_taken);
1054
1055 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1056 callback, &miss);
1057 __ bind(&miss);
1058 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1059 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1060
1061 // Return the generated code.
1062 return GetCode(CALLBACKS);
1063}
1064
1065
1066Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1067 JSObject* receiver,
1068 JSObject* holder,
1069 Object* value) {
1070 // ----------- S t a t e -------------
1071 // -- esp[0] : return address
1072 // -- esp[4] : name
1073 // -- esp[8] : receiver
1074 // -----------------------------------
1075 HandleScope scope;
1076 Label miss;
1077
1078 __ mov(eax, (Operand(esp, kPointerSize)));
1079 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1080 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1081
1082 // Check that the name has not changed.
1083 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1084 __ j(not_equal, &miss, not_taken);
1085
1086 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1087 __ bind(&miss);
1088 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1089 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1090
1091 // Return the generated code.
1092 return GetCode(CONSTANT_FUNCTION);
1093}
1094
1095
1096Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1097 JSObject* holder,
1098 String* name) {
1099 // ----------- S t a t e -------------
1100 // -- esp[0] : return address
1101 // -- esp[4] : name
1102 // -- esp[8] : receiver
1103 // -----------------------------------
1104 HandleScope scope;
1105 Label miss;
1106
1107 __ mov(eax, (Operand(esp, kPointerSize)));
1108 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1109 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1110
1111 // Check that the name has not changed.
1112 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1113 __ j(not_equal, &miss, not_taken);
1114
1115 GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
1116 __ bind(&miss);
1117 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1118 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1119
1120 // Return the generated code.
1121 return GetCode(INTERCEPTOR);
1122}
1123
1124
1125
1126
1127Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1128 // ----------- S t a t e -------------
1129 // -- esp[0] : return address
1130 // -- esp[4] : name
1131 // -- esp[8] : receiver
1132 // -----------------------------------
1133 HandleScope scope;
1134 Label miss;
1135
1136 __ mov(eax, (Operand(esp, kPointerSize)));
1137 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1138 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1139
1140 // Check that the name has not changed.
1141 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1142 __ j(not_equal, &miss, not_taken);
1143
1144 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1145 __ bind(&miss);
1146 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1147 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1148
1149 // Return the generated code.
1150 return GetCode(CALLBACKS);
1151}
1152
1153
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001154Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 // ----------- S t a t e -------------
1156 // -- esp[0] : return address
1157 // -- esp[4] : name
1158 // -- esp[8] : receiver
1159 // -----------------------------------
1160 HandleScope scope;
1161 Label miss;
1162
1163 __ mov(eax, (Operand(esp, kPointerSize)));
1164 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1165 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1166
1167 // Check that the name has not changed.
1168 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1169 __ j(not_equal, &miss, not_taken);
1170
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001171 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 __ bind(&miss);
1173 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1174 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1175
1176 // Return the generated code.
1177 return GetCode(CALLBACKS);
1178}
1179
1180
1181Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1182 // ----------- S t a t e -------------
1183 // -- esp[0] : return address
1184 // -- esp[4] : name
1185 // -- esp[8] : receiver
1186 // -----------------------------------
1187 HandleScope scope;
1188 Label miss;
1189
1190 __ mov(eax, (Operand(esp, kPointerSize)));
1191 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1192 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1193
1194 // Check that the name has not changed.
1195 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1196 __ j(not_equal, &miss, not_taken);
1197
1198 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1199 __ bind(&miss);
1200 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1201 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1202
1203 // Return the generated code.
1204 return GetCode(CALLBACKS);
1205}
1206
1207
1208#undef __
1209
1210} } // namespace v8::internal