blob: 5f794bdef4eec702f6953e1cd7a0eae357062e76 [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"
31#include "compiler.h"
32#include "ic.h"
33#include "macro-assembler.h"
34#include "stub-cache.h"
Steve Block6ded16b2010-05-10 14:33:55 +010035#include "type-info.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010036
37#include "ic-inl.h"
Steve Block6ded16b2010-05-10 14:33:55 +010038#include "objects-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039
40namespace v8 {
41namespace internal {
42
Steve Block6ded16b2010-05-10 14:33:55 +010043
44TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) {
45 TypeInfo info;
46 if (value->IsSmi()) {
47 info = TypeInfo::Smi();
48 } else if (value->IsHeapNumber()) {
49 info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value())
50 ? TypeInfo::Integer32()
51 : TypeInfo::Double();
52 } else if (value->IsString()) {
53 info = TypeInfo::String();
54 } else {
55 info = TypeInfo::Unknown();
56 }
57 return info;
58}
59
Steve Blocka7e24c12009-10-30 11:49:00 +000060
Ben Murdochb8e0da22011-05-16 14:20:40 +010061TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
62 Handle<Context> global_context) {
63 global_context_ = global_context;
Steve Block44f0eee2011-05-26 01:26:41 +010064 PopulateMap(code);
65 ASSERT(reinterpret_cast<Address>(*dictionary_.location()) != kHandleZapValue);
Ben Murdochb0fe1622011-05-05 13:52:32 +010066}
67
68
Ben Murdoch257744e2011-11-30 15:57:28 +000069Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) {
70 int entry = dictionary_->FindEntry(ast_id);
Steve Block44f0eee2011-05-26 01:26:41 +010071 return entry != NumberDictionary::kNotFound
72 ? Handle<Object>(dictionary_->ValueAt(entry))
73 : Isolate::Current()->factory()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010074}
75
76
77bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000078 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +010079 if (map_or_code->IsMap()) return true;
80 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +000081 Handle<Code> code = Handle<Code>::cast(map_or_code);
82 return code->is_keyed_load_stub() &&
83 code->ic_state() == MONOMORPHIC &&
Steve Block44f0eee2011-05-26 01:26:41 +010084 code->FindFirstMap() != NULL;
85 }
86 return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +010087}
88
89
Ben Murdoch8b112d22011-06-08 16:22:53 +010090bool TypeFeedbackOracle::StoreIsMonomorphic(Expression* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000091 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +010092 if (map_or_code->IsMap()) return true;
93 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +000094 Handle<Code> code = Handle<Code>::cast(map_or_code);
95 return code->is_keyed_store_stub() &&
96 code->ic_state() == MONOMORPHIC;
Steve Block44f0eee2011-05-26 01:26:41 +010097 }
98 return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +010099}
100
101
102bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000103 Handle<Object> value = GetInfo(expr->id());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100104 return value->IsMap() || value->IsSmi();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100105}
106
107
108Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
109 ASSERT(LoadIsMonomorphic(expr));
Ben Murdoch257744e2011-11-30 15:57:28 +0000110 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +0100111 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000112 Handle<Code> code = Handle<Code>::cast(map_or_code);
113 Map* first_map = code->FindFirstMap();
114 ASSERT(first_map != NULL);
115 return Handle<Map>(first_map);
Steve Block44f0eee2011-05-26 01:26:41 +0100116 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000117 return Handle<Map>::cast(map_or_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100118}
119
120
Ben Murdoch8b112d22011-06-08 16:22:53 +0100121Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100122 ASSERT(StoreIsMonomorphic(expr));
Ben Murdoch257744e2011-11-30 15:57:28 +0000123 Handle<Object> map_or_code(GetInfo(expr->id()));
Steve Block44f0eee2011-05-26 01:26:41 +0100124 if (map_or_code->IsCode()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000125 Handle<Code> code = Handle<Code>::cast(map_or_code);
Steve Block44f0eee2011-05-26 01:26:41 +0100126 return Handle<Map>(code->FindFirstMap());
127 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000128 return Handle<Map>::cast(map_or_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100129}
130
131
Ben Murdochb0fe1622011-05-05 13:52:32 +0100132ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
133 Handle<String> name) {
134 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Ben Murdoch257744e2011-11-30 15:57:28 +0000135 return CollectReceiverTypes(expr->id(), name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100136}
137
138
139ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
140 Handle<String> name) {
141 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
Ben Murdoch257744e2011-11-30 15:57:28 +0000142 return CollectReceiverTypes(expr->id(), name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100143}
144
145
146ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr,
Ben Murdoch257744e2011-11-30 15:57:28 +0000147 Handle<String> name,
148 CallKind call_kind) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100149 int arity = expr->arguments()->length();
Ben Murdoch257744e2011-11-30 15:57:28 +0000150
151 // Note: Currently we do not take string extra ic data into account
152 // here.
153 Code::ExtraICState extra_ic_state =
154 CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION);
155
Ben Murdochb8e0da22011-05-16 14:20:40 +0100156 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
157 NORMAL,
Ben Murdoch257744e2011-11-30 15:57:28 +0000158 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100159 OWN_MAP,
160 NOT_IN_LOOP,
161 arity);
Ben Murdoch257744e2011-11-30 15:57:28 +0000162 return CollectReceiverTypes(expr->id(), name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100163}
164
165
Ben Murdochb8e0da22011-05-16 14:20:40 +0100166CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000167 Handle<Object> value = GetInfo(expr->id());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100168 if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
169 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
170 ASSERT(check != RECEIVER_MAP_CHECK);
171 return check;
172}
173
Steve Block44f0eee2011-05-26 01:26:41 +0100174ExternalArrayType TypeFeedbackOracle::GetKeyedLoadExternalArrayType(
175 Property* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000176 Handle<Object> stub = GetInfo(expr->id());
Steve Block44f0eee2011-05-26 01:26:41 +0100177 ASSERT(stub->IsCode());
178 return Code::cast(*stub)->external_array_type();
179}
180
181ExternalArrayType TypeFeedbackOracle::GetKeyedStoreExternalArrayType(
Ben Murdoch8b112d22011-06-08 16:22:53 +0100182 Expression* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000183 Handle<Object> stub = GetInfo(expr->id());
Steve Block44f0eee2011-05-26 01:26:41 +0100184 ASSERT(stub->IsCode());
185 return Code::cast(*stub)->external_array_type();
186}
Ben Murdochb8e0da22011-05-16 14:20:40 +0100187
188Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
189 CheckType check) {
190 JSFunction* function = NULL;
191 switch (check) {
192 case RECEIVER_MAP_CHECK:
193 UNREACHABLE();
194 break;
195 case STRING_CHECK:
196 function = global_context_->string_function();
197 break;
198 case NUMBER_CHECK:
199 function = global_context_->number_function();
200 break;
201 case BOOLEAN_CHECK:
202 function = global_context_->boolean_function();
203 break;
204 }
205 ASSERT(function != NULL);
206 return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
207}
208
209
Ben Murdochb0fe1622011-05-05 13:52:32 +0100210bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000211 return *GetInfo(expr->id()) ==
Steve Block44f0eee2011-05-26 01:26:41 +0100212 Isolate::Current()->builtins()->builtin(id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213}
214
215
Steve Block1e0659c2011-05-24 12:43:12 +0100216TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000217 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100218 TypeInfo unknown = TypeInfo::Unknown();
219 if (!object->IsCode()) return unknown;
220 Handle<Code> code = Handle<Code>::cast(object);
221 if (!code->is_compare_ic_stub()) return unknown;
222
223 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
224 switch (state) {
225 case CompareIC::UNINITIALIZED:
226 // Uninitialized means never executed.
227 // TODO(fschneider): Introduce a separate value for never-executed ICs.
228 return unknown;
229 case CompareIC::SMIS:
230 return TypeInfo::Smi();
231 case CompareIC::HEAP_NUMBERS:
232 return TypeInfo::Number();
Ben Murdoch257744e2011-11-30 15:57:28 +0000233 case CompareIC::SYMBOLS:
234 case CompareIC::STRINGS:
235 return TypeInfo::String();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100236 case CompareIC::OBJECTS:
237 // TODO(kasperl): We really need a type for JS objects here.
238 return TypeInfo::NonPrimitive();
239 case CompareIC::GENERIC:
240 default:
241 return unknown;
242 }
243}
244
245
Ben Murdoch257744e2011-11-30 15:57:28 +0000246bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) {
247 Handle<Object> object = GetInfo(expr->id());
248 if (!object->IsCode()) return false;
249 Handle<Code> code = Handle<Code>::cast(object);
250 if (!code->is_compare_ic_stub()) return false;
251 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
252 return state == CompareIC::SYMBOLS;
253}
254
255
256TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
257 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100258 TypeInfo unknown = TypeInfo::Unknown();
259 if (!object->IsCode()) return unknown;
260 Handle<Code> code = Handle<Code>::cast(object);
Ben Murdoch257744e2011-11-30 15:57:28 +0000261 ASSERT(code->is_unary_op_stub());
262 UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>(
263 code->unary_op_type());
264 switch (type) {
265 case UnaryOpIC::SMI:
266 return TypeInfo::Smi();
267 case UnaryOpIC::HEAP_NUMBER:
268 return TypeInfo::Double();
269 default:
270 return unknown;
271 }
272}
273
274
275TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
276 Handle<Object> object = GetInfo(expr->id());
277 TypeInfo unknown = TypeInfo::Unknown();
278 if (!object->IsCode()) return unknown;
279 Handle<Code> code = Handle<Code>::cast(object);
280 if (code->is_binary_op_stub()) {
281 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
282 code->binary_op_type());
283 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>(
284 code->binary_op_result_type());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100285
286 switch (type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000287 case BinaryOpIC::UNINITIALIZED:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100288 // Uninitialized means never executed.
289 // TODO(fschneider): Introduce a separate value for never-executed ICs
290 return unknown;
Ben Murdoch257744e2011-11-30 15:57:28 +0000291 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100292 switch (result_type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000293 case BinaryOpIC::UNINITIALIZED:
294 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100295 return TypeInfo::Smi();
Ben Murdoch257744e2011-11-30 15:57:28 +0000296 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100297 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000298 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100299 return TypeInfo::Double();
300 default:
301 return unknown;
302 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000303 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100304 if (expr->op() == Token::DIV ||
Ben Murdoch257744e2011-11-30 15:57:28 +0000305 result_type == BinaryOpIC::HEAP_NUMBER) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100306 return TypeInfo::Double();
307 }
308 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000309 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100310 return TypeInfo::Double();
Ben Murdoch257744e2011-11-30 15:57:28 +0000311 case BinaryOpIC::BOTH_STRING:
312 return TypeInfo::String();
313 case BinaryOpIC::STRING:
314 case BinaryOpIC::GENERIC:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100315 return unknown;
316 default:
317 return unknown;
318 }
319 }
320 return unknown;
321}
322
Ben Murdochb8e0da22011-05-16 14:20:40 +0100323
Ben Murdochb0fe1622011-05-05 13:52:32 +0100324TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000325 Handle<Object> object = GetInfo(clause->CompareId());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100326 TypeInfo unknown = TypeInfo::Unknown();
327 if (!object->IsCode()) return unknown;
328 Handle<Code> code = Handle<Code>::cast(object);
329 if (!code->is_compare_ic_stub()) return unknown;
330
331 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
332 switch (state) {
333 case CompareIC::UNINITIALIZED:
334 // Uninitialized means never executed.
335 // TODO(fschneider): Introduce a separate value for never-executed ICs.
336 return unknown;
337 case CompareIC::SMIS:
338 return TypeInfo::Smi();
339 case CompareIC::HEAP_NUMBERS:
340 return TypeInfo::Number();
341 case CompareIC::OBJECTS:
342 // TODO(kasperl): We really need a type for JS objects here.
343 return TypeInfo::NonPrimitive();
344 case CompareIC::GENERIC:
345 default:
346 return unknown;
347 }
348}
349
350
Ben Murdoch257744e2011-11-30 15:57:28 +0000351TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
352 Handle<Object> object = GetInfo(expr->CountId());
353 TypeInfo unknown = TypeInfo::Unknown();
354 if (!object->IsCode()) return unknown;
355 Handle<Code> code = Handle<Code>::cast(object);
356 if (!code->is_binary_op_stub()) return unknown;
357
358 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
359 code->binary_op_type());
360 switch (type) {
361 case BinaryOpIC::UNINITIALIZED:
362 case BinaryOpIC::SMI:
363 return TypeInfo::Smi();
364 case BinaryOpIC::INT32:
365 return TypeInfo::Integer32();
366 case BinaryOpIC::HEAP_NUMBER:
367 return TypeInfo::Double();
368 case BinaryOpIC::BOTH_STRING:
369 case BinaryOpIC::STRING:
370 case BinaryOpIC::GENERIC:
371 return unknown;
372 default:
373 return unknown;
374 }
375 UNREACHABLE();
376 return unknown;
377}
378
379
380ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100381 Handle<String> name,
382 Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +0100383 Isolate* isolate = Isolate::Current();
Ben Murdoch257744e2011-11-30 15:57:28 +0000384 Handle<Object> object = GetInfo(ast_id);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100385 if (object->IsUndefined() || object->IsSmi()) return NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100386
Steve Block44f0eee2011-05-26 01:26:41 +0100387 if (*object == isolate->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100388 // TODO(fschneider): We could collect the maps and signal that
389 // we need a generic store (or load) here.
390 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC);
391 return NULL;
392 } else if (object->IsMap()) {
393 ZoneMapList* types = new ZoneMapList(1);
394 types->Add(Handle<Map>::cast(object));
395 return types;
396 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
397 ZoneMapList* types = new ZoneMapList(4);
398 ASSERT(object->IsCode());
Steve Block44f0eee2011-05-26 01:26:41 +0100399 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100400 return types->length() > 0 ? types : NULL;
401 } else {
402 return NULL;
403 }
404}
405
406
Ben Murdoch257744e2011-11-30 15:57:28 +0000407void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
408 ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
409 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100410 USE(maybe_result);
411#ifdef DEBUG
412 Object* result;
413 // Dictionary has been allocated with sufficient size for all elements.
414 ASSERT(maybe_result->ToObject(&result));
415 ASSERT(*dictionary_ == result);
416#endif
417}
418
419
Ben Murdochb0fe1622011-05-05 13:52:32 +0100420void TypeFeedbackOracle::PopulateMap(Handle<Code> code) {
Steve Block44f0eee2011-05-26 01:26:41 +0100421 Isolate* isolate = Isolate::Current();
422 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100423
424 const int kInitialCapacity = 16;
425 List<int> code_positions(kInitialCapacity);
Ben Murdoch257744e2011-11-30 15:57:28 +0000426 List<unsigned> ast_ids(kInitialCapacity);
427 CollectIds(*code, &code_positions, &ast_ids);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100428
Steve Block44f0eee2011-05-26 01:26:41 +0100429 ASSERT(dictionary_.is_null()); // Only initialize once.
430 dictionary_ = isolate->factory()->NewNumberDictionary(
431 code_positions.length());
432
Ben Murdoch257744e2011-11-30 15:57:28 +0000433 const int length = code_positions.length();
434 ASSERT(ast_ids.length() == length);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100435 for (int i = 0; i < length; i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100436 AssertNoAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100437 RelocInfo info(code->instruction_start() + code_positions[i],
438 RelocInfo::CODE_TARGET, 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100439 Code* target = Code::GetCodeFromTargetAddress(info.target_address());
Ben Murdoch257744e2011-11-30 15:57:28 +0000440 unsigned id = ast_ids[i];
Ben Murdochb0fe1622011-05-05 13:52:32 +0100441 InlineCacheState state = target->ic_state();
442 Code::Kind kind = target->kind();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100443
Ben Murdoch257744e2011-11-30 15:57:28 +0000444 if (kind == Code::BINARY_OP_IC ||
445 kind == Code::UNARY_OP_IC ||
Ben Murdochb0fe1622011-05-05 13:52:32 +0100446 kind == Code::COMPARE_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000447 SetInfo(id, target);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100448 } else if (state == MONOMORPHIC) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000449 if (kind == Code::KEYED_LOAD_IC ||
450 kind == Code::KEYED_STORE_IC) {
451 SetInfo(id, target);
452 } else if (kind != Code::CALL_IC ||
453 target->check_type() == RECEIVER_MAP_CHECK) {
Steve Block44f0eee2011-05-26 01:26:41 +0100454 Map* map = target->FindFirstMap();
455 if (map == NULL) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000456 SetInfo(id, target);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100457 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +0000458 SetInfo(id, map);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100459 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100460 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100461 ASSERT(target->kind() == Code::CALL_IC);
462 CheckType check = target->check_type();
463 ASSERT(check != RECEIVER_MAP_CHECK);
Ben Murdoch257744e2011-11-30 15:57:28 +0000464 SetInfo(id, Smi::FromInt(check));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100465 }
466 } else if (state == MEGAMORPHIC) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000467 SetInfo(id, target);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100468 }
469 }
Steve Block44f0eee2011-05-26 01:26:41 +0100470 // Allocate handle in the parent scope.
471 dictionary_ = scope.CloseAndEscape(dictionary_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100472}
473
474
Ben Murdoch257744e2011-11-30 15:57:28 +0000475void TypeFeedbackOracle::CollectIds(Code* code,
476 List<int>* code_positions,
477 List<unsigned>* ast_ids) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100478 AssertNoAllocation no_allocation;
Ben Murdoch257744e2011-11-30 15:57:28 +0000479 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100480 for (RelocIterator it(code, mask); !it.done(); it.next()) {
481 RelocInfo* info = it.rinfo();
Ben Murdoch257744e2011-11-30 15:57:28 +0000482 ASSERT(RelocInfo::IsCodeTarget(info->rmode()));
483 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
484 if (target->is_inline_cache_stub()) {
485 InlineCacheState state = target->ic_state();
486 Code::Kind kind = target->kind();
487 if (kind == Code::BINARY_OP_IC) {
488 if (target->binary_op_type() ==
489 BinaryOpIC::GENERIC) {
490 continue;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100491 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000492 } else if (kind == Code::COMPARE_IC) {
493 if (target->compare_state() == CompareIC::GENERIC) continue;
494 } else {
495 if (state != MONOMORPHIC && state != MEGAMORPHIC) continue;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100496 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000497 code_positions->Add(
498 static_cast<int>(info->pc() - code->instruction_start()));
499 ASSERT(ast_ids->length() == 0 ||
500 (*ast_ids)[ast_ids->length()-1] !=
501 static_cast<unsigned>(info->data()));
502 ast_ids->Add(static_cast<unsigned>(info->data()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100503 }
504 }
505}
506
Steve Blocka7e24c12009-10-30 11:49:00 +0000507} } // namespace v8::internal