blob: 4df7ece086f6face7a5363478ead435e076cb7aa [file] [log] [blame]
Ben Murdoch85b71792012-04-11 18:30:58 +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,
Ben Murdoch85b71792012-04-11 18:30:58 +010063 Handle<Context> global_context) {
Ben Murdochb8e0da22011-05-16 14:20:40 +010064 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);
Ben Murdochc7cc0282012-03-05 14:35:55 +000072 return entry != UnseededNumberDictionary::kNotFound
Steve Block44f0eee2011-05-26 01:26:41 +010073 ? Handle<Object>(dictionary_->ValueAt(entry))
Ben Murdoch85b71792012-04-11 18:30:58 +010074 : Isolate::Current()->factory()->undefined_value();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010075}
76
77
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000078bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) {
Ben Murdoch85b71792012-04-11 18:30:58 +010079 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 &&
Ben Murdoch85b71792012-04-11 18:30:58 +010086 code->FindFirstMap() != NULL;
Steve Block44f0eee2011-05-26 01:26:41 +010087 }
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) {
Ben Murdoch85b71792012-04-11 18:30:58 +010093 Handle<Object> map_or_code(GetInfo(expr->id()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000094 if (map_or_code->IsCode()) {
95 Handle<Code> code = Handle<Code>::cast(map_or_code);
Ben Murdoch85b71792012-04-11 18:30:58 +010096 Builtins* builtins = Isolate::Current()->builtins();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000097 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 Murdoch85b71792012-04-11 18:30:58 +0100106 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 &&
Ben Murdoch85b71792012-04-11 18:30:58 +0100112 Code::ExtractTypeFromFlags(code->flags()) == NORMAL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000113 }
114 return false;
115}
116
117
118bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(Expression* expr) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100119 Handle<Object> map_or_code(GetInfo(expr->id()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000120 if (map_or_code->IsCode()) {
121 Handle<Code> code = Handle<Code>::cast(map_or_code);
Ben Murdoch85b71792012-04-11 18:30:58 +0100122 Builtins* builtins = Isolate::Current()->builtins();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000123 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 Murdoch85b71792012-04-11 18:30:58 +0100134 return value->IsMap() || value->IsSmi();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100135}
136
137
Ben Murdochb0fe1622011-05-05 13:52:32 +0100138Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000139 ASSERT(LoadIsMonomorphicNormal(expr));
Ben Murdoch85b71792012-04-11 18:30:58 +0100140 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);
Ben Murdoch85b71792012-04-11 18:30:58 +0100145 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 Murdoch85b71792012-04-11 18:30:58 +0100153 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);
Ben Murdoch85b71792012-04-11 18:30:58 +0100156 return Handle<Map>(code->FindFirstMap());
Steve Block44f0eee2011-05-26 01:26:41 +0100157 }
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,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100193 arity);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000194 CollectReceiverTypes(expr->id(), name, flags, types);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100195}
196
197
Ben Murdochb8e0da22011-05-16 14:20:40 +0100198CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000199 Handle<Object> value = GetInfo(expr->id());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100200 if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
201 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
202 ASSERT(check != RECEIVER_MAP_CHECK);
203 return check;
204}
205
Ben Murdochb8e0da22011-05-16 14:20:40 +0100206Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
207 CheckType check) {
208 JSFunction* function = NULL;
209 switch (check) {
210 case RECEIVER_MAP_CHECK:
211 UNREACHABLE();
212 break;
213 case STRING_CHECK:
214 function = global_context_->string_function();
215 break;
216 case NUMBER_CHECK:
217 function = global_context_->number_function();
218 break;
219 case BOOLEAN_CHECK:
220 function = global_context_->boolean_function();
221 break;
222 }
223 ASSERT(function != NULL);
224 return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
225}
226
227
Ben Murdochb0fe1622011-05-05 13:52:32 +0100228bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000229 return *GetInfo(expr->id()) ==
Ben Murdoch85b71792012-04-11 18:30:58 +0100230 Isolate::Current()->builtins()->builtin(id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100231}
232
233
Steve Block1e0659c2011-05-24 12:43:12 +0100234TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000235 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100236 TypeInfo unknown = TypeInfo::Unknown();
237 if (!object->IsCode()) return unknown;
238 Handle<Code> code = Handle<Code>::cast(object);
239 if (!code->is_compare_ic_stub()) return unknown;
240
241 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
242 switch (state) {
243 case CompareIC::UNINITIALIZED:
244 // Uninitialized means never executed.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000245 return TypeInfo::Uninitialized();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100246 case CompareIC::SMIS:
247 return TypeInfo::Smi();
248 case CompareIC::HEAP_NUMBERS:
249 return TypeInfo::Number();
Ben Murdoch257744e2011-11-30 15:57:28 +0000250 case CompareIC::SYMBOLS:
251 case CompareIC::STRINGS:
252 return TypeInfo::String();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100253 case CompareIC::OBJECTS:
254 // TODO(kasperl): We really need a type for JS objects here.
255 return TypeInfo::NonPrimitive();
256 case CompareIC::GENERIC:
257 default:
258 return unknown;
259 }
260}
261
262
Ben Murdoch257744e2011-11-30 15:57:28 +0000263bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) {
264 Handle<Object> object = GetInfo(expr->id());
265 if (!object->IsCode()) return false;
266 Handle<Code> code = Handle<Code>::cast(object);
267 if (!code->is_compare_ic_stub()) return false;
268 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
269 return state == CompareIC::SYMBOLS;
270}
271
272
273TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
274 Handle<Object> object = GetInfo(expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100275 TypeInfo unknown = TypeInfo::Unknown();
276 if (!object->IsCode()) return unknown;
277 Handle<Code> code = Handle<Code>::cast(object);
Ben Murdoch257744e2011-11-30 15:57:28 +0000278 ASSERT(code->is_unary_op_stub());
279 UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>(
280 code->unary_op_type());
281 switch (type) {
282 case UnaryOpIC::SMI:
283 return TypeInfo::Smi();
284 case UnaryOpIC::HEAP_NUMBER:
285 return TypeInfo::Double();
286 default:
287 return unknown;
288 }
289}
290
291
292TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
293 Handle<Object> object = GetInfo(expr->id());
294 TypeInfo unknown = TypeInfo::Unknown();
295 if (!object->IsCode()) return unknown;
296 Handle<Code> code = Handle<Code>::cast(object);
297 if (code->is_binary_op_stub()) {
298 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
299 code->binary_op_type());
300 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>(
301 code->binary_op_result_type());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100302
303 switch (type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000304 case BinaryOpIC::UNINITIALIZED:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100305 // Uninitialized means never executed.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000306 return TypeInfo::Uninitialized();
Ben Murdoch257744e2011-11-30 15:57:28 +0000307 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100308 switch (result_type) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000309 case BinaryOpIC::UNINITIALIZED:
310 case BinaryOpIC::SMI:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100311 return TypeInfo::Smi();
Ben Murdoch257744e2011-11-30 15:57:28 +0000312 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100313 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000314 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100315 return TypeInfo::Double();
316 default:
317 return unknown;
318 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000319 case BinaryOpIC::INT32:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100320 if (expr->op() == Token::DIV ||
Ben Murdoch257744e2011-11-30 15:57:28 +0000321 result_type == BinaryOpIC::HEAP_NUMBER) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100322 return TypeInfo::Double();
323 }
324 return TypeInfo::Integer32();
Ben Murdoch257744e2011-11-30 15:57:28 +0000325 case BinaryOpIC::HEAP_NUMBER:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100326 return TypeInfo::Double();
Ben Murdoch257744e2011-11-30 15:57:28 +0000327 case BinaryOpIC::BOTH_STRING:
328 return TypeInfo::String();
329 case BinaryOpIC::STRING:
330 case BinaryOpIC::GENERIC:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100331 return unknown;
332 default:
333 return unknown;
334 }
335 }
336 return unknown;
337}
338
Ben Murdochb8e0da22011-05-16 14:20:40 +0100339
Ben Murdochb0fe1622011-05-05 13:52:32 +0100340TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000341 Handle<Object> object = GetInfo(clause->CompareId());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100342 TypeInfo unknown = TypeInfo::Unknown();
343 if (!object->IsCode()) return unknown;
344 Handle<Code> code = Handle<Code>::cast(object);
345 if (!code->is_compare_ic_stub()) return unknown;
346
347 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
348 switch (state) {
349 case CompareIC::UNINITIALIZED:
350 // Uninitialized means never executed.
351 // TODO(fschneider): Introduce a separate value for never-executed ICs.
352 return unknown;
353 case CompareIC::SMIS:
354 return TypeInfo::Smi();
355 case CompareIC::HEAP_NUMBERS:
356 return TypeInfo::Number();
357 case CompareIC::OBJECTS:
358 // TODO(kasperl): We really need a type for JS objects here.
359 return TypeInfo::NonPrimitive();
360 case CompareIC::GENERIC:
361 default:
362 return unknown;
363 }
364}
365
366
Ben Murdoch257744e2011-11-30 15:57:28 +0000367TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
368 Handle<Object> object = GetInfo(expr->CountId());
369 TypeInfo unknown = TypeInfo::Unknown();
370 if (!object->IsCode()) return unknown;
371 Handle<Code> code = Handle<Code>::cast(object);
372 if (!code->is_binary_op_stub()) return unknown;
373
374 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
375 code->binary_op_type());
376 switch (type) {
377 case BinaryOpIC::UNINITIALIZED:
378 case BinaryOpIC::SMI:
379 return TypeInfo::Smi();
380 case BinaryOpIC::INT32:
381 return TypeInfo::Integer32();
382 case BinaryOpIC::HEAP_NUMBER:
383 return TypeInfo::Double();
384 case BinaryOpIC::BOTH_STRING:
385 case BinaryOpIC::STRING:
386 case BinaryOpIC::GENERIC:
387 return unknown;
388 default:
389 return unknown;
390 }
391 UNREACHABLE();
392 return unknown;
393}
394
395
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000396void TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
397 Handle<String> name,
398 Code::Flags flags,
399 SmallMapList* types) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100400 Isolate* isolate = Isolate::Current();
Ben Murdoch257744e2011-11-30 15:57:28 +0000401 Handle<Object> object = GetInfo(ast_id);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000402 if (object->IsUndefined() || object->IsSmi()) return;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100403
Ben Murdoch85b71792012-04-11 18:30:58 +0100404 if (*object == isolate->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100405 // TODO(fschneider): We could collect the maps and signal that
406 // we need a generic store (or load) here.
407 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100408 } else if (object->IsMap()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100409 types->Add(Handle<Map>::cast(object));
Ben Murdoch85b71792012-04-11 18:30:58 +0100410 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000411 types->Reserve(4);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100412 ASSERT(object->IsCode());
Ben Murdoch85b71792012-04-11 18:30:58 +0100413 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100414 }
415}
416
417
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000418void TypeFeedbackOracle::CollectKeyedReceiverTypes(unsigned ast_id,
419 SmallMapList* types) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000420 Handle<Object> object = GetInfo(ast_id);
421 if (!object->IsCode()) return;
422 Handle<Code> code = Handle<Code>::cast(object);
423 if (code->kind() == Code::KEYED_LOAD_IC ||
424 code->kind() == Code::KEYED_STORE_IC) {
425 AssertNoAllocation no_allocation;
426 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
427 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
428 RelocInfo* info = it.rinfo();
429 Object* object = info->target_object();
430 if (object->IsMap()) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100431 types->Add(Handle<Map>(Map::cast(object)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000432 }
433 }
434 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100435}
436
437
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000438byte TypeFeedbackOracle::ToBooleanTypes(unsigned ast_id) {
439 Handle<Object> object = GetInfo(ast_id);
440 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0;
441}
442
443
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000444// Things are a bit tricky here: The iterator for the RelocInfos and the infos
445// themselves are not GC-safe, so we first get all infos, then we create the
446// dictionary (possibly triggering GC), and finally we relocate the collected
447// infos before we process them.
448void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) {
449 AssertNoAllocation no_allocation;
450 ZoneList<RelocInfo> infos(16);
451 HandleScope scope;
452 GetRelocInfos(code, &infos);
453 CreateDictionary(code, &infos);
454 ProcessRelocInfos(&infos);
Steve Block44f0eee2011-05-26 01:26:41 +0100455 // Allocate handle in the parent scope.
456 dictionary_ = scope.CloseAndEscape(dictionary_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100457}
458
459
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000460void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code,
461 ZoneList<RelocInfo>* infos) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000462 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000463 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
464 infos->Add(*it.rinfo());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100465 }
466}
467
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000468
469void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
470 ZoneList<RelocInfo>* infos) {
471 DisableAssertNoAllocation allocation_allowed;
472 byte* old_start = code->instruction_start();
Ben Murdoch85b71792012-04-11 18:30:58 +0100473 dictionary_ = FACTORY->NewUnseededNumberDictionary(infos->length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000474 byte* new_start = code->instruction_start();
475 RelocateRelocInfos(infos, old_start, new_start);
476}
477
478
479void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
480 byte* old_start,
481 byte* new_start) {
482 for (int i = 0; i < infos->length(); i++) {
483 RelocInfo* info = &(*infos)[i];
484 info->set_pc(new_start + (info->pc() - old_start));
485 }
486}
487
488
489void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
490 for (int i = 0; i < infos->length(); i++) {
491 unsigned ast_id = static_cast<unsigned>((*infos)[i].data());
Ben Murdoch85b71792012-04-11 18:30:58 +0100492 Code* target = Code::GetCodeFromTargetAddress((*infos)[i].target_address());
493 ProcessTarget(ast_id, target);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000494 }
495}
496
497
Ben Murdoch85b71792012-04-11 18:30:58 +0100498void TypeFeedbackOracle::ProcessTarget(unsigned ast_id, Code* target) {
499 switch (target->kind()) {
500 case Code::LOAD_IC:
501 case Code::STORE_IC:
502 case Code::CALL_IC:
503 case Code::KEYED_CALL_IC:
504 if (target->ic_state() == MONOMORPHIC) {
505 if (target->kind() == Code::CALL_IC &&
506 target->check_type() != RECEIVER_MAP_CHECK) {
507 SetInfo(ast_id, Smi::FromInt(target->check_type()));
508 } else {
509 Object* map = target->FindFirstMap();
510 SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
511 }
512 } else if (target->ic_state() == MEGAMORPHIC) {
513 SetInfo(ast_id, target);
514 }
515 break;
516
517 case Code::KEYED_LOAD_IC:
518 case Code::KEYED_STORE_IC:
519 if (target->ic_state() == MONOMORPHIC ||
520 target->ic_state() == MEGAMORPHIC) {
521 SetInfo(ast_id, target);
522 }
523 break;
524
525 case Code::UNARY_OP_IC:
526 case Code::BINARY_OP_IC:
527 case Code::COMPARE_IC:
528 case Code::TO_BOOLEAN_IC:
529 SetInfo(ast_id, target);
530 break;
531
532 default:
533 break;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100534 }
535}
536
537
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000538void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000539 ASSERT(dictionary_->FindEntry(ast_id) == UnseededNumberDictionary::kNotFound);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000540 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
541 USE(maybe_result);
542#ifdef DEBUG
543 Object* result = NULL;
544 // Dictionary has been allocated with sufficient size for all elements.
545 ASSERT(maybe_result->ToObject(&result));
546 ASSERT(*dictionary_ == result);
547#endif
548}
549
Steve Blocka7e24c12009-10-30 11:49:00 +0000550} } // namespace v8::internal