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.
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
|