blob: c2be65d7bb8f24fcc1bb2c28bef549ccc18d01b0 [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.org9bbf9682008-10-30 11:53:07 +0000188 // Check if the object is a string leaving the instance type in the
189 // scratch register.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000190 GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191
192 // Load length directly from the string.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000193 __ bind(&load_length);
194 __ and_(scratch, kStringSizeMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000195 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000196 // ecx is also the receiver.
197 __ lea(ecx, Operand(scratch, String::kLongLengthShift));
198 __ shr(eax); // ecx is implicit shift register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 __ shl(eax, kSmiTagSize);
200 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000201
202 // Check if the object is a JSValue wrapper.
203 __ bind(&check_wrapper);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000204 __ cmp(scratch, JS_VALUE_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000205 __ j(not_equal, miss, not_taken);
206
207 // Check if the wrapped value is a string and load the length
208 // directly if it is.
209 __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
210 GenerateStringCheck(masm, receiver, scratch, miss, miss);
211 __ jmp(&load_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212}
213
214
215void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
216 Register receiver,
217 Register scratch1,
218 Register scratch2,
219 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000220 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221 __ mov(eax, Operand(scratch1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000223}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224
ager@chromium.org7c537e22008-10-16 08:43:32 +0000225
226// Load a fast property out of a holder object (src). In-object properties
227// are loaded directly otherwise the property is loaded from the properties
228// fixed array.
229void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
230 Register dst, Register src,
231 JSObject* holder, int index) {
232 // Adjust for the number of properties stored in the holder.
233 index -= holder->map()->inobject_properties();
234 if (index < 0) {
235 // Get the property straight out of the holder.
236 int offset = holder->map()->instance_size() + (index * kPointerSize);
237 __ mov(dst, FieldOperand(src, offset));
238 } else {
239 // Calculate the offset into the properties array.
240 int offset = index * kPointerSize + Array::kHeaderSize;
241 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
242 __ mov(dst, FieldOperand(dst, offset));
243 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244}
245
246
247void StubCompiler::GenerateLoadField(MacroAssembler* masm,
248 JSObject* object,
249 JSObject* holder,
250 Register receiver,
251 Register scratch1,
252 Register scratch2,
253 int index,
254 Label* miss_label) {
255 // Check that the receiver isn't a smi.
256 __ test(receiver, Immediate(kSmiTagMask));
257 __ j(zero, miss_label, not_taken);
258
259 // Check that the maps haven't changed.
260 Register reg =
261 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
262
ager@chromium.org7c537e22008-10-16 08:43:32 +0000263 // Get the value from the properties.
264 GenerateFastPropertyLoad(masm, eax, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 __ ret(0);
266}
267
268
269void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
270 JSObject* object,
271 JSObject* holder,
272 Register receiver,
273 Register name,
274 Register scratch1,
275 Register scratch2,
276 AccessorInfo* callback,
277 Label* miss_label) {
278 // Check that the receiver isn't a smi.
279 __ test(receiver, Immediate(kSmiTagMask));
280 __ j(zero, miss_label, not_taken);
281
282 // Check that the maps haven't changed.
283 Register reg =
284 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
285
286 // Push the arguments on the JS stack of the caller.
287 __ pop(scratch2); // remove return address
288 __ push(receiver); // receiver
289 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
290 __ push(name); // name
291 __ push(reg); // holder
292 __ push(scratch2); // restore return address
293
mads.s.ager31e71382008-08-13 09:32:07 +0000294 // Do tail-call to the runtime system.
295 ExternalReference load_callback_property =
296 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
297 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298}
299
300
301void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
302 JSObject* object,
303 JSObject* holder,
304 Register receiver,
305 Register scratch1,
306 Register scratch2,
307 Object* value,
308 Label* miss_label) {
309 // Check that the receiver isn't a smi.
310 __ test(receiver, Immediate(kSmiTagMask));
311 __ j(zero, miss_label, not_taken);
312
313 // Check that the maps haven't changed.
314 Register reg =
315 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
316
317 // Return the constant value.
318 __ mov(eax, Handle<Object>(value));
319 __ ret(0);
320}
321
322
323void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
324 JSObject* object,
325 JSObject* holder,
326 Register receiver,
327 Register name,
328 Register scratch1,
329 Register scratch2,
330 Label* miss_label) {
331 // Check that the receiver isn't a smi.
332 __ test(receiver, Immediate(kSmiTagMask));
333 __ j(zero, miss_label, not_taken);
334
335 // Check that the maps haven't changed.
336 Register reg =
337 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
338
339 // Push the arguments on the JS stack of the caller.
340 __ pop(scratch2); // remove return address
341 __ push(receiver); // receiver
342 __ push(reg); // holder
343 __ push(name); // name
344 __ push(scratch2); // restore return address
345
mads.s.ager31e71382008-08-13 09:32:07 +0000346 // Do tail-call to the runtime system.
347 ExternalReference load_ic_property =
348 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
349 __ TailCallRuntime(load_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350}
351
352
353void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
354 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
355 Code* code = NULL;
356 if (kind == Code::LOAD_IC) {
357 code = Builtins::builtin(Builtins::LoadIC_Miss);
358 } else {
359 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
360 }
361
362 Handle<Code> ic(code);
ager@chromium.org236ad962008-09-25 09:45:57 +0000363 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364}
365
366
367void StubCompiler::GenerateStoreField(MacroAssembler* masm,
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000368 Builtins::Name storage_extend,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 JSObject* object,
370 int index,
371 Map* transition,
372 Register receiver_reg,
373 Register name_reg,
374 Register scratch,
375 Label* miss_label) {
376 // Check that the object isn't a smi.
377 __ test(receiver_reg, Immediate(kSmiTagMask));
378 __ j(zero, miss_label, not_taken);
379
380 // Check that the map of the object hasn't changed.
381 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
382 Immediate(Handle<Map>(object->map())));
383 __ j(not_equal, miss_label, not_taken);
384
385 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000386 if (object->IsJSGlobalProxy()) {
387 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000388 }
389
390 // Stub never generated for non-global objects that require access
391 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000392 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000393
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000394 // Perform map transition for the receiver if necessary.
395 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
396 // The properties must be extended before we can store the value.
397 // We jump to a runtime call that extends the propeties array.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000398 __ mov(ecx, Immediate(Handle<Map>(transition)));
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000399 Handle<Code> ic(Builtins::builtin(storage_extend));
400 __ jmp(ic, RelocInfo::CODE_TARGET);
401 return;
402 }
403
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 if (transition != NULL) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000405 // Update the map of the object; no write barrier updating is
406 // needed because the map is never in new space.
407 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
408 Immediate(Handle<Map>(transition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409 }
410
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000411 // Adjust for the number of properties stored in the object. Even in the
412 // face of a transition we can use the old map here because the size of the
413 // object and the number of in-object properties is not going to change.
414 index -= object->map()->inobject_properties();
415
ager@chromium.org7c537e22008-10-16 08:43:32 +0000416 if (index < 0) {
417 // Set the property straight into the object.
418 int offset = object->map()->instance_size() + (index * kPointerSize);
419 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420
ager@chromium.org7c537e22008-10-16 08:43:32 +0000421 // Update the write barrier for the array address.
422 // Pass the value being stored in the now unused name_reg.
423 __ mov(name_reg, Operand(eax));
424 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
425 } else {
426 // Write to the properties array.
427 int offset = index * kPointerSize + Array::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000428 // Get the properties array (optimistically).
429 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000430 __ mov(FieldOperand(scratch, offset), eax);
431
432 // Update the write barrier for the array address.
433 // Pass the value being stored in the now unused name_reg.
434 __ mov(name_reg, Operand(eax));
435 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
438 // Return the value (register eax).
439 __ ret(0);
440}
441
442
443#undef __
444
445#define __ masm()->
446
447
448// TODO(1241006): Avoid having lazy compile stubs specialized by the
449// number of arguments. It is not needed anymore.
450Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
451 HandleScope scope;
452
453 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000454 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455
456 // Push a copy of the function onto the stack.
457 __ push(edi);
458
459 __ push(edi); // function is also the parameter to the runtime call
460 __ CallRuntime(Runtime::kLazyCompile, 1);
461 __ pop(edi);
462
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000463 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000464 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000465
466 // Do a tail-call of the compiled function.
467 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
468 __ jmp(Operand(ecx));
469
470 return GetCodeWithFlags(flags);
471}
472
473
474Object* CallStubCompiler::CompileCallField(Object* object,
475 JSObject* holder,
476 int index) {
477 // ----------- S t a t e -------------
478 // -----------------------------------
479
480 HandleScope scope;
481 Label miss;
482
483 // Get the receiver from the stack.
484 const int argc = arguments().immediate();
485 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
486
487 // Check that the receiver isn't a smi.
488 __ test(edx, Immediate(kSmiTagMask));
489 __ j(zero, &miss, not_taken);
490
491 // Do the right check and compute the holder register.
492 Register reg =
493 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
494
ager@chromium.org7c537e22008-10-16 08:43:32 +0000495 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496
497 // Check that the function really is a function.
498 __ test(edi, Immediate(kSmiTagMask));
499 __ j(zero, &miss, not_taken);
500 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
501 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
502 __ cmp(ebx, JS_FUNCTION_TYPE);
503 __ j(not_equal, &miss, not_taken);
504
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000505 // Patch the receiver on the stack with the global proxy if
506 // necessary.
507 if (object->IsGlobalObject()) {
508 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
509 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
510 }
511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 // Invoke the function.
513 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
514
515 // Handle call cache miss.
516 __ bind(&miss);
517 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000518 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519
520 // Return the generated code.
521 return GetCode(FIELD);
522}
523
524
525Object* CallStubCompiler::CompileCallConstant(Object* object,
526 JSObject* holder,
527 JSFunction* function,
528 CheckType check) {
529 // ----------- S t a t e -------------
530 // -----------------------------------
531
532 HandleScope scope;
533 Label miss;
534
535 // Get the receiver from the stack.
536 const int argc = arguments().immediate();
537 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
538
539 // Check that the receiver isn't a smi.
540 if (check != NUMBER_CHECK) {
541 __ test(edx, Immediate(kSmiTagMask));
542 __ j(zero, &miss, not_taken);
543 }
544
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000545 // Make sure that it's okay not to patch the on stack receiver
546 // unless we're doing a receiver map check.
547 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
548
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 switch (check) {
550 case RECEIVER_MAP_CHECK:
551 // Check that the maps haven't changed.
552 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000553
554 // Patch the receiver on the stack with the global proxy if
555 // necessary.
556 if (object->IsGlobalObject()) {
557 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
558 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
559 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 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.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000628 __ mov(edi, Immediate(Handle<JSFunction>(function)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 __ 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));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000661
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662 // Check that the receiver isn't a smi.
663 __ test(edx, Immediate(kSmiTagMask));
664 __ j(zero, &miss, not_taken);
665
666 // Check that maps have not changed and compute the holder register.
667 Register reg =
668 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
669
670 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000671 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672
673 // Push arguments on the expression stack.
674 __ push(edx); // receiver
675 __ push(reg); // holder
676 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
677
678 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679 ExternalReference load_interceptor =
680 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000681 __ mov(eax, Immediate(3));
682 __ mov(ebx, Immediate(load_interceptor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683
684 CEntryStub stub;
685 __ CallStub(&stub);
686
687 // Move result to edi and restore receiver.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000688 __ mov(edi, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
690
691 // Exit frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000692 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693
694 // Check that the function really is a function.
695 __ test(edi, Immediate(kSmiTagMask));
696 __ j(zero, &miss, not_taken);
697 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
698 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
699 __ cmp(ebx, JS_FUNCTION_TYPE);
700 __ j(not_equal, &miss, not_taken);
701
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000702 // Patch the receiver on the stack with the global proxy if
703 // necessary.
704 if (object->IsGlobalObject()) {
705 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
706 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
707 }
708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 // Invoke the function.
710 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
711
712 // Handle load cache miss.
713 __ bind(&miss);
714 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000715 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716
717 // Return the generated code.
718 return GetCode(INTERCEPTOR);
719}
720
721
722Object* StoreStubCompiler::CompileStoreField(JSObject* object,
723 int index,
724 Map* transition,
725 String* name) {
726 // ----------- S t a t e -------------
727 // -- eax : value
728 // -- ecx : name
729 // -- esp[0] : return address
730 // -- esp[4] : receiver
731 // -----------------------------------
732
733 HandleScope scope;
734 Label miss;
735
736 // Get the object from the stack.
737 __ mov(ebx, Operand(esp, 1 * kPointerSize));
738
739 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000740 GenerateStoreField(masm(),
741 Builtins::StoreIC_ExtendStorage,
742 object,
743 index,
744 transition,
745 ebx, ecx, edx,
746 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000747
748 // Handle store cache miss.
749 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000750 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000752 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000753
754 // Return the generated code.
755 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
756}
757
758
759Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
760 AccessorInfo* callback,
761 String* name) {
762 // ----------- S t a t e -------------
763 // -- eax : value
764 // -- ecx : name
765 // -- esp[0] : return address
766 // -- esp[4] : receiver
767 // -----------------------------------
768
769 HandleScope scope;
770 Label miss;
771
772 // Get the object from the stack.
773 __ mov(ebx, Operand(esp, 1 * kPointerSize));
774
775 // Check that the object isn't a smi.
776 __ test(ebx, Immediate(kSmiTagMask));
777 __ j(zero, &miss, not_taken);
778
779 // Check that the map of the object hasn't changed.
780 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
781 Immediate(Handle<Map>(object->map())));
782 __ j(not_equal, &miss, not_taken);
783
784 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000785 if (object->IsJSGlobalProxy()) {
786 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787 }
788
789 // Stub never generated for non-global objects that require access
790 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000791 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000792
793 __ pop(ebx); // remove the return address
794 __ push(Operand(esp, 0)); // receiver
795 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
796 __ push(ecx); // name
797 __ push(eax); // value
798 __ push(ebx); // restore return address
799
mads.s.ager31e71382008-08-13 09:32:07 +0000800 // Do tail-call to the runtime system.
801 ExternalReference store_callback_property =
802 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
803 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804
805 // Handle store cache miss.
806 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000807 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000809 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810
811 // Return the generated code.
812 return GetCode(CALLBACKS);
813}
814
815
816Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
817 String* name) {
818 // ----------- S t a t e -------------
819 // -- eax : value
820 // -- ecx : name
821 // -- esp[0] : return address
822 // -- esp[4] : receiver
823 // -----------------------------------
824
825 HandleScope scope;
826 Label miss;
827
828 // Get the object from the stack.
829 __ mov(ebx, Operand(esp, 1 * kPointerSize));
830
831 // Check that the object isn't a smi.
832 __ test(ebx, Immediate(kSmiTagMask));
833 __ j(zero, &miss, not_taken);
834
835 // Check that the map of the object hasn't changed.
836 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
837 Immediate(Handle<Map>(receiver->map())));
838 __ j(not_equal, &miss, not_taken);
839
840 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000841 if (receiver->IsJSGlobalProxy()) {
842 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000843 }
844
845 // Stub never generated for non-global objects that require access
846 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000847 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000848
849 __ pop(ebx); // remove the return address
850 __ push(Operand(esp, 0)); // receiver
851 __ push(ecx); // name
852 __ push(eax); // value
853 __ push(ebx); // restore return address
854
mads.s.ager31e71382008-08-13 09:32:07 +0000855 // Do tail-call to the runtime system.
856 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000858 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859
860 // Handle store cache miss.
861 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000862 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000864 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865
866 // Return the generated code.
867 return GetCode(INTERCEPTOR);
868}
869
870
871Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
872 int index,
873 Map* transition,
874 String* name) {
875 // ----------- S t a t e -------------
876 // -- eax : value
877 // -- esp[0] : return address
878 // -- esp[4] : key
879 // -- esp[8] : receiver
880 // -----------------------------------
881 HandleScope scope;
882 Label miss;
883
884 __ IncrementCounter(&Counters::keyed_store_field, 1);
885
886 // Get the name from the stack.
887 __ mov(ecx, Operand(esp, 1 * kPointerSize));
888 // Check that the name has not changed.
889 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
890 __ j(not_equal, &miss, not_taken);
891
892 // Get the object from the stack.
893 __ mov(ebx, Operand(esp, 2 * kPointerSize));
894
895 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000896 GenerateStoreField(masm(),
897 Builtins::KeyedStoreIC_ExtendStorage,
898 object,
899 index,
900 transition,
901 ebx, ecx, edx,
902 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903
904 // Handle store cache miss.
905 __ bind(&miss);
906 __ DecrementCounter(&Counters::keyed_store_field, 1);
907 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000908 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000909
910 // Return the generated code.
911 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
912}
913
914
915Object* LoadStubCompiler::CompileLoadField(JSObject* object,
916 JSObject* holder,
917 int index) {
918 // ----------- S t a t e -------------
919 // -- ecx : name
920 // -- esp[0] : return address
921 // -- esp[4] : receiver
922 // -----------------------------------
923
924 HandleScope scope;
925 Label miss;
926
927 __ mov(eax, (Operand(esp, kPointerSize)));
928 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
929 __ bind(&miss);
930 GenerateLoadMiss(masm(), Code::LOAD_IC);
931
932 // Return the generated code.
933 return GetCode(FIELD);
934}
935
936
937Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
938 JSObject* holder,
939 AccessorInfo* callback) {
940 // ----------- S t a t e -------------
941 // -- ecx : name
942 // -- esp[0] : return address
943 // -- esp[4] : receiver
944 // -----------------------------------
945
946 HandleScope scope;
947 Label miss;
948
949 __ mov(eax, (Operand(esp, kPointerSize)));
950 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
951 edx, callback, &miss);
952 __ bind(&miss);
953 GenerateLoadMiss(masm(), Code::LOAD_IC);
954
955 // Return the generated code.
956 return GetCode(CALLBACKS);
957}
958
959
960Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
961 JSObject* holder,
962 Object* value) {
963 // ----------- S t a t e -------------
964 // -- ecx : name
965 // -- esp[0] : return address
966 // -- esp[4] : receiver
967 // -----------------------------------
968
969 HandleScope scope;
970 Label miss;
971
972 __ mov(eax, (Operand(esp, kPointerSize)));
973 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
974 __ bind(&miss);
975 GenerateLoadMiss(masm(), Code::LOAD_IC);
976
977 // Return the generated code.
978 return GetCode(CONSTANT_FUNCTION);
979}
980
981
982Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
983 JSObject* holder,
984 String* name) {
985 // ----------- S t a t e -------------
986 // -- ecx : name
987 // -- esp[0] : return address
988 // -- esp[4] : receiver
989 // -----------------------------------
990 HandleScope scope;
991 Label miss;
992
993 __ mov(eax, (Operand(esp, kPointerSize)));
994 GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
995 __ bind(&miss);
996 GenerateLoadMiss(masm(), Code::LOAD_IC);
997
998 // Return the generated code.
999 return GetCode(INTERCEPTOR);
1000}
1001
1002
1003Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1004 JSObject* receiver,
1005 JSObject* holder,
1006 int index) {
1007 // ----------- S t a t e -------------
1008 // -- esp[0] : return address
1009 // -- esp[4] : name
1010 // -- esp[8] : receiver
1011 // -----------------------------------
1012 HandleScope scope;
1013 Label miss;
1014
1015 __ mov(eax, (Operand(esp, kPointerSize)));
1016 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1017 __ IncrementCounter(&Counters::keyed_load_field, 1);
1018
1019 // Check that the name has not changed.
1020 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1021 __ j(not_equal, &miss, not_taken);
1022
1023 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1024 __ bind(&miss);
1025 __ DecrementCounter(&Counters::keyed_load_field, 1);
1026 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1027
1028 // Return the generated code.
1029 return GetCode(FIELD);
1030}
1031
1032
1033Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1034 JSObject* receiver,
1035 JSObject* holder,
1036 AccessorInfo* callback) {
1037 // ----------- S t a t e -------------
1038 // -- esp[0] : return address
1039 // -- esp[4] : name
1040 // -- esp[8] : receiver
1041 // -----------------------------------
1042 HandleScope scope;
1043 Label miss;
1044
1045 __ mov(eax, (Operand(esp, kPointerSize)));
1046 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1047 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1048
1049 // Check that the name has not changed.
1050 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1051 __ j(not_equal, &miss, not_taken);
1052
1053 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1054 callback, &miss);
1055 __ bind(&miss);
1056 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1057 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1058
1059 // Return the generated code.
1060 return GetCode(CALLBACKS);
1061}
1062
1063
1064Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1065 JSObject* receiver,
1066 JSObject* holder,
1067 Object* value) {
1068 // ----------- S t a t e -------------
1069 // -- esp[0] : return address
1070 // -- esp[4] : name
1071 // -- esp[8] : receiver
1072 // -----------------------------------
1073 HandleScope scope;
1074 Label miss;
1075
1076 __ mov(eax, (Operand(esp, kPointerSize)));
1077 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1078 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1079
1080 // Check that the name has not changed.
1081 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1082 __ j(not_equal, &miss, not_taken);
1083
1084 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1085 __ bind(&miss);
1086 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1087 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1088
1089 // Return the generated code.
1090 return GetCode(CONSTANT_FUNCTION);
1091}
1092
1093
1094Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1095 JSObject* holder,
1096 String* name) {
1097 // ----------- S t a t e -------------
1098 // -- esp[0] : return address
1099 // -- esp[4] : name
1100 // -- esp[8] : receiver
1101 // -----------------------------------
1102 HandleScope scope;
1103 Label miss;
1104
1105 __ mov(eax, (Operand(esp, kPointerSize)));
1106 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1107 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1108
1109 // Check that the name has not changed.
1110 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1111 __ j(not_equal, &miss, not_taken);
1112
1113 GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
1114 __ bind(&miss);
1115 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1116 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1117
1118 // Return the generated code.
1119 return GetCode(INTERCEPTOR);
1120}
1121
1122
1123
1124
1125Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1126 // ----------- S t a t e -------------
1127 // -- esp[0] : return address
1128 // -- esp[4] : name
1129 // -- esp[8] : receiver
1130 // -----------------------------------
1131 HandleScope scope;
1132 Label miss;
1133
1134 __ mov(eax, (Operand(esp, kPointerSize)));
1135 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1136 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1137
1138 // Check that the name has not changed.
1139 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1140 __ j(not_equal, &miss, not_taken);
1141
1142 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1143 __ bind(&miss);
1144 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1145 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1146
1147 // Return the generated code.
1148 return GetCode(CALLBACKS);
1149}
1150
1151
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001152Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153 // ----------- S t a t e -------------
1154 // -- esp[0] : return address
1155 // -- esp[4] : name
1156 // -- esp[8] : receiver
1157 // -----------------------------------
1158 HandleScope scope;
1159 Label miss;
1160
1161 __ mov(eax, (Operand(esp, kPointerSize)));
1162 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1163 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1164
1165 // Check that the name has not changed.
1166 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1167 __ j(not_equal, &miss, not_taken);
1168
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001169 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 __ bind(&miss);
1171 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1172 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1173
1174 // Return the generated code.
1175 return GetCode(CALLBACKS);
1176}
1177
1178
1179Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1180 // ----------- S t a t e -------------
1181 // -- esp[0] : return address
1182 // -- esp[4] : name
1183 // -- esp[8] : receiver
1184 // -----------------------------------
1185 HandleScope scope;
1186 Label miss;
1187
1188 __ mov(eax, (Operand(esp, kPointerSize)));
1189 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1190 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1191
1192 // Check that the name has not changed.
1193 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1194 __ j(not_equal, &miss, not_taken);
1195
1196 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1197 __ bind(&miss);
1198 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1199 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1200
1201 // Return the generated code.
1202 return GetCode(CALLBACKS);
1203}
1204
1205
1206#undef __
1207
1208} } // namespace v8::internal