blob: e7fe0b9bdfe9c95f7c1de03393ac03a170c56630 [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.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000106 __ ldr(scratch, FieldMemOperand(name, String::kLengthOffset));
107 __ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 __ 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
ager@chromium.org7c537e22008-10-16 08:43:32 +0000151// Load a fast property out of a holder object (src). In-object properties
152// are loaded directly otherwise the property is loaded from the properties
153// fixed array.
154void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
155 Register dst, Register src,
156 JSObject* holder, int index) {
157 // Adjust for the number of properties stored in the holder.
158 index -= holder->map()->inobject_properties();
159 if (index < 0) {
160 // Get the property straight out of the holder.
161 int offset = holder->map()->instance_size() + (index * kPointerSize);
162 __ ldr(dst, FieldMemOperand(src, offset));
163 } else {
164 // Calculate the offset into the properties array.
165 int offset = index * kPointerSize + Array::kHeaderSize;
166 __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
167 __ ldr(dst, FieldMemOperand(dst, offset));
168 }
169}
170
171
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000172void StubCompiler::GenerateLoadField(MacroAssembler* masm,
173 JSObject* object,
174 JSObject* holder,
175 Register receiver,
176 Register scratch1,
177 Register scratch2,
178 int index,
179 Label* miss_label) {
180 // Check that the receiver isn't a smi.
181 __ tst(receiver, Operand(kSmiTagMask));
182 __ b(eq, miss_label);
183
184 // Check that the maps haven't changed.
185 Register reg =
186 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
187 GenerateFastPropertyLoad(masm, r0, reg, holder, index);
188 __ Ret();
189}
190
191
192void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
193 JSObject* object,
194 JSObject* holder,
195 Register receiver,
196 Register scratch1,
197 Register scratch2,
198 Object* value,
199 Label* miss_label) {
200 // Check that the receiver isn't a smi.
201 __ tst(receiver, Operand(kSmiTagMask));
202 __ b(eq, miss_label);
203
204 // Check that the maps haven't changed.
205 Register reg =
206 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
207
208 // Return the constant value.
209 __ mov(r0, Operand(Handle<Object>(value)));
210 __ Ret();
211}
212
213
214void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
215 JSObject* object,
216 JSObject* holder,
217 Register receiver,
218 Register name,
219 Register scratch1,
220 Register scratch2,
221 AccessorInfo* callback,
222 Label* miss_label) {
223 // Check that the receiver isn't a smi.
224 __ tst(receiver, Operand(kSmiTagMask));
225 __ b(eq, miss_label);
226
227 // Check that the maps haven't changed.
228 Register reg =
229 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
230
231 // Push the arguments on the JS stack of the caller.
232 __ push(receiver); // receiver
233 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback data
234 __ push(ip);
235 __ push(name); // name
236 __ push(reg); // holder
237
238 // Do tail-call to the runtime system.
239 ExternalReference load_callback_property =
240 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
241 __ TailCallRuntime(load_callback_property, 4);
242}
243
244
245void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
246 JSObject* object,
247 JSObject* holder,
248 Register receiver,
249 Register name,
250 Register scratch1,
251 Register scratch2,
252 Label* miss_label) {
253 // Check that the receiver isn't a smi.
254 __ tst(receiver, Operand(kSmiTagMask));
255 __ b(eq, miss_label);
256
257 // Check that the maps haven't changed.
258 Register reg =
259 __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
260
261 // Push the arguments on the JS stack of the caller.
262 __ push(receiver); // receiver
263 __ push(reg); // holder
264 __ push(name); // name
265
266 // Do tail-call to the runtime system.
267 ExternalReference load_ic_property =
268 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
269 __ TailCallRuntime(load_ic_property, 3);
270}
271
272
273void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
274 Register receiver,
275 Register scratch,
276 Label* miss_label) {
277 // Check that the receiver isn't a smi.
278 __ tst(receiver, Operand(kSmiTagMask));
279 __ b(eq, miss_label);
280
281 // Check that the object is a JS array.
282 __ ldr(scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
283 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
284 __ cmp(scratch, Operand(JS_ARRAY_TYPE));
285 __ b(ne, miss_label);
286
287 // Load length directly from the JS array.
288 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
289 __ Ret();
290}
291
292
293void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
294 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
295 Code* code = NULL;
296 if (kind == Code::LOAD_IC) {
297 code = Builtins::builtin(Builtins::LoadIC_Miss);
298 } else {
299 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
300 }
301
302 Handle<Code> ic(code);
303 __ Jump(ic, RelocInfo::CODE_TARGET);
304}
305
306
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307#undef __
308
309#define __ masm()->
310
311
312Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000313 // ----------- S t a t e -------------
314 // -- r1: function
315 // -- lr: return address
316 // -----------------------------------
317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 HandleScope scope;
319
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000320 // Enter an internal frame.
321 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000323 // Preserve the function.
324 __ push(r1);
325
326 // Push the function on the stack as the argument to the runtime function.
327 __ push(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328 __ CallRuntime(Runtime::kLazyCompile, 1);
329
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000330 // Calculate the entry point.
331 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000333 // Restore saved function.
334 __ pop(r1);
335
336 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000337 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338
339 // Do a tail-call of the compiled function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000340 __ Jump(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341
342 return GetCodeWithFlags(flags);
343}
344
345
346Object* CallStubCompiler::CompileCallField(Object* object,
347 JSObject* holder,
348 int index) {
349 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 // -- lr: return address
351 // -----------------------------------
352
353 HandleScope scope;
354 Label miss;
355
mads.s.ager31e71382008-08-13 09:32:07 +0000356 const int argc = arguments().immediate();
357
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000358 // Get the receiver of the function from the stack into r0.
359 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 // Check that the receiver isn't a smi.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000361 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 __ b(eq, &miss);
363
364 // Do the right check and compute the holder register.
365 Register reg =
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000366 __ CheckMaps(JSObject::cast(object), r0, holder, r3, r2, &miss);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000367 GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368
369 // Check that the function really is a function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000370 __ tst(r1, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371 __ b(eq, &miss);
372 // Get the map.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000373 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
375 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
376 __ b(ne, &miss);
377
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000378 // Patch the receiver on the stack with the global proxy if
379 // necessary.
380 if (object->IsGlobalObject()) {
381 __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
382 __ str(r3, MemOperand(sp, argc * kPointerSize));
383 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000385 // Invoke the function.
386 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387
388 // Handle call cache miss.
389 __ bind(&miss);
390 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000391 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392
393 // Return the generated code.
394 return GetCode(FIELD);
395}
396
397
398Object* CallStubCompiler::CompileCallConstant(Object* object,
399 JSObject* holder,
400 JSFunction* function,
401 CheckType check) {
402 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000403 // -- lr: return address
404 // -----------------------------------
405
406 HandleScope scope;
407 Label miss;
408
mads.s.ager31e71382008-08-13 09:32:07 +0000409 // Get the receiver from the stack
410 const int argc = arguments().immediate();
411 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 // Check that the receiver isn't a smi.
414 if (check != NUMBER_CHECK) {
415 __ tst(r1, Operand(kSmiTagMask));
416 __ b(eq, &miss);
417 }
418
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000419 // Make sure that it's okay not to patch the on stack receiver
420 // unless we're doing a receiver map check.
421 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423 switch (check) {
424 case RECEIVER_MAP_CHECK:
425 // Check that the maps haven't changed.
426 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000427
428 // Patch the receiver on the stack with the global proxy if
429 // necessary.
430 if (object->IsGlobalObject()) {
431 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
432 __ str(r3, MemOperand(sp, argc * kPointerSize));
433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434 break;
435
436 case STRING_CHECK:
437 // Check that the object is a two-byte string or a symbol.
438 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
439 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
440 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
441 __ b(hs, &miss);
442 // Check that the maps starting from the prototype haven't changed.
443 GenerateLoadGlobalFunctionPrototype(masm(),
444 Context::STRING_FUNCTION_INDEX,
445 r2);
446 __ CheckMaps(JSObject::cast(object->GetPrototype()),
447 r2, holder, r3, r1, &miss);
448 break;
449
450 case NUMBER_CHECK: {
451 Label fast;
452 // Check that the object is a smi or a heap number.
453 __ tst(r1, Operand(kSmiTagMask));
454 __ b(eq, &fast);
455 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
456 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
457 __ cmp(r2, Operand(HEAP_NUMBER_TYPE));
458 __ b(ne, &miss);
459 __ bind(&fast);
460 // Check that the maps starting from the prototype haven't changed.
461 GenerateLoadGlobalFunctionPrototype(masm(),
462 Context::NUMBER_FUNCTION_INDEX,
463 r2);
464 __ CheckMaps(JSObject::cast(object->GetPrototype()),
465 r2, holder, r3, r1, &miss);
466 break;
467 }
468
469 case BOOLEAN_CHECK: {
470 Label fast;
471 // Check that the object is a boolean.
472 __ cmp(r1, Operand(Factory::true_value()));
473 __ b(eq, &fast);
474 __ cmp(r1, Operand(Factory::false_value()));
475 __ b(ne, &miss);
476 __ bind(&fast);
477 // Check that the maps starting from the prototype haven't changed.
478 GenerateLoadGlobalFunctionPrototype(masm(),
479 Context::BOOLEAN_FUNCTION_INDEX,
480 r2);
481 __ CheckMaps(JSObject::cast(object->GetPrototype()),
482 r2, holder, r3, r1, &miss);
483 break;
484 }
485
486 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
487 __ CheckMaps(JSObject::cast(object), r1, holder, r3, r2, &miss);
488 // Make sure object->elements()->map() != Heap::hash_table_map()
489 // Get the elements array of the object.
490 __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
491 // Check that the object is in fast mode (not dictionary).
492 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
493 __ cmp(r2, Operand(Factory::hash_table_map()));
494 __ b(eq, &miss);
495 break;
496
497 default:
498 UNREACHABLE();
499 }
500
501 // Get the function and setup the context.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000502 __ mov(r1, Operand(Handle<JSFunction>(function)));
503 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505 // Jump to the cached code (tail call).
506 Handle<Code> code(function->code());
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000507 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000508 __ InvokeCode(code, expected, arguments(),
509 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510
511 // Handle call cache miss.
512 __ bind(&miss);
513 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000514 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515
516 // Return the generated code.
517 return GetCode(CONSTANT_FUNCTION);
518}
519
520
521Object* CallStubCompiler::CompileCallInterceptor(Object* object,
522 JSObject* holder,
523 String* name) {
524 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525 // -- lr: return address
526 // -----------------------------------
527
528 HandleScope scope;
529 Label miss;
530
531 // TODO(1224669): Implement.
532
533 // Handle call cache miss.
534 __ bind(&miss);
535 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000536 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537
538 // Return the generated code.
539 return GetCode(INTERCEPTOR);
540}
541
542
543Object* StoreStubCompiler::CompileStoreField(JSObject* object,
544 int index,
545 Map* transition,
546 String* name) {
547 // ----------- S t a t e -------------
548 // -- r0 : value
549 // -- r2 : name
550 // -- lr : return address
551 // -- [sp] : receiver
552 // -----------------------------------
553
554 HandleScope scope;
555 Label miss, exit;
556
557 // Get the receiver from the stack.
558 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
559
560 // Check that the receiver isn't a smi.
561 __ tst(r3, Operand(kSmiTagMask));
562 __ b(eq, &miss);
563
564 // Check that the map of the receiver hasn't changed.
565 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
566 __ cmp(r1, Operand(Handle<Map>(object->map())));
567 __ b(ne, &miss);
568
569 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000570 if (object->IsJSGlobalProxy()) {
571 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 }
573
574 // Stub never generated for non-global objects that require access
575 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000576 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578 // Perform map transition for the receiver if necessary.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000579 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
580 // The properties must be extended before we can store the value.
581 // We jump to a runtime call that extends the propeties array.
582 __ mov(r2, Operand(Handle<Map>(transition)));
583 // Please note, if we implement keyed store for arm we need
584 // to call the Builtins::KeyedStoreIC_ExtendStorage.
585 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
586 __ Jump(ic, RelocInfo::CODE_TARGET);
587 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000588 // Adjust for the number of properties stored in the object. Even in the
589 // face of a transition we can use the old map here because the size of the
590 // object and the number of in-object properties is not going to change.
591 index -= object->map()->inobject_properties();
592
593 if (index >= 0) {
594 // Get the properties array
595 __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
596 }
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000597
598 if (transition != NULL) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000599 // Update the map of the object; no write barrier updating is
600 // needed because the map is never in new space.
601 __ mov(ip, Operand(Handle<Map>(transition)));
602 __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
603 }
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000604
ager@chromium.org7c537e22008-10-16 08:43:32 +0000605 if (index < 0) {
606 // Set the property straight into the object.
607 int offset = object->map()->instance_size() + (index * kPointerSize);
608 __ str(r0, FieldMemOperand(r3, offset));
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000609
ager@chromium.org7c537e22008-10-16 08:43:32 +0000610 // Skip updating write barrier if storing a smi.
611 __ tst(r0, Operand(kSmiTagMask));
612 __ b(eq, &exit);
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000613
ager@chromium.org7c537e22008-10-16 08:43:32 +0000614 // Update the write barrier for the array address.
615 __ mov(r1, Operand(offset));
616 __ RecordWrite(r3, r1, r2);
617 } else {
618 // Write to the properties array.
619 int offset = index * kPointerSize + Array::kHeaderSize;
620 __ str(r0, FieldMemOperand(r1, offset));
621
622 // Skip updating write barrier if storing a smi.
623 __ tst(r0, Operand(kSmiTagMask));
624 __ b(eq, &exit);
625
626 // Update the write barrier for the array address.
627 __ mov(r3, Operand(offset));
628 __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return
629 }
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000630
631 // Return the value (register r0).
632 __ bind(&exit);
633 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635 // Handle store cache miss.
636 __ bind(&miss);
637 __ mov(r2, Operand(Handle<String>(name))); // restore name
638 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000639 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640
641 // Return the generated code.
642 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
643}
644
645
646Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
647 AccessorInfo* callback,
648 String* name) {
649 // ----------- S t a t e -------------
650 // -- r0 : value
651 // -- r2 : name
652 // -- lr : return address
653 // -- [sp] : receiver
654 // -----------------------------------
655
656 HandleScope scope;
657 Label miss;
658
659 // Get the object from the stack.
660 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
661
662 // Check that the object isn't a smi.
663 __ tst(r3, Operand(kSmiTagMask));
664 __ b(eq, &miss);
665
666 // Check that the map of the object hasn't changed.
667 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
668 __ cmp(r1, Operand(Handle<Map>(object->map())));
669 __ b(ne, &miss);
670
671 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000672 if (object->IsJSGlobalProxy()) {
673 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 }
675
676 // Stub never generated for non-global objects that require access
677 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000678 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679
680 __ ldr(ip, MemOperand(sp)); // receiver
681 __ push(ip);
682 __ mov(ip, Operand(Handle<AccessorInfo>(callback))); // callback info
683 __ push(ip);
684 __ push(r2); // name
685 __ push(r0); // value
686
mads.s.ager31e71382008-08-13 09:32:07 +0000687 // Do tail-call to the runtime system.
688 ExternalReference store_callback_property =
689 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
690 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691
692 // Handle store cache miss.
693 __ bind(&miss);
694 __ mov(r2, Operand(Handle<String>(name))); // restore name
695 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000696 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697
698 // Return the generated code.
699 return GetCode(CALLBACKS);
700}
701
702
703Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
704 String* name) {
705 // ----------- S t a t e -------------
706 // -- r0 : value
707 // -- r2 : name
708 // -- lr : return address
709 // -- [sp] : receiver
710 // -----------------------------------
711
712 HandleScope scope;
713 Label miss;
714
715 // Get the object from the stack.
716 __ ldr(r3, MemOperand(sp, 0 * kPointerSize));
717
718 // Check that the object isn't a smi.
719 __ tst(r3, Operand(kSmiTagMask));
720 __ b(eq, &miss);
721
722 // Check that the map of the object hasn't changed.
723 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
724 __ cmp(r1, Operand(Handle<Map>(receiver->map())));
725 __ b(ne, &miss);
726
727 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000728 if (receiver->IsJSGlobalProxy()) {
729 __ CheckAccessGlobalProxy(r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 }
731
732 // Stub never generated for non-global objects that require access
733 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000734 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735
736 __ ldr(ip, MemOperand(sp)); // receiver
737 __ push(ip);
738 __ push(r2); // name
739 __ push(r0); // value
740
mads.s.ager31e71382008-08-13 09:32:07 +0000741 // Do tail-call to the runtime system.
742 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000744 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745
746 // Handle store cache miss.
747 __ bind(&miss);
748 __ mov(r2, Operand(Handle<String>(name))); // restore name
749 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000750 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751
752 // Return the generated code.
753 return GetCode(INTERCEPTOR);
754}
755
756
757Object* LoadStubCompiler::CompileLoadField(JSObject* object,
758 JSObject* holder,
759 int index) {
760 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000761 // -- r2 : name
762 // -- lr : return address
763 // -- [sp] : receiver
764 // -----------------------------------
765
766 HandleScope scope;
767 Label miss;
768
mads.s.ager31e71382008-08-13 09:32:07 +0000769 __ ldr(r0, MemOperand(sp, 0));
770
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000771 GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000773 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774
775 // Return the generated code.
776 return GetCode(FIELD);
777}
778
779
780Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
781 JSObject* holder,
782 AccessorInfo* callback) {
783 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784 // -- r2 : name
785 // -- lr : return address
786 // -- [sp] : receiver
787 // -----------------------------------
788
789 HandleScope scope;
790 Label miss;
791
mads.s.ager31e71382008-08-13 09:32:07 +0000792 __ ldr(r0, MemOperand(sp, 0));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000793 GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000794 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000795 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796
797 // Return the generated code.
798 return GetCode(CALLBACKS);
799}
800
801
802Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
803 JSObject* holder,
804 Object* value) {
805 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806 // -- r2 : name
807 // -- lr : return address
808 // -- [sp] : receiver
809 // -----------------------------------
810
811 HandleScope scope;
812 Label miss;
813
mads.s.ager31e71382008-08-13 09:32:07 +0000814 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000815
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000816 GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000818 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819
820 // Return the generated code.
821 return GetCode(CONSTANT_FUNCTION);
822}
823
824
825Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
826 JSObject* holder,
827 String* name) {
828 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829 // -- r2 : name
830 // -- lr : return address
831 // -- [sp] : receiver
832 // -----------------------------------
833
834 HandleScope scope;
835 Label miss;
836
mads.s.ager31e71382008-08-13 09:32:07 +0000837 __ ldr(r0, MemOperand(sp, 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000838
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000839 GenerateLoadInterceptor(masm(), object, holder, r0, r2, r3, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000841 GenerateLoadMiss(masm(), Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
843 // Return the generated code.
844 return GetCode(INTERCEPTOR);
845}
846
847
848// TODO(1224671): IC stubs for keyed loads have not been implemented
849// for ARM.
850Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
851 JSObject* receiver,
852 JSObject* holder,
853 int index) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000854 // ----------- S t a t e -------------
855 // -- lr : return address
856 // -- sp[0] : key
857 // -- sp[4] : receiver
858 // -----------------------------------
859 HandleScope scope;
860 Label miss;
861
862 __ ldr(r2, MemOperand(sp, 0));
863 __ ldr(r0, MemOperand(sp, kPointerSize));
864
865 __ cmp(r2, Operand(Handle<String>(name)));
866 __ b(ne, &miss);
867
868 GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss);
869 __ bind(&miss);
870 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
871
872 return GetCode(FIELD);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873}
874
875
876Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
877 JSObject* receiver,
878 JSObject* holder,
879 AccessorInfo* callback) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000880 // ----------- S t a t e -------------
881 // -- lr : return address
882 // -- sp[0] : key
883 // -- sp[4] : receiver
884 // -----------------------------------
885 HandleScope scope;
886 Label miss;
887
888 __ ldr(r2, MemOperand(sp, 0));
889 __ ldr(r0, MemOperand(sp, kPointerSize));
890
891 __ cmp(r2, Operand(Handle<String>(name)));
892 __ b(ne, &miss);
893
894 GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3,
895 r1, callback, &miss);
896 __ bind(&miss);
897 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
898
899 return GetCode(CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900}
901
902
903Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
904 JSObject* receiver,
905 JSObject* holder,
906 Object* value) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000907 // ----------- S t a t e -------------
908 // -- lr : return address
909 // -- sp[0] : key
910 // -- sp[4] : receiver
911 // -----------------------------------
912 HandleScope scope;
913 Label miss;
914
915 // Check the key is the cached one
916 __ ldr(r2, MemOperand(sp, 0));
917 __ ldr(r0, MemOperand(sp, kPointerSize));
918
919 __ cmp(r2, Operand(Handle<String>(name)));
920 __ b(ne, &miss);
921
922 GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss);
923 __ bind(&miss);
924 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
925
926 // Return the generated code.
927 return GetCode(CONSTANT_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928}
929
930
931Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
932 JSObject* holder,
933 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000934 // ----------- S t a t e -------------
935 // -- lr : return address
936 // -- sp[0] : key
937 // -- sp[4] : receiver
938 // -----------------------------------
939 HandleScope scope;
940 Label miss;
941
942 // Check the key is the cached one
943 __ ldr(r2, MemOperand(sp, 0));
944 __ ldr(r0, MemOperand(sp, kPointerSize));
945
946 __ cmp(r2, Operand(Handle<String>(name)));
947 __ b(ne, &miss);
948
949 GenerateLoadInterceptor(masm(), receiver, holder, r0, r2, r3, r1, &miss);
950 __ bind(&miss);
951 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
952
953 return GetCode(INTERCEPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954}
955
956
957Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000958 // ----------- S t a t e -------------
959 // -- lr : return address
960 // -- sp[0] : key
961 // -- sp[4] : receiver
962 // -----------------------------------
963 HandleScope scope;
964 Label miss;
965
966 // Check the key is the cached one
967 __ ldr(r2, MemOperand(sp, 0));
968 __ ldr(r0, MemOperand(sp, kPointerSize));
969
970 __ cmp(r2, Operand(Handle<String>(name)));
971 __ b(ne, &miss);
972
973 GenerateLoadArrayLength(masm(), r0, r3, &miss);
974 __ bind(&miss);
975 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
976
977 return GetCode(CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000978}
979
980
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000981// TODO(1224671): implement the fast case.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000982Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000983 // ----------- S t a t e -------------
984 // -- lr : return address
985 // -- sp[0] : key
986 // -- sp[4] : receiver
987 // -----------------------------------
988 HandleScope scope;
989 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
990
991 return GetCode(CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000997 // ----------- S t a t e -------------
998 // -- lr : return address
999 // -- sp[0] : key
1000 // -- sp[4] : receiver
1001 // -----------------------------------
1002 HandleScope scope;
1003 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1004
1005 return GetCode(CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001009// TODO(1224671): implement the fast case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
1011 int index,
1012 Map* transition,
1013 String* name) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001014 // ----------- S t a t e -------------
1015 // -- r0 : value
1016 // -- r2 : name
1017 // -- lr : return address
1018 // -- [sp] : receiver
1019 // -----------------------------------
1020 HandleScope scope;
1021 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
1022 __ Jump(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001024 // Return the generated code.
1025 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION);
1026}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027
1028
1029#undef __
1030
1031} } // namespace v8::internal