blob: ce4981d72e8a73e4aa9ed53e30e8c1cd61afebb0 [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,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000044 Register offset,
45 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046 ExternalReference key_offset(SCTableReference::keyReference(table));
47 ExternalReference value_offset(SCTableReference::valueReference(table));
48
49 Label miss;
50
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000051 if (extra.is_valid()) {
52 // Get the code entry from the cache.
53 __ mov(extra, Operand::StaticArray(offset, times_2, value_offset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000055 // Check that the key in the entry matches the name.
56 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
57 __ j(not_equal, &miss, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000059 // Check that the flags match what we're looking for.
60 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
61 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
62 __ cmp(offset, flags);
63 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000065 // Jump to the first instruction in the code stub.
66 __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag));
67 __ jmp(Operand(extra));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000069 __ bind(&miss);
70 } else {
71 // Save the offset on the stack.
72 __ push(offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000074 // Check that the key in the entry matches the name.
75 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
76 __ j(not_equal, &miss, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000078 // Get the code entry from the cache.
79 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
80
81 // Check that the flags match what we're looking for.
82 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
83 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
84 __ cmp(offset, flags);
85 __ j(not_equal, &miss);
86
87 // Restore offset and re-load code entry from cache.
88 __ pop(offset);
89 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
90
91 // Jump to the first instruction in the code stub.
92 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
93 __ jmp(Operand(offset));
94
95 // Pop at miss.
96 __ bind(&miss);
97 __ pop(offset);
98 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099}
100
101
102void StubCache::GenerateProbe(MacroAssembler* masm,
103 Code::Flags flags,
104 Register receiver,
105 Register name,
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000106 Register scratch,
107 Register extra) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 Label miss;
109
110 // Make sure that code is valid. The shifting code relies on the
111 // entry size being 8.
112 ASSERT(sizeof(Entry) == 8);
113
114 // Make sure the flags does not name a specific type.
115 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
116
117 // Make sure that there are no register conflicts.
118 ASSERT(!scratch.is(receiver));
119 ASSERT(!scratch.is(name));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000120 ASSERT(!extra.is(receiver));
121 ASSERT(!extra.is(name));
122 ASSERT(!extra.is(scratch));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
124 // Check that the receiver isn't a smi.
125 __ test(receiver, Immediate(kSmiTagMask));
126 __ j(zero, &miss, not_taken);
127
128 // Get the map of the receiver and compute the hash.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000129 __ mov(scratch, FieldOperand(name, String::kLengthOffset));
130 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 __ xor_(scratch, flags);
132 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
133
134 // Probe the primary table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000135 ProbeTable(masm, flags, kPrimary, name, scratch, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136
137 // Primary miss: Compute hash for secondary probe.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000138 __ mov(scratch, FieldOperand(name, String::kLengthOffset));
139 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
140 __ xor_(scratch, flags);
141 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142 __ sub(scratch, Operand(name));
143 __ add(Operand(scratch), Immediate(flags));
144 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
145
146 // Probe the secondary table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000147 ProbeTable(masm, flags, kSecondary, name, scratch, extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148
149 // Cache miss: Fall-through and let caller handle the miss by
150 // entering the runtime system.
151 __ bind(&miss);
152}
153
154
155void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
156 int index,
157 Register prototype) {
158 // Load the global or builtins object from the current context.
159 __ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
160 // Load the global context from the global or builtins object.
161 __ mov(prototype,
162 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
163 // Load the function from the global context.
164 __ mov(prototype, Operand(prototype, Context::SlotOffset(index)));
165 // Load the initial map. The global functions all have initial maps.
166 __ mov(prototype,
167 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
168 // Load the prototype from the initial map.
169 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
170}
171
172
173void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
174 Register receiver,
175 Register scratch,
176 Label* miss_label) {
177 // Check that the receiver isn't a smi.
178 __ test(receiver, Immediate(kSmiTagMask));
179 __ j(zero, miss_label, not_taken);
180
181 // Check that the object is a JS array.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000182 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 __ j(not_equal, miss_label, not_taken);
184
185 // Load length directly from the JS array.
186 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
187 __ ret(0);
188}
189
190
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000191// Generate code to check if an object is a string. If the object is
192// a string, the map's instance type is left in the scratch register.
193static void GenerateStringCheck(MacroAssembler* masm,
194 Register receiver,
195 Register scratch,
196 Label* smi,
197 Label* non_string_object) {
198 // Check that the object isn't a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 __ test(receiver, Immediate(kSmiTagMask));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000200 __ j(zero, smi, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000202 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
204 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000205 ASSERT(kNotStringTag != 0);
206 __ test(scratch, Immediate(kNotStringTag));
207 __ j(not_zero, non_string_object, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208}
209
210
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000211void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
212 Register receiver,
213 Register scratch,
214 Label* miss) {
215 Label load_length, check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000217 // Check if the object is a string leaving the instance type in the
218 // scratch register.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000219 GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220
221 // Load length directly from the string.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000222 __ bind(&load_length);
223 __ and_(scratch, kStringSizeMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000225 // ecx is also the receiver.
226 __ lea(ecx, Operand(scratch, String::kLongLengthShift));
227 __ shr(eax); // ecx is implicit shift register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228 __ shl(eax, kSmiTagSize);
229 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000230
231 // Check if the object is a JSValue wrapper.
232 __ bind(&check_wrapper);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000233 __ cmp(scratch, JS_VALUE_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000234 __ j(not_equal, miss, not_taken);
235
236 // Check if the wrapped value is a string and load the length
237 // directly if it is.
238 __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
239 GenerateStringCheck(masm, receiver, scratch, miss, miss);
240 __ jmp(&load_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241}
242
243
244void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
245 Register receiver,
246 Register scratch1,
247 Register scratch2,
248 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000249 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 __ mov(eax, Operand(scratch1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000252}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253
ager@chromium.org7c537e22008-10-16 08:43:32 +0000254
255// Load a fast property out of a holder object (src). In-object properties
256// are loaded directly otherwise the property is loaded from the properties
257// fixed array.
258void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000259 Register dst, Register src,
260 JSObject* holder, int index) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000261 // Adjust for the number of properties stored in the holder.
262 index -= holder->map()->inobject_properties();
263 if (index < 0) {
264 // Get the property straight out of the holder.
265 int offset = holder->map()->instance_size() + (index * kPointerSize);
266 __ mov(dst, FieldOperand(src, offset));
267 } else {
268 // Calculate the offset into the properties array.
269 int offset = index * kPointerSize + Array::kHeaderSize;
270 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
271 __ mov(dst, FieldOperand(dst, offset));
272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273}
274
275
276void StubCompiler::GenerateLoadField(MacroAssembler* masm,
277 JSObject* object,
278 JSObject* holder,
279 Register receiver,
280 Register scratch1,
281 Register scratch2,
282 int index,
283 Label* miss_label) {
284 // Check that the receiver isn't a smi.
285 __ test(receiver, Immediate(kSmiTagMask));
286 __ j(zero, miss_label, not_taken);
287
288 // Check that the maps haven't changed.
289 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000290 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291
ager@chromium.org7c537e22008-10-16 08:43:32 +0000292 // Get the value from the properties.
293 GenerateFastPropertyLoad(masm, eax, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000294 __ ret(0);
295}
296
297
298void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
299 JSObject* object,
300 JSObject* holder,
301 Register receiver,
302 Register name,
303 Register scratch1,
304 Register scratch2,
305 AccessorInfo* callback,
306 Label* miss_label) {
307 // Check that the receiver isn't a smi.
308 __ test(receiver, Immediate(kSmiTagMask));
309 __ j(zero, miss_label, not_taken);
310
311 // Check that the maps haven't changed.
312 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000313 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314
315 // Push the arguments on the JS stack of the caller.
316 __ pop(scratch2); // remove return address
317 __ push(receiver); // receiver
318 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
319 __ push(name); // name
320 __ push(reg); // holder
321 __ push(scratch2); // restore return address
322
mads.s.ager31e71382008-08-13 09:32:07 +0000323 // Do tail-call to the runtime system.
324 ExternalReference load_callback_property =
325 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
326 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327}
328
329
330void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
331 JSObject* object,
332 JSObject* holder,
333 Register receiver,
334 Register scratch1,
335 Register scratch2,
336 Object* value,
337 Label* miss_label) {
338 // Check that the receiver isn't a smi.
339 __ test(receiver, Immediate(kSmiTagMask));
340 __ j(zero, miss_label, not_taken);
341
342 // Check that the maps haven't changed.
343 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000344 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
346 // Return the constant value.
347 __ mov(eax, Handle<Object>(value));
348 __ ret(0);
349}
350
351
352void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
353 JSObject* object,
354 JSObject* holder,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000355 Smi* lookup_hint,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356 Register receiver,
357 Register name,
358 Register scratch1,
359 Register scratch2,
360 Label* miss_label) {
361 // Check that the receiver isn't a smi.
362 __ test(receiver, Immediate(kSmiTagMask));
363 __ j(zero, miss_label, not_taken);
364
365 // Check that the maps haven't changed.
366 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000367 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368
369 // Push the arguments on the JS stack of the caller.
370 __ pop(scratch2); // remove return address
371 __ push(receiver); // receiver
372 __ push(reg); // holder
373 __ push(name); // name
ager@chromium.orge2902be2009-06-08 12:21:35 +0000374 // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or
375 // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method?
376 __ push(Immediate(lookup_hint));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377 __ push(scratch2); // restore return address
378
mads.s.ager31e71382008-08-13 09:32:07 +0000379 // Do tail-call to the runtime system.
380 ExternalReference load_ic_property =
381 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000382 __ TailCallRuntime(load_ic_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383}
384
385
386void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
387 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
388 Code* code = NULL;
389 if (kind == Code::LOAD_IC) {
390 code = Builtins::builtin(Builtins::LoadIC_Miss);
391 } else {
392 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
393 }
394
395 Handle<Code> ic(code);
ager@chromium.org236ad962008-09-25 09:45:57 +0000396 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397}
398
399
400void StubCompiler::GenerateStoreField(MacroAssembler* masm,
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000401 Builtins::Name storage_extend,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 JSObject* object,
403 int index,
404 Map* transition,
405 Register receiver_reg,
406 Register name_reg,
407 Register scratch,
408 Label* miss_label) {
409 // Check that the object isn't a smi.
410 __ test(receiver_reg, Immediate(kSmiTagMask));
411 __ j(zero, miss_label, not_taken);
412
413 // Check that the map of the object hasn't changed.
414 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
415 Immediate(Handle<Map>(object->map())));
416 __ j(not_equal, miss_label, not_taken);
417
418 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000419 if (object->IsJSGlobalProxy()) {
420 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421 }
422
423 // Stub never generated for non-global objects that require access
424 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000425 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000426
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000427 // Perform map transition for the receiver if necessary.
428 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
429 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000430 // We jump to a runtime call that extends the properties array.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000431 __ mov(ecx, Immediate(Handle<Map>(transition)));
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000432 Handle<Code> ic(Builtins::builtin(storage_extend));
433 __ jmp(ic, RelocInfo::CODE_TARGET);
434 return;
435 }
436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 if (transition != NULL) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000438 // Update the map of the object; no write barrier updating is
439 // needed because the map is never in new space.
440 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
441 Immediate(Handle<Map>(transition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000442 }
443
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000444 // Adjust for the number of properties stored in the object. Even in the
445 // face of a transition we can use the old map here because the size of the
446 // object and the number of in-object properties is not going to change.
447 index -= object->map()->inobject_properties();
448
ager@chromium.org7c537e22008-10-16 08:43:32 +0000449 if (index < 0) {
450 // Set the property straight into the object.
451 int offset = object->map()->instance_size() + (index * kPointerSize);
452 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453
ager@chromium.org7c537e22008-10-16 08:43:32 +0000454 // Update the write barrier for the array address.
455 // Pass the value being stored in the now unused name_reg.
456 __ mov(name_reg, Operand(eax));
457 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
458 } else {
459 // Write to the properties array.
460 int offset = index * kPointerSize + Array::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000461 // Get the properties array (optimistically).
462 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000463 __ mov(FieldOperand(scratch, offset), eax);
464
465 // Update the write barrier for the array address.
466 // Pass the value being stored in the now unused name_reg.
467 __ mov(name_reg, Operand(eax));
468 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470
471 // Return the value (register eax).
472 __ ret(0);
473}
474
475
476#undef __
477
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000478#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479
480
481// TODO(1241006): Avoid having lazy compile stubs specialized by the
482// number of arguments. It is not needed anymore.
483Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000485 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
487 // Push a copy of the function onto the stack.
488 __ push(edi);
489
490 __ push(edi); // function is also the parameter to the runtime call
491 __ CallRuntime(Runtime::kLazyCompile, 1);
492 __ pop(edi);
493
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000494 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000495 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496
497 // Do a tail-call of the compiled function.
498 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
499 __ jmp(Operand(ecx));
500
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000501 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502}
503
504
505Object* CallStubCompiler::CompileCallField(Object* object,
506 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000507 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000508 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509 // ----------- S t a t e -------------
510 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511 Label miss;
512
513 // Get the receiver from the stack.
514 const int argc = arguments().immediate();
515 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
516
517 // Check that the receiver isn't a smi.
518 __ test(edx, Immediate(kSmiTagMask));
519 __ j(zero, &miss, not_taken);
520
521 // Do the right check and compute the holder register.
522 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000523 masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524
ager@chromium.org7c537e22008-10-16 08:43:32 +0000525 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526
527 // Check that the function really is a function.
528 __ test(edi, Immediate(kSmiTagMask));
529 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000530 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 __ j(not_equal, &miss, not_taken);
532
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000533 // Patch the receiver on the stack with the global proxy if
534 // necessary.
535 if (object->IsGlobalObject()) {
536 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
537 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
538 }
539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 // Invoke the function.
541 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
542
543 // Handle call cache miss.
544 __ bind(&miss);
545 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000546 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547
548 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000549 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550}
551
552
553Object* CallStubCompiler::CompileCallConstant(Object* object,
554 JSObject* holder,
555 JSFunction* function,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000556 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 // ----------- S t a t e -------------
558 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 Label miss;
560
561 // Get the receiver from the stack.
562 const int argc = arguments().immediate();
563 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
564
565 // Check that the receiver isn't a smi.
566 if (check != NUMBER_CHECK) {
567 __ test(edx, Immediate(kSmiTagMask));
568 __ j(zero, &miss, not_taken);
569 }
570
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000571 // Make sure that it's okay not to patch the on stack receiver
572 // unless we're doing a receiver map check.
573 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575 switch (check) {
576 case RECEIVER_MAP_CHECK:
577 // Check that the maps haven't changed.
578 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000579
580 // Patch the receiver on the stack with the global proxy if
581 // necessary.
582 if (object->IsGlobalObject()) {
583 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
584 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000586 break;
587
588 case STRING_CHECK:
589 // Check that the object is a two-byte string or a symbol.
590 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
591 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
592 __ cmp(ecx, FIRST_NONSTRING_TYPE);
593 __ j(above_equal, &miss, not_taken);
594 // Check that the maps starting from the prototype haven't changed.
595 GenerateLoadGlobalFunctionPrototype(masm(),
596 Context::STRING_FUNCTION_INDEX,
597 ecx);
598 __ CheckMaps(JSObject::cast(object->GetPrototype()),
599 ecx, holder, ebx, edx, &miss);
600 break;
601
602 case NUMBER_CHECK: {
603 Label fast;
604 // Check that the object is a smi or a heap number.
605 __ test(edx, Immediate(kSmiTagMask));
606 __ j(zero, &fast, taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000607 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608 __ j(not_equal, &miss, not_taken);
609 __ bind(&fast);
610 // Check that the maps starting from the prototype haven't changed.
611 GenerateLoadGlobalFunctionPrototype(masm(),
612 Context::NUMBER_FUNCTION_INDEX,
613 ecx);
614 __ CheckMaps(JSObject::cast(object->GetPrototype()),
615 ecx, holder, ebx, edx, &miss);
616 break;
617 }
618
619 case BOOLEAN_CHECK: {
620 Label fast;
621 // Check that the object is a boolean.
622 __ cmp(edx, Factory::true_value());
623 __ j(equal, &fast, taken);
624 __ cmp(edx, Factory::false_value());
625 __ j(not_equal, &miss, not_taken);
626 __ bind(&fast);
627 // Check that the maps starting from the prototype haven't changed.
628 GenerateLoadGlobalFunctionPrototype(masm(),
629 Context::BOOLEAN_FUNCTION_INDEX,
630 ecx);
631 __ CheckMaps(JSObject::cast(object->GetPrototype()),
632 ecx, holder, ebx, edx, &miss);
633 break;
634 }
635
636 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
637 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
638 // Make sure object->elements()->map() != Heap::dictionary_array_map()
639 // Get the elements array of the object.
640 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
641 // Check that the object is in fast mode (not dictionary).
642 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
643 Immediate(Factory::hash_table_map()));
644 __ j(equal, &miss, not_taken);
645 break;
646
647 default:
648 UNREACHABLE();
649 }
650
651 // Get the function and setup the context.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000652 __ mov(edi, Immediate(Handle<JSFunction>(function)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
654
655 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000656 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 Handle<Code> code(function->code());
658 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000659 __ InvokeCode(code, expected, arguments(),
660 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661
662 // Handle call cache miss.
663 __ bind(&miss);
664 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000665 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666
667 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000668 String* function_name = NULL;
669 if (function->shared()->name()->IsString()) {
670 function_name = String::cast(function->shared()->name());
671 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000672 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000673}
674
675
676Object* CallStubCompiler::CompileCallInterceptor(Object* object,
677 JSObject* holder,
678 String* name) {
679 // ----------- S t a t e -------------
680 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681 Label miss;
682
683 // Get the number of arguments.
684 const int argc = arguments().immediate();
685
686 // Get the receiver from the stack.
687 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689 // Check that the receiver isn't a smi.
690 __ test(edx, Immediate(kSmiTagMask));
691 __ j(zero, &miss, not_taken);
692
693 // Check that maps have not changed and compute the holder register.
694 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000695 masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
697 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000698 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699
700 // Push arguments on the expression stack.
701 __ push(edx); // receiver
702 __ push(reg); // holder
703 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
ager@chromium.orge2902be2009-06-08 12:21:35 +0000704 __ push(Immediate(holder->InterceptorPropertyLookupHint(name)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705
706 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707 ExternalReference load_interceptor =
708 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000709 __ mov(eax, Immediate(4));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000710 __ mov(ebx, Immediate(load_interceptor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711
712 CEntryStub stub;
713 __ CallStub(&stub);
714
715 // Move result to edi and restore receiver.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000716 __ mov(edi, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
718
719 // Exit frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000720 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721
722 // Check that the function really is a function.
723 __ test(edi, Immediate(kSmiTagMask));
724 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000725 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000726 __ j(not_equal, &miss, not_taken);
727
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000728 // Patch the receiver on the stack with the global proxy if
729 // necessary.
730 if (object->IsGlobalObject()) {
731 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
732 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
733 }
734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 // Invoke the function.
736 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
737
738 // Handle load cache miss.
739 __ bind(&miss);
740 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000741 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742
743 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000744 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745}
746
747
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000748Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
749 JSGlobalPropertyCell* cell,
750 JSFunction* function,
751 String* name) {
752 // ----------- S t a t e -------------
753 // -----------------------------------
754 Label miss;
755
756 __ IncrementCounter(&Counters::call_global_inline, 1);
757
758 // Get the number of arguments.
759 const int argc = arguments().immediate();
760
761 // Check that the map of the global has not changed.
762 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
763 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
764 Immediate(Handle<Map>(object->map())));
765 __ j(not_equal, &miss, not_taken);
766
767 // Get the value from the cell.
768 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
769 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
770
771 // Check that the cell contains the same function.
772 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
773 __ j(not_equal, &miss, not_taken);
774
775 // Patch the receiver on the stack with the global proxy.
776 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
777 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
778
779 // Setup the context (function already in edi).
780 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
781
782 // Jump to the cached code (tail call).
783 ASSERT(function->is_compiled());
784 Handle<Code> code(function->code());
785 ParameterCount expected(function->shared()->formal_parameter_count());
786 __ InvokeCode(code, expected, arguments(),
787 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
788
789 // Handle call cache miss.
790 __ bind(&miss);
791 __ DecrementCounter(&Counters::call_global_inline, 1);
792 __ IncrementCounter(&Counters::call_global_inline_miss, 1);
793 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
794 __ jmp(ic, RelocInfo::CODE_TARGET);
795
796 // Return the generated code.
797 return GetCode(NORMAL, name);
798}
799
800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801Object* StoreStubCompiler::CompileStoreField(JSObject* object,
802 int index,
803 Map* transition,
804 String* name) {
805 // ----------- S t a t e -------------
806 // -- eax : value
807 // -- ecx : name
808 // -- esp[0] : return address
809 // -- esp[4] : receiver
810 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 Label miss;
812
813 // Get the object from the stack.
814 __ mov(ebx, Operand(esp, 1 * kPointerSize));
815
816 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000817 GenerateStoreField(masm(),
818 Builtins::StoreIC_ExtendStorage,
819 object,
820 index,
821 transition,
822 ebx, ecx, edx,
823 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824
825 // Handle store cache miss.
826 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000827 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000829 __ jmp(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 // -- eax : value
841 // -- ecx : name
842 // -- esp[0] : return address
843 // -- esp[4] : receiver
844 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 Label miss;
846
847 // Get the object from the stack.
848 __ mov(ebx, Operand(esp, 1 * kPointerSize));
849
850 // Check that the object isn't a smi.
851 __ test(ebx, Immediate(kSmiTagMask));
852 __ j(zero, &miss, not_taken);
853
854 // Check that the map of the object hasn't changed.
855 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
856 Immediate(Handle<Map>(object->map())));
857 __ j(not_equal, &miss, not_taken);
858
859 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000860 if (object->IsJSGlobalProxy()) {
861 __ CheckAccessGlobalProxy(ebx, edx, &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 __ pop(ebx); // remove the return address
869 __ push(Operand(esp, 0)); // receiver
870 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
871 __ push(ecx); // name
872 __ push(eax); // value
873 __ push(ebx); // restore return address
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);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000882 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000884 __ jmp(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 // -- eax : value
895 // -- ecx : name
896 // -- esp[0] : return address
897 // -- esp[4] : receiver
898 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 Label miss;
900
901 // Get the object from the stack.
902 __ mov(ebx, Operand(esp, 1 * kPointerSize));
903
904 // Check that the object isn't a smi.
905 __ test(ebx, Immediate(kSmiTagMask));
906 __ j(zero, &miss, not_taken);
907
908 // Check that the map of the object hasn't changed.
909 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
910 Immediate(Handle<Map>(receiver->map())));
911 __ j(not_equal, &miss, not_taken);
912
913 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000914 if (receiver->IsJSGlobalProxy()) {
915 __ CheckAccessGlobalProxy(ebx, edx, &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 __ pop(ebx); // remove the return address
923 __ push(Operand(esp, 0)); // receiver
924 __ push(ecx); // name
925 __ push(eax); // value
926 __ push(ebx); // restore return address
927
mads.s.ager31e71382008-08-13 09:32:07 +0000928 // Do tail-call to the runtime system.
929 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000931 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932
933 // Handle store cache miss.
934 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000935 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000936 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000937 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938
939 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000940 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941}
942
943
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000944Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
945 JSGlobalPropertyCell* cell,
946 String* name) {
947 // ----------- S t a t e -------------
948 // -- eax : value
949 // -- ecx : name
950 // -- esp[0] : return address
951 // -- esp[4] : receiver
952 // -----------------------------------
953 Label miss;
954
955 __ IncrementCounter(&Counters::named_store_global_inline, 1);
956
957 // Check that the map of the global has not changed.
958 __ mov(ebx, (Operand(esp, kPointerSize)));
959 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
960 Immediate(Handle<Map>(object->map())));
961 __ j(not_equal, &miss, not_taken);
962
963 // Store the value in the cell.
964 __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
965 __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
966
967 // RecordWrite clobbers the value register. Pass the value being stored in
968 // edx.
969 __ mov(edx, eax);
970 __ RecordWrite(ecx, JSGlobalPropertyCell::kValueOffset, edx, ebx);
971
972 // Return the value (register eax).
973 __ ret(0);
974
975 // Handle store cache miss.
976 __ bind(&miss);
977 __ DecrementCounter(&Counters::named_store_global_inline, 1);
978 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
979 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
980 __ jmp(ic, RelocInfo::CODE_TARGET);
981
982 // Return the generated code.
983 return GetCode(NORMAL, name);
984}
985
986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
988 int index,
989 Map* transition,
990 String* name) {
991 // ----------- S t a t e -------------
992 // -- eax : value
993 // -- esp[0] : return address
994 // -- esp[4] : key
995 // -- esp[8] : receiver
996 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 Label miss;
998
999 __ IncrementCounter(&Counters::keyed_store_field, 1);
1000
1001 // Get the name from the stack.
1002 __ mov(ecx, Operand(esp, 1 * kPointerSize));
1003 // Check that the name has not changed.
1004 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
1005 __ j(not_equal, &miss, not_taken);
1006
1007 // Get the object from the stack.
1008 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1009
1010 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001011 GenerateStoreField(masm(),
1012 Builtins::KeyedStoreIC_ExtendStorage,
1013 object,
1014 index,
1015 transition,
1016 ebx, ecx, edx,
1017 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018
1019 // Handle store cache miss.
1020 __ bind(&miss);
1021 __ DecrementCounter(&Counters::keyed_store_field, 1);
1022 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +00001023 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024
1025 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001026 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027}
1028
1029
1030Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1031 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001032 int index,
1033 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034 // ----------- S t a t e -------------
1035 // -- ecx : name
1036 // -- esp[0] : return address
1037 // -- esp[4] : receiver
1038 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039 Label miss;
1040
1041 __ mov(eax, (Operand(esp, kPointerSize)));
1042 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
1043 __ bind(&miss);
1044 GenerateLoadMiss(masm(), Code::LOAD_IC);
1045
1046 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001047 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048}
1049
1050
1051Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
1052 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001053 AccessorInfo* callback,
1054 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055 // ----------- S t a t e -------------
1056 // -- ecx : name
1057 // -- esp[0] : return address
1058 // -- esp[4] : receiver
1059 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 Label miss;
1061
1062 __ mov(eax, (Operand(esp, kPointerSize)));
1063 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
1064 edx, callback, &miss);
1065 __ bind(&miss);
1066 GenerateLoadMiss(masm(), Code::LOAD_IC);
1067
1068 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001069 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070}
1071
1072
1073Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1074 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001075 Object* value,
1076 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077 // ----------- S t a t e -------------
1078 // -- ecx : name
1079 // -- esp[0] : return address
1080 // -- esp[4] : receiver
1081 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082 Label miss;
1083
1084 __ mov(eax, (Operand(esp, kPointerSize)));
1085 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
1086 __ bind(&miss);
1087 GenerateLoadMiss(masm(), Code::LOAD_IC);
1088
1089 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001090 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091}
1092
1093
1094Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1095 JSObject* holder,
1096 String* name) {
1097 // ----------- S t a t e -------------
1098 // -- ecx : name
1099 // -- esp[0] : return address
1100 // -- esp[4] : receiver
1101 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 Label miss;
1103
1104 __ mov(eax, (Operand(esp, kPointerSize)));
ager@chromium.orge2902be2009-06-08 12:21:35 +00001105 // TODO(368): Compile in the whole chain: all the interceptors in
1106 // prototypes and ultimate answer.
1107 GenerateLoadInterceptor(masm(),
1108 receiver,
1109 holder,
1110 holder->InterceptorPropertyLookupHint(name),
1111 eax,
1112 ecx,
1113 edx,
1114 ebx,
1115 &miss);
1116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117 __ bind(&miss);
1118 GenerateLoadMiss(masm(), Code::LOAD_IC);
1119
1120 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001121 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122}
1123
1124
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001125Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
1126 JSGlobalPropertyCell* cell,
1127 String* name,
1128 bool is_dont_delete) {
1129 // ----------- S t a t e -------------
1130 // -- ecx : name
1131 // -- esp[0] : return address
1132 // -- esp[4] : receiver
1133 // -----------------------------------
1134 Label miss;
1135
1136 __ IncrementCounter(&Counters::named_load_global_inline, 1);
1137
1138 // Check that the map of the global has not changed.
1139 __ mov(eax, (Operand(esp, kPointerSize)));
1140 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1141 Immediate(Handle<Map>(object->map())));
1142 __ j(not_equal, &miss, not_taken);
1143
1144 // Get the value from the cell.
1145 __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1146 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
1147
1148 // Check for deleted property if property can actually be deleted.
1149 if (!is_dont_delete) {
1150 __ cmp(eax, Factory::the_hole_value());
1151 __ j(equal, &miss, not_taken);
1152 }
1153
1154 __ ret(0);
1155
1156 __ bind(&miss);
1157 __ DecrementCounter(&Counters::named_load_global_inline, 1);
1158 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
1159 GenerateLoadMiss(masm(), Code::LOAD_IC);
1160
1161 // Return the generated code.
1162 return GetCode(NORMAL, name);
1163}
1164
1165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1167 JSObject* receiver,
1168 JSObject* holder,
1169 int index) {
1170 // ----------- S t a t e -------------
1171 // -- esp[0] : return address
1172 // -- esp[4] : name
1173 // -- esp[8] : receiver
1174 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 Label miss;
1176
1177 __ mov(eax, (Operand(esp, kPointerSize)));
1178 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1179 __ IncrementCounter(&Counters::keyed_load_field, 1);
1180
1181 // Check that the name has not changed.
1182 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1183 __ j(not_equal, &miss, not_taken);
1184
1185 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1186 __ bind(&miss);
1187 __ DecrementCounter(&Counters::keyed_load_field, 1);
1188 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1189
1190 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001191 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192}
1193
1194
1195Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1196 JSObject* receiver,
1197 JSObject* holder,
1198 AccessorInfo* callback) {
1199 // ----------- S t a t e -------------
1200 // -- esp[0] : return address
1201 // -- esp[4] : name
1202 // -- esp[8] : receiver
1203 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 Label miss;
1205
1206 __ mov(eax, (Operand(esp, kPointerSize)));
1207 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1208 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1209
1210 // Check that the name has not changed.
1211 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1212 __ j(not_equal, &miss, not_taken);
1213
1214 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1215 callback, &miss);
1216 __ bind(&miss);
1217 __ DecrementCounter(&Counters::keyed_load_callback, 1);
1218 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1219
1220 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001221 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222}
1223
1224
1225Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1226 JSObject* receiver,
1227 JSObject* holder,
1228 Object* value) {
1229 // ----------- S t a t e -------------
1230 // -- esp[0] : return address
1231 // -- esp[4] : name
1232 // -- esp[8] : receiver
1233 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 Label miss;
1235
1236 __ mov(eax, (Operand(esp, kPointerSize)));
1237 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1238 __ IncrementCounter(&Counters::keyed_load_constant_function, 1);
1239
1240 // Check that the name has not changed.
1241 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1242 __ j(not_equal, &miss, not_taken);
1243
1244 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1245 __ bind(&miss);
1246 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1247 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1248
1249 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001250 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251}
1252
1253
1254Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1255 JSObject* holder,
1256 String* name) {
1257 // ----------- S t a t e -------------
1258 // -- esp[0] : return address
1259 // -- esp[4] : name
1260 // -- esp[8] : receiver
1261 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 Label miss;
1263
1264 __ mov(eax, (Operand(esp, kPointerSize)));
1265 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1266 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1267
1268 // Check that the name has not changed.
1269 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1270 __ j(not_equal, &miss, not_taken);
1271
ager@chromium.orge2902be2009-06-08 12:21:35 +00001272 GenerateLoadInterceptor(masm(),
1273 receiver,
1274 holder,
1275 Smi::FromInt(JSObject::kLookupInHolder),
1276 ecx,
1277 eax,
1278 edx,
1279 ebx,
1280 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 __ bind(&miss);
1282 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1283 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1284
1285 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001286 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287}
1288
1289
1290
1291
1292Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1293 // ----------- S t a t e -------------
1294 // -- esp[0] : return address
1295 // -- esp[4] : name
1296 // -- esp[8] : receiver
1297 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 Label miss;
1299
1300 __ mov(eax, (Operand(esp, kPointerSize)));
1301 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1302 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1303
1304 // Check that the name has not changed.
1305 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1306 __ j(not_equal, &miss, not_taken);
1307
1308 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1309 __ bind(&miss);
1310 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1311 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1312
1313 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001314 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315}
1316
1317
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001318Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 // ----------- S t a t e -------------
1320 // -- esp[0] : return address
1321 // -- esp[4] : name
1322 // -- esp[8] : receiver
1323 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 Label miss;
1325
1326 __ mov(eax, (Operand(esp, kPointerSize)));
1327 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1328 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1329
1330 // Check that the name has not changed.
1331 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1332 __ j(not_equal, &miss, not_taken);
1333
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001334 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 __ bind(&miss);
1336 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1337 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1338
1339 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001340 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341}
1342
1343
1344Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1345 // ----------- S t a t e -------------
1346 // -- esp[0] : return address
1347 // -- esp[4] : name
1348 // -- esp[8] : receiver
1349 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350 Label miss;
1351
1352 __ mov(eax, (Operand(esp, kPointerSize)));
1353 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1354 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1355
1356 // Check that the name has not changed.
1357 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1358 __ j(not_equal, &miss, not_taken);
1359
1360 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1361 __ bind(&miss);
1362 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1363 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1364
1365 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001366 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367}
1368
1369
1370#undef __
1371
1372} } // namespace v8::internal