blob: 6f84edc1837f938d18422fcc13d90cbb22c7be73 [file] [log] [blame]
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "ic-inl.h"
31#include "codegen-inl.h"
32#include "stub-cache.h"
33
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
ager@chromium.org65dad4b2009-04-23 08:48:43 +000037#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
40static void ProbeTable(MacroAssembler* masm,
41 Code::Flags flags,
42 StubCache::Table table,
43 Register name,
44 Register offset) {
45 ExternalReference key_offset(SCTableReference::keyReference(table));
46 ExternalReference value_offset(SCTableReference::valueReference(table));
47
48 Label miss;
49
50 // Save the offset on the stack.
51 __ push(offset);
52
53 // Check that the key in the entry matches the name.
54 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset));
55 __ j(not_equal, &miss, not_taken);
56
57 // Get the code entry from the cache.
58 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
59
60 // Check that the flags match what we're looking for.
61 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062 __ and_(offset, ~Code::kFlagsNotUsedInLookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063 __ cmp(offset, flags);
64 __ j(not_equal, &miss);
65
66 // Restore offset and re-load code entry from cache.
67 __ pop(offset);
68 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset));
69
70 // Jump to the first instruction in the code stub.
71 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
72 __ jmp(Operand(offset));
73
74 // Miss: Restore offset and fall through.
75 __ bind(&miss);
76 __ pop(offset);
77}
78
79
80void StubCache::GenerateProbe(MacroAssembler* masm,
81 Code::Flags flags,
82 Register receiver,
83 Register name,
84 Register scratch) {
85 Label miss;
86
87 // Make sure that code is valid. The shifting code relies on the
88 // entry size being 8.
89 ASSERT(sizeof(Entry) == 8);
90
91 // Make sure the flags does not name a specific type.
92 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
93
94 // Make sure that there are no register conflicts.
95 ASSERT(!scratch.is(receiver));
96 ASSERT(!scratch.is(name));
97
98 // Check that the receiver isn't a smi.
99 __ test(receiver, Immediate(kSmiTagMask));
100 __ j(zero, &miss, not_taken);
101
102 // Get the map of the receiver and compute the hash.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000103 __ mov(scratch, FieldOperand(name, String::kLengthOffset));
104 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 __ xor_(scratch, flags);
106 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
107
108 // Probe the primary table.
109 ProbeTable(masm, flags, kPrimary, name, scratch);
110
111 // Primary miss: Compute hash for secondary probe.
112 __ sub(scratch, Operand(name));
113 __ add(Operand(scratch), Immediate(flags));
114 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
115
116 // Probe the secondary table.
117 ProbeTable(masm, flags, kSecondary, name, scratch);
118
119 // Cache miss: Fall-through and let caller handle the miss by
120 // entering the runtime system.
121 __ bind(&miss);
122}
123
124
125void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
126 int index,
127 Register prototype) {
128 // Load the global or builtins object from the current context.
129 __ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
130 // Load the global context from the global or builtins object.
131 __ mov(prototype,
132 FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
133 // Load the function from the global context.
134 __ mov(prototype, Operand(prototype, Context::SlotOffset(index)));
135 // Load the initial map. The global functions all have initial maps.
136 __ mov(prototype,
137 FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
138 // Load the prototype from the initial map.
139 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
140}
141
142
143void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
144 Register receiver,
145 Register scratch,
146 Label* miss_label) {
147 // Check that the receiver isn't a smi.
148 __ test(receiver, Immediate(kSmiTagMask));
149 __ j(zero, miss_label, not_taken);
150
151 // Check that the object is a JS array.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000152 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153 __ j(not_equal, miss_label, not_taken);
154
155 // Load length directly from the JS array.
156 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
157 __ ret(0);
158}
159
160
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000161// Generate code to check if an object is a string. If the object is
162// a string, the map's instance type is left in the scratch register.
163static void GenerateStringCheck(MacroAssembler* masm,
164 Register receiver,
165 Register scratch,
166 Label* smi,
167 Label* non_string_object) {
168 // Check that the object isn't a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169 __ test(receiver, Immediate(kSmiTagMask));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000170 __ j(zero, smi, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000172 // Check that the object is a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
174 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000175 ASSERT(kNotStringTag != 0);
176 __ test(scratch, Immediate(kNotStringTag));
177 __ j(not_zero, non_string_object, not_taken);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178}
179
180
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000181void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
182 Register receiver,
183 Register scratch,
184 Label* miss) {
185 Label load_length, check_wrapper;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000187 // Check if the object is a string leaving the instance type in the
188 // scratch register.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000189 GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190
191 // Load length directly from the string.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000192 __ bind(&load_length);
193 __ and_(scratch, kStringSizeMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000195 // ecx is also the receiver.
196 __ lea(ecx, Operand(scratch, String::kLongLengthShift));
197 __ shr(eax); // ecx is implicit shift register.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198 __ shl(eax, kSmiTagSize);
199 __ ret(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000200
201 // Check if the object is a JSValue wrapper.
202 __ bind(&check_wrapper);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000203 __ cmp(scratch, JS_VALUE_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000204 __ j(not_equal, miss, not_taken);
205
206 // Check if the wrapped value is a string and load the length
207 // directly if it is.
208 __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
209 GenerateStringCheck(masm, receiver, scratch, miss, miss);
210 __ jmp(&load_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211}
212
213
214void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
215 Register receiver,
216 Register scratch1,
217 Register scratch2,
218 Label* miss_label) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000219 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 __ mov(eax, Operand(scratch1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221 __ ret(0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000222}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000223
ager@chromium.org7c537e22008-10-16 08:43:32 +0000224
225// Load a fast property out of a holder object (src). In-object properties
226// are loaded directly otherwise the property is loaded from the properties
227// fixed array.
228void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000229 Register dst, Register src,
230 JSObject* holder, int index) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000231 // Adjust for the number of properties stored in the holder.
232 index -= holder->map()->inobject_properties();
233 if (index < 0) {
234 // Get the property straight out of the holder.
235 int offset = holder->map()->instance_size() + (index * kPointerSize);
236 __ mov(dst, FieldOperand(src, offset));
237 } else {
238 // Calculate the offset into the properties array.
239 int offset = index * kPointerSize + Array::kHeaderSize;
240 __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
241 __ mov(dst, FieldOperand(dst, offset));
242 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000243}
244
245
246void StubCompiler::GenerateLoadField(MacroAssembler* masm,
247 JSObject* object,
248 JSObject* holder,
249 Register receiver,
250 Register scratch1,
251 Register scratch2,
252 int index,
253 Label* miss_label) {
254 // Check that the receiver isn't a smi.
255 __ test(receiver, Immediate(kSmiTagMask));
256 __ j(zero, miss_label, not_taken);
257
258 // Check that the maps haven't changed.
259 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000260 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261
ager@chromium.org7c537e22008-10-16 08:43:32 +0000262 // Get the value from the properties.
263 GenerateFastPropertyLoad(masm, eax, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264 __ ret(0);
265}
266
267
268void StubCompiler::GenerateLoadCallback(MacroAssembler* masm,
269 JSObject* object,
270 JSObject* holder,
271 Register receiver,
272 Register name,
273 Register scratch1,
274 Register scratch2,
275 AccessorInfo* callback,
276 Label* miss_label) {
277 // Check that the receiver isn't a smi.
278 __ test(receiver, Immediate(kSmiTagMask));
279 __ j(zero, miss_label, not_taken);
280
281 // Check that the maps haven't changed.
282 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000283 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284
285 // Push the arguments on the JS stack of the caller.
286 __ pop(scratch2); // remove return address
287 __ push(receiver); // receiver
288 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data
289 __ push(name); // name
290 __ push(reg); // holder
291 __ push(scratch2); // restore return address
292
mads.s.ager31e71382008-08-13 09:32:07 +0000293 // Do tail-call to the runtime system.
294 ExternalReference load_callback_property =
295 ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
296 __ TailCallRuntime(load_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297}
298
299
300void StubCompiler::GenerateLoadConstant(MacroAssembler* masm,
301 JSObject* object,
302 JSObject* holder,
303 Register receiver,
304 Register scratch1,
305 Register scratch2,
306 Object* value,
307 Label* miss_label) {
308 // Check that the receiver isn't a smi.
309 __ test(receiver, Immediate(kSmiTagMask));
310 __ j(zero, miss_label, not_taken);
311
312 // Check that the maps haven't changed.
313 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000314 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315
316 // Return the constant value.
317 __ mov(eax, Handle<Object>(value));
318 __ ret(0);
319}
320
321
322void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm,
323 JSObject* object,
324 JSObject* holder,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000325 Smi* lookup_hint,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326 Register receiver,
327 Register name,
328 Register scratch1,
329 Register scratch2,
330 Label* miss_label) {
331 // Check that the receiver isn't a smi.
332 __ test(receiver, Immediate(kSmiTagMask));
333 __ j(zero, miss_label, not_taken);
334
335 // Check that the maps haven't changed.
336 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000337 masm->CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338
339 // Push the arguments on the JS stack of the caller.
340 __ pop(scratch2); // remove return address
341 __ push(receiver); // receiver
342 __ push(reg); // holder
343 __ push(name); // name
ager@chromium.orge2902be2009-06-08 12:21:35 +0000344 // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or
345 // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method?
346 __ push(Immediate(lookup_hint));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347 __ push(scratch2); // restore return address
348
mads.s.ager31e71382008-08-13 09:32:07 +0000349 // Do tail-call to the runtime system.
350 ExternalReference load_ic_property =
351 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000352 __ TailCallRuntime(load_ic_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000353}
354
355
356void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
357 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
358 Code* code = NULL;
359 if (kind == Code::LOAD_IC) {
360 code = Builtins::builtin(Builtins::LoadIC_Miss);
361 } else {
362 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
363 }
364
365 Handle<Code> ic(code);
ager@chromium.org236ad962008-09-25 09:45:57 +0000366 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367}
368
369
370void StubCompiler::GenerateStoreField(MacroAssembler* masm,
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000371 Builtins::Name storage_extend,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372 JSObject* object,
373 int index,
374 Map* transition,
375 Register receiver_reg,
376 Register name_reg,
377 Register scratch,
378 Label* miss_label) {
379 // Check that the object isn't a smi.
380 __ test(receiver_reg, Immediate(kSmiTagMask));
381 __ j(zero, miss_label, not_taken);
382
383 // Check that the map of the object hasn't changed.
384 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
385 Immediate(Handle<Map>(object->map())));
386 __ j(not_equal, miss_label, not_taken);
387
388 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000389 if (object->IsJSGlobalProxy()) {
390 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 }
392
393 // Stub never generated for non-global objects that require access
394 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000395 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000397 // Perform map transition for the receiver if necessary.
398 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
399 // The properties must be extended before we can store the value.
ager@chromium.org32912102009-01-16 10:38:43 +0000400 // We jump to a runtime call that extends the properties array.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000401 __ mov(ecx, Immediate(Handle<Map>(transition)));
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000402 Handle<Code> ic(Builtins::builtin(storage_extend));
403 __ jmp(ic, RelocInfo::CODE_TARGET);
404 return;
405 }
406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 if (transition != NULL) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000408 // Update the map of the object; no write barrier updating is
409 // needed because the map is never in new space.
410 __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset),
411 Immediate(Handle<Map>(transition)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 }
413
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000414 // Adjust for the number of properties stored in the object. Even in the
415 // face of a transition we can use the old map here because the size of the
416 // object and the number of in-object properties is not going to change.
417 index -= object->map()->inobject_properties();
418
ager@chromium.org7c537e22008-10-16 08:43:32 +0000419 if (index < 0) {
420 // Set the property straight into the object.
421 int offset = object->map()->instance_size() + (index * kPointerSize);
422 __ mov(FieldOperand(receiver_reg, offset), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423
ager@chromium.org7c537e22008-10-16 08:43:32 +0000424 // Update the write barrier for the array address.
425 // Pass the value being stored in the now unused name_reg.
426 __ mov(name_reg, Operand(eax));
427 __ RecordWrite(receiver_reg, offset, name_reg, scratch);
428 } else {
429 // Write to the properties array.
430 int offset = index * kPointerSize + Array::kHeaderSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000431 // Get the properties array (optimistically).
432 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000433 __ mov(FieldOperand(scratch, offset), eax);
434
435 // Update the write barrier for the array address.
436 // Pass the value being stored in the now unused name_reg.
437 __ mov(name_reg, Operand(eax));
438 __ RecordWrite(scratch, offset, name_reg, receiver_reg);
439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
441 // Return the value (register eax).
442 __ ret(0);
443}
444
445
446#undef __
447
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000448#define __ ACCESS_MASM(masm())
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449
450
451// TODO(1241006): Avoid having lazy compile stubs specialized by the
452// number of arguments. It is not needed anymore.
453Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000455 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456
457 // Push a copy of the function onto the stack.
458 __ push(edi);
459
460 __ push(edi); // function is also the parameter to the runtime call
461 __ CallRuntime(Runtime::kLazyCompile, 1);
462 __ pop(edi);
463
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000464 // Tear down temporary frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000465 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466
467 // Do a tail-call of the compiled function.
468 __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
469 __ jmp(Operand(ecx));
470
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000471 return GetCodeWithFlags(flags, "LazyCompileStub");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472}
473
474
475Object* CallStubCompiler::CompileCallField(Object* object,
476 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000477 int index,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000478 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479 // ----------- S t a t e -------------
480 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481 Label miss;
482
483 // Get the receiver from the stack.
484 const int argc = arguments().immediate();
485 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
486
487 // Check that the receiver isn't a smi.
488 __ test(edx, Immediate(kSmiTagMask));
489 __ j(zero, &miss, not_taken);
490
491 // Do the right check and compute the holder register.
492 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000493 masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494
ager@chromium.org7c537e22008-10-16 08:43:32 +0000495 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496
497 // Check that the function really is a function.
498 __ test(edi, Immediate(kSmiTagMask));
499 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000500 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501 __ j(not_equal, &miss, not_taken);
502
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000503 // Patch the receiver on the stack with the global proxy if
504 // necessary.
505 if (object->IsGlobalObject()) {
506 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
507 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
508 }
509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 // Invoke the function.
511 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
512
513 // Handle call cache miss.
514 __ bind(&miss);
515 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000516 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517
518 // Return the generated code.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000519 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520}
521
522
523Object* CallStubCompiler::CompileCallConstant(Object* object,
524 JSObject* holder,
525 JSFunction* function,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000526 CheckType check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 // ----------- S t a t e -------------
528 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 Label miss;
530
531 // Get the receiver from the stack.
532 const int argc = arguments().immediate();
533 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
534
535 // Check that the receiver isn't a smi.
536 if (check != NUMBER_CHECK) {
537 __ test(edx, Immediate(kSmiTagMask));
538 __ j(zero, &miss, not_taken);
539 }
540
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000541 // Make sure that it's okay not to patch the on stack receiver
542 // unless we're doing a receiver map check.
543 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
544
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 switch (check) {
546 case RECEIVER_MAP_CHECK:
547 // Check that the maps haven't changed.
548 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000549
550 // Patch the receiver on the stack with the global proxy if
551 // necessary.
552 if (object->IsGlobalObject()) {
553 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
554 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556 break;
557
558 case STRING_CHECK:
559 // Check that the object is a two-byte string or a symbol.
560 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
561 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
562 __ cmp(ecx, FIRST_NONSTRING_TYPE);
563 __ j(above_equal, &miss, not_taken);
564 // Check that the maps starting from the prototype haven't changed.
565 GenerateLoadGlobalFunctionPrototype(masm(),
566 Context::STRING_FUNCTION_INDEX,
567 ecx);
568 __ CheckMaps(JSObject::cast(object->GetPrototype()),
569 ecx, holder, ebx, edx, &miss);
570 break;
571
572 case NUMBER_CHECK: {
573 Label fast;
574 // Check that the object is a smi or a heap number.
575 __ test(edx, Immediate(kSmiTagMask));
576 __ j(zero, &fast, taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000577 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578 __ j(not_equal, &miss, not_taken);
579 __ bind(&fast);
580 // Check that the maps starting from the prototype haven't changed.
581 GenerateLoadGlobalFunctionPrototype(masm(),
582 Context::NUMBER_FUNCTION_INDEX,
583 ecx);
584 __ CheckMaps(JSObject::cast(object->GetPrototype()),
585 ecx, holder, ebx, edx, &miss);
586 break;
587 }
588
589 case BOOLEAN_CHECK: {
590 Label fast;
591 // Check that the object is a boolean.
592 __ cmp(edx, Factory::true_value());
593 __ j(equal, &fast, taken);
594 __ cmp(edx, Factory::false_value());
595 __ j(not_equal, &miss, not_taken);
596 __ bind(&fast);
597 // Check that the maps starting from the prototype haven't changed.
598 GenerateLoadGlobalFunctionPrototype(masm(),
599 Context::BOOLEAN_FUNCTION_INDEX,
600 ecx);
601 __ CheckMaps(JSObject::cast(object->GetPrototype()),
602 ecx, holder, ebx, edx, &miss);
603 break;
604 }
605
606 case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
607 __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
608 // Make sure object->elements()->map() != Heap::dictionary_array_map()
609 // Get the elements array of the object.
610 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
611 // Check that the object is in fast mode (not dictionary).
612 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
613 Immediate(Factory::hash_table_map()));
614 __ j(equal, &miss, not_taken);
615 break;
616
617 default:
618 UNREACHABLE();
619 }
620
621 // Get the function and setup the context.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000622 __ mov(edi, Immediate(Handle<JSFunction>(function)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
624
625 // Jump to the cached code (tail call).
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000626 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627 Handle<Code> code(function->code());
628 ParameterCount expected(function->shared()->formal_parameter_count());
ager@chromium.org236ad962008-09-25 09:45:57 +0000629 __ InvokeCode(code, expected, arguments(),
630 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631
632 // Handle call cache miss.
633 __ bind(&miss);
634 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
ager@chromium.org236ad962008-09-25 09:45:57 +0000635 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636
637 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000638 String* function_name = NULL;
639 if (function->shared()->name()->IsString()) {
640 function_name = String::cast(function->shared()->name());
641 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000642 return GetCode(CONSTANT_FUNCTION, function_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643}
644
645
646Object* CallStubCompiler::CompileCallInterceptor(Object* object,
647 JSObject* holder,
648 String* name) {
649 // ----------- S t a t e -------------
650 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 Label miss;
652
653 // Get the number of arguments.
654 const int argc = arguments().immediate();
655
656 // Get the receiver from the stack.
657 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000659 // Check that the receiver isn't a smi.
660 __ test(edx, Immediate(kSmiTagMask));
661 __ j(zero, &miss, not_taken);
662
663 // Check that maps have not changed and compute the holder register.
664 Register reg =
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000665 masm()->CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666
667 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000668 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669
670 // Push arguments on the expression stack.
671 __ push(edx); // receiver
672 __ push(reg); // holder
673 __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name
ager@chromium.orge2902be2009-06-08 12:21:35 +0000674 __ push(Immediate(holder->InterceptorPropertyLookupHint(name)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675
676 // Perform call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677 ExternalReference load_interceptor =
678 ExternalReference(IC_Utility(IC::kLoadInterceptorProperty));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000679 __ mov(eax, Immediate(4));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000680 __ mov(ebx, Immediate(load_interceptor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681
682 CEntryStub stub;
683 __ CallStub(&stub);
684
685 // Move result to edi and restore receiver.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000686 __ mov(edi, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687 __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
688
689 // Exit frame.
ager@chromium.org236ad962008-09-25 09:45:57 +0000690 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691
692 // Check that the function really is a function.
693 __ test(edi, Immediate(kSmiTagMask));
694 __ j(zero, &miss, not_taken);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000695 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 __ j(not_equal, &miss, not_taken);
697
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000698 // Patch the receiver on the stack with the global proxy if
699 // necessary.
700 if (object->IsGlobalObject()) {
701 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
702 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
703 }
704
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705 // Invoke the function.
706 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION);
707
708 // Handle load cache miss.
709 __ bind(&miss);
710 Handle<Code> ic = ComputeCallMiss(argc);
ager@chromium.org236ad962008-09-25 09:45:57 +0000711 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712
713 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000714 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715}
716
717
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000718Object* CallStubCompiler::CompileCallGlobal(GlobalObject* object,
719 JSGlobalPropertyCell* cell,
720 JSFunction* function,
721 String* name) {
722 // ----------- S t a t e -------------
723 // -----------------------------------
724 Label miss;
725
726 __ IncrementCounter(&Counters::call_global_inline, 1);
727
728 // Get the number of arguments.
729 const int argc = arguments().immediate();
730
731 // Check that the map of the global has not changed.
732 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
733 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
734 Immediate(Handle<Map>(object->map())));
735 __ j(not_equal, &miss, not_taken);
736
737 // Get the value from the cell.
738 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
739 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
740
741 // Check that the cell contains the same function.
742 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
743 __ j(not_equal, &miss, not_taken);
744
745 // Patch the receiver on the stack with the global proxy.
746 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
747 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
748
749 // Setup the context (function already in edi).
750 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
751
752 // Jump to the cached code (tail call).
753 ASSERT(function->is_compiled());
754 Handle<Code> code(function->code());
755 ParameterCount expected(function->shared()->formal_parameter_count());
756 __ InvokeCode(code, expected, arguments(),
757 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
758
759 // Handle call cache miss.
760 __ bind(&miss);
761 __ DecrementCounter(&Counters::call_global_inline, 1);
762 __ IncrementCounter(&Counters::call_global_inline_miss, 1);
763 Handle<Code> ic = ComputeCallMiss(arguments().immediate());
764 __ jmp(ic, RelocInfo::CODE_TARGET);
765
766 // Return the generated code.
767 return GetCode(NORMAL, name);
768}
769
770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771Object* StoreStubCompiler::CompileStoreField(JSObject* object,
772 int index,
773 Map* transition,
774 String* name) {
775 // ----------- S t a t e -------------
776 // -- eax : value
777 // -- ecx : name
778 // -- esp[0] : return address
779 // -- esp[4] : receiver
780 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781 Label miss;
782
783 // Get the object from the stack.
784 __ mov(ebx, Operand(esp, 1 * kPointerSize));
785
786 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000787 GenerateStoreField(masm(),
788 Builtins::StoreIC_ExtendStorage,
789 object,
790 index,
791 transition,
792 ebx, ecx, edx,
793 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000794
795 // Handle store cache miss.
796 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000797 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000799 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000800
801 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000802 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803}
804
805
806Object* StoreStubCompiler::CompileStoreCallback(JSObject* object,
807 AccessorInfo* callback,
808 String* name) {
809 // ----------- S t a t e -------------
810 // -- eax : value
811 // -- ecx : name
812 // -- esp[0] : return address
813 // -- esp[4] : receiver
814 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000815 Label miss;
816
817 // Get the object from the stack.
818 __ mov(ebx, Operand(esp, 1 * kPointerSize));
819
820 // Check that the object isn't a smi.
821 __ test(ebx, Immediate(kSmiTagMask));
822 __ j(zero, &miss, not_taken);
823
824 // Check that the map of the object hasn't changed.
825 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
826 Immediate(Handle<Map>(object->map())));
827 __ j(not_equal, &miss, not_taken);
828
829 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000830 if (object->IsJSGlobalProxy()) {
831 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832 }
833
834 // Stub never generated for non-global objects that require access
835 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000836 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837
838 __ pop(ebx); // remove the return address
839 __ push(Operand(esp, 0)); // receiver
840 __ push(Immediate(Handle<AccessorInfo>(callback))); // callback info
841 __ push(ecx); // name
842 __ push(eax); // value
843 __ push(ebx); // restore return address
844
mads.s.ager31e71382008-08-13 09:32:07 +0000845 // Do tail-call to the runtime system.
846 ExternalReference store_callback_property =
847 ExternalReference(IC_Utility(IC::kStoreCallbackProperty));
848 __ TailCallRuntime(store_callback_property, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849
850 // Handle store cache miss.
851 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000852 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000854 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855
856 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000857 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858}
859
860
861Object* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver,
862 String* name) {
863 // ----------- S t a t e -------------
864 // -- eax : value
865 // -- ecx : name
866 // -- esp[0] : return address
867 // -- esp[4] : receiver
868 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869 Label miss;
870
871 // Get the object from the stack.
872 __ mov(ebx, Operand(esp, 1 * kPointerSize));
873
874 // Check that the object isn't a smi.
875 __ test(ebx, Immediate(kSmiTagMask));
876 __ j(zero, &miss, not_taken);
877
878 // Check that the map of the object hasn't changed.
879 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
880 Immediate(Handle<Map>(receiver->map())));
881 __ j(not_equal, &miss, not_taken);
882
883 // Perform global security token check if needed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000884 if (receiver->IsJSGlobalProxy()) {
885 __ CheckAccessGlobalProxy(ebx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 }
887
888 // Stub never generated for non-global objects that require access
889 // checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000890 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891
892 __ pop(ebx); // remove the return address
893 __ push(Operand(esp, 0)); // receiver
894 __ push(ecx); // name
895 __ push(eax); // value
896 __ push(ebx); // restore return address
897
mads.s.ager31e71382008-08-13 09:32:07 +0000898 // Do tail-call to the runtime system.
899 ExternalReference store_ic_property =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty));
mads.s.ager31e71382008-08-13 09:32:07 +0000901 __ TailCallRuntime(store_ic_property, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902
903 // Handle store cache miss.
904 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000905 __ mov(ecx, Immediate(Handle<String>(name))); // restore name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000907 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000908
909 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000910 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911}
912
913
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000914Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
915 JSGlobalPropertyCell* cell,
916 String* name) {
917 // ----------- S t a t e -------------
918 // -- eax : value
919 // -- ecx : name
920 // -- esp[0] : return address
921 // -- esp[4] : receiver
922 // -----------------------------------
923 Label miss;
924
925 __ IncrementCounter(&Counters::named_store_global_inline, 1);
926
927 // Check that the map of the global has not changed.
928 __ mov(ebx, (Operand(esp, kPointerSize)));
929 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
930 Immediate(Handle<Map>(object->map())));
931 __ j(not_equal, &miss, not_taken);
932
933 // Store the value in the cell.
934 __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
935 __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
936
937 // RecordWrite clobbers the value register. Pass the value being stored in
938 // edx.
939 __ mov(edx, eax);
940 __ RecordWrite(ecx, JSGlobalPropertyCell::kValueOffset, edx, ebx);
941
942 // Return the value (register eax).
943 __ ret(0);
944
945 // Handle store cache miss.
946 __ bind(&miss);
947 __ DecrementCounter(&Counters::named_store_global_inline, 1);
948 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1);
949 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
950 __ jmp(ic, RelocInfo::CODE_TARGET);
951
952 // Return the generated code.
953 return GetCode(NORMAL, name);
954}
955
956
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
958 int index,
959 Map* transition,
960 String* name) {
961 // ----------- S t a t e -------------
962 // -- eax : value
963 // -- esp[0] : return address
964 // -- esp[4] : key
965 // -- esp[8] : receiver
966 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000967 Label miss;
968
969 __ IncrementCounter(&Counters::keyed_store_field, 1);
970
971 // Get the name from the stack.
972 __ mov(ecx, Operand(esp, 1 * kPointerSize));
973 // Check that the name has not changed.
974 __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
975 __ j(not_equal, &miss, not_taken);
976
977 // Get the object from the stack.
978 __ mov(ebx, Operand(esp, 2 * kPointerSize));
979
980 // Generate store field code. Trashes the name register.
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000981 GenerateStoreField(masm(),
982 Builtins::KeyedStoreIC_ExtendStorage,
983 object,
984 index,
985 transition,
986 ebx, ecx, edx,
987 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988
989 // Handle store cache miss.
990 __ bind(&miss);
991 __ DecrementCounter(&Counters::keyed_store_field, 1);
992 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
ager@chromium.org236ad962008-09-25 09:45:57 +0000993 __ jmp(ic, RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994
995 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000996 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997}
998
999
1000Object* LoadStubCompiler::CompileLoadField(JSObject* object,
1001 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001002 int index,
1003 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 // ----------- S t a t e -------------
1005 // -- ecx : name
1006 // -- esp[0] : return address
1007 // -- esp[4] : receiver
1008 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 Label miss;
1010
1011 __ mov(eax, (Operand(esp, kPointerSize)));
1012 GenerateLoadField(masm(), object, holder, eax, ebx, edx, index, &miss);
1013 __ bind(&miss);
1014 GenerateLoadMiss(masm(), Code::LOAD_IC);
1015
1016 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001017 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018}
1019
1020
1021Object* LoadStubCompiler::CompileLoadCallback(JSObject* object,
1022 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001023 AccessorInfo* callback,
1024 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025 // ----------- S t a t e -------------
1026 // -- ecx : name
1027 // -- esp[0] : return address
1028 // -- esp[4] : receiver
1029 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 Label miss;
1031
1032 __ mov(eax, (Operand(esp, kPointerSize)));
1033 GenerateLoadCallback(masm(), object, holder, eax, ecx, ebx,
1034 edx, callback, &miss);
1035 __ bind(&miss);
1036 GenerateLoadMiss(masm(), Code::LOAD_IC);
1037
1038 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001039 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040}
1041
1042
1043Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
1044 JSObject* holder,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001045 Object* value,
1046 String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 // ----------- S t a t e -------------
1048 // -- ecx : name
1049 // -- esp[0] : return address
1050 // -- esp[4] : receiver
1051 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 Label miss;
1053
1054 __ mov(eax, (Operand(esp, kPointerSize)));
1055 GenerateLoadConstant(masm(), object, holder, eax, ebx, edx, value, &miss);
1056 __ bind(&miss);
1057 GenerateLoadMiss(masm(), Code::LOAD_IC);
1058
1059 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001060 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061}
1062
1063
1064Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1065 JSObject* holder,
1066 String* name) {
1067 // ----------- S t a t e -------------
1068 // -- ecx : name
1069 // -- esp[0] : return address
1070 // -- esp[4] : receiver
1071 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 Label miss;
1073
1074 __ mov(eax, (Operand(esp, kPointerSize)));
ager@chromium.orge2902be2009-06-08 12:21:35 +00001075 // TODO(368): Compile in the whole chain: all the interceptors in
1076 // prototypes and ultimate answer.
1077 GenerateLoadInterceptor(masm(),
1078 receiver,
1079 holder,
1080 holder->InterceptorPropertyLookupHint(name),
1081 eax,
1082 ecx,
1083 edx,
1084 ebx,
1085 &miss);
1086
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 __ bind(&miss);
1088 GenerateLoadMiss(masm(), Code::LOAD_IC);
1089
1090 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001091 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092}
1093
1094
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001095Object* LoadStubCompiler::CompileLoadGlobal(GlobalObject* object,
1096 JSGlobalPropertyCell* cell,
1097 String* name,
1098 bool is_dont_delete) {
1099 // ----------- S t a t e -------------
1100 // -- ecx : name
1101 // -- esp[0] : return address
1102 // -- esp[4] : receiver
1103 // -----------------------------------
1104 Label miss;
1105
1106 __ IncrementCounter(&Counters::named_load_global_inline, 1);
1107
1108 // Check that the map of the global has not changed.
1109 __ mov(eax, (Operand(esp, kPointerSize)));
1110 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1111 Immediate(Handle<Map>(object->map())));
1112 __ j(not_equal, &miss, not_taken);
1113
1114 // Get the value from the cell.
1115 __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1116 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
1117
1118 // Check for deleted property if property can actually be deleted.
1119 if (!is_dont_delete) {
1120 __ cmp(eax, Factory::the_hole_value());
1121 __ j(equal, &miss, not_taken);
1122 }
1123
1124 __ ret(0);
1125
1126 __ bind(&miss);
1127 __ DecrementCounter(&Counters::named_load_global_inline, 1);
1128 __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
1129 GenerateLoadMiss(masm(), Code::LOAD_IC);
1130
1131 // Return the generated code.
1132 return GetCode(NORMAL, name);
1133}
1134
1135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
1137 JSObject* receiver,
1138 JSObject* holder,
1139 int index) {
1140 // ----------- S t a t e -------------
1141 // -- esp[0] : return address
1142 // -- esp[4] : name
1143 // -- esp[8] : receiver
1144 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 Label miss;
1146
1147 __ mov(eax, (Operand(esp, kPointerSize)));
1148 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1149 __ IncrementCounter(&Counters::keyed_load_field, 1);
1150
1151 // Check that the name has not changed.
1152 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1153 __ j(not_equal, &miss, not_taken);
1154
1155 GenerateLoadField(masm(), receiver, holder, ecx, ebx, edx, index, &miss);
1156 __ bind(&miss);
1157 __ DecrementCounter(&Counters::keyed_load_field, 1);
1158 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1159
1160 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001161 return GetCode(FIELD, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162}
1163
1164
1165Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name,
1166 JSObject* receiver,
1167 JSObject* holder,
1168 AccessorInfo* callback) {
1169 // ----------- S t a t e -------------
1170 // -- esp[0] : return address
1171 // -- esp[4] : name
1172 // -- esp[8] : receiver
1173 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 Label miss;
1175
1176 __ mov(eax, (Operand(esp, kPointerSize)));
1177 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1178 __ IncrementCounter(&Counters::keyed_load_callback, 1);
1179
1180 // Check that the name has not changed.
1181 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1182 __ j(not_equal, &miss, not_taken);
1183
1184 GenerateLoadCallback(masm(), receiver, holder, ecx, eax, ebx, edx,
1185 callback, &miss);
1186 __ bind(&miss);
1187 __ DecrementCounter(&Counters::keyed_load_callback, 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(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192}
1193
1194
1195Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name,
1196 JSObject* receiver,
1197 JSObject* holder,
1198 Object* value) {
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_constant_function, 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 GenerateLoadConstant(masm(), receiver, holder, ecx, ebx, edx, value, &miss);
1215 __ bind(&miss);
1216 __ DecrementCounter(&Counters::keyed_load_constant_function, 1);
1217 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1218
1219 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001220 return GetCode(CONSTANT_FUNCTION, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221}
1222
1223
1224Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
1225 JSObject* holder,
1226 String* name) {
1227 // ----------- S t a t e -------------
1228 // -- esp[0] : return address
1229 // -- esp[4] : name
1230 // -- esp[8] : receiver
1231 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 Label miss;
1233
1234 __ mov(eax, (Operand(esp, kPointerSize)));
1235 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1236 __ IncrementCounter(&Counters::keyed_load_interceptor, 1);
1237
1238 // Check that the name has not changed.
1239 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1240 __ j(not_equal, &miss, not_taken);
1241
ager@chromium.orge2902be2009-06-08 12:21:35 +00001242 GenerateLoadInterceptor(masm(),
1243 receiver,
1244 holder,
1245 Smi::FromInt(JSObject::kLookupInHolder),
1246 ecx,
1247 eax,
1248 edx,
1249 ebx,
1250 &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 __ bind(&miss);
1252 __ DecrementCounter(&Counters::keyed_load_interceptor, 1);
1253 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1254
1255 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001256 return GetCode(INTERCEPTOR, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257}
1258
1259
1260
1261
1262Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
1263 // ----------- S t a t e -------------
1264 // -- esp[0] : return address
1265 // -- esp[4] : name
1266 // -- esp[8] : receiver
1267 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 Label miss;
1269
1270 __ mov(eax, (Operand(esp, kPointerSize)));
1271 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1272 __ IncrementCounter(&Counters::keyed_load_array_length, 1);
1273
1274 // Check that the name has not changed.
1275 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1276 __ j(not_equal, &miss, not_taken);
1277
1278 GenerateLoadArrayLength(masm(), ecx, edx, &miss);
1279 __ bind(&miss);
1280 __ DecrementCounter(&Counters::keyed_load_array_length, 1);
1281 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1282
1283 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001284 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285}
1286
1287
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001288Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 // ----------- S t a t e -------------
1290 // -- esp[0] : return address
1291 // -- esp[4] : name
1292 // -- esp[8] : receiver
1293 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 Label miss;
1295
1296 __ mov(eax, (Operand(esp, kPointerSize)));
1297 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1298 __ IncrementCounter(&Counters::keyed_load_string_length, 1);
1299
1300 // Check that the name has not changed.
1301 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1302 __ j(not_equal, &miss, not_taken);
1303
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001304 GenerateLoadStringLength(masm(), ecx, edx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 __ bind(&miss);
1306 __ DecrementCounter(&Counters::keyed_load_string_length, 1);
1307 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1308
1309 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001310 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
1314Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
1315 // ----------- S t a t e -------------
1316 // -- esp[0] : return address
1317 // -- esp[4] : name
1318 // -- esp[8] : receiver
1319 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 Label miss;
1321
1322 __ mov(eax, (Operand(esp, kPointerSize)));
1323 __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
1324 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1);
1325
1326 // Check that the name has not changed.
1327 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
1328 __ j(not_equal, &miss, not_taken);
1329
1330 GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
1331 __ bind(&miss);
1332 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
1333 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
1334
1335 // Return the generated code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001336 return GetCode(CALLBACKS, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337}
1338
1339
1340#undef __
1341
1342} } // namespace v8::internal