blob: bdf7bc3c865338d017b07a6469ebddd18df5c48c [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Steve Block6ded16b2010-05-10 14:33:55 +010028#include "v8.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010029
30#include "ast.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000031#include "code-stubs.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010032#include "compiler.h"
33#include "ic.h"
34#include "macro-assembler.h"
35#include "stub-cache.h"
Steve Block6ded16b2010-05-10 14:33:55 +010036#include "type-info.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010037
38#include "ic-inl.h"
Steve Block6ded16b2010-05-10 14:33:55 +010039#include "objects-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000040
41namespace v8 {
42namespace internal {
43
Steve Block6ded16b2010-05-10 14:33:55 +010044
45TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) {
46 TypeInfo info;
47 if (value->IsSmi()) {
48 info = TypeInfo::Smi();
49 } else if (value->IsHeapNumber()) {
50 info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value())
51 ? TypeInfo::Integer32()
52 : TypeInfo::Double();
53 } else if (value->IsString()) {
54 info = TypeInfo::String();
55 } else {
56 info = TypeInfo::Unknown();
57 }
58 return info;
59}
60
Steve Blocka7e24c12009-10-30 11:49:00 +000061
Ben Murdochb8e0da22011-05-16 14:20:40 +010062TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
63 Handle<Context> global_context) {
64 global_context_ = global_context;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000065 BuildDictionary(code);
Steve Block44f0eee2011-05-26 01:26:41 +010066 ASSERT(reinterpret_cast<Address>(*dictionary_.location()) != kHandleZapValue);
Ben Murdochb0fe1622011-05-05 13:52:32 +010067}
68
69
Ben Murdoch257744e2011-11-30 15:57:28 +000070Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) {
71 int entry = dictionary_->FindEntry(ast_id);
Steve Block44f0eee2011-05-26 01:26:41 +010072 return entry != NumberDictionary::kNotFound
73 ? Handle<Object>(dictionary_->ValueAt(entry))
74 : Isolate::Current()->factory()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010075}
76
77
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000078bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000079 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +010080 if (map_or_code->IsMap()) return true;
81 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +000082 Handle<Code> code = Handle<Code>::cast(map_or_code);
83 return code->is_keyed_load_stub() &&
84 code->ic_state() == MONOMORPHIC &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000085 Code::ExtractTypeFromFlags(code->flags()) == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010086 code->FindFirstMap() != NULL;
87 }
88 return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +010089}
90
91
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000092bool TypeFeedbackOracle::LoadIsMegamorphicWithTypeInfo(Property* expr) {
93 Handle<Object> map_or_code(GetInfo(expr->id()));
94 if (map_or_code->IsCode()) {
95 Handle<Code> code = Handle<Code>::cast(map_or_code);
96 Builtins* builtins = Isolate::Current()->builtins();
97 return code->is_keyed_load_stub() &&
98 *code != builtins->builtin(Builtins::kKeyedLoadIC_Generic) &&
99 code->ic_state() == MEGAMORPHIC;
100 }
101 return false;
102}
103
104
105bool TypeFeedbackOracle::StoreIsMonomorphicNormal(Expression* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000106 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +0100107 if (map_or_code->IsMap()) return true;
108 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000109 Handle<Code> code = Handle<Code>::cast(map_or_code);
110 return code->is_keyed_store_stub() &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000111 code->ic_state() == MONOMORPHIC &&
112 Code::ExtractTypeFromFlags(code->flags()) == NORMAL;
113 }
114 return false;
115}
116
117
118bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(Expression* expr) {
119 Handle<Object> map_or_code(GetInfo(expr->id()));
120 if (map_or_code->IsCode()) {
121 Handle<Code> code = Handle<Code>::cast(map_or_code);
122 Builtins* builtins = Isolate::Current()->builtins();
123 return code->is_keyed_store_stub() &&
124 *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) &&
125 *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic_Strict) &&
126 code->ic_state() == MEGAMORPHIC;
Steve Block44f0eee2011-05-26 01:26:41 +0100127 }
128 return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100129}
130
131
132bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000133 Handle<Object> value = GetInfo(expr->id());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100134 return value->IsMap() || value->IsSmi();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100135}
136
137
138Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000139 ASSERT(LoadIsMonomorphicNormal(expr));
Ben Murdoch257744e2011-11-30 15:57:28 +0000140 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +0100141 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000142 Handle<Code> code = Handle<Code>::cast(map_or_code);
143 Map* first_map = code->FindFirstMap();
144 ASSERT(first_map != NULL);
145 return Handle<Map>(first_map);
Steve Block44f0eee2011-05-26 01:26:41 +0100146 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000147 return Handle<Map>::cast(map_or_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100148}
149
150
Ben Murdoch8b112d22011-06-08 16:22:53 +0100151Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000152 ASSERT(StoreIsMonomorphicNormal(expr));
Ben Murdoch257744e2011-11-30 15:57:28 +0000153 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +0100154 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000155 Handle<Code> code = Handle<Code>::cast(map_or_code);
Steve Block44f0eee2011-05-26 01:26:41 +0100156 return Handle<Map>(code->FindFirstMap());
157 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000158 return Handle<Map>::cast(map_or_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100159}
160
161
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000162void TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
163 Handle<String> name,
164 SmallMapList* types) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100165 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000166 CollectReceiverTypes(expr->id(), name, flags, types);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100167}
168
169
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000170void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
171 Handle<String> name,
172 SmallMapList* types) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100173 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000174 CollectReceiverTypes(expr->id(), name, flags, types);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100175}
176
177
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000178void TypeFeedbackOracle::CallReceiverTypes(Call* expr,
179 Handle<String> name,
180 CallKind call_kind,
181 SmallMapList* types) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100182 int arity = expr->arguments()->length();
Ben Murdoch257744e2011-11-30 15:57:28 +0000183
184 // Note: Currently we do not take string extra ic data into account
185 // here.
186 Code::ExtraICState extra_ic_state =
187 CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION);
188
Ben Murdochb8e0da22011-05-16 14:20:40 +0100189 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
190 NORMAL,
Ben Murdoch257744e2011-11-30 15:57:28 +0000191 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100192 OWN_MAP,
193 NOT_IN_LOOP,
194 arity);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000195 CollectReceiverTypes(expr->id(), name, flags, types);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100196}
197
198
Ben Murdochb8e0da22011-05-16 14:20:40 +0100199CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000200 Handle<Object> value = GetInfo(expr->id());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100201 if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
202 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
203 ASSERT(check != RECEIVER_MAP_CHECK);
204 return check;
205}
206
Ben Murdochb8e0da22011-05-16 14:20:40 +0100207Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
208 CheckType check) {
209 JSFunction* function = NULL;
210 switch (check) {
211 case RECEIVER_MAP_CHECK:
212 UNREACHABLE();
213 break;
214 case STRING_CHECK:
215 function = global_context_->string_function();
216 break;
217 case NUMBER_CHECK:
218 function = global_context_->number_function();
219 break;
220 case BOOLEAN_CHECK:
221 function = global_context_->boolean_function();
222 break;
223 }
224 ASSERT(function != NULL);
225 return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
226}
227
228
Ben Murdochb0fe1622011-05-05 13:52:32 +0100229bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000230 return *GetInfo(expr->id()) ==
Steve Block44f0eee2011-05-26 01:26:41 +0100231 Isolate::Current()->builtins()->builtin(id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100232}
233
234
Steve Block1e0659c2011-05-24 12:43:12 +0100235TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000236 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100237 TypeInfo unknown = TypeInfo::Unknown();
238 if (!object->IsCode()) return unknown;
239 Handle<Code> code = Handle<Code>::cast(object);
240 if (!code->is_compare_ic_stub()) return unknown;
241
242 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
243 switch (state) {
244 case CompareIC::UNINITIALIZED:
245 // Uninitialized means never executed.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000246 return TypeInfo::Uninitialized();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100247 case CompareIC::SMIS:
248 return TypeInfo::Smi();
249 case CompareIC::HEAP_NUMBERS:
250 return TypeInfo::Number();
Ben Murdoch257744e2011-11-30 15:57:28 +0000251 case CompareIC::SYMBOLS:
252 case CompareIC::STRINGS:
253 return TypeInfo::String();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100254 case CompareIC::OBJECTS:
255 // TODO(kasperl): We really need a type for JS objects here.
256 return TypeInfo::NonPrimitive();
257 case CompareIC::GENERIC:
258 default:
259 return unknown;
260 }
261}
262
263
Ben Murdoch257744e2011-11-30 15:57:28 +0000264bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) {
265 Handle<Object> object = GetInfo(expr->id());
266 if (!object->IsCode()) return false;
267 Handle<Code> code = Handle<Code>::cast(object);
268 if (!code->is_compare_ic_stub()) return false;
269 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
270 return state == CompareIC::SYMBOLS;
271}
272
273
274TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
275 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100276 TypeInfo unknown = TypeInfo::Unknown();
277 if (!object->IsCode()) return unknown;
278 Handle<Code> code = Handle<Code>::cast(object);
Ben Murdoch257744e2011-11-30 15:57:28 +0000279 ASSERT(code->is_unary_op_stub());
280 UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>(
281 code->unary_op_type());
282 switch (type) {
283 case UnaryOpIC::SMI:
284 return TypeInfo::Smi();
285 case UnaryOpIC::HEAP_NUMBER:
286 return TypeInfo::Double();
287 default:
288 return unknown;
289 }
290}
291
292
293TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
294 Handle<Object> object = GetInfo(expr->id());
295 TypeInfo unknown = TypeInfo::Unknown();
296 if (!object->IsCode()) return unknown;
297 Handle<Code> code = Handle<Code>::cast(object);
298 if (code->is_binary_op_stub()) {
299 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
300 code->binary_op_type());
301 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>(
302 code->binary_op_result_type());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100303
304 switch (type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000305 case BinaryOpIC::UNINITIALIZED:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100306 // Uninitialized means never executed.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000307 return TypeInfo::Uninitialized();
Ben Murdoch257744e2011-11-30 15:57:28 +0000308 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309 switch (result_type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000310 case BinaryOpIC::UNINITIALIZED:
311 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100312 return TypeInfo::Smi();
Ben Murdoch257744e2011-11-30 15:57:28 +0000313 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100314 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000315 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100316 return TypeInfo::Double();
317 default:
318 return unknown;
319 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000320 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100321 if (expr->op() == Token::DIV ||
Ben Murdoch257744e2011-11-30 15:57:28 +0000322 result_type == BinaryOpIC::HEAP_NUMBER) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100323 return TypeInfo::Double();
324 }
325 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000326 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100327 return TypeInfo::Double();
Ben Murdoch257744e2011-11-30 15:57:28 +0000328 case BinaryOpIC::BOTH_STRING:
329 return TypeInfo::String();
330 case BinaryOpIC::STRING:
331 case BinaryOpIC::GENERIC:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100332 return unknown;
333 default:
334 return unknown;
335 }
336 }
337 return unknown;
338}
339
Ben Murdochb8e0da22011-05-16 14:20:40 +0100340
Ben Murdochb0fe1622011-05-05 13:52:32 +0100341TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000342 Handle<Object> object = GetInfo(clause->CompareId());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100343 TypeInfo unknown = TypeInfo::Unknown();
344 if (!object->IsCode()) return unknown;
345 Handle<Code> code = Handle<Code>::cast(object);
346 if (!code->is_compare_ic_stub()) return unknown;
347
348 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
349 switch (state) {
350 case CompareIC::UNINITIALIZED:
351 // Uninitialized means never executed.
352 // TODO(fschneider): Introduce a separate value for never-executed ICs.
353 return unknown;
354 case CompareIC::SMIS:
355 return TypeInfo::Smi();
356 case CompareIC::HEAP_NUMBERS:
357 return TypeInfo::Number();
358 case CompareIC::OBJECTS:
359 // TODO(kasperl): We really need a type for JS objects here.
360 return TypeInfo::NonPrimitive();
361 case CompareIC::GENERIC:
362 default:
363 return unknown;
364 }
365}
366
367
Ben Murdoch257744e2011-11-30 15:57:28 +0000368TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
369 Handle<Object> object = GetInfo(expr->CountId());
370 TypeInfo unknown = TypeInfo::Unknown();
371 if (!object->IsCode()) return unknown;
372 Handle<Code> code = Handle<Code>::cast(object);
373 if (!code->is_binary_op_stub()) return unknown;
374
375 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
376 code->binary_op_type());
377 switch (type) {
378 case BinaryOpIC::UNINITIALIZED:
379 case BinaryOpIC::SMI:
380 return TypeInfo::Smi();
381 case BinaryOpIC::INT32:
382 return TypeInfo::Integer32();
383 case BinaryOpIC::HEAP_NUMBER:
384 return TypeInfo::Double();
385 case BinaryOpIC::BOTH_STRING:
386 case BinaryOpIC::STRING:
387 case BinaryOpIC::GENERIC:
388 return unknown;
389 default:
390 return unknown;
391 }
392 UNREACHABLE();
393 return unknown;
394}
395
396
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000397void TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
398 Handle<String> name,
399 Code::Flags flags,
400 SmallMapList* types) {
Steve Block44f0eee2011-05-26 01:26:41 +0100401 Isolate* isolate = Isolate::Current();
Ben Murdoch257744e2011-11-30 15:57:28 +0000402 Handle<Object> object = GetInfo(ast_id);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000403 if (object->IsUndefined() || object->IsSmi()) return;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100404
Steve Block44f0eee2011-05-26 01:26:41 +0100405 if (*object == isolate->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100406 // TODO(fschneider): We could collect the maps and signal that
407 // we need a generic store (or load) here.
408 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100409 } else if (object->IsMap()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100410 types->Add(Handle<Map>::cast(object));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100411 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000412 types->Reserve(4);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100413 ASSERT(object->IsCode());
Steve Block44f0eee2011-05-26 01:26:41 +0100414 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100415 }
416}
417
418
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000419void TypeFeedbackOracle::CollectKeyedReceiverTypes(unsigned ast_id,
420 SmallMapList* types) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000421 Handle<Object> object = GetInfo(ast_id);
422 if (!object->IsCode()) return;
423 Handle<Code> code = Handle<Code>::cast(object);
424 if (code->kind() == Code::KEYED_LOAD_IC ||
425 code->kind() == Code::KEYED_STORE_IC) {
426 AssertNoAllocation no_allocation;
427 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
428 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
429 RelocInfo* info = it.rinfo();
430 Object* object = info->target_object();
431 if (object->IsMap()) {
432 types->Add(Handle<Map>(Map::cast(object)));
433 }
434 }
435 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100436}
437
438
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000439byte TypeFeedbackOracle::ToBooleanTypes(unsigned ast_id) {
440 Handle<Object> object = GetInfo(ast_id);
441 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0;
442}
443
444
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000445// Things are a bit tricky here: The iterator for the RelocInfos and the infos
446// themselves are not GC-safe, so we first get all infos, then we create the
447// dictionary (possibly triggering GC), and finally we relocate the collected
448// infos before we process them.
449void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) {
450 AssertNoAllocation no_allocation;
451 ZoneList<RelocInfo> infos(16);
452 HandleScope scope;
453 GetRelocInfos(code, &infos);
454 CreateDictionary(code, &infos);
455 ProcessRelocInfos(&infos);
Steve Block44f0eee2011-05-26 01:26:41 +0100456 // Allocate handle in the parent scope.
457 dictionary_ = scope.CloseAndEscape(dictionary_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100458}
459
460
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000461void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code,
462 ZoneList<RelocInfo>* infos) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000463 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000464 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
465 infos->Add(*it.rinfo());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100466 }
467}
468
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000469
470void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
471 ZoneList<RelocInfo>* infos) {
472 DisableAssertNoAllocation allocation_allowed;
473 byte* old_start = code->instruction_start();
474 dictionary_ = FACTORY->NewNumberDictionary(infos->length());
475 byte* new_start = code->instruction_start();
476 RelocateRelocInfos(infos, old_start, new_start);
477}
478
479
480void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
481 byte* old_start,
482 byte* new_start) {
483 for (int i = 0; i < infos->length(); i++) {
484 RelocInfo* info = &(*infos)[i];
485 info->set_pc(new_start + (info->pc() - old_start));
486 }
487}
488
489
490void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
491 for (int i = 0; i < infos->length(); i++) {
492 unsigned ast_id = static_cast<unsigned>((*infos)[i].data());
493 Code* target = Code::GetCodeFromTargetAddress((*infos)[i].target_address());
494 ProcessTarget(ast_id, target);
495 }
496}
497
498
499void TypeFeedbackOracle::ProcessTarget(unsigned ast_id, Code* target) {
500 switch (target->kind()) {
501 case Code::LOAD_IC:
502 case Code::STORE_IC:
503 case Code::CALL_IC:
504 case Code::KEYED_CALL_IC:
505 if (target->ic_state() == MONOMORPHIC) {
506 if (target->kind() == Code::CALL_IC &&
507 target->check_type() != RECEIVER_MAP_CHECK) {
508 SetInfo(ast_id, Smi::FromInt(target->check_type()));
509 } else {
510 Object* map = target->FindFirstMap();
511 SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
512 }
513 } else if (target->ic_state() == MEGAMORPHIC) {
514 SetInfo(ast_id, target);
515 }
516 break;
517
518 case Code::KEYED_LOAD_IC:
519 case Code::KEYED_STORE_IC:
520 if (target->ic_state() == MONOMORPHIC ||
521 target->ic_state() == MEGAMORPHIC) {
522 SetInfo(ast_id, target);
523 }
524 break;
525
526 case Code::UNARY_OP_IC:
527 case Code::BINARY_OP_IC:
528 case Code::COMPARE_IC:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000529 case Code::TO_BOOLEAN_IC:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000530 SetInfo(ast_id, target);
531 break;
532
533 default:
534 break;
535 }
536}
537
538
539void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
540 ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
541 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
542 USE(maybe_result);
543#ifdef DEBUG
544 Object* result = NULL;
545 // Dictionary has been allocated with sufficient size for all elements.
546 ASSERT(maybe_result->ToObject(&result));
547 ASSERT(*dictionary_ == result);
548#endif
549}
550
Steve Blocka7e24c12009-10-30 11:49:00 +0000551} } // namespace v8::internal