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 / type-info.cc @ f230a1cf

History | View | Annotate | Download (24.5 KB)

1
// Copyright 2012 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 "ast.h"
31
#include "code-stubs.h"
32
#include "compiler.h"
33
#include "ic.h"
34
#include "macro-assembler.h"
35
#include "stub-cache.h"
36
#include "type-info.h"
37

    
38
#include "ic-inl.h"
39
#include "objects-inl.h"
40

    
41
namespace v8 {
42
namespace internal {
43

    
44

    
45
TypeInfo TypeInfo::FromValue(Handle<Object> value) {
46
  if (value->IsSmi()) {
47
    return TypeInfo::Smi();
48
  } else if (value->IsHeapNumber()) {
49
    return TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value())
50
        ? TypeInfo::Integer32()
51
        : TypeInfo::Double();
52
  } else if (value->IsString()) {
53
    return TypeInfo::String();
54
  }
55
  return TypeInfo::Unknown();
56
}
57

    
58

    
59
TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
60
                                       Handle<Context> native_context,
61
                                       Isolate* isolate,
62
                                       Zone* zone)
63
    : native_context_(native_context),
64
      isolate_(isolate),
65
      zone_(zone) {
66
  BuildDictionary(code);
67
  ASSERT(dictionary_->IsDictionary());
68
}
69

    
70

    
71
static uint32_t IdToKey(TypeFeedbackId ast_id) {
72
  return static_cast<uint32_t>(ast_id.ToInt());
73
}
74

    
75

    
76
Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) {
77
  int entry = dictionary_->FindEntry(IdToKey(ast_id));
78
  if (entry != UnseededNumberDictionary::kNotFound) {
79
    Object* value = dictionary_->ValueAt(entry);
80
    if (value->IsCell()) {
81
      Cell* cell = Cell::cast(value);
82
      return Handle<Object>(cell->value(), isolate_);
83
    } else {
84
      return Handle<Object>(value, isolate_);
85
    }
86
  }
87
  return Handle<Object>::cast(isolate_->factory()->undefined_value());
88
}
89

    
90

    
91
Handle<Cell> TypeFeedbackOracle::GetInfoCell(
92
    TypeFeedbackId ast_id) {
93
  int entry = dictionary_->FindEntry(IdToKey(ast_id));
94
  if (entry != UnseededNumberDictionary::kNotFound) {
95
    Cell* cell = Cell::cast(dictionary_->ValueAt(entry));
96
    return Handle<Cell>(cell, isolate_);
97
  }
98
  return Handle<Cell>::null();
99
}
100

    
101

    
102
bool TypeFeedbackOracle::LoadIsUninitialized(Property* expr) {
103
  Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId());
104
  if (map_or_code->IsMap()) return false;
105
  if (map_or_code->IsCode()) {
106
    Handle<Code> code = Handle<Code>::cast(map_or_code);
107
    return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED;
108
  }
109
  return false;
110
}
111

    
112

    
113
bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) {
114
  Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId());
115
  if (map_or_code->IsMap()) return true;
116
  if (map_or_code->IsCode()) {
117
    Handle<Code> code = Handle<Code>::cast(map_or_code);
118
    bool preliminary_checks = code->is_keyed_load_stub() &&
119
        code->ic_state() == MONOMORPHIC &&
120
        Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
121
    if (!preliminary_checks) return false;
122
    Map* map = code->FindFirstMap();
123
    if (map == NULL) return false;
124
    map = map->CurrentMapForDeprecated();
125
    return map != NULL && !CanRetainOtherContext(map, *native_context_);
126
  }
127
  return false;
128
}
129

    
130

    
131
bool TypeFeedbackOracle::LoadIsPreMonomorphic(Property* expr) {
132
  Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId());
133
  if (map_or_code->IsCode()) {
134
    Handle<Code> code = Handle<Code>::cast(map_or_code);
135
    return code->is_inline_cache_stub() && code->ic_state() == PREMONOMORPHIC;
136
  }
137
  return false;
138
}
139

    
140

    
141
bool TypeFeedbackOracle::LoadIsPolymorphic(Property* expr) {
142
  Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId());
143
  if (map_or_code->IsCode()) {
144
    Handle<Code> code = Handle<Code>::cast(map_or_code);
145
    return code->is_keyed_load_stub() && code->ic_state() == POLYMORPHIC;
146
  }
147
  return false;
148
}
149

    
150

    
151
bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) {
152
  Handle<Object> map_or_code = GetInfo(ast_id);
153
  if (map_or_code->IsMap()) return false;
154
  if (!map_or_code->IsCode()) return false;
155
  Handle<Code> code = Handle<Code>::cast(map_or_code);
156
  return code->ic_state() == UNINITIALIZED;
157
}
158

    
159

    
160
bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) {
161
  Handle<Object> map_or_code = GetInfo(ast_id);
162
  if (map_or_code->IsMap()) return true;
163
  if (map_or_code->IsCode()) {
164
    Handle<Code> code = Handle<Code>::cast(map_or_code);
165
    bool preliminary_checks =
166
        code->is_keyed_store_stub() &&
167
        code->ic_state() == MONOMORPHIC &&
168
        Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
169
    if (!preliminary_checks) return false;
170
    Map* map = code->FindFirstMap();
171
    if (map == NULL) return false;
172
    map = map->CurrentMapForDeprecated();
173
    return map != NULL && !CanRetainOtherContext(map, *native_context_);
174
  }
175
  return false;
176
}
177

    
178

    
179
bool TypeFeedbackOracle::StoreIsPreMonomorphic(TypeFeedbackId ast_id) {
180
  Handle<Object> map_or_code = GetInfo(ast_id);
181
  if (map_or_code->IsCode()) {
182
    Handle<Code> code = Handle<Code>::cast(map_or_code);
183
    return code->ic_state() == PREMONOMORPHIC;
184
  }
185
  return false;
186
}
187

    
188

    
189
bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) {
190
  Handle<Object> map_or_code = GetInfo(ast_id);
191
  if (map_or_code->IsCode()) {
192
    Handle<Code> code = Handle<Code>::cast(map_or_code);
193
    return code->is_keyed_store_stub() &&
194
        code->ic_state() == POLYMORPHIC;
195
  }
196
  return false;
197
}
198

    
199

    
200
bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
201
  Handle<Object> value = GetInfo(expr->CallFeedbackId());
202
  return value->IsMap() || value->IsAllocationSite() || value->IsJSFunction() ||
203
      value->IsSmi();
204
}
205

    
206

    
207
bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) {
208
  Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
209
  return info->IsAllocationSite() || info->IsJSFunction();
210
}
211

    
212

    
213
bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic(
214
    ObjectLiteral::Property* prop) {
215
  Handle<Object> map_or_code = GetInfo(prop->key()->LiteralFeedbackId());
216
  return map_or_code->IsMap();
217
}
218

    
219

    
220
byte TypeFeedbackOracle::ForInType(ForInStatement* stmt) {
221
  Handle<Object> value = GetInfo(stmt->ForInFeedbackId());
222
  return value->IsSmi() &&
223
      Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker
224
          ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN;
225
}
226

    
227

    
228
Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
229
  ASSERT(LoadIsMonomorphicNormal(expr));
230
  Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId());
231
  if (map_or_code->IsCode()) {
232
    Handle<Code> code = Handle<Code>::cast(map_or_code);
233
    Map* map = code->FindFirstMap()->CurrentMapForDeprecated();
234
    return map == NULL || CanRetainOtherContext(map, *native_context_)
235
        ? Handle<Map>::null()
236
        : Handle<Map>(map);
237
  }
238
  return Handle<Map>::cast(map_or_code);
239
}
240

    
241

    
242
Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(
243
    TypeFeedbackId ast_id) {
244
  ASSERT(StoreIsMonomorphicNormal(ast_id));
245
  Handle<Object> map_or_code = GetInfo(ast_id);
246
  if (map_or_code->IsCode()) {
247
    Handle<Code> code = Handle<Code>::cast(map_or_code);
248
    Map* map = code->FindFirstMap()->CurrentMapForDeprecated();
249
    return map == NULL || CanRetainOtherContext(map, *native_context_)
250
        ? Handle<Map>::null()
251
        : Handle<Map>(map);
252
  }
253
  return Handle<Map>::cast(map_or_code);
254
}
255

    
256

    
257
KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode(
258
    TypeFeedbackId ast_id) {
259
  Handle<Object> map_or_code = GetInfo(ast_id);
260
  if (map_or_code->IsCode()) {
261
    Handle<Code> code = Handle<Code>::cast(map_or_code);
262
    if (code->kind() == Code::KEYED_STORE_IC) {
263
      return Code::GetKeyedAccessStoreMode(code->extra_ic_state());
264
    }
265
  }
266
  return STANDARD_STORE;
267
}
268

    
269

    
270
void TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
271
                                           Handle<String> name,
272
                                           SmallMapList* types) {
273
  Code::Flags flags = Code::ComputeFlags(
274
      Code::HANDLER, MONOMORPHIC, Code::kNoExtraICState,
275
      Code::NORMAL, Code::LOAD_IC);
276
  CollectReceiverTypes(expr->PropertyFeedbackId(), name, flags, types);
277
}
278

    
279

    
280
void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
281
                                            Handle<String> name,
282
                                            SmallMapList* types) {
283
  Code::Flags flags = Code::ComputeFlags(
284
      Code::HANDLER, MONOMORPHIC, Code::kNoExtraICState,
285
      Code::NORMAL, Code::STORE_IC);
286
  CollectReceiverTypes(expr->AssignmentFeedbackId(), name, flags, types);
287
}
288

    
289

    
290
void TypeFeedbackOracle::CallReceiverTypes(Call* expr,
291
                                           Handle<String> name,
292
                                           CallKind call_kind,
293
                                           SmallMapList* types) {
294
  int arity = expr->arguments()->length();
295

    
296
  // Note: Currently we do not take string extra ic data into account
297
  // here.
298
  Code::ExtraICState extra_ic_state =
299
      CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION);
300

    
301
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
302
                                                    extra_ic_state,
303
                                                    Code::NORMAL,
304
                                                    arity,
305
                                                    OWN_MAP);
306
  CollectReceiverTypes(expr->CallFeedbackId(), name, flags, types);
307
}
308

    
309

    
310
CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
311
  Handle<Object> value = GetInfo(expr->CallFeedbackId());
312
  if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
313
  CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
314
  ASSERT(check != RECEIVER_MAP_CHECK);
315
  return check;
316
}
317

    
318

    
319
Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) {
320
  Handle<Object> info = GetInfo(expr->CallFeedbackId());
321
  if (info->IsAllocationSite()) {
322
    return Handle<JSFunction>(isolate_->global_context()->array_function());
323
  } else {
324
    return Handle<JSFunction>::cast(info);
325
  }
326
}
327

    
328

    
329
Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(CallNew* expr) {
330
  Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
331
  if (info->IsAllocationSite()) {
332
    return Handle<JSFunction>(isolate_->global_context()->array_function());
333
  } else {
334
    return Handle<JSFunction>::cast(info);
335
  }
336
}
337

    
338

    
339
Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell(CallNew* expr) {
340
  return GetInfoCell(expr->CallNewFeedbackId());
341
}
342

    
343

    
344
Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap(
345
    ObjectLiteral::Property* prop) {
346
  ASSERT(ObjectLiteralStoreIsMonomorphic(prop));
347
  return Handle<Map>::cast(GetInfo(prop->key()->LiteralFeedbackId()));
348
}
349

    
350

    
351
bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
352
  return *GetInfo(expr->PropertyFeedbackId()) ==
353
      isolate_->builtins()->builtin(id);
354
}
355

    
356

    
357
bool TypeFeedbackOracle::LoadIsStub(Property* expr, ICStub* stub) {
358
  Handle<Object> object = GetInfo(expr->PropertyFeedbackId());
359
  if (!object->IsCode()) return false;
360
  Handle<Code> code = Handle<Code>::cast(object);
361
  if (!code->is_load_stub()) return false;
362
  if (code->ic_state() != MONOMORPHIC) return false;
363
  return stub->Describes(*code);
364
}
365

    
366

    
367
void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
368
                                     Handle<Type>* left_type,
369
                                     Handle<Type>* right_type,
370
                                     Handle<Type>* combined_type) {
371
  Handle<Object> info = GetInfo(id);
372
  if (!info->IsCode()) {
373
    // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof.
374
    *left_type = *right_type = *combined_type = handle(Type::None(), isolate_);
375
    return;
376
  }
377
  Handle<Code> code = Handle<Code>::cast(info);
378

    
379
  Handle<Map> map;
380
  Map* raw_map = code->FindFirstMap();
381
  if (raw_map != NULL) {
382
    raw_map = raw_map->CurrentMapForDeprecated();
383
    if (raw_map != NULL && !CanRetainOtherContext(raw_map, *native_context_)) {
384
      map = handle(raw_map, isolate_);
385
    }
386
  }
387

    
388
  if (code->is_compare_ic_stub()) {
389
    int stub_minor_key = code->stub_info();
390
    CompareIC::StubInfoToType(
391
        stub_minor_key, left_type, right_type, combined_type, map, isolate());
392
  } else if (code->is_compare_nil_ic_stub()) {
393
    CompareNilICStub stub(code->extended_extra_ic_state());
394
    *combined_type = stub.GetType(isolate_, map);
395
    *left_type = *right_type = stub.GetInputType(isolate_, map);
396
  }
397
}
398

    
399

    
400
void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
401
                                    Handle<Type>* left,
402
                                    Handle<Type>* right,
403
                                    Handle<Type>* result,
404
                                    Maybe<int>* fixed_right_arg,
405
                                    Token::Value operation) {
406
  Handle<Object> object = GetInfo(id);
407
  if (!object->IsCode()) {
408
    // For some binary ops we don't have ICs, e.g. Token::COMMA, but for the
409
    // operations covered by the BinaryOpStub we should always have them.
410
    ASSERT(!(operation >= BinaryOpStub::FIRST_TOKEN &&
411
             operation <= BinaryOpStub::LAST_TOKEN));
412
    *left = *right = *result = handle(Type::None(), isolate_);
413
    return;
414
  }
415
  Handle<Code> code = Handle<Code>::cast(object);
416
  ASSERT(code->is_binary_op_stub());
417

    
418
  BinaryOpStub stub(code->extended_extra_ic_state());
419

    
420
  // Sanity check.
421
  ASSERT(stub.operation() == operation);
422

    
423
  *left = stub.GetLeftType(isolate());
424
  *right = stub.GetRightType(isolate());
425
  *result = stub.GetResultType(isolate());
426
  *fixed_right_arg = stub.fixed_right_arg();
427
}
428

    
429

    
430
Handle<Type> TypeFeedbackOracle::ClauseType(TypeFeedbackId id) {
431
  Handle<Object> info = GetInfo(id);
432
  Handle<Type> result(Type::None(), isolate_);
433
  if (info->IsCode() && Handle<Code>::cast(info)->is_compare_ic_stub()) {
434
    Handle<Code> code = Handle<Code>::cast(info);
435
    CompareIC::State state = ICCompareStub::CompareState(code->stub_info());
436
    result = CompareIC::StateToType(isolate_, state);
437
  }
438
  return result;
439
}
440

    
441

    
442
Handle<Type> TypeFeedbackOracle::IncrementType(CountOperation* expr) {
443
  Handle<Object> object = GetInfo(expr->CountBinOpFeedbackId());
444
  Handle<Type> unknown(Type::None(), isolate_);
445
  if (!object->IsCode()) return unknown;
446
  Handle<Code> code = Handle<Code>::cast(object);
447
  if (!code->is_binary_op_stub()) return unknown;
448

    
449
  BinaryOpStub stub(code->extended_extra_ic_state());
450
  return stub.GetLeftType(isolate());
451
}
452

    
453

    
454
void TypeFeedbackOracle::CollectPolymorphicMaps(Handle<Code> code,
455
                                                SmallMapList* types) {
456
  MapHandleList maps;
457
  code->FindAllMaps(&maps);
458
  types->Reserve(maps.length(), zone());
459
  for (int i = 0; i < maps.length(); i++) {
460
    Handle<Map> map(maps.at(i));
461
    if (!CanRetainOtherContext(*map, *native_context_)) {
462
      types->AddMapIfMissing(map, zone());
463
    }
464
  }
465
}
466

    
467

    
468
void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
469
                                              Handle<String> name,
470
                                              Code::Flags flags,
471
                                              SmallMapList* types) {
472
  Handle<Object> object = GetInfo(ast_id);
473
  if (object->IsUndefined() || object->IsSmi()) return;
474

    
475
  if (object.is_identical_to(isolate_->builtins()->StoreIC_GlobalProxy())) {
476
    // TODO(fschneider): We could collect the maps and signal that
477
    // we need a generic store (or load) here.
478
    ASSERT(Handle<Code>::cast(object)->ic_state() == GENERIC);
479
  } else if (object->IsMap()) {
480
    types->AddMapIfMissing(Handle<Map>::cast(object), zone());
481
  } else if (Handle<Code>::cast(object)->ic_state() == POLYMORPHIC ||
482
             Handle<Code>::cast(object)->ic_state() == MONOMORPHIC) {
483
    CollectPolymorphicMaps(Handle<Code>::cast(object), types);
484
  } else if (FLAG_collect_megamorphic_maps_from_stub_cache &&
485
      Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
486
    types->Reserve(4, zone());
487
    ASSERT(object->IsCode());
488
    isolate_->stub_cache()->CollectMatchingMaps(types,
489
                                                name,
490
                                                flags,
491
                                                native_context_,
492
                                                zone());
493
  }
494
}
495

    
496

    
497
// Check if a map originates from a given native context. We use this
498
// information to filter out maps from different context to avoid
499
// retaining objects from different tabs in Chrome via optimized code.
500
bool TypeFeedbackOracle::CanRetainOtherContext(Map* map,
501
                                               Context* native_context) {
502
  Object* constructor = NULL;
503
  while (!map->prototype()->IsNull()) {
504
    constructor = map->constructor();
505
    if (!constructor->IsNull()) {
506
      // If the constructor is not null or a JSFunction, we have to
507
      // conservatively assume that it may retain a native context.
508
      if (!constructor->IsJSFunction()) return true;
509
      // Check if the constructor directly references a foreign context.
510
      if (CanRetainOtherContext(JSFunction::cast(constructor),
511
                                native_context)) {
512
        return true;
513
      }
514
    }
515
    map = HeapObject::cast(map->prototype())->map();
516
  }
517
  constructor = map->constructor();
518
  if (constructor->IsNull()) return false;
519
  JSFunction* function = JSFunction::cast(constructor);
520
  return CanRetainOtherContext(function, native_context);
521
}
522

    
523

    
524
bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function,
525
                                               Context* native_context) {
526
  return function->context()->global_object() != native_context->global_object()
527
      && function->context()->global_object() != native_context->builtins();
528
}
529

    
530

    
531
void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
532
                                                   SmallMapList* types) {
533
  Handle<Object> object = GetInfo(ast_id);
534
  if (!object->IsCode()) return;
535
  Handle<Code> code = Handle<Code>::cast(object);
536
  if (code->kind() == Code::KEYED_LOAD_IC ||
537
      code->kind() == Code::KEYED_STORE_IC) {
538
    CollectPolymorphicMaps(code, types);
539
  }
540
}
541

    
542

    
543
void TypeFeedbackOracle::CollectPolymorphicStoreReceiverTypes(
544
    TypeFeedbackId ast_id,
545
    SmallMapList* types) {
546
  Handle<Object> object = GetInfo(ast_id);
547
  if (!object->IsCode()) return;
548
  Handle<Code> code = Handle<Code>::cast(object);
549
  if (code->kind() == Code::STORE_IC && code->ic_state() == POLYMORPHIC) {
550
    CollectPolymorphicMaps(code, types);
551
  }
552
}
553

    
554

    
555
byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) {
556
  Handle<Object> object = GetInfo(id);
557
  return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0;
558
}
559

    
560

    
561
// Things are a bit tricky here: The iterator for the RelocInfos and the infos
562
// themselves are not GC-safe, so we first get all infos, then we create the
563
// dictionary (possibly triggering GC), and finally we relocate the collected
564
// infos before we process them.
565
void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) {
566
  DisallowHeapAllocation no_allocation;
567
  ZoneList<RelocInfo> infos(16, zone());
568
  HandleScope scope(isolate_);
569
  GetRelocInfos(code, &infos);
570
  CreateDictionary(code, &infos);
571
  ProcessRelocInfos(&infos);
572
  ProcessTypeFeedbackCells(code);
573
  // Allocate handle in the parent scope.
574
  dictionary_ = scope.CloseAndEscape(dictionary_);
575
}
576

    
577

    
578
void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code,
579
                                       ZoneList<RelocInfo>* infos) {
580
  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
581
  for (RelocIterator it(*code, mask); !it.done(); it.next()) {
582
    infos->Add(*it.rinfo(), zone());
583
  }
584
}
585

    
586

    
587
void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
588
                                          ZoneList<RelocInfo>* infos) {
589
  AllowHeapAllocation allocation_allowed;
590
  int cell_count = code->type_feedback_info()->IsTypeFeedbackInfo()
591
      ? TypeFeedbackInfo::cast(code->type_feedback_info())->
592
          type_feedback_cells()->CellCount()
593
      : 0;
594
  int length = infos->length() + cell_count;
595
  byte* old_start = code->instruction_start();
596
  dictionary_ = isolate()->factory()->NewUnseededNumberDictionary(length);
597
  byte* new_start = code->instruction_start();
598
  RelocateRelocInfos(infos, old_start, new_start);
599
}
600

    
601

    
602
void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
603
                                            byte* old_start,
604
                                            byte* new_start) {
605
  for (int i = 0; i < infos->length(); i++) {
606
    RelocInfo* info = &(*infos)[i];
607
    info->set_pc(new_start + (info->pc() - old_start));
608
  }
609
}
610

    
611

    
612
void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
613
  for (int i = 0; i < infos->length(); i++) {
614
    RelocInfo reloc_entry = (*infos)[i];
615
    Address target_address = reloc_entry.target_address();
616
    TypeFeedbackId ast_id =
617
        TypeFeedbackId(static_cast<unsigned>((*infos)[i].data()));
618
    Code* target = Code::GetCodeFromTargetAddress(target_address);
619
    switch (target->kind()) {
620
      case Code::LOAD_IC:
621
      case Code::STORE_IC:
622
      case Code::CALL_IC:
623
      case Code::KEYED_CALL_IC:
624
        if (target->ic_state() == MONOMORPHIC) {
625
          if (target->kind() == Code::CALL_IC &&
626
              target->check_type() != RECEIVER_MAP_CHECK) {
627
            SetInfo(ast_id, Smi::FromInt(target->check_type()));
628
          } else {
629
            Object* map = target->FindFirstMap();
630
            if (map == NULL) {
631
              SetInfo(ast_id, static_cast<Object*>(target));
632
            } else if (!CanRetainOtherContext(Map::cast(map),
633
                                              *native_context_)) {
634
              Map* feedback = Map::cast(map)->CurrentMapForDeprecated();
635
              if (feedback != NULL) SetInfo(ast_id, feedback);
636
            }
637
          }
638
        } else {
639
          SetInfo(ast_id, target);
640
        }
641
        break;
642

    
643
      case Code::KEYED_LOAD_IC:
644
      case Code::KEYED_STORE_IC:
645
      case Code::BINARY_OP_IC:
646
      case Code::COMPARE_IC:
647
      case Code::TO_BOOLEAN_IC:
648
      case Code::COMPARE_NIL_IC:
649
        SetInfo(ast_id, target);
650
        break;
651

    
652
      default:
653
        break;
654
    }
655
  }
656
}
657

    
658

    
659
void TypeFeedbackOracle::ProcessTypeFeedbackCells(Handle<Code> code) {
660
  Object* raw_info = code->type_feedback_info();
661
  if (!raw_info->IsTypeFeedbackInfo()) return;
662
  Handle<TypeFeedbackCells> cache(
663
      TypeFeedbackInfo::cast(raw_info)->type_feedback_cells());
664
  for (int i = 0; i < cache->CellCount(); i++) {
665
    TypeFeedbackId ast_id = cache->AstId(i);
666
    Cell* cell = cache->GetCell(i);
667
    Object* value = cell->value();
668
    if (value->IsSmi() ||
669
        value->IsAllocationSite() ||
670
        (value->IsJSFunction() &&
671
         !CanRetainOtherContext(JSFunction::cast(value),
672
                                *native_context_))) {
673
      SetInfo(ast_id, cell);
674
    }
675
  }
676
}
677

    
678

    
679
void TypeFeedbackOracle::SetInfo(TypeFeedbackId ast_id, Object* target) {
680
  ASSERT(dictionary_->FindEntry(IdToKey(ast_id)) ==
681
         UnseededNumberDictionary::kNotFound);
682
  MaybeObject* maybe_result = dictionary_->AtNumberPut(IdToKey(ast_id), target);
683
  USE(maybe_result);
684
#ifdef DEBUG
685
  Object* result = NULL;
686
  // Dictionary has been allocated with sufficient size for all elements.
687
  ASSERT(maybe_result->ToObject(&result));
688
  ASSERT(*dictionary_ == result);
689
#endif
690
}
691

    
692

    
693
Representation Representation::FromType(TypeInfo info) {
694
  if (info.IsUninitialized()) return Representation::None();
695
  if (info.IsSmi()) return Representation::Smi();
696
  if (info.IsInteger32()) return Representation::Integer32();
697
  if (info.IsDouble()) return Representation::Double();
698
  if (info.IsNumber()) return Representation::Double();
699
  return Representation::Tagged();
700
}
701

    
702

    
703
} }  // namespace v8::internal