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 41namespace v8 { 42namespace internal { 43 44 45TypeInfo 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 59TypeFeedbackOracle::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 71static uint32_t IdToKey(TypeFeedbackId ast_id) { 72 return static_cast<uint32_t>(ast_id.ToInt()); 73} 74 75 76Handle<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 91Handle<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 102bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { 103 Handle<Object> maybe_code = GetInfo(id); 104 if (maybe_code->IsCode()) { 105 Handle<Code> code = Handle<Code>::cast(maybe_code); 106 return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; 107 } 108 return false; 109} 110 111 112bool TypeFeedbackOracle::LoadIsPreMonomorphic(TypeFeedbackId id) { 113 Handle<Object> maybe_code = GetInfo(id); 114 if (maybe_code->IsCode()) { 115 Handle<Code> code = Handle<Code>::cast(maybe_code); 116 return code->is_inline_cache_stub() && code->ic_state() == PREMONOMORPHIC; 117 } 118 return false; 119} 120 121 122bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) { 123 Handle<Object> maybe_code = GetInfo(ast_id); 124 if (!maybe_code->IsCode()) return false; 125 Handle<Code> code = Handle<Code>::cast(maybe_code); 126 return code->ic_state() == UNINITIALIZED; 127} 128 129 130bool TypeFeedbackOracle::StoreIsPreMonomorphic(TypeFeedbackId ast_id) { 131 Handle<Object> maybe_code = GetInfo(ast_id); 132 if (maybe_code->IsCode()) { 133 Handle<Code> code = Handle<Code>::cast(maybe_code); 134 return code->ic_state() == PREMONOMORPHIC; 135 } 136 return false; 137} 138 139 140bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) { 141 Handle<Object> maybe_code = GetInfo(ast_id); 142 if (maybe_code->IsCode()) { 143 Handle<Code> code = Handle<Code>::cast(maybe_code); 144 return code->is_keyed_store_stub() && 145 code->ic_state() == POLYMORPHIC; 146 } 147 return false; 148} 149 150 151bool TypeFeedbackOracle::CallIsMonomorphic(TypeFeedbackId id) { 152 Handle<Object> value = GetInfo(id); 153 return value->IsAllocationSite() || value->IsJSFunction() || value->IsSmi() || 154 (value->IsCode() && Handle<Code>::cast(value)->ic_state() == MONOMORPHIC); 155} 156 157 158bool TypeFeedbackOracle::KeyedArrayCallIsHoley(TypeFeedbackId id) { 159 Handle<Object> value = GetInfo(id); 160 Handle<Code> code = Handle<Code>::cast(value); 161 return KeyedArrayCallStub::IsHoley(code); 162} 163 164 165bool TypeFeedbackOracle::CallNewIsMonomorphic(TypeFeedbackId id) { 166 Handle<Object> info = GetInfo(id); 167 return info->IsAllocationSite() || info->IsJSFunction(); 168} 169 170 171byte TypeFeedbackOracle::ForInType(TypeFeedbackId id) { 172 Handle<Object> value = GetInfo(id); 173 return value->IsSmi() && 174 Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker 175 ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN; 176} 177 178 179KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode( 180 TypeFeedbackId ast_id) { 181 Handle<Object> maybe_code = GetInfo(ast_id); 182 if (maybe_code->IsCode()) { 183 Handle<Code> code = Handle<Code>::cast(maybe_code); 184 if (code->kind() == Code::KEYED_STORE_IC) { 185 return KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()); 186 } 187 } 188 return STANDARD_STORE; 189} 190 191 192void TypeFeedbackOracle::CallReceiverTypes(TypeFeedbackId id, 193 Handle<String> name, 194 int arity, 195 CallKind call_kind, 196 SmallMapList* types) { 197 // Note: Currently we do not take string extra ic data into account 198 // here. 199 ContextualMode contextual_mode = call_kind == CALL_AS_FUNCTION 200 ? CONTEXTUAL 201 : NOT_CONTEXTUAL; 202 ExtraICState extra_ic_state = 203 CallIC::Contextual::encode(contextual_mode); 204 205 Code::Flags flags = Code::ComputeMonomorphicFlags( 206 Code::CALL_IC, extra_ic_state, OWN_MAP, Code::NORMAL, arity); 207 CollectReceiverTypes(id, name, flags, types); 208} 209 210 211CheckType TypeFeedbackOracle::GetCallCheckType(TypeFeedbackId id) { 212 Handle<Object> value = GetInfo(id); 213 if (!value->IsSmi()) return RECEIVER_MAP_CHECK; 214 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value()); 215 ASSERT(check != RECEIVER_MAP_CHECK); 216 return check; 217} 218 219 220Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(TypeFeedbackId id) { 221 Handle<Object> info = GetInfo(id); 222 if (info->IsAllocationSite()) { 223 return Handle<JSFunction>(isolate_->global_context()->array_function()); 224 } else { 225 return Handle<JSFunction>::cast(info); 226 } 227} 228 229 230Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(TypeFeedbackId id) { 231 Handle<Object> info = GetInfo(id); 232 if (info->IsAllocationSite()) { 233 return Handle<JSFunction>(isolate_->global_context()->array_function()); 234 } else { 235 return Handle<JSFunction>::cast(info); 236 } 237} 238 239 240Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell( 241 TypeFeedbackId id) { 242 return GetInfoCell(id); 243} 244 245 246bool TypeFeedbackOracle::LoadIsBuiltin( 247 TypeFeedbackId id, Builtins::Name builtin) { 248 return *GetInfo(id) == isolate_->builtins()->builtin(builtin); 249} 250 251 252bool TypeFeedbackOracle::LoadIsStub(TypeFeedbackId id, ICStub* stub) { 253 Handle<Object> object = GetInfo(id); 254 if (!object->IsCode()) return false; 255 Handle<Code> code = Handle<Code>::cast(object); 256 if (!code->is_load_stub()) return false; 257 if (code->ic_state() != MONOMORPHIC) return false; 258 return stub->Describes(*code); 259} 260 261 262void TypeFeedbackOracle::CompareType(TypeFeedbackId id, 263 Handle<Type>* left_type, 264 Handle<Type>* right_type, 265 Handle<Type>* combined_type) { 266 Handle<Object> info = GetInfo(id); 267 if (!info->IsCode()) { 268 // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof. 269 *left_type = *right_type = *combined_type = handle(Type::None(), isolate_); 270 return; 271 } 272 Handle<Code> code = Handle<Code>::cast(info); 273 274 Handle<Map> map; 275 Map* raw_map = code->FindFirstMap(); 276 if (raw_map != NULL) { 277 map = Map::CurrentMapForDeprecated(handle(raw_map)); 278 if (!map.is_null() && CanRetainOtherContext(*map, *native_context_)) { 279 map = Handle<Map>::null(); 280 } 281 } 282 283 if (code->is_compare_ic_stub()) { 284 int stub_minor_key = code->stub_info(); 285 CompareIC::StubInfoToType( 286 stub_minor_key, left_type, right_type, combined_type, map, isolate()); 287 } else if (code->is_compare_nil_ic_stub()) { 288 CompareNilICStub stub(code->extended_extra_ic_state()); 289 *combined_type = stub.GetType(isolate_, map); 290 *left_type = *right_type = stub.GetInputType(isolate_, map); 291 } 292} 293 294 295void TypeFeedbackOracle::BinaryType(TypeFeedbackId id, 296 Handle<Type>* left, 297 Handle<Type>* right, 298 Handle<Type>* result, 299 Maybe<int>* fixed_right_arg, 300 Token::Value op) { 301 Handle<Object> object = GetInfo(id); 302 if (!object->IsCode()) { 303 // For some binary ops we don't have ICs, e.g. Token::COMMA, but for the 304 // operations covered by the BinaryOpIC we should always have them. 305 ASSERT(op < BinaryOpIC::State::FIRST_TOKEN || 306 op > BinaryOpIC::State::LAST_TOKEN); 307 *left = *right = *result = handle(Type::None(), isolate_); 308 *fixed_right_arg = Maybe<int>(); 309 return; 310 } 311 Handle<Code> code = Handle<Code>::cast(object); 312 ASSERT_EQ(Code::BINARY_OP_IC, code->kind()); 313 BinaryOpIC::State state(code->extended_extra_ic_state()); 314 ASSERT_EQ(op, state.op()); 315 316 *left = state.GetLeftType(isolate()); 317 *right = state.GetRightType(isolate()); 318 *result = state.GetResultType(isolate()); 319 *fixed_right_arg = state.fixed_right_arg(); 320} 321 322 323Handle<Type> TypeFeedbackOracle::ClauseType(TypeFeedbackId id) { 324 Handle<Object> info = GetInfo(id); 325 Handle<Type> result(Type::None(), isolate_); 326 if (info->IsCode() && Handle<Code>::cast(info)->is_compare_ic_stub()) { 327 Handle<Code> code = Handle<Code>::cast(info); 328 CompareIC::State state = ICCompareStub::CompareState(code->stub_info()); 329 result = CompareIC::StateToType(isolate_, state); 330 } 331 return result; 332} 333 334 335Handle<Type> TypeFeedbackOracle::CountType(TypeFeedbackId id) { 336 Handle<Object> object = GetInfo(id); 337 if (!object->IsCode()) return handle(Type::None(), isolate_); 338 Handle<Code> code = Handle<Code>::cast(object); 339 ASSERT_EQ(Code::BINARY_OP_IC, code->kind()); 340 BinaryOpIC::State state(code->extended_extra_ic_state()); 341 return state.GetLeftType(isolate()); 342} 343 344 345void TypeFeedbackOracle::PropertyReceiverTypes( 346 TypeFeedbackId id, Handle<String> name, 347 SmallMapList* receiver_types, bool* is_prototype) { 348 receiver_types->Clear(); 349 FunctionPrototypeStub proto_stub(Code::LOAD_IC); 350 *is_prototype = LoadIsStub(id, &proto_stub); 351 if (!*is_prototype) { 352 Code::Flags flags = Code::ComputeFlags( 353 Code::HANDLER, MONOMORPHIC, kNoExtraICState, 354 Code::NORMAL, Code::LOAD_IC); 355 CollectReceiverTypes(id, name, flags, receiver_types); 356 } 357} 358 359 360void TypeFeedbackOracle::KeyedPropertyReceiverTypes( 361 TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) { 362 receiver_types->Clear(); 363 *is_string = false; 364 if (LoadIsBuiltin(id, Builtins::kKeyedLoadIC_String)) { 365 *is_string = true; 366 } else { 367 CollectReceiverTypes(id, receiver_types); 368 } 369} 370 371 372void TypeFeedbackOracle::AssignmentReceiverTypes( 373 TypeFeedbackId id, Handle<String> name, SmallMapList* receiver_types) { 374 receiver_types->Clear(); 375 Code::Flags flags = Code::ComputeFlags( 376 Code::HANDLER, MONOMORPHIC, kNoExtraICState, 377 Code::NORMAL, Code::STORE_IC); 378 CollectReceiverTypes(id, name, flags, receiver_types); 379} 380 381 382void TypeFeedbackOracle::KeyedAssignmentReceiverTypes( 383 TypeFeedbackId id, SmallMapList* receiver_types, 384 KeyedAccessStoreMode* store_mode) { 385 receiver_types->Clear(); 386 CollectReceiverTypes(id, receiver_types); 387 *store_mode = GetStoreMode(id); 388} 389 390 391void TypeFeedbackOracle::CountReceiverTypes(TypeFeedbackId id, 392 SmallMapList* receiver_types) { 393 receiver_types->Clear(); 394 CollectReceiverTypes(id, receiver_types); 395} 396 397 398void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, 399 Handle<String> name, 400 Code::Flags flags, 401 SmallMapList* types) { 402 Handle<Object> object = GetInfo(ast_id); 403 if (object->IsUndefined() || object->IsSmi()) return; 404 405 ASSERT(object->IsCode()); 406 Handle<Code> code(Handle<Code>::cast(object)); 407 408 if (FLAG_collect_megamorphic_maps_from_stub_cache && 409 code->ic_state() == MEGAMORPHIC) { 410 types->Reserve(4, zone()); 411 isolate_->stub_cache()->CollectMatchingMaps( 412 types, name, flags, native_context_, zone()); 413 } else { 414 CollectReceiverTypes(ast_id, types); 415 } 416} 417 418 419// Check if a map originates from a given native context. We use this 420// information to filter out maps from different context to avoid 421// retaining objects from different tabs in Chrome via optimized code. 422bool TypeFeedbackOracle::CanRetainOtherContext(Map* map, 423 Context* native_context) { 424 Object* constructor = NULL; 425 while (!map->prototype()->IsNull()) { 426 constructor = map->constructor(); 427 if (!constructor->IsNull()) { 428 // If the constructor is not null or a JSFunction, we have to 429 // conservatively assume that it may retain a native context. 430 if (!constructor->IsJSFunction()) return true; 431 // Check if the constructor directly references a foreign context. 432 if (CanRetainOtherContext(JSFunction::cast(constructor), 433 native_context)) { 434 return true; 435 } 436 } 437 map = HeapObject::cast(map->prototype())->map(); 438 } 439 constructor = map->constructor(); 440 if (constructor->IsNull()) return false; 441 JSFunction* function = JSFunction::cast(constructor); 442 return CanRetainOtherContext(function, native_context); 443} 444 445 446bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function, 447 Context* native_context) { 448 return function->context()->global_object() != native_context->global_object() 449 && function->context()->global_object() != native_context->builtins(); 450} 451 452 453void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, 454 SmallMapList* types) { 455 Handle<Object> object = GetInfo(ast_id); 456 if (!object->IsCode()) return; 457 Handle<Code> code = Handle<Code>::cast(object); 458 MapHandleList maps; 459 if (code->ic_state() == MONOMORPHIC) { 460 Map* map = code->FindFirstMap(); 461 if (map != NULL) maps.Add(handle(map)); 462 } else if (code->ic_state() == POLYMORPHIC) { 463 code->FindAllMaps(&maps); 464 } else { 465 return; 466 } 467 types->Reserve(maps.length(), zone()); 468 for (int i = 0; i < maps.length(); i++) { 469 Handle<Map> map(maps.at(i)); 470 if (!CanRetainOtherContext(*map, *native_context_)) { 471 types->AddMapIfMissing(map, zone()); 472 } 473 } 474} 475 476 477byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) { 478 Handle<Object> object = GetInfo(id); 479 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0; 480} 481 482 483// Things are a bit tricky here: The iterator for the RelocInfos and the infos 484// themselves are not GC-safe, so we first get all infos, then we create the 485// dictionary (possibly triggering GC), and finally we relocate the collected 486// infos before we process them. 487void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) { 488 DisallowHeapAllocation no_allocation; 489 ZoneList<RelocInfo> infos(16, zone()); 490 HandleScope scope(isolate_); 491 GetRelocInfos(code, &infos); 492 CreateDictionary(code, &infos); 493 ProcessRelocInfos(&infos); 494 ProcessTypeFeedbackCells(code); 495 // Allocate handle in the parent scope. 496 dictionary_ = scope.CloseAndEscape(dictionary_); 497} 498 499 500void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code, 501 ZoneList<RelocInfo>* infos) { 502 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); 503 for (RelocIterator it(*code, mask); !it.done(); it.next()) { 504 infos->Add(*it.rinfo(), zone()); 505 } 506} 507 508 509void TypeFeedbackOracle::CreateDictionary(Handle<Code> code, 510 ZoneList<RelocInfo>* infos) { 511 AllowHeapAllocation allocation_allowed; 512 int cell_count = code->type_feedback_info()->IsTypeFeedbackInfo() 513 ? TypeFeedbackInfo::cast(code->type_feedback_info())-> 514 type_feedback_cells()->CellCount() 515 : 0; 516 int length = infos->length() + cell_count; 517 byte* old_start = code->instruction_start(); 518 dictionary_ = isolate()->factory()->NewUnseededNumberDictionary(length); 519 byte* new_start = code->instruction_start(); 520 RelocateRelocInfos(infos, old_start, new_start); 521} 522 523 524void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos, 525 byte* old_start, 526 byte* new_start) { 527 for (int i = 0; i < infos->length(); i++) { 528 RelocInfo* info = &(*infos)[i]; 529 info->set_pc(new_start + (info->pc() - old_start)); 530 } 531} 532 533 534void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) { 535 for (int i = 0; i < infos->length(); i++) { 536 RelocInfo reloc_entry = (*infos)[i]; 537 Address target_address = reloc_entry.target_address(); 538 TypeFeedbackId ast_id = 539 TypeFeedbackId(static_cast<unsigned>((*infos)[i].data())); 540 Code* target = Code::GetCodeFromTargetAddress(target_address); 541 switch (target->kind()) { 542 case Code::CALL_IC: 543 if (target->ic_state() == MONOMORPHIC && 544 target->check_type() != RECEIVER_MAP_CHECK) { 545 SetInfo(ast_id, Smi::FromInt(target->check_type())); 546 break; 547 } 548 case Code::LOAD_IC: 549 case Code::STORE_IC: 550 case Code::KEYED_CALL_IC: 551 case Code::KEYED_LOAD_IC: 552 case Code::KEYED_STORE_IC: 553 case Code::BINARY_OP_IC: 554 case Code::COMPARE_IC: 555 case Code::TO_BOOLEAN_IC: 556 case Code::COMPARE_NIL_IC: 557 SetInfo(ast_id, target); 558 break; 559 560 default: 561 break; 562 } 563 } 564} 565 566 567void TypeFeedbackOracle::ProcessTypeFeedbackCells(Handle<Code> code) { 568 Object* raw_info = code->type_feedback_info(); 569 if (!raw_info->IsTypeFeedbackInfo()) return; 570 Handle<TypeFeedbackCells> cache( 571 TypeFeedbackInfo::cast(raw_info)->type_feedback_cells()); 572 for (int i = 0; i < cache->CellCount(); i++) { 573 TypeFeedbackId ast_id = cache->AstId(i); 574 Cell* cell = cache->GetCell(i); 575 Object* value = cell->value(); 576 if (value->IsSmi() || 577 value->IsAllocationSite() || 578 (value->IsJSFunction() && 579 !CanRetainOtherContext(JSFunction::cast(value), 580 *native_context_))) { 581 SetInfo(ast_id, cell); 582 } 583 } 584} 585 586 587void TypeFeedbackOracle::SetInfo(TypeFeedbackId ast_id, Object* target) { 588 ASSERT(dictionary_->FindEntry(IdToKey(ast_id)) == 589 UnseededNumberDictionary::kNotFound); 590 MaybeObject* maybe_result = dictionary_->AtNumberPut(IdToKey(ast_id), target); 591 USE(maybe_result); 592#ifdef DEBUG 593 Object* result = NULL; 594 // Dictionary has been allocated with sufficient size for all elements. 595 ASSERT(maybe_result->ToObject(&result)); 596 ASSERT(*dictionary_ == result); 597#endif 598} 599 600 601Representation Representation::FromType(TypeInfo info) { 602 if (info.IsUninitialized()) return Representation::None(); 603 if (info.IsSmi()) return Representation::Smi(); 604 if (info.IsInteger32()) return Representation::Integer32(); 605 if (info.IsDouble()) return Representation::Double(); 606 if (info.IsNumber()) return Representation::Double(); 607 return Representation::Tagged(); 608} 609 610 611} } // namespace v8::internal 612