The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / ic-ia32.cc @ 40c0f755

History | View | Annotate | Download (29.8 KB)

1
// Copyright 2006-2008 the V8 project authors. All rights reserved.
2
// 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 "codegen-inl.h"
31
#include "ic-inl.h"
32
#include "runtime.h"
33
#include "stub-cache.h"
34

    
35
namespace v8 { namespace internal {
36

    
37
// ----------------------------------------------------------------------------
38
// Static IC stub generators.
39
//
40

    
41
#define __ masm->
42

    
43

    
44
// Helper function used to load a property from a dictionary backing storage.
45
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
46
                                   Register r0, Register r1, Register r2,
47
                                   Register name) {
48
  // Register use:
49
  //
50
  // r0   - used to hold the property dictionary.
51
  //
52
  // r1   - initially the receiver
53
  //      - used for the index into the property dictionary
54
  //      - holds the result on exit.
55
  //
56
  // r2   - used to hold the capacity of the property dictionary.
57
  //
58
  // name - holds the name of the property and is unchanges.
59

    
60
  Label done;
61

    
62
  // Check for the absence of an interceptor.
63
  // Load the map into r0.
64
  __ mov(r0, FieldOperand(r1, JSObject::kMapOffset));
65
  // Test the has_named_interceptor bit in the map.
66
  __ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
67
          Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
68
  // Jump to miss if the interceptor bit is set.
69
  __ j(not_zero, miss_label, not_taken);
70

    
71
  // Check that the properties array is a dictionary.
72
  __ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
73
  __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
74
         Immediate(Factory::hash_table_map()));
75
  __ j(not_equal, miss_label);
76

    
77
  // Compute the capacity mask.
78
  const int kCapacityOffset =
79
      Array::kHeaderSize + Dictionary::kCapacityIndex * kPointerSize;
80
  __ mov(r2, FieldOperand(r0, kCapacityOffset));
81
  __ shr(r2, kSmiTagSize);  // convert smi to int
82
  __ dec(r2);
83

    
84
  // Generate an unrolled loop that performs a few probes before
85
  // giving up. Measurements done on Gmail indicate that 2 probes
86
  // cover ~93% of loads from dictionaries.
87
  static const int kProbes = 4;
88
  const int kElementsStartOffset =
89
      Array::kHeaderSize + Dictionary::kElementsStartIndex * kPointerSize;
90
  for (int i = 0; i < kProbes; i++) {
91
    // Compute the masked index: (hash + i + i * i) & mask.
92
    __ mov(r1, FieldOperand(name, String::kLengthOffset));
93
    __ shr(r1, String::kHashShift);
94
    if (i > 0) __ add(Operand(r1), Immediate(Dictionary::GetProbeOffset(i)));
95
    __ and_(r1, Operand(r2));
96

    
97
    // Scale the index by multiplying by the element size.
98
    ASSERT(Dictionary::kElementSize == 3);
99
    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
100

    
101
    // Check if the key is identical to the name.
102
    __ cmp(name,
103
           Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
104
    if (i != kProbes - 1) {
105
      __ j(equal, &done, taken);
106
    } else {
107
      __ j(not_equal, miss_label, not_taken);
108
    }
109
  }
110

    
111
  // Check that the value is a normal property.
112
  __ bind(&done);
113
  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
114
  __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
115
          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
116
  __ j(not_zero, miss_label, not_taken);
117

    
118
  // Get the value at the masked, scaled index.
119
  const int kValueOffset = kElementsStartOffset + kPointerSize;
120
  __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
121
}
122

    
123

    
124
// Helper function used to check that a value is either not a function
125
// or is loaded if it is a function.
126
static void GenerateCheckNonFunctionOrLoaded(MacroAssembler* masm, Label* miss,
127
                                             Register value, Register scratch) {
128
  Label done;
129
  // Check if the value is a Smi.
130
  __ test(value, Immediate(kSmiTagMask));
131
  __ j(zero, &done, not_taken);
132
  // Check if the value is a function.
133
  __ CmpObjectType(value, JS_FUNCTION_TYPE, scratch);
134
  __ j(not_equal, &done, taken);
135
  // Check if the function has been loaded.
136
  __ mov(scratch, FieldOperand(value, JSFunction::kSharedFunctionInfoOffset));
137
  __ mov(scratch,
138
         FieldOperand(scratch, SharedFunctionInfo::kLazyLoadDataOffset));
139
  __ cmp(scratch, Factory::undefined_value());
140
  __ j(not_equal, miss, not_taken);
141
  __ bind(&done);
142
}
143

    
144

    
145
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
146
  // ----------- S t a t e -------------
147
  //  -- ecx    : name
148
  //  -- esp[0] : return address
149
  //  -- esp[4] : receiver
150
  // -----------------------------------
151

    
152
  Label miss;
153

    
154
  __ mov(eax, Operand(esp, kPointerSize));
155

    
156
  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
157
  __ bind(&miss);
158
  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
159
}
160

    
161

    
162
void LoadIC::GenerateStringLength(MacroAssembler* masm) {
163
  // ----------- S t a t e -------------
164
  //  -- ecx    : name
165
  //  -- esp[0] : return address
166
  //  -- esp[4] : receiver
167
  // -----------------------------------
168

    
169
  Label miss;
170

    
171
  __ mov(eax, Operand(esp, kPointerSize));
172

    
173
  StubCompiler::GenerateLoadStringLength(masm, eax, edx, &miss);
174
  __ bind(&miss);
175
  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
176
}
177

    
178

    
179
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
180
  // ----------- S t a t e -------------
181
  //  -- ecx    : name
182
  //  -- esp[0] : return address
183
  //  -- esp[4] : receiver
184
  // -----------------------------------
185

    
186
  Label miss;
187

    
188
  __ mov(eax, Operand(esp, kPointerSize));
189

    
190
  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
191
  __ bind(&miss);
192
  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
193
}
194

    
195

    
196
#ifdef DEBUG
197
// For use in assert below.
198
static int TenToThe(int exponent) {
199
  ASSERT(exponent <= 9);
200
  ASSERT(exponent >= 1);
201
  int answer = 10;
202
  for (int i = 1; i < exponent; i++) answer *= 10;
203
  return answer;
204
}
205
#endif
206

    
207

    
208
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
209
  // ----------- S t a t e -------------
210
  //  -- esp[0] : return address
211
  //  -- esp[4] : name
212
  //  -- esp[8] : receiver
213
  // -----------------------------------
214
  Label slow, fast, check_string, index_int, index_string;
215

    
216
  // Load name and receiver.
217
  __ mov(eax, (Operand(esp, kPointerSize)));
218
  __ mov(ecx, (Operand(esp, 2 * kPointerSize)));
219

    
220
  // Check that the object isn't a smi.
221
  __ test(ecx, Immediate(kSmiTagMask));
222
  __ j(zero, &slow, not_taken);
223

    
224
  // Get the map of the receiver.
225
  __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset));
226
  // Check that the receiver does not require access checks.  We need
227
  // to check this explicitly since this generic stub does not perform
228
  // map checks.
229
  __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
230
  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
231
  __ j(not_zero, &slow, not_taken);
232
  // Check that the object is some kind of JS object EXCEPT JS Value type.
233
  // In the case that the object is a value-wrapper object,
234
  // we enter the runtime system to make sure that indexing
235
  // into string objects work as intended.
236
  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
237
  __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
238
  __ cmp(edx, JS_OBJECT_TYPE);
239
  __ j(less, &slow, not_taken);
240
  // Check that the key is a smi.
241
  __ test(eax, Immediate(kSmiTagMask));
242
  __ j(not_zero, &check_string, not_taken);
243
  __ sar(eax, kSmiTagSize);
244
  // Get the elements array of the object.
245
  __ bind(&index_int);
246
  __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
247
  // Check that the object is in fast mode (not dictionary).
248
  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
249
         Immediate(Factory::hash_table_map()));
250
  __ j(equal, &slow, not_taken);
251
  // Check that the key (index) is within bounds.
252
  __ cmp(eax, FieldOperand(ecx, Array::kLengthOffset));
253
  __ j(below, &fast, taken);
254
  // Slow case: Load name and receiver from stack and jump to runtime.
255
  __ bind(&slow);
256
  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
257
  KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
258
  // Check if the key is a symbol that is not an array index.
259
  __ bind(&check_string);
260
  __ mov(ebx, FieldOperand(eax, String::kLengthOffset));
261
  __ test(ebx, Immediate(String::kIsArrayIndexMask));
262
  __ j(not_zero, &index_string, not_taken);
263
  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
264
  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
265
  __ test(ebx, Immediate(kIsSymbolMask));
266
  __ j(not_zero, &slow, not_taken);
267
  // Probe the dictionary leaving result in ecx.
268
  GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
269
  GenerateCheckNonFunctionOrLoaded(masm, &slow, ecx, edx);
270
  __ mov(eax, Operand(ecx));
271
  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
272
  __ ret(0);
273
  // Array index string: If short enough use cache in length/hash field (ebx).
274
  // We assert that there are enough bits in an int32_t after the hash shift
275
  // bits have been subtracted to allow space for the length and the cached
276
  // array index.
277
  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
278
         (1 << (String::kShortLengthShift - String::kHashShift)));
279
  __ bind(&index_string);
280
  const int kLengthFieldLimit =
281
      (String::kMaxCachedArrayIndexLength + 1) << String::kShortLengthShift;
282
  __ cmp(ebx, kLengthFieldLimit);
283
  __ j(above_equal, &slow);
284
  __ mov(eax, Operand(ebx));
285
  __ and_(eax, (1 << String::kShortLengthShift) - 1);
286
  __ shr(eax, String::kLongLengthShift);
287
  __ jmp(&index_int);
288
  // Fast case: Do the load.
289
  __ bind(&fast);
290
  __ mov(eax, Operand(ecx, eax, times_4, Array::kHeaderSize - kHeapObjectTag));
291
  __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
292
  // In case the loaded value is the_hole we have to consult GetProperty
293
  // to ensure the prototype chain is searched.
294
  __ j(equal, &slow, not_taken);
295
  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
296
  __ ret(0);
297
}
298

    
299

    
300
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
301
  // ----------- S t a t e -------------
302
  //  -- eax    : value
303
  //  -- esp[0] : return address
304
  //  -- esp[4] : key
305
  //  -- esp[8] : receiver
306
  // -----------------------------------
307
  Label slow, fast, array, extra;
308

    
309
  // Get the receiver from the stack.
310
  __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
311
  // Check that the object isn't a smi.
312
  __ test(edx, Immediate(kSmiTagMask));
313
  __ j(zero, &slow, not_taken);
314
  // Get the map from the receiver.
315
  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
316
  // Check that the receiver does not require access checks.  We need
317
  // to do this because this generic stub does not perform map checks.
318
  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
319
  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
320
  __ j(not_zero, &slow, not_taken);
321
  // Get the key from the stack.
322
  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
323
  // Check that the key is a smi.
324
  __ test(ebx, Immediate(kSmiTagMask));
325
  __ j(not_zero, &slow, not_taken);
326
  // Get the instance type from the map of the receiver.
327
  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
328
  // Check if the object is a JS array or not.
329
  __ cmp(ecx, JS_ARRAY_TYPE);
330
  __ j(equal, &array);
331
  // Check that the object is some kind of JS object.
332
  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
333
  __ j(less, &slow, not_taken);
334

    
335
  // Object case: Check key against length in the elements array.
336
  // eax: value
337
  // edx: JSObject
338
  // ebx: index (as a smi)
339
  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
340
  // Check that the object is in fast mode (not dictionary).
341
  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
342
         Immediate(Factory::hash_table_map()));
343
  __ j(equal, &slow, not_taken);
344
  // Untag the key (for checking against untagged length in the fixed array).
345
  __ mov(edx, Operand(ebx));
346
  __ sar(edx, kSmiTagSize);  // untag the index and use it for the comparison
347
  __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset));
348
  // eax: value
349
  // ecx: FixedArray
350
  // ebx: index (as a smi)
351
  __ j(below, &fast, taken);
352

    
353

    
354
  // Slow case: Push extra copies of the arguments (3).
355
  __ bind(&slow);
356
  __ pop(ecx);
357
  __ push(Operand(esp, 1 * kPointerSize));
358
  __ push(Operand(esp, 1 * kPointerSize));
359
  __ push(eax);
360
  __ push(ecx);
361
  // Do tail-call to runtime routine.
362
  __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
363

    
364

    
365
  // Extra capacity case: Check if there is extra capacity to
366
  // perform the store and update the length. Used for adding one
367
  // element to the array by writing to array[array.length].
368
  __ bind(&extra);
369
  // eax: value
370
  // edx: JSArray
371
  // ecx: FixedArray
372
  // ebx: index (as a smi)
373
  // flags: compare (ebx, edx.length())
374
  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
375
  __ sar(ebx, kSmiTagSize);  // untag
376
  __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset));
377
  __ j(above_equal, &slow, not_taken);
378
  // Restore tag and increment.
379
  __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize));
380
  __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx);
381
  __ sub(Operand(ebx), Immediate(1 << kSmiTagSize));  // decrement ebx again
382
  __ jmp(&fast);
383

    
384

    
385
  // Array case: Get the length and the elements array from the JS
386
  // array. Check that the array is in fast mode; if it is the
387
  // length is always a smi.
388
  __ bind(&array);
389
  // eax: value
390
  // edx: JSArray
391
  // ebx: index (as a smi)
392
  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
393
  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
394
         Immediate(Factory::hash_table_map()));
395
  __ j(equal, &slow, not_taken);
396

    
397
  // Check the key against the length in the array, compute the
398
  // address to store into and fall through to fast case.
399
  __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
400
  __ j(above_equal, &extra, not_taken);
401

    
402

    
403
  // Fast case: Do the store.
404
  __ bind(&fast);
405
  // eax: value
406
  // ecx: FixedArray
407
  // ebx: index (as a smi)
408
  __ mov(Operand(ecx, ebx, times_2, Array::kHeaderSize - kHeapObjectTag), eax);
409
  // Update write barrier for the elements array address.
410
  __ mov(edx, Operand(eax));
411
  __ RecordWrite(ecx, 0, edx, ebx);
412
  __ ret(0);
413
}
414

    
415

    
416
// Defined in ic.cc.
417
Object* CallIC_Miss(Arguments args);
418

    
419
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
420
  // ----------- S t a t e -------------
421
  // -----------------------------------
422
  Label number, non_number, non_string, boolean, probe, miss;
423

    
424
  // Get the receiver of the function from the stack; 1 ~ return address.
425
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
426
  // Get the name of the function from the stack; 2 ~ return address, receiver
427
  __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize));
428

    
429
  // Probe the stub cache.
430
  Code::Flags flags =
431
      Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc);
432
  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx);
433

    
434
  // If the stub cache probing failed, the receiver might be a value.
435
  // For value objects, we use the map of the prototype objects for
436
  // the corresponding JSValue for the cache and that is what we need
437
  // to probe.
438
  //
439
  // Check for number.
440
  __ test(edx, Immediate(kSmiTagMask));
441
  __ j(zero, &number, not_taken);
442
  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
443
  __ j(not_equal, &non_number, taken);
444
  __ bind(&number);
445
  StubCompiler::GenerateLoadGlobalFunctionPrototype(
446
      masm, Context::NUMBER_FUNCTION_INDEX, edx);
447
  __ jmp(&probe);
448

    
449
  // Check for string.
450
  __ bind(&non_number);
451
  __ cmp(ebx, FIRST_NONSTRING_TYPE);
452
  __ j(above_equal, &non_string, taken);
453
  StubCompiler::GenerateLoadGlobalFunctionPrototype(
454
      masm, Context::STRING_FUNCTION_INDEX, edx);
455
  __ jmp(&probe);
456

    
457
  // Check for boolean.
458
  __ bind(&non_string);
459
  __ cmp(edx, Factory::true_value());
460
  __ j(equal, &boolean, not_taken);
461
  __ cmp(edx, Factory::false_value());
462
  __ j(not_equal, &miss, taken);
463
  __ bind(&boolean);
464
  StubCompiler::GenerateLoadGlobalFunctionPrototype(
465
      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
466

    
467
  // Probe the stub cache for the value object.
468
  __ bind(&probe);
469
  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx);
470

    
471
  // Cache miss: Jump to runtime.
472
  __ bind(&miss);
473
  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
474
}
475

    
476

    
477
static void GenerateNormalHelper(MacroAssembler* masm,
478
                                 int argc,
479
                                 bool is_global_object,
480
                                 Label* miss) {
481
  // Search dictionary - put result in register edx.
482
  GenerateDictionaryLoad(masm, miss, eax, edx, ebx, ecx);
483

    
484
  // Move the result to register edi and check that it isn't a smi.
485
  __ mov(edi, Operand(edx));
486
  __ test(edx, Immediate(kSmiTagMask));
487
  __ j(zero, miss, not_taken);
488

    
489
  // Check that the value is a JavaScript function.
490
  __ CmpObjectType(edx, JS_FUNCTION_TYPE, edx);
491
  __ j(not_equal, miss, not_taken);
492

    
493
  // Check that the function has been loaded.
494
  __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
495
  __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kLazyLoadDataOffset));
496
  __ cmp(edx, Factory::undefined_value());
497
  __ j(not_equal, miss, not_taken);
498

    
499
  // Patch the receiver with the global proxy if necessary.
500
  if (is_global_object) {
501
    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
502
    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
503
    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
504
  }
505

    
506
  // Invoke the function.
507
  ParameterCount actual(argc);
508
  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
509
}
510

    
511

    
512
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
513
  // ----------- S t a t e -------------
514
  // -----------------------------------
515

    
516
  Label miss, global_object, non_global_object;
517

    
518
  // Get the receiver of the function from the stack; 1 ~ return address.
519
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
520
  // Get the name of the function from the stack; 2 ~ return address, receiver.
521
  __ mov(ecx, Operand(esp, (argc + 2) * kPointerSize));
522

    
523
  // Check that the receiver isn't a smi.
524
  __ test(edx, Immediate(kSmiTagMask));
525
  __ j(zero, &miss, not_taken);
526

    
527
  // Check that the receiver is a valid JS object.
528
  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
529
  __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
530
  __ cmp(eax, FIRST_JS_OBJECT_TYPE);
531
  __ j(less, &miss, not_taken);
532

    
533
  // If this assert fails, we have to check upper bound too.
534
  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
535

    
536
  // Check for access to global object.
537
  __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
538
  __ j(equal, &global_object);
539
  __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
540
  __ j(not_equal, &non_global_object);
541

    
542
  // Accessing global object: Load and invoke.
543
  __ bind(&global_object);
544
  // Check that the global object does not require access checks.
545
  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
546
  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
547
  __ j(not_equal, &miss, not_taken);
548
  GenerateNormalHelper(masm, argc, true, &miss);
549

    
550
  // Accessing non-global object: Check for access to global proxy.
551
  Label global_proxy, invoke;
552
  __ bind(&non_global_object);
553
  __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
554
  __ j(equal, &global_proxy, not_taken);
555
  // Check that the non-global, non-global-proxy object does not
556
  // require access checks.
557
  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
558
  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
559
  __ j(not_equal, &miss, not_taken);
560
  __ bind(&invoke);
561
  GenerateNormalHelper(masm, argc, false, &miss);
562

    
563
  // Global object proxy access: Check access rights.
564
  __ bind(&global_proxy);
565
  __ CheckAccessGlobalProxy(edx, eax, &miss);
566
  __ jmp(&invoke);
567

    
568
  // Cache miss: Jump to runtime.
569
  __ bind(&miss);
570
  Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
571
}
572

    
573

    
574
void CallIC::Generate(MacroAssembler* masm,
575
                      int argc,
576
                      const ExternalReference& f) {
577
  // ----------- S t a t e -------------
578
  // -----------------------------------
579

    
580
  // Get the receiver of the function from the stack; 1 ~ return address.
581
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
582
  // Get the name of the function to call from the stack.
583
  // 2 ~ receiver, return address.
584
  __ mov(ebx, Operand(esp, (argc + 2) * kPointerSize));
585

    
586
  // Enter an internal frame.
587
  __ EnterInternalFrame();
588

    
589
  // Push the receiver and the name of the function.
590
  __ push(edx);
591
  __ push(ebx);
592

    
593
  // Call the entry.
594
  CEntryStub stub;
595
  __ mov(eax, Immediate(2));
596
  __ mov(ebx, Immediate(f));
597
  __ CallStub(&stub);
598

    
599
  // Move result to edi and exit the internal frame.
600
  __ mov(edi, eax);
601
  __ LeaveInternalFrame();
602

    
603
  // Check if the receiver is a global object of some sort.
604
  Label invoke, global;
605
  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
606
  __ test(edx, Immediate(kSmiTagMask));
607
  __ j(zero, &invoke, not_taken);
608
  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
609
  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
610
  __ cmp(ecx, JS_GLOBAL_OBJECT_TYPE);
611
  __ j(equal, &global);
612
  __ cmp(ecx, JS_BUILTINS_OBJECT_TYPE);
613
  __ j(not_equal, &invoke);
614

    
615
  // Patch the receiver on the stack.
616
  __ bind(&global);
617
  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
618
  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
619

    
620
  // Invoke the function.
621
  ParameterCount actual(argc);
622
  __ bind(&invoke);
623
  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
624
}
625

    
626

    
627
// Defined in ic.cc.
628
Object* LoadIC_Miss(Arguments args);
629

    
630
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
631
  // ----------- S t a t e -------------
632
  //  -- ecx    : name
633
  //  -- esp[0] : return address
634
  //  -- esp[4] : receiver
635
  // -----------------------------------
636

    
637
  __ mov(eax, Operand(esp, kPointerSize));
638

    
639
  // Probe the stub cache.
640
  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
641
  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx);
642

    
643
  // Cache miss: Jump to runtime.
644
  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
645
}
646

    
647

    
648
void LoadIC::GenerateNormal(MacroAssembler* masm) {
649
  // ----------- S t a t e -------------
650
  //  -- ecx    : name
651
  //  -- esp[0] : return address
652
  //  -- esp[4] : receiver
653
  // -----------------------------------
654

    
655
  Label miss, probe, global;
656

    
657
  __ mov(eax, Operand(esp, kPointerSize));
658

    
659
  // Check that the receiver isn't a smi.
660
  __ test(eax, Immediate(kSmiTagMask));
661
  __ j(zero, &miss, not_taken);
662

    
663
  // Check that the receiver is a valid JS object.
664
  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
665
  __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
666
  __ cmp(edx, FIRST_JS_OBJECT_TYPE);
667
  __ j(less, &miss, not_taken);
668

    
669
  // If this assert fails, we have to check upper bound too.
670
  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
671

    
672
  // Check for access to global object (unlikely).
673
  __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
674
  __ j(equal, &global, not_taken);
675

    
676
  // Check for non-global object that requires access check.
677
  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
678
  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
679
  __ j(not_zero, &miss, not_taken);
680

    
681
  // Search the dictionary placing the result in eax.
682
  __ bind(&probe);
683
  GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx);
684
  GenerateCheckNonFunctionOrLoaded(masm, &miss, eax, edx);
685
  __ ret(0);
686

    
687
  // Global object access: Check access rights.
688
  __ bind(&global);
689
  __ CheckAccessGlobalProxy(eax, edx, &miss);
690
  __ jmp(&probe);
691

    
692
  // Cache miss: Restore receiver from stack and jump to runtime.
693
  __ bind(&miss);
694
  __ mov(eax, Operand(esp, 1 * kPointerSize));
695
  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
696
}
697

    
698

    
699
void LoadIC::GenerateMiss(MacroAssembler* masm) {
700
  // ----------- S t a t e -------------
701
  //  -- ecx    : name
702
  //  -- esp[0] : return address
703
  //  -- esp[4] : receiver
704
  // -----------------------------------
705

    
706
  Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
707
}
708

    
709

    
710
void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
711
  // ----------- S t a t e -------------
712
  //  -- ecx    : name
713
  //  -- esp[0] : return address
714
  //  -- esp[4] : receiver
715
  // -----------------------------------
716

    
717
  __ mov(eax, Operand(esp, kPointerSize));
718

    
719
  // Move the return address below the arguments.
720
  __ pop(ebx);
721
  __ push(eax);
722
  __ push(ecx);
723
  __ push(ebx);
724

    
725
  // Perform tail call to the entry.
726
  __ TailCallRuntime(f, 2);
727
}
728

    
729

    
730
void KeyedLoadIC::PatchInlinedMapCheck(Address address, Object* value) {
731
  static const byte kTestEaxByte = 0xA9;
732
  Address test_instruction_address = address + 4;  // 4 = stub address
733
  // The keyed load has a fast inlined case if the IC call instruction
734
  // is immediately followed by a test instruction.
735
  if (*test_instruction_address == kTestEaxByte) {
736
    // Fetch the offset from the test instruction to the map cmp
737
    // instruction.  This offset is stored in the last 4 bytes of the
738
    // 5 byte test instruction.
739
    Address offset_address = test_instruction_address + 1;
740
    int offset_value = *(reinterpret_cast<int*>(offset_address));
741
    // Compute the map address.  The map address is in the last 4
742
    // bytes of the 7-byte operand-immediate compare instruction, so
743
    // we add 3 to the offset to get the map address.
744
    Address map_address = test_instruction_address + offset_value + 3;
745
    // patch the map check.
746
    (*(reinterpret_cast<Object**>(map_address))) = value;
747
  }
748
}
749

    
750

    
751
// Defined in ic.cc.
752
Object* KeyedLoadIC_Miss(Arguments args);
753

    
754

    
755
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
756
  // ----------- S t a t e -------------
757
  //  -- esp[0] : return address
758
  //  -- esp[4] : name
759
  //  -- esp[8] : receiver
760
  // -----------------------------------
761

    
762
  Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
763
}
764

    
765

    
766
void KeyedLoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
767
  // ----------- S t a t e -------------
768
  //  -- esp[0] : return address
769
  //  -- esp[4] : name
770
  //  -- esp[8] : receiver
771
  // -----------------------------------
772

    
773
  __ mov(eax, Operand(esp, kPointerSize));
774
  __ mov(ecx, Operand(esp, 2 * kPointerSize));
775

    
776
  // Move the return address below the arguments.
777
  __ pop(ebx);
778
  __ push(ecx);
779
  __ push(eax);
780
  __ push(ebx);
781

    
782
  // Perform tail call to the entry.
783
  __ TailCallRuntime(f, 2);
784
}
785

    
786

    
787
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
788
  // ----------- S t a t e -------------
789
  //  -- eax    : value
790
  //  -- ecx    : name
791
  //  -- esp[0] : return address
792
  //  -- esp[4] : receiver
793
  // -----------------------------------
794

    
795
  // Get the receiver from the stack and probe the stub cache.
796
  __ mov(edx, Operand(esp, 4));
797
  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC);
798
  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx);
799

    
800
  // Cache miss: Jump to runtime.
801
  Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
802
}
803

    
804

    
805
void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
806
  // ----------- S t a t e -------------
807
  //  -- eax    : value
808
  //  -- ecx    : transition map
809
  //  -- esp[0] : return address
810
  //  -- esp[4] : receiver
811
  // -----------------------------------
812

    
813
  // Move the return address below the arguments.
814
  __ pop(ebx);
815
  __ push(Operand(esp, 0));
816
  __ push(ecx);
817
  __ push(eax);
818
  __ push(ebx);
819
  // Perform tail call to the entry.
820
  __ TailCallRuntime(
821
      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
822
}
823

    
824

    
825
void StoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
826
  // ----------- S t a t e -------------
827
  //  -- eax    : value
828
  //  -- ecx    : name
829
  //  -- esp[0] : return address
830
  //  -- esp[4] : receiver
831
  // -----------------------------------
832

    
833
  // Move the return address below the arguments.
834
  __ pop(ebx);
835
  __ push(Operand(esp, 0));
836
  __ push(ecx);
837
  __ push(eax);
838
  __ push(ebx);
839

    
840
  // Perform tail call to the entry.
841
  __ TailCallRuntime(f, 3);
842
}
843

    
844

    
845
// Defined in ic.cc.
846
Object* KeyedStoreIC_Miss(Arguments args);
847

    
848
void KeyedStoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) {
849
  // ----------- S t a t e -------------
850
  //  -- eax    : value
851
  //  -- esp[0] : return address
852
  //  -- esp[4] : key
853
  //  -- esp[8] : receiver
854
  // -----------------------------------
855

    
856
  // Move the return address below the arguments.
857
  __ pop(ecx);
858
  __ push(Operand(esp, 1 * kPointerSize));
859
  __ push(Operand(esp, 1 * kPointerSize));
860
  __ push(eax);
861
  __ push(ecx);
862

    
863
  // Do tail-call to runtime routine.
864
  __ TailCallRuntime(f, 3);
865
}
866

    
867

    
868
void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
869
  // ----------- S t a t e -------------
870
  //  -- eax    : value
871
  //  -- ecx    : transition map
872
  //  -- esp[0] : return address
873
  //  -- esp[4] : key
874
  //  -- esp[8] : receiver
875
  // -----------------------------------
876

    
877
  // Move the return address below the arguments.
878
  __ pop(ebx);
879
  __ push(Operand(esp, 1 * kPointerSize));
880
  __ push(ecx);
881
  __ push(eax);
882
  __ push(ebx);
883

    
884
  // Do tail-call to runtime routine.
885
  __ TailCallRuntime(
886
      ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3);
887
}
888

    
889
#undef __
890

    
891

    
892
} }  // namespace v8::internal