blob: 19777e6a7844bc137e0e893446dda9ead66ab9d3 [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.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000151 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000152 __ j(not_equal, miss_label, not_taken);
153
154 // Load length directly from the JS array.
155 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
156 __ ret(0);
157}
158
159
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000160// Generate code to check if an object is a string. If the object is
161// a string, the map's instance type is left in the scratch register.
162static void GenerateStringCheck(MacroAssembler* masm,
163 Register receiver,
164 Register scratch,
165 Label* smi,
166 Label* non_string_object) {
167 // Check that the object isn't a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168 __ test(receiver, Immediate(kSmiTagMask));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000169 __ j(zero, smi, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000170
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000171 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
173 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000174 ASSERT(kNotStringTag != 0);
175 __ test(scratch, Immediate(kNotStringTag));
176 __ j(not_zero, non_string_object, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000177}
178
179
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000180void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
181 Register receiver,
182 Register scratch,
183 Label* miss) {
184 Label load_length, check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000186 // Check if the object is a string leaving the instance type in the
187 // scratch register.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000188 GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189
190 // Load length directly from the string.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000191 __ bind(&load_length);
192 __ and_(scratch, kStringSizeMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000194 // ecx is also the receiver.
195 __ lea(ecx, Operand(scratch, String::kLongLengthShift));
196 __ shr(eax); // ecx is implicit shift register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197 __ shl(eax, kSmiTagSize);
198 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000199
200 // Check if the object is a JSValue wrapper.
201 __ bind(&check_wrapper);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000202 __ cmp(scratch, JS_VALUE_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000203 __ j(not_equal, miss, not_taken);
204
205 // Check if the wrapped value is a string and load the length
206 // directly if it is.
207 __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
208 GenerateStringCheck(masm, receiver, scratch, miss, miss);
209 __ jmp(&load_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210}
211
212
213void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
214 Register receiver,
215 Register scratch1,
216 Register scratch2,
217 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000218 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 __ mov(eax, Operand(scratch1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000221}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222
ager@chromium.org7c537e22008-10-16 08:43:32 +0000223
224// Load a fast property out of a holder object (src). In-object properties
225// are loaded directly otherwise the property is loaded from the properties
226// fixed array.
227void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000228 Register dst, Register src,
229 JSObject* holder, int index) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000230 // Adjust for the number of properties stored in the holder.
231 index -= holder->map()->inobject_properties();
232 if (index < 0) {
233 // Get the property straight out of the holder.
234 int offset = holder->map()->instance_size() + (index * kPointerSize);
235 __ mov(dst, FieldOperand(src, offset));
236 } else {
237 // Calculate the offset into the properties array.
238 int offset = index * kPointerSize + Array::kHeaderSize;
239 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
240 __ mov(dst, FieldOperand(dst, offset));
241 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242}
243
244
245void StubCompiler::GenerateLoadField(MacroAssembler* masm,
246 JSObject* object,
247 JSObject* holder,
248 Register receiver,
249 Register scratch1,
250 Register scratch2,
251 int index,
252 Label* miss_label) {
253 // Check that the receiver isn't a smi.
254 __ test(receiver, Immediate(kSmiTagMask));
255 __ j(zero, miss_label, not_taken);
256
257 // Check that the maps haven't changed.
258 Register reg =
259 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
260
ager@chromium.org7c537e22008-10-16 08:43:32 +0000261 // Get the value from the properties.
262 GenerateFastPropertyLoad(masm, eax, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000263 __ ret(0);
264}
265
266
267void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
268 JSObject* object,
269 JSObject* holder,
270 Register receiver,
271 Register name,
272 Register scratch1,
273 Register scratch2,
274 AccessorInfo* callback,
275 Label* miss_label) {
276 // Check that the receiver isn't a smi.
277 __ test(receiver, Immediate(kSmiTagMask));
278 __ j(zero, miss_label, not_taken);
279
280 // Check that the maps haven't changed.
281 Register reg =
282 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
283
284 // Push the arguments on the JS stack of the caller.
285 __ pop(scratch2); // remove return address
286 __ push(receiver); // receiver
287 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
288 __ push(name); // name
289 __ push(reg); // holder
290 __ push(scratch2); // restore return address
291
mads.s.ager31e71382008-08-13 09:32:07 +0000292 // Do tail-call to the runtime system.
293 ExternalReference load_callback_property =
294 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
295 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296}
297
298
299void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
300 JSObject* object,
301 JSObject* holder,
302 Register receiver,
303 Register scratch1,
304 Register scratch2,
305 Object* value,
306 Label* miss_label) {
307 // Check that the receiver isn't a smi.
308 __ test(receiver, Immediate(kSmiTagMask));
309 __ j(zero, miss_label, not_taken);
310
311 // Check that the maps haven't changed.
312 Register reg =
313 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
314
315 // Return the constant value.
316 __ mov(eax, Handle<Object>(value));
317 __ ret(0);
318}
319
320
321void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
322 JSObject* object,
323 JSObject* holder,
324 Register receiver,
325 Register name,
326 Register scratch1,
327 Register scratch2,
328 Label* miss_label) {
329 // Check that the receiver isn't a smi.
330 __ test(receiver, Immediate(kSmiTagMask));
331 __ j(zero, miss_label, not_taken);
332
333 // Check that the maps haven't changed.
334 Register reg =
335 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
336
337 // Push the arguments on the JS stack of the caller.
338 __ pop(scratch2); // remove return address
339 __ push(receiver); // receiver
340 __ push(reg); // holder
341 __ push(name); // name
342 __ push(scratch2); // restore return address
343
mads.s.ager31e71382008-08-13 09:32:07 +0000344 // Do tail-call to the runtime system.
345 ExternalReference load_ic_property =
346 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
347 __ TailCallRuntime(load_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348}
349
350
351void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
352 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
353 Code* code = NULL;
354 if (kind == Code::LOAD_IC) {
355 code = Builtins::builtin(Builtins::LoadIC_Miss);
356 } else {
357 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
358 }
359
360 Handle<Code> ic(code);
ager@chromium.org236ad962008-09-25 09:45:57 +0000361 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362}
363
364
365void StubCompiler::GenerateStoreField(MacroAssembler* masm,
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000366 Builtins::Name storage_extend,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 JSObject* object,
368 int index,
369 Map* transition,
370 Register receiver_reg,
371 Register name_reg,
372 Register scratch,
373 Label* miss_label) {
374 // Check that the object isn't a smi.
375 __ test(receiver_reg, Immediate(kSmiTagMask));
376 __ j(zero, miss_label, not_taken);
377
378 // Check that the map of the object hasn't changed.
379 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
380 Immediate(Handle<Map>(object->map())));
381 __ j(not_equal, miss_label, not_taken);
382
383 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000384 if (object->IsJSGlobalProxy()) {
385 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
387
388 // Stub never generated for non-global objects that require access
389 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000390 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000392 // Perform map transition for the receiver if necessary.
393 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
394 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000395 // We jump to a runtime call that extends the properties array.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000396 __ mov(ecx, Immediate(Handle<Map>(transition)));
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000397 Handle<Code> ic(Builtins::builtin(storage_extend));
398 __ jmp(ic, RelocInfo::CODE_TARGET);
399 return;
400 }
401
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 if (transition != NULL) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000403 // Update the map of the object; no write barrier updating is
404 // needed because the map is never in new space.
405 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
406 Immediate(Handle<Map>(transition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 }
408
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000409 // Adjust for the number of properties stored in the object. Even in the
410 // face of a transition we can use the old map here because the size of the
411 // object and the number of in-object properties is not going to change.
412 index -= object->map()->inobject_properties();
413
ager@chromium.org7c537e22008-10-16 08:43:32 +0000414 if (index < 0) {
415 // Set the property straight into the object.
416 int offset = object->map()->instance_size() + (index * kPointerSize);
417 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000418
ager@chromium.org7c537e22008-10-16 08:43:32 +0000419 // Update the write barrier for the array address.
420 // Pass the value being stored in the now unused name_reg.
421 __ mov(name_reg, Operand(eax));
422 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
423 } else {
424 // Write to the properties array.
425 int offset = index * kPointerSize + Array::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000426 // Get the properties array (optimistically).
427 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000428 __ mov(FieldOperand(scratch, offset), eax);
429
430 // Update the write barrier for the array address.
431 // Pass the value being stored in the now unused name_reg.
432 __ mov(name_reg, Operand(eax));
433 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
434 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435
436 // Return the value (register eax).
437 __ ret(0);
438}
439
440
441#undef __
442
443#define __ masm()->
444
445
446// TODO(1241006): Avoid having lazy compile stubs specialized by the
447// number of arguments. It is not needed anymore.
448Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000450 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451
452 // Push a copy of the function onto the stack.
453 __ push(edi);
454
455 __ push(edi); // function is also the parameter to the runtime call
456 __ CallRuntime(Runtime::kLazyCompile, 1);
457 __ pop(edi);
458
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000459 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000460 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461
462 // Do a tail-call of the compiled function.
463 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
464 __ jmp(Operand(ecx));
465
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000466 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467}
468
469
470Object* CallStubCompiler::CompileCallField(Object* object,
471 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000472 int index,
473 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474 // ----------- S t a t e -------------
475 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476 Label miss;
477
478 // Get the receiver from the stack.
479 const int argc = arguments().immediate();
480 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
481
482 // Check that the receiver isn't a smi.
483 __ test(edx, Immediate(kSmiTagMask));
484 __ j(zero, &miss, not_taken);
485
486 // Do the right check and compute the holder register.
487 Register reg =
488 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
489
ager@chromium.org7c537e22008-10-16 08:43:32 +0000490 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
492 // Check that the function really is a function.
493 __ test(edi, Immediate(kSmiTagMask));
494 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000495 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496 __ j(not_equal, &miss, not_taken);
497
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000498 // Patch the receiver on the stack with the global proxy if
499 // necessary.
500 if (object->IsGlobalObject()) {
501 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
502 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
503 }
504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505 // Invoke the function.
506 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
507
508 // Handle call cache miss.
509 __ bind(&miss);
510 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000511 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512
513 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000514 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515}
516
517
518Object* CallStubCompiler::CompileCallConstant(Object* object,
519 JSObject* holder,
520 JSFunction* function,
521 CheckType check) {
522 // ----------- S t a t e -------------
523 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524 Label miss;
525
526 // Get the receiver from the stack.
527 const int argc = arguments().immediate();
528 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
529
530 // Check that the receiver isn't a smi.
531 if (check != NUMBER_CHECK) {
532 __ test(edx, Immediate(kSmiTagMask));
533 __ j(zero, &miss, not_taken);
534 }
535
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000536 // Make sure that it's okay not to patch the on stack receiver
537 // unless we're doing a receiver map check.
538 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 switch (check) {
541 case RECEIVER_MAP_CHECK:
542 // Check that the maps haven't changed.
543 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000544
545 // Patch the receiver on the stack with the global proxy if
546 // necessary.
547 if (object->IsGlobalObject()) {
548 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
549 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 break;
552
553 case STRING_CHECK:
554 // Check that the object is a two-byte string or a symbol.
555 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
556 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
557 __ cmp(ecx, FIRST_NONSTRING_TYPE);
558 __ j(above_equal, &miss, not_taken);
559 // Check that the maps starting from the prototype haven't changed.
560 GenerateLoadGlobalFunctionPrototype(masm(),
561 Context::STRING_FUNCTION_INDEX,
562 ecx);
563 __ CheckMaps(JSObject::cast(object->GetPrototype()),
564 ecx, holder, ebx, edx, &miss);
565 break;
566
567 case NUMBER_CHECK: {
568 Label fast;
569 // Check that the object is a smi or a heap number.
570 __ test(edx, Immediate(kSmiTagMask));
571 __ j(zero, &fast, taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000572 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 __ j(not_equal, &miss, not_taken);
574 __ bind(&fast);
575 // Check that the maps starting from the prototype haven't changed.
576 GenerateLoadGlobalFunctionPrototype(masm(),
577 Context::NUMBER_FUNCTION_INDEX,
578 ecx);
579 __ CheckMaps(JSObject::cast(object->GetPrototype()),
580 ecx, holder, ebx, edx, &miss);
581 break;
582 }
583
584 case BOOLEAN_CHECK: {
585 Label fast;
586 // Check that the object is a boolean.
587 __ cmp(edx, Factory::true_value());
588 __ j(equal, &fast, taken);
589 __ cmp(edx, Factory::false_value());
590 __ j(not_equal, &miss, not_taken);
591 __ bind(&fast);
592 // Check that the maps starting from the prototype haven't changed.
593 GenerateLoadGlobalFunctionPrototype(masm(),
594 Context::BOOLEAN_FUNCTION_INDEX,
595 ecx);
596 __ CheckMaps(JSObject::cast(object->GetPrototype()),
597 ecx, holder, ebx, edx, &miss);
598 break;
599 }
600
601 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
602 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
603 // Make sure object->elements()->map() != Heap::dictionary_array_map()
604 // Get the elements array of the object.
605 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
606 // Check that the object is in fast mode (not dictionary).
607 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
608 Immediate(Factory::hash_table_map()));
609 __ j(equal, &miss, not_taken);
610 break;
611
612 default:
613 UNREACHABLE();
614 }
615
616 // Get the function and setup the context.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000617 __ mov(edi, Immediate(Handle<JSFunction>(function)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
619
620 // Jump to the cached code (tail call).
621 Handle<Code> code(function->code());
622 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000623 __ InvokeCode(code, expected, arguments(),
624 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625
626 // Handle call cache miss.
627 __ bind(&miss);
628 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000629 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630
631 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000632 String* function_name = NULL;
633 if (function->shared()->name()->IsString()) {
634 function_name = String::cast(function->shared()->name());
635 }
636 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637}
638
639
640Object* CallStubCompiler::CompileCallInterceptor(Object* object,
641 JSObject* holder,
642 String* name) {
643 // ----------- S t a t e -------------
644 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 Label miss;
646
647 // Get the number of arguments.
648 const int argc = arguments().immediate();
649
650 // Get the receiver from the stack.
651 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000652
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653 // Check that the receiver isn't a smi.
654 __ test(edx, Immediate(kSmiTagMask));
655 __ j(zero, &miss, not_taken);
656
657 // Check that maps have not changed and compute the holder register.
658 Register reg =
659 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
660
661 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000662 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663
664 // Push arguments on the expression stack.
665 __ push(edx); // receiver
666 __ push(reg); // holder
667 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
668
669 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670 ExternalReference load_interceptor =
671 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000672 __ mov(eax, Immediate(3));
673 __ mov(ebx, Immediate(load_interceptor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674
675 CEntryStub stub;
676 __ CallStub(&stub);
677
678 // Move result to edi and restore receiver.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000679 __ mov(edi, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
681
682 // Exit frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000683 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684
685 // Check that the function really is a function.
686 __ test(edi, Immediate(kSmiTagMask));
687 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000688 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689 __ j(not_equal, &miss, not_taken);
690
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000691 // Patch the receiver on the stack with the global proxy if
692 // necessary.
693 if (object->IsGlobalObject()) {
694 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
695 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
696 }
697
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 // Invoke the function.
699 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
700
701 // Handle load cache miss.
702 __ bind(&miss);
703 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000704 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705
706 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000707 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708}
709
710
711Object* StoreStubCompiler::CompileStoreField(JSObject* object,
712 int index,
713 Map* transition,
714 String* name) {
715 // ----------- S t a t e -------------
716 // -- eax : value
717 // -- ecx : name
718 // -- esp[0] : return address
719 // -- esp[4] : receiver
720 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721 Label miss;
722
723 // Get the object from the stack.
724 __ mov(ebx, Operand(esp, 1 * kPointerSize));
725
726 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000727 GenerateStoreField(masm(),
728 Builtins::StoreIC_ExtendStorage,
729 object,
730 index,
731 transition,
732 ebx, ecx, edx,
733 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734
735 // Handle store cache miss.
736 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000737 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000738 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000739 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000740
741 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000742 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743}
744
745
746Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
747 AccessorInfo* callback,
748 String* name) {
749 // ----------- S t a t e -------------
750 // -- eax : value
751 // -- ecx : name
752 // -- esp[0] : return address
753 // -- esp[4] : receiver
754 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000755 Label miss;
756
757 // Get the object from the stack.
758 __ mov(ebx, Operand(esp, 1 * kPointerSize));
759
760 // Check that the object isn't a smi.
761 __ test(ebx, Immediate(kSmiTagMask));
762 __ j(zero, &miss, not_taken);
763
764 // Check that the map of the object hasn't changed.
765 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
766 Immediate(Handle<Map>(object->map())));
767 __ j(not_equal, &miss, not_taken);
768
769 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000770 if (object->IsJSGlobalProxy()) {
771 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772 }
773
774 // Stub never generated for non-global objects that require access
775 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000776 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777
778 __ pop(ebx); // remove the return address
779 __ push(Operand(esp, 0)); // receiver
780 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
781 __ push(ecx); // name
782 __ push(eax); // value
783 __ push(ebx); // restore return address
784
mads.s.ager31e71382008-08-13 09:32:07 +0000785 // Do tail-call to the runtime system.
786 ExternalReference store_callback_property =
787 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
788 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000789
790 // Handle store cache miss.
791 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000792 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000794 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795
796 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000797 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798}
799
800
801Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
802 String* name) {
803 // ----------- S t a t e -------------
804 // -- eax : value
805 // -- ecx : name
806 // -- esp[0] : return address
807 // -- esp[4] : receiver
808 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809 Label miss;
810
811 // Get the object from the stack.
812 __ mov(ebx, Operand(esp, 1 * kPointerSize));
813
814 // Check that the object isn't a smi.
815 __ test(ebx, Immediate(kSmiTagMask));
816 __ j(zero, &miss, not_taken);
817
818 // Check that the map of the object hasn't changed.
819 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
820 Immediate(Handle<Map>(receiver->map())));
821 __ j(not_equal, &miss, not_taken);
822
823 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000824 if (receiver->IsJSGlobalProxy()) {
825 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 }
827
828 // Stub never generated for non-global objects that require access
829 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000830 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831
832 __ pop(ebx); // remove the return address
833 __ push(Operand(esp, 0)); // receiver
834 __ push(ecx); // name
835 __ push(eax); // value
836 __ push(ebx); // restore return address
837
mads.s.ager31e71382008-08-13 09:32:07 +0000838 // Do tail-call to the runtime system.
839 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000841 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
843 // Handle store cache miss.
844 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000845 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000847 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000848
849 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000850 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851}
852
853
854Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
855 int index,
856 Map* transition,
857 String* name) {
858 // ----------- S t a t e -------------
859 // -- eax : value
860 // -- esp[0] : return address
861 // -- esp[4] : key
862 // -- esp[8] : receiver
863 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 Label miss;
865
866 __ IncrementCounter(&Counters::keyed_store_field, 1);
867
868 // Get the name from the stack.
869 __ mov(ecx, Operand(esp, 1 * kPointerSize));
870 // Check that the name has not changed.
871 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
872 __ j(not_equal, &miss, not_taken);
873
874 // Get the object from the stack.
875 __ mov(ebx, Operand(esp, 2 * kPointerSize));
876
877 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000878 GenerateStoreField(masm(),
879 Builtins::KeyedStoreIC_ExtendStorage,
880 object,
881 index,
882 transition,
883 ebx, ecx, edx,
884 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885
886 // Handle store cache miss.
887 __ bind(&miss);
888 __ DecrementCounter(&Counters::keyed_store_field, 1);
889 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000890 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891
892 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000893 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894}
895
896
897Object* LoadStubCompiler::CompileLoadField(JSObject* object,
898 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000899 int index,
900 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901 // ----------- S t a t e -------------
902 // -- ecx : name
903 // -- esp[0] : return address
904 // -- esp[4] : receiver
905 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 Label miss;
907
908 __ mov(eax, (Operand(esp, kPointerSize)));
909 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
910 __ bind(&miss);
911 GenerateLoadMiss(masm(), Code::LOAD_IC);
912
913 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000914 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915}
916
917
918Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
919 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000920 AccessorInfo* callback,
921 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922 // ----------- S t a t e -------------
923 // -- ecx : name
924 // -- esp[0] : return address
925 // -- esp[4] : receiver
926 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927 Label miss;
928
929 __ mov(eax, (Operand(esp, kPointerSize)));
930 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
931 edx, callback, &miss);
932 __ bind(&miss);
933 GenerateLoadMiss(masm(), Code::LOAD_IC);
934
935 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000936 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937}
938
939
940Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
941 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000942 Object* value,
943 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944 // ----------- S t a t e -------------
945 // -- ecx : name
946 // -- esp[0] : return address
947 // -- esp[4] : receiver
948 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 Label miss;
950
951 __ mov(eax, (Operand(esp, kPointerSize)));
952 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
953 __ bind(&miss);
954 GenerateLoadMiss(masm(), Code::LOAD_IC);
955
956 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000957 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958}
959
960
961Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
962 JSObject* holder,
963 String* name) {
964 // ----------- S t a t e -------------
965 // -- ecx : name
966 // -- esp[0] : return address
967 // -- esp[4] : receiver
968 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 Label miss;
970
971 __ mov(eax, (Operand(esp, kPointerSize)));
972 GenerateLoadInterceptor(masm(), receiver, holder, eax, ecx, edx, ebx, &miss);
973 __ bind(&miss);
974 GenerateLoadMiss(masm(), Code::LOAD_IC);
975
976 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000977 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000978}
979
980
981Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
982 JSObject* receiver,
983 JSObject* holder,
984 int index) {
985 // ----------- S t a t e -------------
986 // -- esp[0] : return address
987 // -- esp[4] : name
988 // -- esp[8] : receiver
989 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990 Label miss;
991
992 __ mov(eax, (Operand(esp, kPointerSize)));
993 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
994 __ IncrementCounter(&Counters::keyed_load_field, 1);
995
996 // Check that the name has not changed.
997 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
998 __ j(not_equal, &miss, not_taken);
999
1000 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1001 __ bind(&miss);
1002 __ DecrementCounter(&Counters::keyed_load_field, 1);
1003 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1004
1005 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001006 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007}
1008
1009
1010Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1011 JSObject* receiver,
1012 JSObject* holder,
1013 AccessorInfo* callback) {
1014 // ----------- S t a t e -------------
1015 // -- esp[0] : return address
1016 // -- esp[4] : name
1017 // -- esp[8] : receiver
1018 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 Label miss;
1020
1021 __ mov(eax, (Operand(esp, kPointerSize)));
1022 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1023 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1024
1025 // Check that the name has not changed.
1026 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1027 __ j(not_equal, &miss, not_taken);
1028
1029 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1030 callback, &miss);
1031 __ bind(&miss);
1032 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1033 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1034
1035 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001036 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037}
1038
1039
1040Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1041 JSObject* receiver,
1042 JSObject* holder,
1043 Object* value) {
1044 // ----------- S t a t e -------------
1045 // -- esp[0] : return address
1046 // -- esp[4] : name
1047 // -- esp[8] : receiver
1048 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049 Label miss;
1050
1051 __ mov(eax, (Operand(esp, kPointerSize)));
1052 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1053 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1054
1055 // Check that the name has not changed.
1056 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1057 __ j(not_equal, &miss, not_taken);
1058
1059 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1060 __ bind(&miss);
1061 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1062 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1063
1064 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001065 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066}
1067
1068
1069Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1070 JSObject* holder,
1071 String* name) {
1072 // ----------- S t a t e -------------
1073 // -- esp[0] : return address
1074 // -- esp[4] : name
1075 // -- esp[8] : receiver
1076 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077 Label miss;
1078
1079 __ mov(eax, (Operand(esp, kPointerSize)));
1080 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1081 __ IncrementCounter(&Counters::keyed_load_interceptor, 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 GenerateLoadInterceptor(masm(), receiver, holder, ecx, eax, edx, ebx, &miss);
1088 __ bind(&miss);
1089 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1090 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1091
1092 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001093 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001094}
1095
1096
1097
1098
1099Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1100 // ----------- S t a t e -------------
1101 // -- esp[0] : return address
1102 // -- esp[4] : name
1103 // -- esp[8] : receiver
1104 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 Label miss;
1106
1107 __ mov(eax, (Operand(esp, kPointerSize)));
1108 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1109 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1110
1111 // Check that the name has not changed.
1112 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1113 __ j(not_equal, &miss, not_taken);
1114
1115 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1116 __ bind(&miss);
1117 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1118 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1119
1120 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001121 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122}
1123
1124
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001125Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126 // ----------- S t a t e -------------
1127 // -- esp[0] : return address
1128 // -- esp[4] : name
1129 // -- esp[8] : receiver
1130 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131 Label miss;
1132
1133 __ mov(eax, (Operand(esp, kPointerSize)));
1134 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1135 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1136
1137 // Check that the name has not changed.
1138 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1139 __ j(not_equal, &miss, not_taken);
1140
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001141 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 __ bind(&miss);
1143 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1144 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1145
1146 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001147 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148}
1149
1150
1151Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1152 // ----------- S t a t e -------------
1153 // -- esp[0] : return address
1154 // -- esp[4] : name
1155 // -- esp[8] : receiver
1156 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 Label miss;
1158
1159 __ mov(eax, (Operand(esp, kPointerSize)));
1160 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1161 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1162
1163 // Check that the name has not changed.
1164 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1165 __ j(not_equal, &miss, not_taken);
1166
1167 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1168 __ bind(&miss);
1169 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1170 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1171
1172 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001173 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174}
1175
1176
1177#undef __
1178
1179} } // namespace v8::internal