blob: d15b19de43b857a21a7e4465d7e76c4357a7c669 [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
ager@chromium.org7c537e22008-10-16 08:43:32 +0000404 // Adjust for the number of properties stored in the object. Even in the
405 // face of a transition we can use the old map here because the size of the
406 // object and the number of in-object properties is not going to change.
407 index -= object->map()->inobject_properties();
408
409 if (index >= 0) {
410 // Get the properties array (optimistically).
411 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
412 }
413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 if (transition != NULL) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000415 // Update the map of the object; no write barrier updating is
416 // needed because the map is never in new space.
417 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
418 Immediate(Handle<Map>(transition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419 }
420
ager@chromium.org7c537e22008-10-16 08:43:32 +0000421 if (index < 0) {
422 // Set the property straight into the object.
423 int offset = object->map()->instance_size() + (index * kPointerSize);
424 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425
ager@chromium.org7c537e22008-10-16 08:43:32 +0000426 // Update the write barrier for the array address.
427 // Pass the value being stored in the now unused name_reg.
428 __ mov(name_reg, Operand(eax));
429 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
430 } else {
431 // Write to the properties array.
432 int offset = index * kPointerSize + Array::kHeaderSize;
433 __ mov(FieldOperand(scratch, offset), eax);
434
435 // Update the write barrier for the array address.
436 // Pass the value being stored in the now unused name_reg.
437 __ mov(name_reg, Operand(eax));
438 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
441 // Return the value (register eax).
442 __ ret(0);
443}
444
445
446#undef __
447
448#define __ masm()->
449
450
451// TODO(1241006): Avoid having lazy compile stubs specialized by the
452// number of arguments. It is not needed anymore.
453Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
454 HandleScope scope;
455
456 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000457 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458
459 // Push a copy of the function onto the stack.
460 __ push(edi);
461
462 __ push(edi); // function is also the parameter to the runtime call
463 __ CallRuntime(Runtime::kLazyCompile, 1);
464 __ pop(edi);
465
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000466 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000467 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468
469 // Do a tail-call of the compiled function.
470 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
471 __ jmp(Operand(ecx));
472
473 return GetCodeWithFlags(flags);
474}
475
476
477Object* CallStubCompiler::CompileCallField(Object* object,
478 JSObject* holder,
479 int index) {
480 // ----------- S t a t e -------------
481 // -----------------------------------
482
483 HandleScope scope;
484 Label miss;
485
486 // Get the receiver from the stack.
487 const int argc = arguments().immediate();
488 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
489
490 // Check that the receiver isn't a smi.
491 __ test(edx, Immediate(kSmiTagMask));
492 __ j(zero, &miss, not_taken);
493
494 // Do the right check and compute the holder register.
495 Register reg =
496 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
497
ager@chromium.org7c537e22008-10-16 08:43:32 +0000498 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000499
500 // Check that the function really is a function.
501 __ test(edi, Immediate(kSmiTagMask));
502 __ j(zero, &miss, not_taken);
503 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
504 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
505 __ cmp(ebx, JS_FUNCTION_TYPE);
506 __ j(not_equal, &miss, not_taken);
507
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000508 // Patch the receiver on the stack with the global proxy if
509 // necessary.
510 if (object->IsGlobalObject()) {
511 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
512 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
513 }
514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 // Invoke the function.
516 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
517
518 // Handle call cache miss.
519 __ bind(&miss);
520 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000521 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522
523 // Return the generated code.
524 return GetCode(FIELD);
525}
526
527
528Object* CallStubCompiler::CompileCallConstant(Object* object,
529 JSObject* holder,
530 JSFunction* function,
531 CheckType check) {
532 // ----------- S t a t e -------------
533 // -----------------------------------
534
535 HandleScope scope;
536 Label miss;
537
538 // Get the receiver from the stack.
539 const int argc = arguments().immediate();
540 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
541
542 // Check that the receiver isn't a smi.
543 if (check != NUMBER_CHECK) {
544 __ test(edx, Immediate(kSmiTagMask));
545 __ j(zero, &miss, not_taken);
546 }
547
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000548 // Make sure that it's okay not to patch the on stack receiver
549 // unless we're doing a receiver map check.
550 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 switch (check) {
553 case RECEIVER_MAP_CHECK:
554 // Check that the maps haven't changed.
555 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000556
557 // Patch the receiver on the stack with the global proxy if
558 // necessary.
559 if (object->IsGlobalObject()) {
560 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
561 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 break;
564
565 case STRING_CHECK:
566 // Check that the object is a two-byte string or a symbol.
567 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
568 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
569 __ cmp(ecx, FIRST_NONSTRING_TYPE);
570 __ j(above_equal, &miss, not_taken);
571 // Check that the maps starting from the prototype haven't changed.
572 GenerateLoadGlobalFunctionPrototype(masm(),
573 Context::STRING_FUNCTION_INDEX,
574 ecx);
575 __ CheckMaps(JSObject::cast(object->GetPrototype()),
576 ecx, holder, ebx, edx, &miss);
577 break;
578
579 case NUMBER_CHECK: {
580 Label fast;
581 // Check that the object is a smi or a heap number.
582 __ test(edx, Immediate(kSmiTagMask));
583 __ j(zero, &fast, taken);
584 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
585 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
586 __ cmp(ecx, HEAP_NUMBER_TYPE);
587 __ j(not_equal, &miss, not_taken);
588 __ bind(&fast);
589 // Check that the maps starting from the prototype haven't changed.
590 GenerateLoadGlobalFunctionPrototype(masm(),
591 Context::NUMBER_FUNCTION_INDEX,
592 ecx);
593 __ CheckMaps(JSObject::cast(object->GetPrototype()),
594 ecx, holder, ebx, edx, &miss);
595 break;
596 }
597
598 case BOOLEAN_CHECK: {
599 Label fast;
600 // Check that the object is a boolean.
601 __ cmp(edx, Factory::true_value());
602 __ j(equal, &fast, taken);
603 __ cmp(edx, Factory::false_value());
604 __ j(not_equal, &miss, not_taken);
605 __ bind(&fast);
606 // Check that the maps starting from the prototype haven't changed.
607 GenerateLoadGlobalFunctionPrototype(masm(),
608 Context::BOOLEAN_FUNCTION_INDEX,
609 ecx);
610 __ CheckMaps(JSObject::cast(object->GetPrototype()),
611 ecx, holder, ebx, edx, &miss);
612 break;
613 }
614
615 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
616 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
617 // Make sure object->elements()->map() != Heap::dictionary_array_map()
618 // Get the elements array of the object.
619 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
620 // Check that the object is in fast mode (not dictionary).
621 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
622 Immediate(Factory::hash_table_map()));
623 __ j(equal, &miss, not_taken);
624 break;
625
626 default:
627 UNREACHABLE();
628 }
629
630 // Get the function and setup the context.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000631 __ mov(edi, Immediate(Handle<JSFunction>(function)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
633
634 // Jump to the cached code (tail call).
635 Handle<Code> code(function->code());
636 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000637 __ InvokeCode(code, expected, arguments(),
638 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639
640 // Handle call cache miss.
641 __ bind(&miss);
642 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000643 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644
645 // Return the generated code.
646 return GetCode(CONSTANT_FUNCTION);
647}
648
649
650Object* CallStubCompiler::CompileCallInterceptor(Object* object,
651 JSObject* holder,
652 String* name) {
653 // ----------- S t a t e -------------
654 // -----------------------------------
655
656 HandleScope scope;
657 Label miss;
658
659 // Get the number of arguments.
660 const int argc = arguments().immediate();
661
662 // Get the receiver from the stack.
663 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000664
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 // Check that the receiver isn't a smi.
666 __ test(edx, Immediate(kSmiTagMask));
667 __ j(zero, &miss, not_taken);
668
669 // Check that maps have not changed and compute the holder register.
670 Register reg =
671 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
672
673 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000674 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675
676 // Push arguments on the expression stack.
677 __ push(edx); // receiver
678 __ push(reg); // holder
679 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
680
681 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 ExternalReference load_interceptor =
683 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000684 __ mov(eax, Immediate(3));
685 __ mov(ebx, Immediate(load_interceptor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686
687 CEntryStub stub;
688 __ CallStub(&stub);
689
690 // Move result to edi and restore receiver.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000691 __ mov(edi, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000692 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
693
694 // Exit frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000695 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
697 // Check that the function really is a function.
698 __ test(edi, Immediate(kSmiTagMask));
699 __ j(zero, &miss, not_taken);
700 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
701 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
702 __ cmp(ebx, JS_FUNCTION_TYPE);
703 __ j(not_equal, &miss, not_taken);
704
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000705 // Patch the receiver on the stack with the global proxy if
706 // necessary.
707 if (object->IsGlobalObject()) {
708 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
709 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
710 }
711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 // Invoke the function.
713 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
714
715 // Handle load cache miss.
716 __ bind(&miss);
717 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000718 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719
720 // Return the generated code.
721 return GetCode(INTERCEPTOR);
722}
723
724
725Object* StoreStubCompiler::CompileStoreField(JSObject* object,
726 int index,
727 Map* transition,
728 String* name) {
729 // ----------- S t a t e -------------
730 // -- eax : value
731 // -- ecx : name
732 // -- esp[0] : return address
733 // -- esp[4] : receiver
734 // -----------------------------------
735
736 HandleScope scope;
737 Label miss;
738
739 // Get the object from the stack.
740 __ mov(ebx, Operand(esp, 1 * kPointerSize));
741
742 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000743 GenerateStoreField(masm(),
744 Builtins::StoreIC_ExtendStorage,
745 object,
746 index,
747 transition,
748 ebx, ecx, edx,
749 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750
751 // Handle store cache miss.
752 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000753 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000755 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756
757 // Return the generated code.
758 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
759}
760
761
762Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
763 AccessorInfo* callback,
764 String* name) {
765 // ----------- S t a t e -------------
766 // -- eax : value
767 // -- ecx : name
768 // -- esp[0] : return address
769 // -- esp[4] : receiver
770 // -----------------------------------
771
772 HandleScope scope;
773 Label miss;
774
775 // Get the object from the stack.
776 __ mov(ebx, Operand(esp, 1 * kPointerSize));
777
778 // Check that the object isn't a smi.
779 __ test(ebx, Immediate(kSmiTagMask));
780 __ j(zero, &miss, not_taken);
781
782 // Check that the map of the object hasn't changed.
783 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
784 Immediate(Handle<Map>(object->map())));
785 __ j(not_equal, &miss, not_taken);
786
787 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000788 if (object->IsJSGlobalProxy()) {
789 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000790 }
791
792 // Stub never generated for non-global objects that require access
793 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000794 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795
796 __ pop(ebx); // remove the return address
797 __ push(Operand(esp, 0)); // receiver
798 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
799 __ push(ecx); // name
800 __ push(eax); // value
801 __ push(ebx); // restore return address
802
mads.s.ager31e71382008-08-13 09:32:07 +0000803 // Do tail-call to the runtime system.
804 ExternalReference store_callback_property =
805 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
806 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807
808 // Handle store cache miss.
809 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000810 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000812 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813
814 // Return the generated code.
815 return GetCode(CALLBACKS);
816}
817
818
819Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
820 String* name) {
821 // ----------- S t a t e -------------
822 // -- eax : value
823 // -- ecx : name
824 // -- esp[0] : return address
825 // -- esp[4] : receiver
826 // -----------------------------------
827
828 HandleScope scope;
829 Label miss;
830
831 // Get the object from the stack.
832 __ mov(ebx, Operand(esp, 1 * kPointerSize));
833
834 // Check that the object isn't a smi.
835 __ test(ebx, Immediate(kSmiTagMask));
836 __ j(zero, &miss, not_taken);
837
838 // Check that the map of the object hasn't changed.
839 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
840 Immediate(Handle<Map>(receiver->map())));
841 __ j(not_equal, &miss, not_taken);
842
843 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000844 if (receiver->IsJSGlobalProxy()) {
845 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846 }
847
848 // Stub never generated for non-global objects that require access
849 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000850 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851
852 __ pop(ebx); // remove the return address
853 __ push(Operand(esp, 0)); // receiver
854 __ push(ecx); // name
855 __ push(eax); // value
856 __ push(ebx); // restore return address
857
mads.s.ager31e71382008-08-13 09:32:07 +0000858 // Do tail-call to the runtime system.
859 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000861 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862
863 // Handle store cache miss.
864 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000865 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000867 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868
869 // Return the generated code.
870 return GetCode(INTERCEPTOR);
871}
872
873
874Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
875 int index,
876 Map* transition,
877 String* name) {
878 // ----------- S t a t e -------------
879 // -- eax : value
880 // -- esp[0] : return address
881 // -- esp[4] : key
882 // -- esp[8] : receiver
883 // -----------------------------------
884 HandleScope scope;
885 Label miss;
886
887 __ IncrementCounter(&Counters::keyed_store_field, 1);
888
889 // Get the name from the stack.
890 __ mov(ecx, Operand(esp, 1 * kPointerSize));
891 // Check that the name has not changed.
892 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
893 __ j(not_equal, &miss, not_taken);
894
895 // Get the object from the stack.
896 __ mov(ebx, Operand(esp, 2 * kPointerSize));
897
898 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000899 GenerateStoreField(masm(),
900 Builtins::KeyedStoreIC_ExtendStorage,
901 object,
902 index,
903 transition,
904 ebx, ecx, edx,
905 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906
907 // Handle store cache miss.
908 __ bind(&miss);
909 __ DecrementCounter(&Counters::keyed_store_field, 1);
910 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000911 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912
913 // Return the generated code.
914 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
915}
916
917
918Object* LoadStubCompiler::CompileLoadField(JSObject* object,
919 JSObject* holder,
920 int index) {
921 // ----------- S t a t e -------------
922 // -- ecx : name
923 // -- esp[0] : return address
924 // -- esp[4] : receiver
925 // -----------------------------------
926
927 HandleScope scope;
928 Label miss;
929
930 __ mov(eax, (Operand(esp, kPointerSize)));
931 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
932 __ bind(&miss);
933 GenerateLoadMiss(masm(), Code::LOAD_IC);
934
935 // Return the generated code.
936 return GetCode(FIELD);
937}
938
939
940Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
941 JSObject* holder,
942 AccessorInfo* callback) {
943 // ----------- S t a t e -------------
944 // -- ecx : name
945 // -- esp[0] : return address
946 // -- esp[4] : receiver
947 // -----------------------------------
948
949 HandleScope scope;
950 Label miss;
951
952 __ mov(eax, (Operand(esp, kPointerSize)));
953 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
954 edx, callback, &miss);
955 __ bind(&miss);
956 GenerateLoadMiss(masm(), Code::LOAD_IC);
957
958 // Return the generated code.
959 return GetCode(CALLBACKS);
960}
961
962
963Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
964 JSObject* holder,
965 Object* value) {
966 // ----------- S t a t e -------------
967 // -- ecx : name
968 // -- esp[0] : return address
969 // -- esp[4] : receiver
970 // -----------------------------------
971
972 HandleScope scope;
973 Label miss;
974
975 __ mov(eax, (Operand(esp, kPointerSize)));
976 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
977 __ bind(&miss);
978 GenerateLoadMiss(masm(), Code::LOAD_IC);
979
980 // Return the generated code.
981 return GetCode(CONSTANT_FUNCTION);
982}
983
984
985Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
986 JSObject* holder,
987 String* name) {
988 // ----------- S t a t e -------------
989 // -- ecx : name
990 // -- esp[0] : return address
991 // -- esp[4] : receiver
992 // -----------------------------------
993 HandleScope scope;
994 Label miss;
995
996 __ mov(eax, (Operand(esp, kPointerSize)));
997 GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
998 __ bind(&miss);
999 GenerateLoadMiss(masm(), Code::LOAD_IC);
1000
1001 // Return the generated code.
1002 return GetCode(INTERCEPTOR);
1003}
1004
1005
1006Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1007 JSObject* receiver,
1008 JSObject* holder,
1009 int index) {
1010 // ----------- S t a t e -------------
1011 // -- esp[0] : return address
1012 // -- esp[4] : name
1013 // -- esp[8] : receiver
1014 // -----------------------------------
1015 HandleScope scope;
1016 Label miss;
1017
1018 __ mov(eax, (Operand(esp, kPointerSize)));
1019 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1020 __ IncrementCounter(&Counters::keyed_load_field, 1);
1021
1022 // Check that the name has not changed.
1023 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1024 __ j(not_equal, &miss, not_taken);
1025
1026 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1027 __ bind(&miss);
1028 __ DecrementCounter(&Counters::keyed_load_field, 1);
1029 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1030
1031 // Return the generated code.
1032 return GetCode(FIELD);
1033}
1034
1035
1036Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1037 JSObject* receiver,
1038 JSObject* holder,
1039 AccessorInfo* callback) {
1040 // ----------- S t a t e -------------
1041 // -- esp[0] : return address
1042 // -- esp[4] : name
1043 // -- esp[8] : receiver
1044 // -----------------------------------
1045 HandleScope scope;
1046 Label miss;
1047
1048 __ mov(eax, (Operand(esp, kPointerSize)));
1049 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1050 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1051
1052 // Check that the name has not changed.
1053 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1054 __ j(not_equal, &miss, not_taken);
1055
1056 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1057 callback, &miss);
1058 __ bind(&miss);
1059 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1060 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1061
1062 // Return the generated code.
1063 return GetCode(CALLBACKS);
1064}
1065
1066
1067Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1068 JSObject* receiver,
1069 JSObject* holder,
1070 Object* value) {
1071 // ----------- S t a t e -------------
1072 // -- esp[0] : return address
1073 // -- esp[4] : name
1074 // -- esp[8] : receiver
1075 // -----------------------------------
1076 HandleScope scope;
1077 Label miss;
1078
1079 __ mov(eax, (Operand(esp, kPointerSize)));
1080 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1081 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1082
1083 // Check that the name has not changed.
1084 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1085 __ j(not_equal, &miss, not_taken);
1086
1087 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1088 __ bind(&miss);
1089 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1090 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1091
1092 // Return the generated code.
1093 return GetCode(CONSTANT_FUNCTION);
1094}
1095
1096
1097Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1098 JSObject* holder,
1099 String* name) {
1100 // ----------- S t a t e -------------
1101 // -- esp[0] : return address
1102 // -- esp[4] : name
1103 // -- esp[8] : receiver
1104 // -----------------------------------
1105 HandleScope scope;
1106 Label miss;
1107
1108 __ mov(eax, (Operand(esp, kPointerSize)));
1109 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1110 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1111
1112 // Check that the name has not changed.
1113 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1114 __ j(not_equal, &miss, not_taken);
1115
1116 GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
1117 __ bind(&miss);
1118 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1119 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1120
1121 // Return the generated code.
1122 return GetCode(INTERCEPTOR);
1123}
1124
1125
1126
1127
1128Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1129 // ----------- S t a t e -------------
1130 // -- esp[0] : return address
1131 // -- esp[4] : name
1132 // -- esp[8] : receiver
1133 // -----------------------------------
1134 HandleScope scope;
1135 Label miss;
1136
1137 __ mov(eax, (Operand(esp, kPointerSize)));
1138 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1139 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1140
1141 // Check that the name has not changed.
1142 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1143 __ j(not_equal, &miss, not_taken);
1144
1145 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1146 __ bind(&miss);
1147 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1148 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1149
1150 // Return the generated code.
1151 return GetCode(CALLBACKS);
1152}
1153
1154
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001155Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 // ----------- S t a t e -------------
1157 // -- esp[0] : return address
1158 // -- esp[4] : name
1159 // -- esp[8] : receiver
1160 // -----------------------------------
1161 HandleScope scope;
1162 Label miss;
1163
1164 __ mov(eax, (Operand(esp, kPointerSize)));
1165 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1166 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1167
1168 // Check that the name has not changed.
1169 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1170 __ j(not_equal, &miss, not_taken);
1171
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001172 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 __ bind(&miss);
1174 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1175 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1176
1177 // Return the generated code.
1178 return GetCode(CALLBACKS);
1179}
1180
1181
1182Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1183 // ----------- S t a t e -------------
1184 // -- esp[0] : return address
1185 // -- esp[4] : name
1186 // -- esp[8] : receiver
1187 // -----------------------------------
1188 HandleScope scope;
1189 Label miss;
1190
1191 __ mov(eax, (Operand(esp, kPointerSize)));
1192 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1193 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1194
1195 // Check that the name has not changed.
1196 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1197 __ j(not_equal, &miss, not_taken);
1198
1199 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1200 __ bind(&miss);
1201 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1202 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1203
1204 // Return the generated code.
1205 return GetCode(CALLBACKS);
1206}
1207
1208
1209#undef __
1210
1211} } // namespace v8::internal