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 / stub-cache.cc @ 40c0f755

History | View | Annotate | Download (33.3 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 "api.h"
31
#include "arguments.h"
32
#include "ic-inl.h"
33
#include "stub-cache.h"
34

    
35
namespace v8 { namespace internal {
36

    
37
// -----------------------------------------------------------------------
38
// StubCache implementation.
39

    
40

    
41
StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
42
StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
43

    
44
void StubCache::Initialize(bool create_heap_objects) {
45
  ASSERT(IsPowerOf2(kPrimaryTableSize));
46
  ASSERT(IsPowerOf2(kSecondaryTableSize));
47
  if (create_heap_objects) {
48
    HandleScope scope;
49
    Clear();
50
  }
51
}
52

    
53

    
54
Code* StubCache::Set(String* name, Map* map, Code* code) {
55
  // Get the flags from the code.
56
  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
57

    
58
  // Validate that the name does not move on scavenge, and that we
59
  // can use identity checks instead of string equality checks.
60
  ASSERT(!Heap::InNewSpace(name));
61
  ASSERT(name->IsSymbol());
62

    
63
  // The state bits are not important to the hash function because
64
  // the stub cache only contains monomorphic stubs. Make sure that
65
  // the bits are the least significant so they will be the ones
66
  // masked out.
67
  ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
68
  ASSERT(Code::kFlagsICStateShift == 0);
69

    
70
  // Make sure that the code type is not included in the hash.
71
  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
72

    
73
  // Compute the primary entry.
74
  int primary_offset = PrimaryOffset(name, flags, map);
75
  Entry* primary = entry(primary_, primary_offset);
76
  Code* hit = primary->value;
77

    
78
  // If the primary entry has useful data in it, we retire it to the
79
  // secondary cache before overwriting it.
80
  if (hit != Builtins::builtin(Builtins::Illegal)) {
81
    Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
82
    int secondary_offset =
83
        SecondaryOffset(primary->key, primary_flags, primary_offset);
84
    Entry* secondary = entry(secondary_, secondary_offset);
85
    *secondary = *primary;
86
  }
87

    
88
  // Update primary cache.
89
  primary->key = name;
90
  primary->value = code;
91
  return code;
92
}
93

    
94

    
95
Object* StubCache::ComputeLoadField(String* name,
96
                                    JSObject* receiver,
97
                                    JSObject* holder,
98
                                    int field_index) {
99
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
100
  Object* code = receiver->map()->FindInCodeCache(name, flags);
101
  if (code->IsUndefined()) {
102
    LoadStubCompiler compiler;
103
    code = compiler.CompileLoadField(receiver, holder, field_index, name);
104
    if (code->IsFailure()) return code;
105
    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
106
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
107
    if (result->IsFailure()) return code;
108
  }
109
  return Set(name, receiver->map(), Code::cast(code));
110
}
111

    
112

    
113
Object* StubCache::ComputeLoadCallback(String* name,
114
                                       JSObject* receiver,
115
                                       JSObject* holder,
116
                                       AccessorInfo* callback) {
117
  ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
118
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
119
  Object* code = receiver->map()->FindInCodeCache(name, flags);
120
  if (code->IsUndefined()) {
121
    LoadStubCompiler compiler;
122
    code = compiler.CompileLoadCallback(receiver, holder, callback, name);
123
    if (code->IsFailure()) return code;
124
    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
125
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
126
    if (result->IsFailure()) return code;
127
  }
128
  return Set(name, receiver->map(), Code::cast(code));
129
}
130

    
131

    
132
Object* StubCache::ComputeLoadConstant(String* name,
133
                                       JSObject* receiver,
134
                                       JSObject* holder,
135
                                       Object* value) {
136
  Code::Flags flags =
137
      Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
138
  Object* code = receiver->map()->FindInCodeCache(name, flags);
139
  if (code->IsUndefined()) {
140
    LoadStubCompiler compiler;
141
    code = compiler.CompileLoadConstant(receiver, holder, value, name);
142
    if (code->IsFailure()) return code;
143
    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
144
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
145
    if (result->IsFailure()) return code;
146
  }
147
  return Set(name, receiver->map(), Code::cast(code));
148
}
149

    
150

    
151
Object* StubCache::ComputeLoadInterceptor(String* name,
152
                                          JSObject* receiver,
153
                                          JSObject* holder) {
154
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
155
  Object* code = receiver->map()->FindInCodeCache(name, flags);
156
  if (code->IsUndefined()) {
157
    LoadStubCompiler compiler;
158
    code = compiler.CompileLoadInterceptor(receiver, holder, name);
159
    if (code->IsFailure()) return code;
160
    LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
161
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
162
    if (result->IsFailure()) return code;
163
  }
164
  return Set(name, receiver->map(), Code::cast(code));
165
}
166

    
167

    
168
Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
169
  Code* code = Builtins::builtin(Builtins::LoadIC_Normal);
170
  return Set(name, receiver->map(), code);
171
}
172

    
173

    
174
Object* StubCache::ComputeKeyedLoadField(String* name,
175
                                         JSObject* receiver,
176
                                         JSObject* holder,
177
                                         int field_index) {
178
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
179
  Object* code = receiver->map()->FindInCodeCache(name, flags);
180
  if (code->IsUndefined()) {
181
    KeyedLoadStubCompiler compiler;
182
    code = compiler.CompileLoadField(name, receiver, holder, field_index);
183
    if (code->IsFailure()) return code;
184
    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
185
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
186
    if (result->IsFailure()) return result;
187
  }
188
  return code;
189
}
190

    
191

    
192
Object* StubCache::ComputeKeyedLoadConstant(String* name,
193
                                            JSObject* receiver,
194
                                            JSObject* holder,
195
                                            Object* value) {
196
  Code::Flags flags =
197
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
198
  Object* code = receiver->map()->FindInCodeCache(name, flags);
199
  if (code->IsUndefined()) {
200
    KeyedLoadStubCompiler compiler;
201
    code = compiler.CompileLoadConstant(name, receiver, holder, value);
202
    if (code->IsFailure()) return code;
203
    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
204
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
205
    if (result->IsFailure()) return result;
206
  }
207
  return code;
208
}
209

    
210

    
211
Object* StubCache::ComputeKeyedLoadInterceptor(String* name,
212
                                               JSObject* receiver,
213
                                               JSObject* holder) {
214
  Code::Flags flags =
215
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
216
  Object* code = receiver->map()->FindInCodeCache(name, flags);
217
  if (code->IsUndefined()) {
218
    KeyedLoadStubCompiler compiler;
219
    code = compiler.CompileLoadInterceptor(receiver, holder, name);
220
    if (code->IsFailure()) return code;
221
    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
222
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
223
    if (result->IsFailure()) return result;
224
  }
225
  return code;
226
}
227

    
228

    
229
Object* StubCache::ComputeKeyedLoadCallback(String* name,
230
                                            JSObject* receiver,
231
                                            JSObject* holder,
232
                                            AccessorInfo* callback) {
233
  Code::Flags flags =
234
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
235
  Object* code = receiver->map()->FindInCodeCache(name, flags);
236
  if (code->IsUndefined()) {
237
    KeyedLoadStubCompiler compiler;
238
    code = compiler.CompileLoadCallback(name, receiver, holder, callback);
239
    if (code->IsFailure()) return code;
240
    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
241
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
242
    if (result->IsFailure()) return result;
243
  }
244
  return code;
245
}
246

    
247

    
248

    
249
Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
250
                                               JSArray* receiver) {
251
  Code::Flags flags =
252
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
253
  Object* code = receiver->map()->FindInCodeCache(name, flags);
254
  if (code->IsUndefined()) {
255
    KeyedLoadStubCompiler compiler;
256
    code = compiler.CompileLoadArrayLength(name);
257
    if (code->IsFailure()) return code;
258
    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
259
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
260
    if (result->IsFailure()) return result;
261
  }
262
  return code;
263
}
264

    
265

    
266
Object* StubCache::ComputeKeyedLoadStringLength(String* name,
267
                                                String* receiver) {
268
  Code::Flags flags =
269
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
270
  Object* code = receiver->map()->FindInCodeCache(name, flags);
271
  if (code->IsUndefined()) {
272
    KeyedLoadStubCompiler compiler;
273
    code = compiler.CompileLoadStringLength(name);
274
    if (code->IsFailure()) return code;
275
    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
276
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
277
    if (result->IsFailure()) return result;
278
  }
279
  return code;
280
}
281

    
282

    
283
Object* StubCache::ComputeKeyedLoadFunctionPrototype(String* name,
284
                                                     JSFunction* receiver) {
285
  Code::Flags flags =
286
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
287
  Object* code = receiver->map()->FindInCodeCache(name, flags);
288
  if (code->IsUndefined()) {
289
    KeyedLoadStubCompiler compiler;
290
    code = compiler.CompileLoadFunctionPrototype(name);
291
    if (code->IsFailure()) return code;
292
    LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
293
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
294
    if (result->IsFailure()) return result;
295
  }
296
  return code;
297
}
298

    
299

    
300
Object* StubCache::ComputeStoreField(String* name,
301
                                     JSObject* receiver,
302
                                     int field_index,
303
                                     Map* transition) {
304
  PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
305
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
306
  Object* code = receiver->map()->FindInCodeCache(name, flags);
307
  if (code->IsUndefined()) {
308
    StoreStubCompiler compiler;
309
    code = compiler.CompileStoreField(receiver, field_index, transition, name);
310
    if (code->IsFailure()) return code;
311
    LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
312
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
313
    if (result->IsFailure()) return result;
314
  }
315
  return Set(name, receiver->map(), Code::cast(code));
316
}
317

    
318

    
319
Object* StubCache::ComputeStoreCallback(String* name,
320
                                        JSObject* receiver,
321
                                        AccessorInfo* callback) {
322
  ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
323
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
324
  Object* code = receiver->map()->FindInCodeCache(name, flags);
325
  if (code->IsUndefined()) {
326
    StoreStubCompiler compiler;
327
    code = compiler.CompileStoreCallback(receiver, callback, name);
328
    if (code->IsFailure()) return code;
329
    LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
330
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
331
    if (result->IsFailure()) return result;
332
  }
333
  return Set(name, receiver->map(), Code::cast(code));
334
}
335

    
336

    
337
Object* StubCache::ComputeStoreInterceptor(String* name,
338
                                           JSObject* receiver) {
339
  Code::Flags flags =
340
      Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
341
  Object* code = receiver->map()->FindInCodeCache(name, flags);
342
  if (code->IsUndefined()) {
343
    StoreStubCompiler compiler;
344
    code = compiler.CompileStoreInterceptor(receiver, name);
345
    if (code->IsFailure()) return code;
346
    LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
347
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
348
    if (result->IsFailure()) return result;
349
  }
350
  return Set(name, receiver->map(), Code::cast(code));
351
}
352

    
353

    
354
Object* StubCache::ComputeKeyedStoreField(String* name, JSObject* receiver,
355
                                          int field_index, Map* transition) {
356
  PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
357
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
358
  Object* code = receiver->map()->FindInCodeCache(name, flags);
359
  if (code->IsUndefined()) {
360
    KeyedStoreStubCompiler compiler;
361
    code = compiler.CompileStoreField(receiver, field_index, transition, name);
362
    if (code->IsFailure()) return code;
363
    LOG(CodeCreateEvent("KeyedStoreIC", Code::cast(code), name));
364
    Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
365
    if (result->IsFailure()) return result;
366
  }
367
  return code;
368
}
369

    
370

    
371
Object* StubCache::ComputeCallConstant(int argc,
372
                                       String* name,
373
                                       Object* object,
374
                                       JSObject* holder,
375
                                       JSFunction* function) {
376
  // Compute the check type and the map.
377
  Map* map = IC::GetCodeCacheMapForObject(object);
378

    
379
  // Compute check type based on receiver/holder.
380
  StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK;
381
  if (object->IsString()) {
382
    check = StubCompiler::STRING_CHECK;
383
  } else if (object->IsNumber()) {
384
    check = StubCompiler::NUMBER_CHECK;
385
  } else if (object->IsBoolean()) {
386
    check = StubCompiler::BOOLEAN_CHECK;
387
  }
388

    
389
  Code::Flags flags =
390
      Code::ComputeMonomorphicFlags(Code::CALL_IC, CONSTANT_FUNCTION, argc);
391
  Object* code = map->FindInCodeCache(name, flags);
392
  if (code->IsUndefined()) {
393
    if (object->IsJSObject()) {
394
      Object* opt =
395
          Top::LookupSpecialFunction(JSObject::cast(object), holder, function);
396
      if (opt->IsJSFunction()) {
397
        check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK;
398
        function = JSFunction::cast(opt);
399
      }
400
    }
401
    // If the function hasn't been compiled yet, we cannot do it now
402
    // because it may cause GC. To avoid this issue, we return an
403
    // internal error which will make sure we do not update any
404
    // caches.
405
    if (!function->is_compiled()) return Failure::InternalError();
406
    // Compile the stub - only create stubs for fully compiled functions.
407
    CallStubCompiler compiler(argc);
408
    code = compiler.CompileCallConstant(object, holder, function, check);
409
    if (code->IsFailure()) return code;
410
    LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
411
    Object* result = map->UpdateCodeCache(name, Code::cast(code));
412
    if (result->IsFailure()) return result;
413
  }
414
  return Set(name, map, Code::cast(code));
415
}
416

    
417

    
418
Object* StubCache::ComputeCallField(int argc,
419
                                    String* name,
420
                                    Object* object,
421
                                    JSObject* holder,
422
                                    int index) {
423
  // Compute the check type and the map.
424
  Map* map = IC::GetCodeCacheMapForObject(object);
425

    
426
  // TODO(1233596): We cannot do receiver map check for non-JS objects
427
  // because they may be represented as immediates without a
428
  // map. Instead, we check against the map in the holder.
429
  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
430
    object = holder;
431
  }
432

    
433
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, FIELD, argc);
434
  Object* code = map->FindInCodeCache(name, flags);
435
  if (code->IsUndefined()) {
436
    CallStubCompiler compiler(argc);
437
    code = compiler.CompileCallField(object, holder, index, name);
438
    if (code->IsFailure()) return code;
439
    LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
440
    Object* result = map->UpdateCodeCache(name, Code::cast(code));
441
    if (result->IsFailure()) return result;
442
  }
443
  return Set(name, map, Code::cast(code));
444
}
445

    
446

    
447
Object* StubCache::ComputeCallInterceptor(int argc,
448
                                          String* name,
449
                                          Object* object,
450
                                          JSObject* holder) {
451
  // Compute the check type and the map.
452
  // If the object is a value, we use the prototype map for the cache.
453
  Map* map = IC::GetCodeCacheMapForObject(object);
454

    
455
  // TODO(1233596): We cannot do receiver map check for non-JS objects
456
  // because they may be represented as immediates without a
457
  // map. Instead, we check against the map in the holder.
458
  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
459
    object = holder;
460
  }
461

    
462
  Code::Flags flags =
463
      Code::ComputeMonomorphicFlags(Code::CALL_IC, INTERCEPTOR, argc);
464
  Object* code = map->FindInCodeCache(name, flags);
465
  if (code->IsUndefined()) {
466
    CallStubCompiler compiler(argc);
467
    code = compiler.CompileCallInterceptor(object, holder, name);
468
    if (code->IsFailure()) return code;
469
    LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
470
    Object* result = map->UpdateCodeCache(name, Code::cast(code));
471
    if (result->IsFailure()) return result;
472
  }
473
  return Set(name, map, Code::cast(code));
474
}
475

    
476

    
477
Object* StubCache::ComputeCallNormal(int argc,
478
                                     String* name,
479
                                     JSObject* receiver) {
480
  Object* code = ComputeCallNormal(argc);
481
  if (code->IsFailure()) return code;
482
  return Set(name, receiver->map(), Code::cast(code));
483
}
484

    
485

    
486
static Object* GetProbeValue(Code::Flags flags) {
487
  Dictionary* dictionary = Heap::non_monomorphic_cache();
488
  int entry = dictionary->FindNumberEntry(flags);
489
  if (entry != -1) return dictionary->ValueAt(entry);
490
  return Heap::undefined_value();
491
}
492

    
493

    
494
static Object* ProbeCache(Code::Flags flags) {
495
  Object* probe = GetProbeValue(flags);
496
  if (probe != Heap::undefined_value()) return probe;
497
  // Seed the cache with an undefined value to make sure that any
498
  // generated code object can always be inserted into the cache
499
  // without causing  allocation failures.
500
  Object* result =
501
      Heap::non_monomorphic_cache()->AtNumberPut(flags,
502
                                                 Heap::undefined_value());
503
  if (result->IsFailure()) return result;
504
  Heap::set_non_monomorphic_cache(Dictionary::cast(result));
505
  return probe;
506
}
507

    
508

    
509
static Object* FillCache(Object* code) {
510
  if (code->IsCode()) {
511
    int entry =
512
        Heap::non_monomorphic_cache()->FindNumberEntry(
513
            Code::cast(code)->flags());
514
    // The entry must be present see comment in ProbeCache.
515
    ASSERT(entry != -1);
516
    ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
517
           Heap::undefined_value());
518
    Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
519
    CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
520
  }
521
  return code;
522
}
523

    
524

    
525
Code* StubCache::FindCallInitialize(int argc) {
526
  Code::Flags flags =
527
      Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc);
528
  Object* result = ProbeCache(flags);
529
  ASSERT(!result->IsUndefined());
530
  // This might be called during the marking phase of the collector
531
  // hence the unchecked cast.
532
  return reinterpret_cast<Code*>(result);
533
}
534

    
535

    
536
Object* StubCache::ComputeCallInitialize(int argc) {
537
  Code::Flags flags =
538
      Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc);
539
  Object* probe = ProbeCache(flags);
540
  if (!probe->IsUndefined()) return probe;
541
  StubCompiler compiler;
542
  return FillCache(compiler.CompileCallInitialize(flags));
543
}
544

    
545

    
546
Object* StubCache::ComputeCallInitializeInLoop(int argc) {
547
  Code::Flags flags =
548
      Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED_IN_LOOP, NORMAL, argc);
549
  Object* probe = ProbeCache(flags);
550
  if (!probe->IsUndefined()) return probe;
551
  StubCompiler compiler;
552
  return FillCache(compiler.CompileCallInitialize(flags));
553
}
554

    
555

    
556

    
557
Object* StubCache::ComputeCallPreMonomorphic(int argc) {
558
  Code::Flags flags =
559
      Code::ComputeFlags(Code::CALL_IC, PREMONOMORPHIC, NORMAL, argc);
560
  Object* probe = ProbeCache(flags);
561
  if (!probe->IsUndefined()) return probe;
562
  StubCompiler compiler;
563
  return FillCache(compiler.CompileCallPreMonomorphic(flags));
564
}
565

    
566

    
567
Object* StubCache::ComputeCallNormal(int argc) {
568
  Code::Flags flags =
569
      Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc);
570
  Object* probe = ProbeCache(flags);
571
  if (!probe->IsUndefined()) return probe;
572
  StubCompiler compiler;
573
  return FillCache(compiler.CompileCallNormal(flags));
574
}
575

    
576

    
577
Object* StubCache::ComputeCallMegamorphic(int argc) {
578
  Code::Flags flags =
579
      Code::ComputeFlags(Code::CALL_IC, MEGAMORPHIC, NORMAL, argc);
580
  Object* probe = ProbeCache(flags);
581
  if (!probe->IsUndefined()) return probe;
582
  StubCompiler compiler;
583
  return FillCache(compiler.CompileCallMegamorphic(flags));
584
}
585

    
586

    
587
Object* StubCache::ComputeCallMiss(int argc) {
588
  Code::Flags flags =
589
      Code::ComputeFlags(Code::STUB, MEGAMORPHIC, NORMAL, argc);
590
  Object* probe = ProbeCache(flags);
591
  if (!probe->IsUndefined()) return probe;
592
  StubCompiler compiler;
593
  return FillCache(compiler.CompileCallMiss(flags));
594
}
595

    
596

    
597
Object* StubCache::ComputeCallDebugBreak(int argc) {
598
  Code::Flags flags =
599
      Code::ComputeFlags(Code::CALL_IC, DEBUG_BREAK, NORMAL, argc);
600
  Object* probe = ProbeCache(flags);
601
  if (!probe->IsUndefined()) return probe;
602
  StubCompiler compiler;
603
  return FillCache(compiler.CompileCallDebugBreak(flags));
604
}
605

    
606

    
607
Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) {
608
  Code::Flags flags =
609
      Code::ComputeFlags(Code::CALL_IC, DEBUG_PREPARE_STEP_IN, NORMAL, argc);
610
  Object* probe = ProbeCache(flags);
611
  if (!probe->IsUndefined()) return probe;
612
  StubCompiler compiler;
613
  return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
614
}
615

    
616

    
617
Object* StubCache::ComputeLazyCompile(int argc) {
618
  Code::Flags flags =
619
      Code::ComputeFlags(Code::STUB, UNINITIALIZED, NORMAL, argc);
620
  Object* probe = ProbeCache(flags);
621
  if (!probe->IsUndefined()) return probe;
622
  StubCompiler compiler;
623
  Object* result = FillCache(compiler.CompileLazyCompile(flags));
624
  if (result->IsCode()) {
625
    Code* code = Code::cast(result);
626
    USE(code);
627
    LOG(CodeCreateEvent("LazyCompile", code, code->arguments_count()));
628
  }
629
  return result;
630
}
631

    
632

    
633
void StubCache::Clear() {
634
  for (int i = 0; i < kPrimaryTableSize; i++) {
635
    primary_[i].key = Heap::empty_string();
636
    primary_[i].value = Builtins::builtin(Builtins::Illegal);
637
  }
638
  for (int j = 0; j < kSecondaryTableSize; j++) {
639
    secondary_[j].key = Heap::empty_string();
640
    secondary_[j].value = Builtins::builtin(Builtins::Illegal);
641
  }
642
}
643

    
644

    
645
// ------------------------------------------------------------------------
646
// StubCompiler implementation.
647

    
648

    
649
// Support function for computing call IC miss stubs.
650
Handle<Code> ComputeCallMiss(int argc) {
651
  CALL_HEAP_FUNCTION(StubCache::ComputeCallMiss(argc), Code);
652
}
653

    
654

    
655

    
656
Object* LoadCallbackProperty(Arguments args) {
657
  Handle<JSObject> recv = args.at<JSObject>(0);
658
  AccessorInfo* callback = AccessorInfo::cast(args[1]);
659
  Address getter_address = v8::ToCData<Address>(callback->getter());
660
  v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
661
  ASSERT(fun != NULL);
662
  Handle<String> name = args.at<String>(2);
663
  Handle<JSObject> holder = args.at<JSObject>(3);
664
  HandleScope scope;
665
  Handle<Object> data(callback->data());
666
  LOG(ApiNamedPropertyAccess("load", *recv, *name));
667
  // NOTE: If we can align the structure of an AccessorInfo with the
668
  // locations of the arguments to this function maybe we don't have
669
  // to explicitly create the structure but can just pass a pointer
670
  // into the stack.
671
  v8::AccessorInfo info(v8::Utils::ToLocal(recv),
672
                        v8::Utils::ToLocal(data),
673
                        v8::Utils::ToLocal(holder));
674
  v8::Handle<v8::Value> result;
675
  {
676
    // Leaving JavaScript.
677
    VMState state(EXTERNAL);
678
    result = fun(v8::Utils::ToLocal(name), info);
679
  }
680
  RETURN_IF_SCHEDULED_EXCEPTION();
681
  if (result.IsEmpty()) return Heap::undefined_value();
682
  return *v8::Utils::OpenHandle(*result);
683
}
684

    
685

    
686
Object* StoreCallbackProperty(Arguments args) {
687
  Handle<JSObject> recv = args.at<JSObject>(0);
688
  AccessorInfo* callback = AccessorInfo::cast(args[1]);
689
  Address setter_address = v8::ToCData<Address>(callback->setter());
690
  v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
691
  ASSERT(fun != NULL);
692
  Handle<String> name = args.at<String>(2);
693
  Handle<Object> value = args.at<Object>(3);
694
  HandleScope scope;
695
  Handle<Object> data(callback->data());
696
  LOG(ApiNamedPropertyAccess("store", *recv, *name));
697
  v8::AccessorInfo info(v8::Utils::ToLocal(recv),
698
                        v8::Utils::ToLocal(data),
699
                        v8::Utils::ToLocal(recv));
700
  {
701
    // Leaving JavaScript.
702
    VMState state(EXTERNAL);
703
    fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
704
  }
705
  RETURN_IF_SCHEDULED_EXCEPTION();
706
  return *value;
707
}
708

    
709

    
710
Object* LoadInterceptorProperty(Arguments args) {
711
  JSObject* recv = JSObject::cast(args[0]);
712
  JSObject* holder = JSObject::cast(args[1]);
713
  String* name = String::cast(args[2]);
714
  ASSERT(holder->HasNamedInterceptor());
715
  PropertyAttributes attr = NONE;
716
  Object* result = holder->GetPropertyWithInterceptor(recv, name, &attr);
717

    
718
  if (result->IsFailure()) return result;
719

    
720
  // If the property is present, return it.
721
  if (attr != ABSENT) return result;
722

    
723
  // If the top frame is an internal frame, this is really a call
724
  // IC. In this case, we simply return the undefined result which
725
  // will lead to an exception when trying to invoke the result as a
726
  // function.
727
  StackFrameIterator it;
728
  it.Advance();  // skip exit frame
729
  if (it.frame()->is_internal()) return result;
730

    
731
  // If the load is non-contextual, just return the undefined result.
732
  // Note that both keyed and non-keyed loads may end up here, so we
733
  // can't use either LoadIC or KeyedLoadIC constructors.
734
  IC ic(IC::NO_EXTRA_FRAME);
735
  ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
736
  if (!ic.is_contextual()) return result;
737

    
738
  // Throw a reference error.
739
  {
740
    HandleScope scope;
741
    // We cannot use the raw name pointer here since getting the
742
    // property might cause a GC.  However, we can get the name from
743
    // the stack using the arguments object.
744
    Handle<String> name_handle = args.at<String>(2);
745
    Handle<Object> error =
746
        Factory::NewReferenceError("not_defined",
747
                                   HandleVector(&name_handle, 1));
748
    return Top::Throw(*error);
749
  }
750
}
751

    
752

    
753
Object* StoreInterceptorProperty(Arguments args) {
754
  JSObject* recv = JSObject::cast(args[0]);
755
  String* name = String::cast(args[1]);
756
  Object* value = args[2];
757
  ASSERT(recv->HasNamedInterceptor());
758
  PropertyAttributes attr = NONE;
759
  Object* result = recv->SetPropertyWithInterceptor(name, value, attr);
760
  return result;
761
}
762

    
763

    
764
Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
765
  HandleScope scope;
766
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
767
  CallIC::GenerateInitialize(masm(), argc);
768
  Object* result = GetCodeWithFlags(flags, "CompileCallInitialize");
769
  if (!result->IsFailure()) {
770
    Counters::call_initialize_stubs.Increment();
771
    Code* code = Code::cast(result);
772
    USE(code);
773
    LOG(CodeCreateEvent("CallInitialize", code, code->arguments_count()));
774
  }
775
  return result;
776
}
777

    
778

    
779
Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
780
  HandleScope scope;
781
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
782
  CallIC::GenerateInitialize(masm(), argc);
783
  Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
784
  if (!result->IsFailure()) {
785
    Counters::call_premonomorphic_stubs.Increment();
786
    Code* code = Code::cast(result);
787
    USE(code);
788
    LOG(CodeCreateEvent("CallPreMonomorphic", code, code->arguments_count()));
789
  }
790
  return result;
791
}
792

    
793

    
794
Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
795
  HandleScope scope;
796
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
797
  CallIC::GenerateNormal(masm(), argc);
798
  Object* result = GetCodeWithFlags(flags, "CompileCallNormal");
799
  if (!result->IsFailure()) {
800
    Counters::call_normal_stubs.Increment();
801
    Code* code = Code::cast(result);
802
    USE(code);
803
    LOG(CodeCreateEvent("CallNormal", code, code->arguments_count()));
804
  }
805
  return result;
806
}
807

    
808

    
809
Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
810
  HandleScope scope;
811
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
812
  CallIC::GenerateMegamorphic(masm(), argc);
813
  Object* result = GetCodeWithFlags(flags, "CompileCallMegamorphic");
814
  if (!result->IsFailure()) {
815
    Counters::call_megamorphic_stubs.Increment();
816
    Code* code = Code::cast(result);
817
    USE(code);
818
    LOG(CodeCreateEvent("CallMegamorphic", code, code->arguments_count()));
819
  }
820
  return result;
821
}
822

    
823

    
824
Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
825
  HandleScope scope;
826
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
827
  CallIC::GenerateMiss(masm(), argc);
828
  Object* result = GetCodeWithFlags(flags, "CompileCallMiss");
829
  if (!result->IsFailure()) {
830
    Counters::call_megamorphic_stubs.Increment();
831
    Code* code = Code::cast(result);
832
    USE(code);
833
    LOG(CodeCreateEvent("CallMiss", code, code->arguments_count()));
834
  }
835
  return result;
836
}
837

    
838

    
839
Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
840
  HandleScope scope;
841
  Debug::GenerateCallICDebugBreak(masm());
842
  Object* result = GetCodeWithFlags(flags, "CompileCallDebugBreak");
843
  if (!result->IsFailure()) {
844
    Code* code = Code::cast(result);
845
    USE(code);
846
    LOG(CodeCreateEvent("CallDebugBreak", code, code->arguments_count()));
847
  }
848
  return result;
849
}
850

    
851

    
852
Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
853
  HandleScope scope;
854
  // Use the same code for the the step in preparations as we do for
855
  // the miss case.
856
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
857
  CallIC::GenerateMiss(masm(), argc);
858
  Object* result = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
859
  if (!result->IsFailure()) {
860
    Code* code = Code::cast(result);
861
    USE(code);
862
    LOG(CodeCreateEvent("CallDebugPrepareStepIn", code,
863
                        code->arguments_count()));
864
  }
865
  return result;
866
}
867

    
868

    
869
Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
870
  CodeDesc desc;
871
  masm_.GetCode(&desc);
872
  Object* result = Heap::CreateCode(desc, NULL, flags, masm_.CodeObject());
873
#ifdef ENABLE_DISASSEMBLER
874
  if (FLAG_print_code_stubs && !result->IsFailure()) {
875
    Code::cast(result)->Disassemble(name);
876
  }
877
#endif
878
  return result;
879
}
880

    
881

    
882
Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
883
  if (FLAG_print_code_stubs && (name != NULL)) {
884
    return GetCodeWithFlags(flags, *name->ToCString());
885
  }
886
  return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
887
}
888

    
889

    
890
Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
891
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
892
  return GetCodeWithFlags(flags, name);
893
}
894

    
895

    
896
Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
897
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
898
  return GetCodeWithFlags(flags, name);
899
}
900

    
901

    
902
Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
903
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
904
  return GetCodeWithFlags(flags, name);
905
}
906

    
907

    
908
Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
909
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
910
  return GetCodeWithFlags(flags, name);
911
}
912

    
913

    
914
Object* CallStubCompiler::GetCode(PropertyType type, String* name) {
915
  int argc = arguments_.immediate();
916
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, type, argc);
917
  return GetCodeWithFlags(flags, name);
918
}
919

    
920

    
921
} }  // namespace v8::internal