blob: defb1ae9666a48da8f41cc83eb7f5e028354da01 [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 Murdochb0fe1622011-05-05 13:52:32 +0100162ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
163 Handle<String> name) {
164 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Ben Murdoch257744e2011-11-30 15:57:28 +0000165 return CollectReceiverTypes(expr->id(), name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100166}
167
168
169ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
170 Handle<String> name) {
171 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
Ben Murdoch257744e2011-11-30 15:57:28 +0000172 return CollectReceiverTypes(expr->id(), name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100173}
174
175
176ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr,
Ben Murdoch257744e2011-11-30 15:57:28 +0000177 Handle<String> name,
178 CallKind call_kind) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100179 int arity = expr->arguments()->length();
Ben Murdoch257744e2011-11-30 15:57:28 +0000180
181 // Note: Currently we do not take string extra ic data into account
182 // here.
183 Code::ExtraICState extra_ic_state =
184 CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION);
185
Ben Murdochb8e0da22011-05-16 14:20:40 +0100186 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
187 NORMAL,
Ben Murdoch257744e2011-11-30 15:57:28 +0000188 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100189 OWN_MAP,
190 NOT_IN_LOOP,
191 arity);
Ben Murdoch257744e2011-11-30 15:57:28 +0000192 return CollectReceiverTypes(expr->id(), name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100193}
194
195
Ben Murdochb8e0da22011-05-16 14:20:40 +0100196CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000197 Handle<Object> value = GetInfo(expr->id());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100198 if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
199 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
200 ASSERT(check != RECEIVER_MAP_CHECK);
201 return check;
202}
203
Ben Murdochb8e0da22011-05-16 14:20:40 +0100204Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
205 CheckType check) {
206 JSFunction* function = NULL;
207 switch (check) {
208 case RECEIVER_MAP_CHECK:
209 UNREACHABLE();
210 break;
211 case STRING_CHECK:
212 function = global_context_->string_function();
213 break;
214 case NUMBER_CHECK:
215 function = global_context_->number_function();
216 break;
217 case BOOLEAN_CHECK:
218 function = global_context_->boolean_function();
219 break;
220 }
221 ASSERT(function != NULL);
222 return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
223}
224
225
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000227 return *GetInfo(expr->id()) ==
Steve Block44f0eee2011-05-26 01:26:41 +0100228 Isolate::Current()->builtins()->builtin(id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100229}
230
231
Steve Block1e0659c2011-05-24 12:43:12 +0100232TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000233 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100234 TypeInfo unknown = TypeInfo::Unknown();
235 if (!object->IsCode()) return unknown;
236 Handle<Code> code = Handle<Code>::cast(object);
237 if (!code->is_compare_ic_stub()) return unknown;
238
239 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
240 switch (state) {
241 case CompareIC::UNINITIALIZED:
242 // Uninitialized means never executed.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000243 return TypeInfo::Uninitialized();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100244 case CompareIC::SMIS:
245 return TypeInfo::Smi();
246 case CompareIC::HEAP_NUMBERS:
247 return TypeInfo::Number();
Ben Murdoch257744e2011-11-30 15:57:28 +0000248 case CompareIC::SYMBOLS:
249 case CompareIC::STRINGS:
250 return TypeInfo::String();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100251 case CompareIC::OBJECTS:
252 // TODO(kasperl): We really need a type for JS objects here.
253 return TypeInfo::NonPrimitive();
254 case CompareIC::GENERIC:
255 default:
256 return unknown;
257 }
258}
259
260
Ben Murdoch257744e2011-11-30 15:57:28 +0000261bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) {
262 Handle<Object> object = GetInfo(expr->id());
263 if (!object->IsCode()) return false;
264 Handle<Code> code = Handle<Code>::cast(object);
265 if (!code->is_compare_ic_stub()) return false;
266 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
267 return state == CompareIC::SYMBOLS;
268}
269
270
271TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
272 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100273 TypeInfo unknown = TypeInfo::Unknown();
274 if (!object->IsCode()) return unknown;
275 Handle<Code> code = Handle<Code>::cast(object);
Ben Murdoch257744e2011-11-30 15:57:28 +0000276 ASSERT(code->is_unary_op_stub());
277 UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>(
278 code->unary_op_type());
279 switch (type) {
280 case UnaryOpIC::SMI:
281 return TypeInfo::Smi();
282 case UnaryOpIC::HEAP_NUMBER:
283 return TypeInfo::Double();
284 default:
285 return unknown;
286 }
287}
288
289
290TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
291 Handle<Object> object = GetInfo(expr->id());
292 TypeInfo unknown = TypeInfo::Unknown();
293 if (!object->IsCode()) return unknown;
294 Handle<Code> code = Handle<Code>::cast(object);
295 if (code->is_binary_op_stub()) {
296 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
297 code->binary_op_type());
298 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>(
299 code->binary_op_result_type());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100300
301 switch (type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000302 case BinaryOpIC::UNINITIALIZED:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100303 // Uninitialized means never executed.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000304 return TypeInfo::Uninitialized();
Ben Murdoch257744e2011-11-30 15:57:28 +0000305 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100306 switch (result_type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000307 case BinaryOpIC::UNINITIALIZED:
308 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309 return TypeInfo::Smi();
Ben Murdoch257744e2011-11-30 15:57:28 +0000310 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100311 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000312 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100313 return TypeInfo::Double();
314 default:
315 return unknown;
316 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000317 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100318 if (expr->op() == Token::DIV ||
Ben Murdoch257744e2011-11-30 15:57:28 +0000319 result_type == BinaryOpIC::HEAP_NUMBER) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100320 return TypeInfo::Double();
321 }
322 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000323 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100324 return TypeInfo::Double();
Ben Murdoch257744e2011-11-30 15:57:28 +0000325 case BinaryOpIC::BOTH_STRING:
326 return TypeInfo::String();
327 case BinaryOpIC::STRING:
328 case BinaryOpIC::GENERIC:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100329 return unknown;
330 default:
331 return unknown;
332 }
333 }
334 return unknown;
335}
336
Ben Murdochb8e0da22011-05-16 14:20:40 +0100337
Ben Murdochb0fe1622011-05-05 13:52:32 +0100338TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000339 Handle<Object> object = GetInfo(clause->CompareId());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100340 TypeInfo unknown = TypeInfo::Unknown();
341 if (!object->IsCode()) return unknown;
342 Handle<Code> code = Handle<Code>::cast(object);
343 if (!code->is_compare_ic_stub()) return unknown;
344
345 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
346 switch (state) {
347 case CompareIC::UNINITIALIZED:
348 // Uninitialized means never executed.
349 // TODO(fschneider): Introduce a separate value for never-executed ICs.
350 return unknown;
351 case CompareIC::SMIS:
352 return TypeInfo::Smi();
353 case CompareIC::HEAP_NUMBERS:
354 return TypeInfo::Number();
355 case CompareIC::OBJECTS:
356 // TODO(kasperl): We really need a type for JS objects here.
357 return TypeInfo::NonPrimitive();
358 case CompareIC::GENERIC:
359 default:
360 return unknown;
361 }
362}
363
364
Ben Murdoch257744e2011-11-30 15:57:28 +0000365TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
366 Handle<Object> object = GetInfo(expr->CountId());
367 TypeInfo unknown = TypeInfo::Unknown();
368 if (!object->IsCode()) return unknown;
369 Handle<Code> code = Handle<Code>::cast(object);
370 if (!code->is_binary_op_stub()) return unknown;
371
372 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
373 code->binary_op_type());
374 switch (type) {
375 case BinaryOpIC::UNINITIALIZED:
376 case BinaryOpIC::SMI:
377 return TypeInfo::Smi();
378 case BinaryOpIC::INT32:
379 return TypeInfo::Integer32();
380 case BinaryOpIC::HEAP_NUMBER:
381 return TypeInfo::Double();
382 case BinaryOpIC::BOTH_STRING:
383 case BinaryOpIC::STRING:
384 case BinaryOpIC::GENERIC:
385 return unknown;
386 default:
387 return unknown;
388 }
389 UNREACHABLE();
390 return unknown;
391}
392
393
394ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100395 Handle<String> name,
396 Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +0100397 Isolate* isolate = Isolate::Current();
Ben Murdoch257744e2011-11-30 15:57:28 +0000398 Handle<Object> object = GetInfo(ast_id);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100399 if (object->IsUndefined() || object->IsSmi()) return NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100400
Steve Block44f0eee2011-05-26 01:26:41 +0100401 if (*object == isolate->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100402 // TODO(fschneider): We could collect the maps and signal that
403 // we need a generic store (or load) here.
404 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC);
405 return NULL;
406 } else if (object->IsMap()) {
407 ZoneMapList* types = new ZoneMapList(1);
408 types->Add(Handle<Map>::cast(object));
409 return types;
410 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
411 ZoneMapList* types = new ZoneMapList(4);
412 ASSERT(object->IsCode());
Steve Block44f0eee2011-05-26 01:26:41 +0100413 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100414 return types->length() > 0 ? types : NULL;
415 } else {
416 return NULL;
417 }
418}
419
420
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000421void TypeFeedbackOracle::CollectKeyedReceiverTypes(
422 unsigned ast_id,
423 ZoneMapList* types) {
424 Handle<Object> object = GetInfo(ast_id);
425 if (!object->IsCode()) return;
426 Handle<Code> code = Handle<Code>::cast(object);
427 if (code->kind() == Code::KEYED_LOAD_IC ||
428 code->kind() == Code::KEYED_STORE_IC) {
429 AssertNoAllocation no_allocation;
430 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
431 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
432 RelocInfo* info = it.rinfo();
433 Object* object = info->target_object();
434 if (object->IsMap()) {
435 types->Add(Handle<Map>(Map::cast(object)));
436 }
437 }
438 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100439}
440
441
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000442// Things are a bit tricky here: The iterator for the RelocInfos and the infos
443// themselves are not GC-safe, so we first get all infos, then we create the
444// dictionary (possibly triggering GC), and finally we relocate the collected
445// infos before we process them.
446void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) {
447 AssertNoAllocation no_allocation;
448 ZoneList<RelocInfo> infos(16);
449 HandleScope scope;
450 GetRelocInfos(code, &infos);
451 CreateDictionary(code, &infos);
452 ProcessRelocInfos(&infos);
Steve Block44f0eee2011-05-26 01:26:41 +0100453 // Allocate handle in the parent scope.
454 dictionary_ = scope.CloseAndEscape(dictionary_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100455}
456
457
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000458void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code,
459 ZoneList<RelocInfo>* infos) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000460 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000461 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
462 infos->Add(*it.rinfo());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100463 }
464}
465
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000466
467void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
468 ZoneList<RelocInfo>* infos) {
469 DisableAssertNoAllocation allocation_allowed;
470 byte* old_start = code->instruction_start();
471 dictionary_ = FACTORY->NewNumberDictionary(infos->length());
472 byte* new_start = code->instruction_start();
473 RelocateRelocInfos(infos, old_start, new_start);
474}
475
476
477void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
478 byte* old_start,
479 byte* new_start) {
480 for (int i = 0; i < infos->length(); i++) {
481 RelocInfo* info = &(*infos)[i];
482 info->set_pc(new_start + (info->pc() - old_start));
483 }
484}
485
486
487void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
488 for (int i = 0; i < infos->length(); i++) {
489 unsigned ast_id = static_cast<unsigned>((*infos)[i].data());
490 Code* target = Code::GetCodeFromTargetAddress((*infos)[i].target_address());
491 ProcessTarget(ast_id, target);
492 }
493}
494
495
496void TypeFeedbackOracle::ProcessTarget(unsigned ast_id, Code* target) {
497 switch (target->kind()) {
498 case Code::LOAD_IC:
499 case Code::STORE_IC:
500 case Code::CALL_IC:
501 case Code::KEYED_CALL_IC:
502 if (target->ic_state() == MONOMORPHIC) {
503 if (target->kind() == Code::CALL_IC &&
504 target->check_type() != RECEIVER_MAP_CHECK) {
505 SetInfo(ast_id, Smi::FromInt(target->check_type()));
506 } else {
507 Object* map = target->FindFirstMap();
508 SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
509 }
510 } else if (target->ic_state() == MEGAMORPHIC) {
511 SetInfo(ast_id, target);
512 }
513 break;
514
515 case Code::KEYED_LOAD_IC:
516 case Code::KEYED_STORE_IC:
517 if (target->ic_state() == MONOMORPHIC ||
518 target->ic_state() == MEGAMORPHIC) {
519 SetInfo(ast_id, target);
520 }
521 break;
522
523 case Code::UNARY_OP_IC:
524 case Code::BINARY_OP_IC:
525 case Code::COMPARE_IC:
526 SetInfo(ast_id, target);
527 break;
528
529 default:
530 break;
531 }
532}
533
534
535void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
536 ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
537 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
538 USE(maybe_result);
539#ifdef DEBUG
540 Object* result = NULL;
541 // Dictionary has been allocated with sufficient size for all elements.
542 ASSERT(maybe_result->ToObject(&result));
543 ASSERT(*dictionary_ == result);
544#endif
545}
546
Steve Blocka7e24c12009-10-30 11:49:00 +0000547} } // namespace v8::internal