blob: 6d9ace84cf184c5ee43f1cd08698c258c103face [file] [log] [blame]
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001// Copyright 2006-2009 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
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
ager@chromium.org65dad4b2009-04-23 08:48:43 +000037#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
40static void ProbeTable(MacroAssembler* masm,
41 Code::Flags flags,
42 StubCache::Table table,
43 Register name,
44 Register offset) {
45 ExternalReference key_offset(SCTableReference::keyReference(table));
46 ExternalReference value_offset(SCTableReference::valueReference(table));
47
48 Label miss;
49
50 // Save the offset on the stack.
51 __ push(offset);
52
53 // Check that the key in the entry matches the name.
54 __ mov(ip, Operand(key_offset));
55 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
56 __ cmp(name, Operand(ip));
57 __ b(ne, &miss);
58
59 // Get the code entry from the cache.
60 __ mov(ip, Operand(value_offset));
61 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
62
63 // Check that the flags match what we're looking for.
64 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
kasperl@chromium.org71affb52009-05-26 05:44:31 +000065 __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066 __ cmp(offset, Operand(flags));
67 __ b(ne, &miss);
68
69 // Restore offset and re-load code entry from cache.
70 __ pop(offset);
71 __ mov(ip, Operand(value_offset));
72 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
73
74 // Jump to the first instruction in the code stub.
75 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
76 __ Jump(offset);
77
78 // Miss: Restore offset and fall through.
79 __ bind(&miss);
80 __ pop(offset);
81}
82
83
84void StubCache::GenerateProbe(MacroAssembler* masm,
85 Code::Flags flags,
86 Register receiver,
87 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000088 Register scratch,
89 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090 Label miss;
91
92 // Make sure that code is valid. The shifting code relies on the
93 // entry size being 8.
94 ASSERT(sizeof(Entry) == 8);
95
96 // Make sure the flags does not name a specific type.
97 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
98
99 // Make sure that there are no register conflicts.
100 ASSERT(!scratch.is(receiver));
101 ASSERT(!scratch.is(name));
102
103 // Check that the receiver isn't a smi.
104 __ tst(receiver, Operand(kSmiTagMask));
105 __ b(eq, &miss);
106
107 // Get the map of the receiver and compute the hash.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000108 __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
109 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 __ add(scratch, scratch, Operand(ip));
111 __ eor(scratch, scratch, Operand(flags));
112 __ and_(scratch,
113 scratch,
114 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
115
116 // Probe the primary table.
117 ProbeTable(masm, flags, kPrimary, name, scratch);
118
119 // Primary miss: Compute hash for secondary probe.
120 __ sub(scratch, scratch, Operand(name));
121 __ add(scratch, scratch, Operand(flags));
122 __ and_(scratch,
123 scratch,
124 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
125
126 // Probe the secondary table.
127 ProbeTable(masm, flags, kSecondary, name, scratch);
128
129 // Cache miss: Fall-through and let caller handle the miss by
130 // entering the runtime system.
131 __ bind(&miss);
132}
133
134
135void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
136 int index,
137 Register prototype) {
138 // Load the global or builtins object from the current context.
139 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
140 // Load the global context from the global or builtins object.
141 __ ldr(prototype,
142 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
143 // Load the function from the global context.
144 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
145 // Load the initial map. The global functions all have initial maps.
146 __ ldr(prototype,
147 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
148 // Load the prototype from the initial map.
149 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
150}
151
152
ager@chromium.org7c537e22008-10-16 08:43:32 +0000153// Load a fast property out of a holder object (src). In-object properties
154// are loaded directly otherwise the property is loaded from the properties
155// fixed array.
156void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
157 Register dst, Register src,
158 JSObject* holder, int index) {
159 // Adjust for the number of properties stored in the holder.
160 index -= holder->map()->inobject_properties();
161 if (index < 0) {
162 // Get the property straight out of the holder.
163 int offset = holder->map()->instance_size() + (index * kPointerSize);
164 __ ldr(dst, FieldMemOperand(src, offset));
165 } else {
166 // Calculate the offset into the properties array.
167 int offset = index * kPointerSize + Array::kHeaderSize;
168 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
169 __ ldr(dst, FieldMemOperand(dst, offset));
170 }
171}
172
173
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000174void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
175 Register receiver,
176 Register scratch,
177 Label* miss_label) {
178 // Check that the receiver isn't a smi.
179 __ tst(receiver, Operand(kSmiTagMask));
180 __ b(eq, miss_label);
181
182 // Check that the object is a JS array.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000183 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000184 __ b(ne, miss_label);
185
186 // Load length directly from the JS array.
187 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
188 __ Ret();
189}
190
191
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000192// Generate code to check if an object is a string. If the object is
193// a string, the map's instance type is left in the scratch1 register.
194static void GenerateStringCheck(MacroAssembler* masm,
195 Register receiver,
196 Register scratch1,
197 Register scratch2,
198 Label* smi,
199 Label* non_string_object) {
200 // Check that the receiver isn't a smi.
201 __ tst(receiver, Operand(kSmiTagMask));
202 __ b(eq, smi);
203
204 // Check that the object is a string.
205 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
206 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
207 __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
208 // The cast is to resolve the overload for the argument of 0x0.
209 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
210 __ b(ne, non_string_object);
211}
212
213
ager@chromium.org32912102009-01-16 10:38:43 +0000214// Generate code to load the length from a string object and return the length.
215// If the receiver object is not a string or a wrapped string object the
216// execution continues at the miss label. The register containing the
217// receiver is potentially clobbered.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000218void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
219 Register receiver,
220 Register scratch1,
221 Register scratch2,
222 Label* miss) {
ager@chromium.org32912102009-01-16 10:38:43 +0000223 Label check_string, check_wrapper;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000224
ager@chromium.org32912102009-01-16 10:38:43 +0000225 __ bind(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000226 // Check if the object is a string leaving the instance type in the
227 // scratch1 register.
228 GenerateStringCheck(masm, receiver, scratch1, scratch2,
229 miss, &check_wrapper);
230
231 // Load length directly from the string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000232 __ and_(scratch1, scratch1, Operand(kStringSizeMask));
233 __ add(scratch1, scratch1, Operand(String::kHashShift));
234 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
235 __ mov(r0, Operand(r0, LSR, scratch1));
236 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
237 __ Ret();
238
239 // Check if the object is a JSValue wrapper.
240 __ bind(&check_wrapper);
241 __ cmp(scratch1, Operand(JS_VALUE_TYPE));
242 __ b(ne, miss);
243
ager@chromium.org32912102009-01-16 10:38:43 +0000244 // Unwrap the value in place and check if the wrapped value is a string.
245 __ ldr(receiver, FieldMemOperand(receiver, JSValue::kValueOffset));
246 __ b(&check_string);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000247}
248
249
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000250void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
251 Register receiver,
252 Register scratch1,
253 Register scratch2,
254 Label* miss_label) {
255 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
256 __ mov(r0, scratch1);
257 __ Ret();
258}
259
260
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000261// Generate StoreField code, value is passed in r0 register.
262// After executing generated code, the receiver_reg and name_reg
263// may be clobbered.
264void StubCompiler::GenerateStoreField(MacroAssembler* masm,
265 Builtins::Name storage_extend,
266 JSObject* object,
267 int index,
268 Map* transition,
269 Register receiver_reg,
270 Register name_reg,
271 Register scratch,
272 Label* miss_label) {
273 // r0 : value
274 Label exit;
275
276 // Check that the receiver isn't a smi.
277 __ tst(receiver_reg, Operand(kSmiTagMask));
278 __ b(eq, miss_label);
279
280 // Check that the map of the receiver hasn't changed.
281 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
282 __ cmp(scratch, Operand(Handle<Map>(object->map())));
283 __ b(ne, miss_label);
284
285 // Perform global security token check if needed.
286 if (object->IsJSGlobalProxy()) {
287 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
288 }
289
290 // Stub never generated for non-global objects that require access
291 // checks.
292 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
293
294 // Perform map transition for the receiver if necessary.
295 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
296 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000297 // We jump to a runtime call that extends the properties array.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000298 __ mov(r2, Operand(Handle<Map>(transition)));
299 // Please note, if we implement keyed store for arm we need
300 // to call the Builtins::KeyedStoreIC_ExtendStorage.
301 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
302 __ Jump(ic, RelocInfo::CODE_TARGET);
303 return;
304 }
305
306 if (transition != NULL) {
307 // Update the map of the object; no write barrier updating is
308 // needed because the map is never in new space.
309 __ mov(ip, Operand(Handle<Map>(transition)));
310 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
311 }
312
313 // Adjust for the number of properties stored in the object. Even in the
314 // face of a transition we can use the old map here because the size of the
315 // object and the number of in-object properties is not going to change.
316 index -= object->map()->inobject_properties();
317
318 if (index < 0) {
319 // Set the property straight into the object.
320 int offset = object->map()->instance_size() + (index * kPointerSize);
321 __ str(r0, FieldMemOperand(receiver_reg, offset));
322
323 // Skip updating write barrier if storing a smi.
324 __ tst(r0, Operand(kSmiTagMask));
325 __ b(eq, &exit);
326
327 // Update the write barrier for the array address.
328 // Pass the value being stored in the now unused name_reg.
329 __ mov(name_reg, Operand(offset));
330 __ RecordWrite(receiver_reg, name_reg, scratch);
331 } else {
332 // Write to the properties array.
333 int offset = index * kPointerSize + Array::kHeaderSize;
334 // Get the properties array
335 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
336 __ str(r0, FieldMemOperand(scratch, offset));
337
338 // Skip updating write barrier if storing a smi.
339 __ tst(r0, Operand(kSmiTagMask));
340 __ b(eq, &exit);
341
342 // Update the write barrier for the array address.
343 // Ok to clobber receiver_reg and name_reg, since we return.
344 __ mov(name_reg, Operand(offset));
345 __ RecordWrite(scratch, name_reg, receiver_reg);
346 }
347
348 // Return the value (register r0).
349 __ bind(&exit);
350 __ Ret();
351}
352
353
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000354void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
355 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
356 Code* code = NULL;
357 if (kind == Code::LOAD_IC) {
358 code = Builtins::builtin(Builtins::LoadIC_Miss);
359 } else {
360 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
361 }
362
363 Handle<Code> ic(code);
364 __ Jump(ic, RelocInfo::CODE_TARGET);
365}
366
367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368#undef __
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000369#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370
371
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000372Register StubCompiler::CheckPrototypes(JSObject* object,
373 Register object_reg,
374 JSObject* holder,
375 Register holder_reg,
376 Register scratch,
377 String* name,
378 Label* miss) {
379 // Check that the maps haven't changed.
380 Register result =
381 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
382
383 // If we've skipped any global objects, it's not enough to verify
384 // that their maps haven't changed.
385 while (object != holder) {
386 if (object->IsGlobalObject()) {
387 GlobalObject* global = GlobalObject::cast(object);
388 Object* probe = global->EnsurePropertyCell(name);
389 if (probe->IsFailure()) {
390 set_failure(Failure::cast(probe));
391 return result;
392 }
393 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
394 ASSERT(cell->value()->IsTheHole());
395 __ mov(scratch, Operand(Handle<Object>(cell)));
396 __ ldr(scratch,
397 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
398 __ cmp(scratch, Operand(Factory::the_hole_value()));
399 __ b(ne, miss);
400 }
401 object = JSObject::cast(object->GetPrototype());
402 }
403
404 // Return the register containin the holder.
405 return result;
406}
407
408
409void StubCompiler::GenerateLoadField(JSObject* object,
410 JSObject* holder,
411 Register receiver,
412 Register scratch1,
413 Register scratch2,
414 int index,
415 String* name,
416 Label* miss) {
417 // Check that the receiver isn't a smi.
418 __ tst(receiver, Operand(kSmiTagMask));
419 __ b(eq, miss);
420
421 // Check that the maps haven't changed.
422 Register reg =
423 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
424 GenerateFastPropertyLoad(masm(), r0, reg, holder, index);
425 __ Ret();
426}
427
428
429void StubCompiler::GenerateLoadConstant(JSObject* object,
430 JSObject* holder,
431 Register receiver,
432 Register scratch1,
433 Register scratch2,
434 Object* value,
435 String* name,
436 Label* miss) {
437 // Check that the receiver isn't a smi.
438 __ tst(receiver, Operand(kSmiTagMask));
439 __ b(eq, miss);
440
441 // Check that the maps haven't changed.
442 Register reg =
443 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
444
445 // Return the constant value.
446 __ mov(r0, Operand(Handle<Object>(value)));
447 __ Ret();
448}
449
450
451void StubCompiler::GenerateLoadCallback(JSObject* object,
452 JSObject* holder,
453 Register receiver,
454 Register name_reg,
455 Register scratch1,
456 Register scratch2,
457 AccessorInfo* callback,
458 String* name,
459 Label* miss) {
460 // Check that the receiver isn't a smi.
461 __ tst(receiver, Operand(kSmiTagMask));
462 __ b(eq, miss);
463
464 // Check that the maps haven't changed.
465 Register reg =
466 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
467
468 // Push the arguments on the JS stack of the caller.
469 __ push(receiver); // receiver
470 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
471 __ push(ip);
472 __ push(name_reg); // name
473 __ push(reg); // holder
474
475 // Do tail-call to the runtime system.
476 ExternalReference load_callback_property =
477 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
478 __ TailCallRuntime(load_callback_property, 4);
479}
480
481
482void StubCompiler::GenerateLoadInterceptor(JSObject* object,
483 JSObject* holder,
484 Smi* lookup_hint,
485 Register receiver,
486 Register name_reg,
487 Register scratch1,
488 Register scratch2,
489 String* name,
490 Label* miss) {
491 // Check that the receiver isn't a smi.
492 __ tst(receiver, Operand(kSmiTagMask));
493 __ b(eq, miss);
494
495 // Check that the maps haven't changed.
496 Register reg =
497 CheckPrototypes(object, receiver, holder, scratch1, scratch2, name, miss);
498
499 // Push the arguments on the JS stack of the caller.
500 __ push(receiver); // receiver
501 __ push(reg); // holder
502 __ push(name_reg); // name
503 __ mov(scratch1, Operand(lookup_hint));
504 __ push(scratch1);
505
506 // Do tail-call to the runtime system.
507 ExternalReference load_ic_property =
508 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
509 __ TailCallRuntime(load_ic_property, 4);
510}
511
512
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000513Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000514 // ----------- S t a t e -------------
515 // -- r1: function
516 // -- lr: return address
517 // -----------------------------------
518
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000519 // Enter an internal frame.
520 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000521
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000522 // Preserve the function.
523 __ push(r1);
524
525 // Push the function on the stack as the argument to the runtime function.
526 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 __ CallRuntime(Runtime::kLazyCompile, 1);
528
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000529 // Calculate the entry point.
530 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000532 // Restore saved function.
533 __ pop(r1);
534
535 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000536 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537
538 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000539 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000541 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542}
543
544
545Object* CallStubCompiler::CompileCallField(Object* object,
546 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000547 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000548 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 // -- lr: return address
551 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 Label miss;
553
mads.s.ager31e71382008-08-13 09:32:07 +0000554 const int argc = arguments().immediate();
555
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000556 // Get the receiver of the function from the stack into r0.
557 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000559 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 __ b(eq, &miss);
561
562 // Do the right check and compute the holder register.
563 Register reg =
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000564 CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000565 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566
567 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000568 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 __ b(eq, &miss);
570 // Get the map.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000571 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 __ b(ne, &miss);
573
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000574 // Patch the receiver on the stack with the global proxy if
575 // necessary.
576 if (object->IsGlobalObject()) {
577 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
578 __ str(r3, MemOperand(sp, argc * kPointerSize));
579 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000581 // Invoke the function.
582 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583
584 // Handle call cache miss.
585 __ bind(&miss);
586 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000587 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588
589 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000590 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000591}
592
593
594Object* CallStubCompiler::CompileCallConstant(Object* object,
595 JSObject* holder,
596 JSFunction* function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000597 String* name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000598 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 // -- lr: return address
601 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602 Label miss;
603
mads.s.ager31e71382008-08-13 09:32:07 +0000604 // Get the receiver from the stack
605 const int argc = arguments().immediate();
606 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608 // Check that the receiver isn't a smi.
609 if (check != NUMBER_CHECK) {
610 __ tst(r1, Operand(kSmiTagMask));
611 __ b(eq, &miss);
612 }
613
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000614 // Make sure that it's okay not to patch the on stack receiver
615 // unless we're doing a receiver map check.
616 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 switch (check) {
619 case RECEIVER_MAP_CHECK:
620 // Check that the maps haven't changed.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000621 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000622
623 // Patch the receiver on the stack with the global proxy if
624 // necessary.
625 if (object->IsGlobalObject()) {
626 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
627 __ str(r3, MemOperand(sp, argc * kPointerSize));
628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 break;
630
631 case STRING_CHECK:
632 // Check that the object is a two-byte string or a symbol.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000633 __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 __ b(hs, &miss);
635 // Check that the maps starting from the prototype haven't changed.
636 GenerateLoadGlobalFunctionPrototype(masm(),
637 Context::STRING_FUNCTION_INDEX,
638 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000639 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
640 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 break;
642
643 case NUMBER_CHECK: {
644 Label fast;
645 // Check that the object is a smi or a heap number.
646 __ tst(r1, Operand(kSmiTagMask));
647 __ b(eq, &fast);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000648 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 __ b(ne, &miss);
650 __ bind(&fast);
651 // Check that the maps starting from the prototype haven't changed.
652 GenerateLoadGlobalFunctionPrototype(masm(),
653 Context::NUMBER_FUNCTION_INDEX,
654 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000655 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
656 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 break;
658 }
659
660 case BOOLEAN_CHECK: {
661 Label fast;
662 // Check that the object is a boolean.
663 __ cmp(r1, Operand(Factory::true_value()));
664 __ b(eq, &fast);
665 __ cmp(r1, Operand(Factory::false_value()));
666 __ b(ne, &miss);
667 __ bind(&fast);
668 // Check that the maps starting from the prototype haven't changed.
669 GenerateLoadGlobalFunctionPrototype(masm(),
670 Context::BOOLEAN_FUNCTION_INDEX,
671 r2);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000672 CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
673 r1, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 break;
675 }
676
677 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000678 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679 // Make sure object->elements()->map() != Heap::hash_table_map()
680 // Get the elements array of the object.
681 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
682 // Check that the object is in fast mode (not dictionary).
683 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
684 __ cmp(r2, Operand(Factory::hash_table_map()));
685 __ b(eq, &miss);
686 break;
687
688 default:
689 UNREACHABLE();
690 }
691
692 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000693 __ mov(r1, Operand(Handle<JSFunction>(function)));
694 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000697 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000699 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000700 __ InvokeCode(code, expected, arguments(),
701 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702
703 // Handle call cache miss.
704 __ bind(&miss);
705 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000706 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707
708 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000709 String* function_name = NULL;
710 if (function->shared()->name()->IsString()) {
711 function_name = String::cast(function->shared()->name());
712 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000713 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000714}
715
716
717Object* CallStubCompiler::CompileCallInterceptor(Object* object,
718 JSObject* holder,
719 String* name) {
720 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721 // -- lr: return address
722 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723 Label miss;
724
725 // TODO(1224669): Implement.
726
727 // Handle call cache miss.
728 __ bind(&miss);
729 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000730 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731
732 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000733 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734}
735
736
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000737Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
738 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000739 JSGlobalPropertyCell* cell,
740 JSFunction* function,
741 String* name) {
742 // ----------- S t a t e -------------
743 // -- lr: return address
744 // -----------------------------------
745 Label miss;
746
747 __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
748
749 // Get the number of arguments.
750 const int argc = arguments().immediate();
751
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000752 // Get the receiver from the stack.
753 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
754
755 // If the object is the holder then we know that it's a global
756 // object which can only happen for contextual calls. In this case,
757 // the receiver cannot be a smi.
758 if (object != holder) {
759 __ tst(r0, Operand(kSmiTagMask));
760 __ b(eq, &miss);
761 }
762
763 // Check that the maps haven't changed.
764 CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000765
766 // Get the value from the cell.
767 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
768 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
769
770 // Check that the cell contains the same function.
771 __ cmp(r1, Operand(Handle<JSFunction>(function)));
772 __ b(ne, &miss);
773
774 // Patch the receiver on the stack with the global proxy if
775 // necessary.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000776 if (object->IsGlobalObject()) {
777 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
778 __ str(r3, MemOperand(sp, argc * kPointerSize));
779 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000780
781 // Setup the context (function already in r1).
782 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
783
784 // Jump to the cached code (tail call).
785 ASSERT(function->is_compiled());
786 Handle<Code> code(function->code());
787 ParameterCount expected(function->shared()->formal_parameter_count());
788 __ InvokeCode(code, expected, arguments(),
789 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
790
791 // Handle call cache miss.
792 __ bind(&miss);
793 __ DecrementCounter(&Counters::call_global_inline, 1, r1, r3);
794 __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
795 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
796 __ Jump(ic, RelocInfo::CODE_TARGET);
797
798 // Return the generated code.
799 return GetCode(NORMAL, name);
800}
801
802
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803Object* StoreStubCompiler::CompileStoreField(JSObject* object,
804 int index,
805 Map* transition,
806 String* name) {
807 // ----------- S t a t e -------------
808 // -- r0 : value
809 // -- r2 : name
810 // -- lr : return address
811 // -- [sp] : receiver
812 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000813 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814
815 // Get the receiver from the stack.
816 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
817
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000818 // name register might be clobbered.
819 GenerateStoreField(masm(),
820 Builtins::StoreIC_ExtendStorage,
821 object,
822 index,
823 transition,
824 r3, r2, r1,
825 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 __ bind(&miss);
827 __ mov(r2, Operand(Handle<String>(name))); // restore name
828 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000829 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830
831 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000832 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833}
834
835
836Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
837 AccessorInfo* callback,
838 String* name) {
839 // ----------- S t a t e -------------
840 // -- r0 : value
841 // -- r2 : name
842 // -- lr : return address
843 // -- [sp] : receiver
844 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 Label miss;
846
847 // Get the object from the stack.
848 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
849
850 // Check that the object isn't a smi.
851 __ tst(r3, Operand(kSmiTagMask));
852 __ b(eq, &miss);
853
854 // Check that the map of the object hasn't changed.
855 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
856 __ cmp(r1, Operand(Handle<Map>(object->map())));
857 __ b(ne, &miss);
858
859 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000860 if (object->IsJSGlobalProxy()) {
861 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000862 }
863
864 // Stub never generated for non-global objects that require access
865 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000866 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867
868 __ ldr(ip, MemOperand(sp)); // receiver
869 __ push(ip);
870 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
871 __ push(ip);
872 __ push(r2); // name
873 __ push(r0); // value
874
mads.s.ager31e71382008-08-13 09:32:07 +0000875 // Do tail-call to the runtime system.
876 ExternalReference store_callback_property =
877 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
878 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879
880 // Handle store cache miss.
881 __ bind(&miss);
882 __ mov(r2, Operand(Handle<String>(name))); // restore name
883 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000884 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885
886 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000887 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888}
889
890
891Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
892 String* name) {
893 // ----------- S t a t e -------------
894 // -- r0 : value
895 // -- r2 : name
896 // -- lr : return address
897 // -- [sp] : receiver
898 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 Label miss;
900
901 // Get the object from the stack.
902 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
903
904 // Check that the object isn't a smi.
905 __ tst(r3, Operand(kSmiTagMask));
906 __ b(eq, &miss);
907
908 // Check that the map of the object hasn't changed.
909 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
910 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
911 __ b(ne, &miss);
912
913 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000914 if (receiver->IsJSGlobalProxy()) {
915 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 }
917
918 // Stub never generated for non-global objects that require access
919 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000920 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921
922 __ ldr(ip, MemOperand(sp)); // receiver
923 __ push(ip);
924 __ push(r2); // name
925 __ push(r0); // value
926
mads.s.ager31e71382008-08-13 09:32:07 +0000927 // Do tail-call to the runtime system.
928 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000930 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931
932 // Handle store cache miss.
933 __ bind(&miss);
934 __ mov(r2, Operand(Handle<String>(name))); // restore name
935 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000936 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937
938 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000939 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940}
941
942
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000943Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
944 JSGlobalPropertyCell* cell,
945 String* name) {
946 // ----------- S t a t e -------------
947 // -- r0 : value
948 // -- r2 : name
949 // -- lr : return address
950 // -- [sp] : receiver
951 // -----------------------------------
952 Label miss;
953
954 __ IncrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
955
956 // Check that the map of the global has not changed.
957 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
958 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
959 __ cmp(r3, Operand(Handle<Map>(object->map())));
960 __ b(ne, &miss);
961
962 // Store the value in the cell.
963 __ mov(r2, Operand(Handle<JSGlobalPropertyCell>(cell)));
964 __ str(r0, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000965
966 __ Ret();
967
968 // Handle store cache miss.
969 __ bind(&miss);
970 __ DecrementCounter(&Counters::named_store_global_inline, 1, r1, r3);
971 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1, r1, r3);
972 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
973 __ Jump(ic, RelocInfo::CODE_TARGET);
974
975 // Return the generated code.
976 return GetCode(NORMAL, name);
977}
978
979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980Object* LoadStubCompiler::CompileLoadField(JSObject* object,
981 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000982 int index,
983 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985 // -- r2 : name
986 // -- lr : return address
987 // -- [sp] : receiver
988 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 Label miss;
990
mads.s.ager31e71382008-08-13 09:32:07 +0000991 __ ldr(r0, MemOperand(sp, 0));
992
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000993 GenerateLoadField(object, holder, r0, r3, r1, index, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996
997 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000998 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999}
1000
1001
1002Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
1003 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001004 AccessorInfo* callback,
1005 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 // -- r2 : name
1008 // -- lr : return address
1009 // -- [sp] : receiver
1010 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 Label miss;
1012
mads.s.ager31e71382008-08-13 09:32:07 +00001013 __ ldr(r0, MemOperand(sp, 0));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001014 GenerateLoadCallback(object, holder, r0, r2, r3, r1, callback, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001016 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017
1018 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001019 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020}
1021
1022
1023Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1024 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001025 Object* value,
1026 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028 // -- r2 : name
1029 // -- lr : return address
1030 // -- [sp] : receiver
1031 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032 Label miss;
1033
mads.s.ager31e71382008-08-13 09:32:07 +00001034 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001035
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001036 GenerateLoadConstant(object, holder, r0, r3, r1, value, name, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001038 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039
1040 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001041 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042}
1043
1044
1045Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
1046 JSObject* holder,
1047 String* name) {
1048 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049 // -- r2 : name
1050 // -- lr : return address
1051 // -- [sp] : receiver
1052 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053 Label miss;
1054
mads.s.ager31e71382008-08-13 09:32:07 +00001055 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001057 GenerateLoadInterceptor(object,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001058 holder,
1059 holder->InterceptorPropertyLookupHint(name),
1060 r0,
1061 r2,
1062 r3,
1063 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001064 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001065 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001067 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068
1069 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001070 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071}
1072
1073
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001074Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
1075 GlobalObject* holder,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001076 JSGlobalPropertyCell* cell,
1077 String* name,
1078 bool is_dont_delete) {
1079 // ----------- S t a t e -------------
1080 // -- r2 : name
1081 // -- lr : return address
1082 // -- [sp] : receiver
1083 // -----------------------------------
1084 Label miss;
1085
1086 __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1087
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001088 // Get the receiver from the stack.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001089 __ ldr(r1, MemOperand(sp, 0 * kPointerSize));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001090
1091 // If the object is the holder then we know that it's a global
1092 // object which can only happen for contextual calls. In this case,
1093 // the receiver cannot be a smi.
1094 if (object != holder) {
1095 __ tst(r1, Operand(kSmiTagMask));
1096 __ b(eq, &miss);
1097 }
1098
1099 // Check that the map of the global has not changed.
1100 CheckPrototypes(object, r1, holder, r3, r0, name, &miss);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001101
1102 // Get the value from the cell.
1103 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
1104 __ ldr(r0, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset));
1105
1106 // Check for deleted property if property can actually be deleted.
1107 if (!is_dont_delete) {
1108 __ cmp(r0, Operand(Factory::the_hole_value()));
1109 __ b(eq, &miss);
1110 }
1111
1112 __ Ret();
1113
1114 __ bind(&miss);
1115 __ DecrementCounter(&Counters::named_load_global_inline, 1, r1, r3);
1116 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3);
1117 GenerateLoadMiss(masm(), Code::LOAD_IC);
1118
1119 // Return the generated code.
1120 return GetCode(NORMAL, name);
1121}
1122
1123
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124// TODO(1224671): IC stubs for keyed loads have not been implemented
1125// for ARM.
1126Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1127 JSObject* receiver,
1128 JSObject* holder,
1129 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001130 // ----------- S t a t e -------------
1131 // -- lr : return address
1132 // -- sp[0] : key
1133 // -- sp[4] : receiver
1134 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001135 Label miss;
1136
1137 __ ldr(r2, MemOperand(sp, 0));
1138 __ ldr(r0, MemOperand(sp, kPointerSize));
1139
1140 __ cmp(r2, Operand(Handle<String>(name)));
1141 __ b(ne, &miss);
1142
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001143 GenerateLoadField(receiver, holder, r0, r3, r1, index, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001144 __ bind(&miss);
1145 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1146
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001147 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148}
1149
1150
1151Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1152 JSObject* receiver,
1153 JSObject* holder,
1154 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001155 // ----------- S t a t e -------------
1156 // -- lr : return address
1157 // -- sp[0] : key
1158 // -- sp[4] : receiver
1159 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001160 Label miss;
1161
1162 __ ldr(r2, MemOperand(sp, 0));
1163 __ ldr(r0, MemOperand(sp, kPointerSize));
1164
1165 __ cmp(r2, Operand(Handle<String>(name)));
1166 __ b(ne, &miss);
1167
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001168 GenerateLoadCallback(receiver, holder, r0, r2, r3, r1, callback, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001169 __ bind(&miss);
1170 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1171
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001172 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173}
1174
1175
1176Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1177 JSObject* receiver,
1178 JSObject* holder,
1179 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001180 // ----------- S t a t e -------------
1181 // -- lr : return address
1182 // -- sp[0] : key
1183 // -- sp[4] : receiver
1184 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001185 Label miss;
1186
1187 // Check the key is the cached one
1188 __ ldr(r2, MemOperand(sp, 0));
1189 __ ldr(r0, MemOperand(sp, kPointerSize));
1190
1191 __ cmp(r2, Operand(Handle<String>(name)));
1192 __ b(ne, &miss);
1193
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001194 GenerateLoadConstant(receiver, holder, r0, r3, r1, value, name, &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001195 __ bind(&miss);
1196 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1197
1198 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001199 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200}
1201
1202
1203Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1204 JSObject* holder,
1205 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001206 // ----------- S t a t e -------------
1207 // -- lr : return address
1208 // -- sp[0] : key
1209 // -- sp[4] : receiver
1210 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001211 Label miss;
1212
1213 // Check the key is the cached one
1214 __ ldr(r2, MemOperand(sp, 0));
1215 __ ldr(r0, MemOperand(sp, kPointerSize));
1216
1217 __ cmp(r2, Operand(Handle<String>(name)));
1218 __ b(ne, &miss);
1219
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001220 GenerateLoadInterceptor(receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001221 holder,
1222 Smi::FromInt(JSObject::kLookupInHolder),
1223 r0,
1224 r2,
1225 r3,
1226 r1,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001227 name,
ager@chromium.orge2902be2009-06-08 12:21:35 +00001228 &miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001229 __ bind(&miss);
1230 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1231
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001232 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233}
1234
1235
1236Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001237 // ----------- S t a t e -------------
1238 // -- lr : return address
1239 // -- sp[0] : key
1240 // -- sp[4] : receiver
1241 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001242 Label miss;
1243
1244 // Check the key is the cached one
1245 __ ldr(r2, MemOperand(sp, 0));
1246 __ ldr(r0, MemOperand(sp, kPointerSize));
1247
1248 __ cmp(r2, Operand(Handle<String>(name)));
1249 __ b(ne, &miss);
1250
1251 GenerateLoadArrayLength(masm(), r0, r3, &miss);
1252 __ bind(&miss);
1253 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1254
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001255 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256}
1257
1258
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001259Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001260 // ----------- S t a t e -------------
1261 // -- lr : return address
1262 // -- sp[0] : key
1263 // -- sp[4] : receiver
1264 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001265 Label miss;
1266 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1267
1268 __ ldr(r2, MemOperand(sp));
1269 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
1270
1271 __ cmp(r2, Operand(Handle<String>(name)));
1272 __ b(ne, &miss);
1273
1274 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss);
1275 __ bind(&miss);
1276 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
1277
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001278 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1279
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001280 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281}
1282
1283
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001284// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001286 // ----------- S t a t e -------------
1287 // -- lr : return address
1288 // -- sp[0] : key
1289 // -- sp[4] : receiver
1290 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001291 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1292
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001293 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294}
1295
1296
1297Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1298 int index,
1299 Map* transition,
1300 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001301 // ----------- S t a t e -------------
1302 // -- r0 : value
1303 // -- r2 : name
1304 // -- lr : return address
1305 // -- [sp] : receiver
1306 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001307 Label miss;
1308
1309 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1310
1311 // Check that the name has not changed.
1312 __ cmp(r2, Operand(Handle<String>(name)));
1313 __ b(ne, &miss);
1314
1315 // Load receiver from the stack.
1316 __ ldr(r3, MemOperand(sp));
1317 // r1 is used as scratch register, r3 and r2 might be clobbered.
1318 GenerateStoreField(masm(),
1319 Builtins::StoreIC_ExtendStorage,
1320 object,
1321 index,
1322 transition,
1323 r3, r2, r1,
1324 &miss);
1325 __ bind(&miss);
1326
1327 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
1328 __ mov(r2, Operand(Handle<String>(name))); // restore name register.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001329 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1330 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001332 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001333 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001334}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335
1336
1337#undef __
1338
1339} } // namespace v8::internal