blob: a31ff2f73f2cda4cafd62bdda948032e8e7c3a57 [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 __ mov(ip, Operand(key_offset));
54 __ ldr(ip, MemOperand(ip, offset, LSL, 1));
55 __ cmp(name, Operand(ip));
56 __ b(ne, &miss);
57
58 // Get the code entry from the cache.
59 __ mov(ip, Operand(value_offset));
60 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
61
62 // Check that the flags match what we're looking for.
63 __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
64 __ and_(offset, offset, Operand(~Code::kFlagsTypeMask));
65 __ cmp(offset, Operand(flags));
66 __ b(ne, &miss);
67
68 // Restore offset and re-load code entry from cache.
69 __ pop(offset);
70 __ mov(ip, Operand(value_offset));
71 __ ldr(offset, MemOperand(ip, offset, LSL, 1));
72
73 // Jump to the first instruction in the code stub.
74 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
75 __ Jump(offset);
76
77 // Miss: Restore offset and fall through.
78 __ bind(&miss);
79 __ pop(offset);
80}
81
82
83void StubCache::GenerateProbe(MacroAssembler* masm,
84 Code::Flags flags,
85 Register receiver,
86 Register name,
87 Register scratch) {
88 Label miss;
89
90 // Make sure that code is valid. The shifting code relies on the
91 // entry size being 8.
92 ASSERT(sizeof(Entry) == 8);
93
94 // Make sure the flags does not name a specific type.
95 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
96
97 // Make sure that there are no register conflicts.
98 ASSERT(!scratch.is(receiver));
99 ASSERT(!scratch.is(name));
100
101 // Check that the receiver isn't a smi.
102 __ tst(receiver, Operand(kSmiTagMask));
103 __ b(eq, &miss);
104
105 // Get the map of the receiver and compute the hash.
106 __ ldr(scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
107 __ ldr(ip, FieldMemOperand(name, String::kLengthOffset));
108 __ add(scratch, scratch, Operand(ip));
109 __ eor(scratch, scratch, Operand(flags));
110 __ and_(scratch,
111 scratch,
112 Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
113
114 // Probe the primary table.
115 ProbeTable(masm, flags, kPrimary, name, scratch);
116
117 // Primary miss: Compute hash for secondary probe.
118 __ sub(scratch, scratch, Operand(name));
119 __ add(scratch, scratch, Operand(flags));
120 __ and_(scratch,
121 scratch,
122 Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
123
124 // Probe the secondary table.
125 ProbeTable(masm, flags, kSecondary, name, scratch);
126
127 // Cache miss: Fall-through and let caller handle the miss by
128 // entering the runtime system.
129 __ bind(&miss);
130}
131
132
133void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
134 int index,
135 Register prototype) {
136 // Load the global or builtins object from the current context.
137 __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
138 // Load the global context from the global or builtins object.
139 __ ldr(prototype,
140 FieldMemOperand(prototype, GlobalObject::kGlobalContextOffset));
141 // Load the function from the global context.
142 __ ldr(prototype, MemOperand(prototype, Context::SlotOffset(index)));
143 // Load the initial map. The global functions all have initial maps.
144 __ ldr(prototype,
145 FieldMemOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
146 // Load the prototype from the initial map.
147 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset));
148}
149
150
151#undef __
152
153#define __ masm()->
154
155
156Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000157 // ----------- S t a t e -------------
158 // -- r1: function
159 // -- lr: return address
160 // -----------------------------------
161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 HandleScope scope;
163
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000164 // Enter an internal frame.
165 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000167 // Preserve the function.
168 __ push(r1);
169
170 // Push the function on the stack as the argument to the runtime function.
171 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172 __ CallRuntime(Runtime::kLazyCompile, 1);
173
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000174 // Calculate the entry point.
175 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000176
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000177 // Restore saved function.
178 __ pop(r1);
179
180 // Tear down temporary frame.
181 __ ExitInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000182
183 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000184 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185
186 return GetCodeWithFlags(flags);
187}
188
189
190Object* CallStubCompiler::CompileCallField(Object* object,
191 JSObject* holder,
192 int index) {
193 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194 // -- lr: return address
195 // -----------------------------------
196
197 HandleScope scope;
198 Label miss;
199
mads.s.ager31e71382008-08-13 09:32:07 +0000200 const int argc = arguments().immediate();
201
202 // Get the receiver of the function from the stack into r1.
203 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 // Check that the receiver isn't a smi.
205 __ tst(r1, Operand(kSmiTagMask));
206 __ b(eq, &miss);
207
208 // Do the right check and compute the holder register.
209 Register reg =
210 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
211
212 // Get the properties array of the holder and get the function from the field.
213 int offset = index * kPointerSize + Array::kHeaderSize;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000214 __ ldr(r1, FieldMemOperand(reg, JSObject::kPropertiesOffset));
215 __ ldr(r1, FieldMemOperand(r1, offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216
217 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000218 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 __ b(eq, &miss);
220 // Get the map.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000221 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
223 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
224 __ b(ne, &miss);
225
226 // Patch the function on the stack; 1 ~ receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000227 __ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000229 // Invoke the function.
230 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231
232 // Handle call cache miss.
233 __ bind(&miss);
234 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
235 __ Jump(ic, code_target);
236
237 // Return the generated code.
238 return GetCode(FIELD);
239}
240
241
242Object* CallStubCompiler::CompileCallConstant(Object* object,
243 JSObject* holder,
244 JSFunction* function,
245 CheckType check) {
246 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247 // -- lr: return address
248 // -----------------------------------
249
250 HandleScope scope;
251 Label miss;
252
mads.s.ager31e71382008-08-13 09:32:07 +0000253 // Get the receiver from the stack
254 const int argc = arguments().immediate();
255 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 // Check that the receiver isn't a smi.
258 if (check != NUMBER_CHECK) {
259 __ tst(r1, Operand(kSmiTagMask));
260 __ b(eq, &miss);
261 }
262
263 switch (check) {
264 case RECEIVER_MAP_CHECK:
265 // Check that the maps haven't changed.
266 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
267 break;
268
269 case STRING_CHECK:
270 // Check that the object is a two-byte string or a symbol.
271 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
272 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
273 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
274 __ b(hs, &miss);
275 // Check that the maps starting from the prototype haven't changed.
276 GenerateLoadGlobalFunctionPrototype(masm(),
277 Context::STRING_FUNCTION_INDEX,
278 r2);
279 __ CheckMaps(JSObject::cast(object->GetPrototype()),
280 r2, holder, r3, r1, &miss);
281 break;
282
283 case NUMBER_CHECK: {
284 Label fast;
285 // Check that the object is a smi or a heap number.
286 __ tst(r1, Operand(kSmiTagMask));
287 __ b(eq, &fast);
288 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
289 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
290 __ cmp(r2, Operand(HEAP_NUMBER_TYPE));
291 __ b(ne, &miss);
292 __ bind(&fast);
293 // Check that the maps starting from the prototype haven't changed.
294 GenerateLoadGlobalFunctionPrototype(masm(),
295 Context::NUMBER_FUNCTION_INDEX,
296 r2);
297 __ CheckMaps(JSObject::cast(object->GetPrototype()),
298 r2, holder, r3, r1, &miss);
299 break;
300 }
301
302 case BOOLEAN_CHECK: {
303 Label fast;
304 // Check that the object is a boolean.
305 __ cmp(r1, Operand(Factory::true_value()));
306 __ b(eq, &fast);
307 __ cmp(r1, Operand(Factory::false_value()));
308 __ b(ne, &miss);
309 __ bind(&fast);
310 // Check that the maps starting from the prototype haven't changed.
311 GenerateLoadGlobalFunctionPrototype(masm(),
312 Context::BOOLEAN_FUNCTION_INDEX,
313 r2);
314 __ CheckMaps(JSObject::cast(object->GetPrototype()),
315 r2, holder, r3, r1, &miss);
316 break;
317 }
318
319 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
320 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
321 // Make sure object->elements()->map() != Heap::hash_table_map()
322 // Get the elements array of the object.
323 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
324 // Check that the object is in fast mode (not dictionary).
325 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
326 __ cmp(r2, Operand(Factory::hash_table_map()));
327 __ b(eq, &miss);
328 break;
329
330 default:
331 UNREACHABLE();
332 }
333
334 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000335 __ mov(r1, Operand(Handle<JSFunction>(function)));
336 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337
338 // Patch the function on the stack; 1 ~ receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000339 __ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
341 // Jump to the cached code (tail call).
342 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000343 ParameterCount expected(function->shared()->formal_parameter_count());
344 __ InvokeCode(code, expected, arguments(), code_target, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
346 // Handle call cache miss.
347 __ bind(&miss);
348 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
349 __ Jump(ic, code_target);
350
351 // Return the generated code.
352 return GetCode(CONSTANT_FUNCTION);
353}
354
355
356Object* CallStubCompiler::CompileCallInterceptor(Object* object,
357 JSObject* holder,
358 String* name) {
359 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 // -- lr: return address
361 // -----------------------------------
362
363 HandleScope scope;
364 Label miss;
365
366 // TODO(1224669): Implement.
367
368 // Handle call cache miss.
369 __ bind(&miss);
370 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
371 __ Jump(ic, code_target);
372
373 // Return the generated code.
374 return GetCode(INTERCEPTOR);
375}
376
377
378Object* StoreStubCompiler::CompileStoreField(JSObject* object,
379 int index,
380 Map* transition,
381 String* name) {
382 // ----------- S t a t e -------------
383 // -- r0 : value
384 // -- r2 : name
385 // -- lr : return address
386 // -- [sp] : receiver
387 // -----------------------------------
388
389 HandleScope scope;
390 Label miss, exit;
391
392 // Get the receiver from the stack.
393 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
394
395 // Check that the receiver isn't a smi.
396 __ tst(r3, Operand(kSmiTagMask));
397 __ b(eq, &miss);
398
399 // Check that the map of the receiver hasn't changed.
400 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
401 __ cmp(r1, Operand(Handle<Map>(object->map())));
402 __ b(ne, &miss);
403
404 // Perform global security token check if needed.
405 if (object->IsJSGlobalObject()) {
406 __ CheckAccessGlobal(r3, r1, &miss);
407 }
408
409 // Stub never generated for non-global objects that require access
410 // checks.
411 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
412
413 // Get the properties array
414 __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
415
416 // Perform map transition for the receiver if necessary.
417 if (transition != NULL) {
418 // Update the map of the object; no write barrier updating is
419 // needed because the map is never in new space.
420 __ mov(ip, Operand(Handle<Map>(transition)));
421 __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
422 }
423
424 // Write to the properties array.
425 int offset = index * kPointerSize + Array::kHeaderSize;
426 __ str(r0, FieldMemOperand(r1, offset));
427
428 // Skip updating write barrier if storing a smi.
429 __ tst(r0, Operand(kSmiTagMask));
430 __ b(eq, &exit);
431
432 // Update the write barrier for the array address.
433 __ mov(r3, Operand(offset));
434 __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return
435
436 // Return the value (register r0).
437 __ bind(&exit);
438 __ Ret();
439
440 // Handle store cache miss.
441 __ bind(&miss);
442 __ mov(r2, Operand(Handle<String>(name))); // restore name
443 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
444 __ Jump(ic, code_target);
445
446 // Return the generated code.
447 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
448}
449
450
451Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
452 AccessorInfo* callback,
453 String* name) {
454 // ----------- S t a t e -------------
455 // -- r0 : value
456 // -- r2 : name
457 // -- lr : return address
458 // -- [sp] : receiver
459 // -----------------------------------
460
461 HandleScope scope;
462 Label miss;
463
464 // Get the object from the stack.
465 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
466
467 // Check that the object isn't a smi.
468 __ tst(r3, Operand(kSmiTagMask));
469 __ b(eq, &miss);
470
471 // Check that the map of the object hasn't changed.
472 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
473 __ cmp(r1, Operand(Handle<Map>(object->map())));
474 __ b(ne, &miss);
475
476 // Perform global security token check if needed.
477 if (object->IsJSGlobalObject()) {
478 __ CheckAccessGlobal(r3, r1, &miss);
479 }
480
481 // Stub never generated for non-global objects that require access
482 // checks.
483 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded());
484
485 __ ldr(ip, MemOperand(sp)); // receiver
486 __ push(ip);
487 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
488 __ push(ip);
489 __ push(r2); // name
490 __ push(r0); // value
491
mads.s.ager31e71382008-08-13 09:32:07 +0000492 // Do tail-call to the runtime system.
493 ExternalReference store_callback_property =
494 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
495 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496
497 // Handle store cache miss.
498 __ bind(&miss);
499 __ mov(r2, Operand(Handle<String>(name))); // restore name
500 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
501 __ Jump(ic, code_target);
502
503 // Return the generated code.
504 return GetCode(CALLBACKS);
505}
506
507
508Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
509 String* name) {
510 // ----------- S t a t e -------------
511 // -- r0 : value
512 // -- r2 : name
513 // -- lr : return address
514 // -- [sp] : receiver
515 // -----------------------------------
516
517 HandleScope scope;
518 Label miss;
519
520 // Get the object from the stack.
521 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
522
523 // Check that the object isn't a smi.
524 __ tst(r3, Operand(kSmiTagMask));
525 __ b(eq, &miss);
526
527 // Check that the map of the object hasn't changed.
528 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
529 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
530 __ b(ne, &miss);
531
532 // Perform global security token check if needed.
533 if (receiver->IsJSGlobalObject()) {
534 __ CheckAccessGlobal(r3, r1, &miss);
535 }
536
537 // Stub never generated for non-global objects that require access
538 // checks.
539 ASSERT(receiver->IsJSGlobalObject() || !receiver->IsAccessCheckNeeded());
540
541 __ ldr(ip, MemOperand(sp)); // receiver
542 __ push(ip);
543 __ push(r2); // name
544 __ push(r0); // value
545
mads.s.ager31e71382008-08-13 09:32:07 +0000546 // Do tail-call to the runtime system.
547 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000549 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550
551 // Handle store cache miss.
552 __ bind(&miss);
553 __ mov(r2, Operand(Handle<String>(name))); // restore name
554 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
555 __ Jump(ic, code_target);
556
557 // Return the generated code.
558 return GetCode(INTERCEPTOR);
559}
560
561
562Object* LoadStubCompiler::CompileLoadField(JSObject* object,
563 JSObject* holder,
564 int index) {
565 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 // -- r2 : name
567 // -- lr : return address
568 // -- [sp] : receiver
569 // -----------------------------------
570
571 HandleScope scope;
572 Label miss;
573
mads.s.ager31e71382008-08-13 09:32:07 +0000574 __ ldr(r0, MemOperand(sp, 0));
575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576 // Check that the receiver isn't a smi.
577 __ tst(r0, Operand(kSmiTagMask));
578 __ b(eq, &miss);
579
580 // Check that the maps haven't changed.
581 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
582
583 // Get the properties array of the holder.
584 __ ldr(r3, FieldMemOperand(reg, JSObject::kPropertiesOffset));
585
586 // Return the value from the properties array.
587 int offset = index * kPointerSize + Array::kHeaderSize;
588 __ ldr(r0, FieldMemOperand(r3, offset));
589 __ Ret();
590
591 // Handle load cache miss.
592 __ bind(&miss);
593 __ ldr(r0, MemOperand(sp)); // restore receiver
594 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
595 __ Jump(ic, code_target);
596
597 // Return the generated code.
598 return GetCode(FIELD);
599}
600
601
602Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
603 JSObject* holder,
604 AccessorInfo* callback) {
605 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000606 // -- r2 : name
607 // -- lr : return address
608 // -- [sp] : receiver
609 // -----------------------------------
610
611 HandleScope scope;
612 Label miss;
613
mads.s.ager31e71382008-08-13 09:32:07 +0000614 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 // Check that the receiver isn't a smi.
616 __ tst(r0, Operand(kSmiTagMask));
617 __ b(eq, &miss);
618
619 // Check that the maps haven't changed.
620 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
621
622 // Push the arguments on the JS stack of the caller.
623 __ push(r0); // receiver
624 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
625 __ push(ip);
626 __ push(r2); // name
627 __ push(reg); // holder
628
mads.s.ager31e71382008-08-13 09:32:07 +0000629 // Do tail-call to the runtime system.
630 ExternalReference load_callback_property =
631 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
632 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633
634 // Handle load cache miss.
635 __ bind(&miss);
636 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
637 __ Jump(ic, code_target);
638
639 // Return the generated code.
640 return GetCode(CALLBACKS);
641}
642
643
644Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
645 JSObject* holder,
646 Object* value) {
647 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 // -- r2 : name
649 // -- lr : return address
650 // -- [sp] : receiver
651 // -----------------------------------
652
653 HandleScope scope;
654 Label miss;
655
mads.s.ager31e71382008-08-13 09:32:07 +0000656 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 // Check that the receiver isn't a smi.
658 __ tst(r0, Operand(kSmiTagMask));
659 __ b(eq, &miss);
660
661 // Check that the maps haven't changed.
662 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
663
664 // Return the constant value.
665 __ mov(r0, Operand(Handle<Object>(value)));
666 __ Ret();
667
668 // Handle load cache miss.
669 __ bind(&miss);
670 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
671 __ Jump(ic, code_target);
672
673 // Return the generated code.
674 return GetCode(CONSTANT_FUNCTION);
675}
676
677
678Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
679 JSObject* holder,
680 String* name) {
681 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 // -- r2 : name
683 // -- lr : return address
684 // -- [sp] : receiver
685 // -----------------------------------
686
687 HandleScope scope;
688 Label miss;
689
mads.s.ager31e71382008-08-13 09:32:07 +0000690 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691 // Check that the receiver isn't a smi.
692 __ tst(r0, Operand(kSmiTagMask));
693 __ b(eq, &miss);
694
695 // Check that the maps haven't changed.
696 Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss);
697
698 // Push the arguments on the JS stack of the caller.
699 __ push(r0); // receiver
700 __ push(reg); // holder
701 __ push(r2); // name
702
mads.s.ager31e71382008-08-13 09:32:07 +0000703 // Do tail-call to the runtime system.
704 ExternalReference load_ic_property =
705 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
706 __ TailCallRuntime(load_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707
708 // Handle load cache miss.
709 __ bind(&miss);
710 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Miss));
711 __ Jump(ic, code_target);
712
713 // Return the generated code.
714 return GetCode(INTERCEPTOR);
715}
716
717
718// TODO(1224671): IC stubs for keyed loads have not been implemented
719// for ARM.
720Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
721 JSObject* receiver,
722 JSObject* holder,
723 int index) {
724 UNIMPLEMENTED();
725 return Heap::undefined_value();
726}
727
728
729Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
730 JSObject* receiver,
731 JSObject* holder,
732 AccessorInfo* callback) {
733 UNIMPLEMENTED();
734 return Heap::undefined_value();
735}
736
737
738Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
739 JSObject* receiver,
740 JSObject* holder,
741 Object* value) {
742 UNIMPLEMENTED();
743 return Heap::undefined_value();
744}
745
746
747Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
748 JSObject* holder,
749 String* name) {
750 UNIMPLEMENTED();
751 return Heap::undefined_value();
752}
753
754
755Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
756 UNIMPLEMENTED();
757 return Heap::undefined_value();
758}
759
760
761Object* KeyedLoadStubCompiler::CompileLoadShortStringLength(String* name) {
762 UNIMPLEMENTED();
763 return Heap::undefined_value();
764}
765
766
767Object* KeyedLoadStubCompiler::CompileLoadMediumStringLength(String* name) {
768 UNIMPLEMENTED();
769 return Heap::undefined_value();
770}
771
772
773Object* KeyedLoadStubCompiler::CompileLoadLongStringLength(String* name) {
774 UNIMPLEMENTED();
775 return Heap::undefined_value();
776}
777
778
779Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
780 UNIMPLEMENTED();
781 return Heap::undefined_value();
782}
783
784
785Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
786 int index,
787 Map* transition,
788 String* name) {
789 UNIMPLEMENTED();
790 return Heap::undefined_value();
791}
792
793
794
795#undef __
796
797} } // namespace v8::internal