Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 5 | #include "src/v8.h" |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 6 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 7 | #include "src/ast.h" |
| 8 | #include "src/code-stubs.h" |
| 9 | #include "src/compiler.h" |
| 10 | #include "src/ic/ic.h" |
| 11 | #include "src/ic/stub-cache.h" |
| 12 | #include "src/macro-assembler.h" |
| 13 | #include "src/type-info.h" |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 14 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 15 | #include "src/objects-inl.h" |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 16 | |
| 17 | namespace v8 { |
| 18 | namespace internal { |
| 19 | |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 20 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 21 | TypeFeedbackOracle::TypeFeedbackOracle( |
| 22 | Handle<Code> code, Handle<TypeFeedbackVector> feedback_vector, |
| 23 | Handle<Context> native_context, Zone* zone) |
| 24 | : native_context_(native_context), zone_(zone) { |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 25 | BuildDictionary(code); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 26 | DCHECK(dictionary_->IsDictionary()); |
| 27 | // We make a copy of the feedback vector because a GC could clear |
| 28 | // the type feedback info contained therein. |
| 29 | // TODO(mvstanton): revisit the decision to copy when we weakly |
| 30 | // traverse the feedback vector at GC time. |
| 31 | feedback_vector_ = TypeFeedbackVector::Copy(isolate(), feedback_vector); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 32 | } |
| 33 | |
| 34 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 35 | static uint32_t IdToKey(TypeFeedbackId ast_id) { |
| 36 | return static_cast<uint32_t>(ast_id.ToInt()); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 37 | } |
| 38 | |
| 39 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 40 | Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) { |
| 41 | int entry = dictionary_->FindEntry(IdToKey(ast_id)); |
| 42 | if (entry != UnseededNumberDictionary::kNotFound) { |
| 43 | Object* value = dictionary_->ValueAt(entry); |
| 44 | if (value->IsCell()) { |
| 45 | Cell* cell = Cell::cast(value); |
| 46 | return Handle<Object>(cell->value(), isolate()); |
| 47 | } else { |
| 48 | return Handle<Object>(value, isolate()); |
| 49 | } |
| 50 | } |
| 51 | return Handle<Object>::cast(isolate()->factory()->undefined_value()); |
| 52 | } |
| 53 | |
| 54 | |
| 55 | Handle<Object> TypeFeedbackOracle::GetInfo(int slot) { |
| 56 | DCHECK(slot >= 0 && slot < feedback_vector_->length()); |
| 57 | Object* obj = feedback_vector_->get(slot); |
| 58 | if (!obj->IsJSFunction() || |
| 59 | !CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) { |
| 60 | return Handle<Object>(obj, isolate()); |
| 61 | } |
| 62 | return Handle<Object>::cast(isolate()->factory()->undefined_value()); |
| 63 | } |
| 64 | |
| 65 | |
| 66 | bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { |
| 67 | Handle<Object> maybe_code = GetInfo(id); |
| 68 | if (maybe_code->IsCode()) { |
| 69 | Handle<Code> code = Handle<Code>::cast(maybe_code); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 70 | return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; |
| 71 | } |
| 72 | return false; |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 76 | bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) { |
| 77 | Handle<Object> maybe_code = GetInfo(ast_id); |
| 78 | if (!maybe_code->IsCode()) return false; |
| 79 | Handle<Code> code = Handle<Code>::cast(maybe_code); |
| 80 | return code->ic_state() == UNINITIALIZED; |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 84 | bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) { |
| 85 | Handle<Object> maybe_code = GetInfo(ast_id); |
| 86 | if (maybe_code->IsCode()) { |
| 87 | Handle<Code> code = Handle<Code>::cast(maybe_code); |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 88 | return code->is_keyed_store_stub() && |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 89 | code->ic_state() == POLYMORPHIC; |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 90 | } |
| 91 | return false; |
| 92 | } |
| 93 | |
| 94 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 95 | bool TypeFeedbackOracle::CallIsMonomorphic(int slot) { |
| 96 | Handle<Object> value = GetInfo(slot); |
| 97 | return value->IsAllocationSite() || value->IsJSFunction(); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 101 | bool TypeFeedbackOracle::CallNewIsMonomorphic(int slot) { |
| 102 | Handle<Object> info = GetInfo(slot); |
| 103 | return FLAG_pretenuring_call_new |
| 104 | ? info->IsJSFunction() |
| 105 | : info->IsAllocationSite() || info->IsJSFunction(); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 109 | byte TypeFeedbackOracle::ForInType(int feedback_vector_slot) { |
| 110 | Handle<Object> value = GetInfo(feedback_vector_slot); |
| 111 | return value.is_identical_to( |
| 112 | TypeFeedbackVector::UninitializedSentinel(isolate())) |
| 113 | ? ForInStatement::FAST_FOR_IN |
| 114 | : ForInStatement::SLOW_FOR_IN; |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 118 | KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode( |
| 119 | TypeFeedbackId ast_id) { |
| 120 | Handle<Object> maybe_code = GetInfo(ast_id); |
| 121 | if (maybe_code->IsCode()) { |
| 122 | Handle<Code> code = Handle<Code>::cast(maybe_code); |
| 123 | if (code->kind() == Code::KEYED_STORE_IC) { |
| 124 | return KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 125 | } |
| 126 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 127 | return STANDARD_STORE; |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 128 | } |
| 129 | |
Ben Murdoch | b8e0da2 | 2011-05-16 14:20:40 +0100 | [diff] [blame] | 130 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 131 | Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(int slot) { |
| 132 | Handle<Object> info = GetInfo(slot); |
| 133 | if (info->IsAllocationSite()) { |
| 134 | return Handle<JSFunction>(isolate()->native_context()->array_function()); |
| 135 | } |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 136 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 137 | return Handle<JSFunction>::cast(info); |
| 138 | } |
| 139 | |
| 140 | |
| 141 | Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(int slot) { |
| 142 | Handle<Object> info = GetInfo(slot); |
| 143 | if (FLAG_pretenuring_call_new || info->IsJSFunction()) { |
| 144 | return Handle<JSFunction>::cast(info); |
| 145 | } |
| 146 | |
| 147 | DCHECK(info->IsAllocationSite()); |
| 148 | return Handle<JSFunction>(isolate()->native_context()->array_function()); |
| 149 | } |
| 150 | |
| 151 | |
| 152 | Handle<AllocationSite> TypeFeedbackOracle::GetCallAllocationSite(int slot) { |
| 153 | Handle<Object> info = GetInfo(slot); |
| 154 | if (info->IsAllocationSite()) { |
| 155 | return Handle<AllocationSite>::cast(info); |
| 156 | } |
| 157 | return Handle<AllocationSite>::null(); |
| 158 | } |
| 159 | |
| 160 | |
| 161 | Handle<AllocationSite> TypeFeedbackOracle::GetCallNewAllocationSite(int slot) { |
| 162 | Handle<Object> info = GetInfo(slot); |
| 163 | if (FLAG_pretenuring_call_new || info->IsAllocationSite()) { |
| 164 | return Handle<AllocationSite>::cast(info); |
| 165 | } |
| 166 | return Handle<AllocationSite>::null(); |
| 167 | } |
| 168 | |
| 169 | |
| 170 | bool TypeFeedbackOracle::LoadIsBuiltin( |
| 171 | TypeFeedbackId id, Builtins::Name builtin) { |
| 172 | return *GetInfo(id) == isolate()->builtins()->builtin(builtin); |
| 173 | } |
| 174 | |
| 175 | |
| 176 | void TypeFeedbackOracle::CompareType(TypeFeedbackId id, |
| 177 | Type** left_type, |
| 178 | Type** right_type, |
| 179 | Type** combined_type) { |
| 180 | Handle<Object> info = GetInfo(id); |
| 181 | if (!info->IsCode()) { |
| 182 | // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof. |
| 183 | *left_type = *right_type = *combined_type = Type::None(zone()); |
| 184 | return; |
| 185 | } |
| 186 | Handle<Code> code = Handle<Code>::cast(info); |
| 187 | |
| 188 | Handle<Map> map; |
| 189 | Map* raw_map = code->FindFirstMap(); |
| 190 | if (raw_map != NULL) { |
| 191 | if (Map::TryUpdate(handle(raw_map)).ToHandle(&map) && |
| 192 | CanRetainOtherContext(*map, *native_context_)) { |
| 193 | map = Handle<Map>::null(); |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | if (code->is_compare_ic_stub()) { |
| 198 | CompareICStub stub(code->stub_key(), isolate()); |
| 199 | *left_type = CompareICState::StateToType(zone(), stub.left()); |
| 200 | *right_type = CompareICState::StateToType(zone(), stub.right()); |
| 201 | *combined_type = CompareICState::StateToType(zone(), stub.state(), map); |
| 202 | } else if (code->is_compare_nil_ic_stub()) { |
| 203 | CompareNilICStub stub(isolate(), code->extra_ic_state()); |
| 204 | *combined_type = stub.GetType(zone(), map); |
| 205 | *left_type = *right_type = stub.GetInputType(zone(), map); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 206 | } |
| 207 | } |
| 208 | |
| 209 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 210 | void TypeFeedbackOracle::BinaryType(TypeFeedbackId id, |
| 211 | Type** left, |
| 212 | Type** right, |
| 213 | Type** result, |
| 214 | Maybe<int>* fixed_right_arg, |
| 215 | Handle<AllocationSite>* allocation_site, |
| 216 | Token::Value op) { |
| 217 | Handle<Object> object = GetInfo(id); |
| 218 | if (!object->IsCode()) { |
| 219 | // For some binary ops we don't have ICs, e.g. Token::COMMA, but for the |
| 220 | // operations covered by the BinaryOpIC we should always have them. |
| 221 | DCHECK(op < BinaryOpICState::FIRST_TOKEN || |
| 222 | op > BinaryOpICState::LAST_TOKEN); |
| 223 | *left = *right = *result = Type::None(zone()); |
| 224 | *fixed_right_arg = Maybe<int>(); |
| 225 | *allocation_site = Handle<AllocationSite>::null(); |
| 226 | return; |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 227 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 228 | Handle<Code> code = Handle<Code>::cast(object); |
| 229 | DCHECK_EQ(Code::BINARY_OP_IC, code->kind()); |
| 230 | BinaryOpICState state(isolate(), code->extra_ic_state()); |
| 231 | DCHECK_EQ(op, state.op()); |
| 232 | |
| 233 | *left = state.GetLeftType(zone()); |
| 234 | *right = state.GetRightType(zone()); |
| 235 | *result = state.GetResultType(zone()); |
| 236 | *fixed_right_arg = state.fixed_right_arg(); |
| 237 | |
| 238 | AllocationSite* first_allocation_site = code->FindFirstAllocationSite(); |
| 239 | if (first_allocation_site != NULL) { |
| 240 | *allocation_site = handle(first_allocation_site); |
| 241 | } else { |
| 242 | *allocation_site = Handle<AllocationSite>::null(); |
| 243 | } |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 247 | Type* TypeFeedbackOracle::CountType(TypeFeedbackId id) { |
| 248 | Handle<Object> object = GetInfo(id); |
| 249 | if (!object->IsCode()) return Type::None(zone()); |
| 250 | Handle<Code> code = Handle<Code>::cast(object); |
| 251 | DCHECK_EQ(Code::BINARY_OP_IC, code->kind()); |
| 252 | BinaryOpICState state(isolate(), code->extra_ic_state()); |
| 253 | return state.GetLeftType(zone()); |
| 254 | } |
| 255 | |
| 256 | |
| 257 | void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id, |
| 258 | Handle<String> name, |
| 259 | SmallMapList* receiver_types) { |
| 260 | receiver_types->Clear(); |
| 261 | Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC); |
| 262 | CollectReceiverTypes(id, name, flags, receiver_types); |
| 263 | } |
| 264 | |
| 265 | |
| 266 | void TypeFeedbackOracle::KeyedPropertyReceiverTypes( |
| 267 | TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) { |
| 268 | receiver_types->Clear(); |
| 269 | *is_string = false; |
| 270 | if (LoadIsBuiltin(id, Builtins::kKeyedLoadIC_String)) { |
| 271 | *is_string = true; |
| 272 | } else { |
| 273 | CollectReceiverTypes(id, receiver_types); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | |
| 278 | void TypeFeedbackOracle::AssignmentReceiverTypes( |
| 279 | TypeFeedbackId id, Handle<String> name, SmallMapList* receiver_types) { |
| 280 | receiver_types->Clear(); |
| 281 | Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC); |
| 282 | CollectReceiverTypes(id, name, flags, receiver_types); |
| 283 | } |
| 284 | |
| 285 | |
| 286 | void TypeFeedbackOracle::KeyedAssignmentReceiverTypes( |
| 287 | TypeFeedbackId id, SmallMapList* receiver_types, |
| 288 | KeyedAccessStoreMode* store_mode) { |
| 289 | receiver_types->Clear(); |
| 290 | CollectReceiverTypes(id, receiver_types); |
| 291 | *store_mode = GetStoreMode(id); |
| 292 | } |
| 293 | |
| 294 | |
| 295 | void TypeFeedbackOracle::CountReceiverTypes(TypeFeedbackId id, |
| 296 | SmallMapList* receiver_types) { |
| 297 | receiver_types->Clear(); |
| 298 | CollectReceiverTypes(id, receiver_types); |
| 299 | } |
| 300 | |
| 301 | |
| 302 | void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 303 | Handle<String> name, |
| 304 | Code::Flags flags, |
| 305 | SmallMapList* types) { |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 306 | Handle<Object> object = GetInfo(ast_id); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 307 | if (object->IsUndefined() || object->IsSmi()) return; |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 308 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 309 | DCHECK(object->IsCode()); |
| 310 | Handle<Code> code(Handle<Code>::cast(object)); |
| 311 | |
| 312 | if (FLAG_collect_megamorphic_maps_from_stub_cache && |
| 313 | code->ic_state() == MEGAMORPHIC) { |
| 314 | types->Reserve(4, zone()); |
| 315 | isolate()->stub_cache()->CollectMatchingMaps( |
| 316 | types, name, flags, native_context_, zone()); |
| 317 | } else { |
| 318 | CollectReceiverTypes(ast_id, types); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 319 | } |
| 320 | } |
| 321 | |
| 322 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 323 | // Check if a map originates from a given native context. We use this |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 324 | // information to filter out maps from different context to avoid |
| 325 | // retaining objects from different tabs in Chrome via optimized code. |
| 326 | bool TypeFeedbackOracle::CanRetainOtherContext(Map* map, |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 327 | Context* native_context) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 328 | Object* constructor = NULL; |
| 329 | while (!map->prototype()->IsNull()) { |
| 330 | constructor = map->constructor(); |
| 331 | if (!constructor->IsNull()) { |
| 332 | // If the constructor is not null or a JSFunction, we have to |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 333 | // conservatively assume that it may retain a native context. |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 334 | if (!constructor->IsJSFunction()) return true; |
| 335 | // Check if the constructor directly references a foreign context. |
| 336 | if (CanRetainOtherContext(JSFunction::cast(constructor), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 337 | native_context)) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 338 | return true; |
| 339 | } |
| 340 | } |
| 341 | map = HeapObject::cast(map->prototype())->map(); |
| 342 | } |
| 343 | constructor = map->constructor(); |
| 344 | if (constructor->IsNull()) return false; |
| 345 | JSFunction* function = JSFunction::cast(constructor); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 346 | return CanRetainOtherContext(function, native_context); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | |
| 350 | bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function, |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 351 | Context* native_context) { |
| 352 | return function->context()->global_object() != native_context->global_object() |
| 353 | && function->context()->global_object() != native_context->builtins(); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 354 | } |
| 355 | |
| 356 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 357 | void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, |
| 358 | SmallMapList* types) { |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 359 | Handle<Object> object = GetInfo(ast_id); |
| 360 | if (!object->IsCode()) return; |
| 361 | Handle<Code> code = Handle<Code>::cast(object); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 362 | MapHandleList maps; |
| 363 | if (code->ic_state() == MONOMORPHIC) { |
| 364 | Map* map = code->FindFirstMap(); |
| 365 | if (map != NULL) maps.Add(handle(map)); |
| 366 | } else if (code->ic_state() == POLYMORPHIC) { |
| 367 | code->FindAllMaps(&maps); |
| 368 | } else { |
| 369 | return; |
| 370 | } |
| 371 | types->Reserve(maps.length(), zone()); |
| 372 | for (int i = 0; i < maps.length(); i++) { |
| 373 | Handle<Map> map(maps.at(i)); |
| 374 | if (!CanRetainOtherContext(*map, *native_context_)) { |
| 375 | types->AddMapIfMissing(map, zone()); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 376 | } |
| 377 | } |
Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 378 | } |
| 379 | |
| 380 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 381 | byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) { |
| 382 | Handle<Object> object = GetInfo(id); |
Ben Murdoch | 69a99ed | 2011-11-30 16:03:39 +0000 | [diff] [blame] | 383 | return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0; |
| 384 | } |
| 385 | |
| 386 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 387 | // Things are a bit tricky here: The iterator for the RelocInfos and the infos |
| 388 | // themselves are not GC-safe, so we first get all infos, then we create the |
| 389 | // dictionary (possibly triggering GC), and finally we relocate the collected |
| 390 | // infos before we process them. |
| 391 | void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 392 | DisallowHeapAllocation no_allocation; |
| 393 | ZoneList<RelocInfo> infos(16, zone()); |
| 394 | HandleScope scope(isolate()); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 395 | GetRelocInfos(code, &infos); |
| 396 | CreateDictionary(code, &infos); |
| 397 | ProcessRelocInfos(&infos); |
Steve Block | 44f0eee | 2011-05-26 01:26:41 +0100 | [diff] [blame] | 398 | // Allocate handle in the parent scope. |
| 399 | dictionary_ = scope.CloseAndEscape(dictionary_); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 400 | } |
| 401 | |
| 402 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 403 | void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code, |
| 404 | ZoneList<RelocInfo>* infos) { |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 405 | int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 406 | for (RelocIterator it(*code, mask); !it.done(); it.next()) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 407 | infos->Add(*it.rinfo(), zone()); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 408 | } |
| 409 | } |
| 410 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 411 | |
| 412 | void TypeFeedbackOracle::CreateDictionary(Handle<Code> code, |
| 413 | ZoneList<RelocInfo>* infos) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 414 | AllowHeapAllocation allocation_allowed; |
| 415 | Code* old_code = *code; |
| 416 | dictionary_ = UnseededNumberDictionary::New(isolate(), infos->length()); |
| 417 | RelocateRelocInfos(infos, old_code, *code); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 418 | } |
| 419 | |
| 420 | |
| 421 | void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos, |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 422 | Code* old_code, |
| 423 | Code* new_code) { |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 424 | for (int i = 0; i < infos->length(); i++) { |
| 425 | RelocInfo* info = &(*infos)[i]; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 426 | info->set_host(new_code); |
| 427 | info->set_pc(new_code->instruction_start() + |
| 428 | (info->pc() - old_code->instruction_start())); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 429 | } |
| 430 | } |
| 431 | |
| 432 | |
| 433 | void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) { |
| 434 | for (int i = 0; i < infos->length(); i++) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 435 | RelocInfo reloc_entry = (*infos)[i]; |
| 436 | Address target_address = reloc_entry.target_address(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 437 | TypeFeedbackId ast_id = |
| 438 | TypeFeedbackId(static_cast<unsigned>((*infos)[i].data())); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 439 | Code* target = Code::GetCodeFromTargetAddress(target_address); |
| 440 | switch (target->kind()) { |
| 441 | case Code::LOAD_IC: |
| 442 | case Code::STORE_IC: |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 443 | case Code::KEYED_LOAD_IC: |
| 444 | case Code::KEYED_STORE_IC: |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 445 | case Code::BINARY_OP_IC: |
| 446 | case Code::COMPARE_IC: |
| 447 | case Code::TO_BOOLEAN_IC: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 448 | case Code::COMPARE_NIL_IC: |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 449 | SetInfo(ast_id, target); |
| 450 | break; |
| 451 | |
| 452 | default: |
| 453 | break; |
| 454 | } |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 455 | } |
| 456 | } |
| 457 | |
| 458 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 459 | void TypeFeedbackOracle::SetInfo(TypeFeedbackId ast_id, Object* target) { |
| 460 | DCHECK(dictionary_->FindEntry(IdToKey(ast_id)) == |
| 461 | UnseededNumberDictionary::kNotFound); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 462 | // Dictionary has been allocated with sufficient size for all elements. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 463 | DisallowHeapAllocation no_need_to_resize_dictionary; |
| 464 | HandleScope scope(isolate()); |
| 465 | USE(UnseededNumberDictionary::AtNumberPut( |
| 466 | dictionary_, IdToKey(ast_id), handle(target, isolate()))); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 467 | } |
| 468 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame^] | 469 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 470 | } } // namespace v8::internal |