blob: e10c5f40e45e1769a58313f8a03adfda153e1d15 [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 the V8 project authors. All rights reserved.
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +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
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +000028#include "v8.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000029
30#include "ast.h"
whesse@chromium.org7b260152011-06-20 15:33:18 +000031#include "code-stubs.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "compiler.h"
33#include "ic.h"
34#include "macro-assembler.h"
35#include "stub-cache.h"
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +000036#include "type-info.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037
38#include "ic-inl.h"
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +000039#include "objects-inl.h"
40
41namespace v8 {
42namespace internal {
43
44
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();
lrn@chromium.org25156de2010-04-06 13:10:27 +000053 } else if (value->IsString()) {
54 info = TypeInfo::String();
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +000055 } else {
56 info = TypeInfo::Unknown();
57 }
58 return info;
59}
60
61
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000062TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
63 Handle<Context> global_context) {
64 global_context_ = global_context;
whesse@chromium.org7b260152011-06-20 15:33:18 +000065 BuildDictionary(code);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000066 ASSERT(reinterpret_cast<Address>(*dictionary_.location()) != kHandleZapValue);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000067}
68
69
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000070Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) {
71 int entry = dictionary_->FindEntry(ast_id);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000072 return entry != NumberDictionary::kNotFound
73 ? Handle<Object>(dictionary_->ValueAt(entry))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000074 : Isolate::Current()->factory()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000075}
76
77
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000078bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000079 Handle<Object> map_or_code(GetInfo(expr->id()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000080 if (map_or_code->IsMap()) return true;
81 if (map_or_code->IsCode()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +000082 Handle<Code> code = Handle<Code>::cast(map_or_code);
83 return code->is_keyed_load_stub() &&
84 code->ic_state() == MONOMORPHIC &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000085 Code::ExtractTypeFromFlags(code->flags()) == NORMAL &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000086 code->FindFirstMap() != NULL;
87 }
88 return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000089}
90
91
whesse@chromium.org7b260152011-06-20 15:33:18 +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
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000105bool TypeFeedbackOracle::StoreIsMonomorphicNormal(Expression* expr) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000106 Handle<Object> map_or_code(GetInfo(expr->id()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000107 if (map_or_code->IsMap()) return true;
108 if (map_or_code->IsCode()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000109 Handle<Code> code = Handle<Code>::cast(map_or_code);
110 return code->is_keyed_store_stub() &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000111 code->ic_state() == MONOMORPHIC &&
112 Code::ExtractTypeFromFlags(code->flags()) == NORMAL;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000113 }
114 return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000115}
116
117
whesse@chromium.org7b260152011-06-20 15:33:18 +0000118bool 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) &&
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000125 *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic_Strict) &&
whesse@chromium.org7b260152011-06-20 15:33:18 +0000126 code->ic_state() == MEGAMORPHIC;
127 }
128 return false;
129}
130
131
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000132bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000133 Handle<Object> value = GetInfo(expr->id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000134 return value->IsMap() || value->IsSmi();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000135}
136
137
138Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000139 ASSERT(LoadIsMonomorphicNormal(expr));
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000140 Handle<Object> map_or_code(GetInfo(expr->id()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000141 if (map_or_code->IsCode()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +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);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000146 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000147 return Handle<Map>::cast(map_or_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000148}
149
150
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000151Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000152 ASSERT(StoreIsMonomorphicNormal(expr));
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000153 Handle<Object> map_or_code(GetInfo(expr->id()));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000154 if (map_or_code->IsCode()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000155 Handle<Code> code = Handle<Code>::cast(map_or_code);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000156 return Handle<Map>(code->FindFirstMap());
157 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000158 return Handle<Map>::cast(map_or_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000159}
160
161
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000162ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
163 Handle<String> name) {
164 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000165 return CollectReceiverTypes(expr->id(), name, flags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000166}
167
168
169ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
170 Handle<String> name) {
171 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000172 return CollectReceiverTypes(expr->id(), name, flags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000173}
174
175
176ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000177 Handle<String> name,
178 CallKind call_kind) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000179 int arity = expr->arguments()->length();
danno@chromium.org40cb8782011-05-25 07:58:50 +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
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000186 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
187 NORMAL,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000188 extra_ic_state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000189 OWN_MAP,
190 NOT_IN_LOOP,
191 arity);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000192 return CollectReceiverTypes(expr->id(), name, flags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000193}
194
195
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000196CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000197 Handle<Object> value = GetInfo(expr->id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000198 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
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000204Handle<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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000226bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000227 return *GetInfo(expr->id()) ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 Isolate::Current()->builtins()->builtin(id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000229}
230
231
ager@chromium.org378b34e2011-01-28 08:04:38 +0000232TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000233 Handle<Object> object = GetInfo(expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000234 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:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000242 // Uninitialized means never executed.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000243 return TypeInfo::Uninitialized();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000244 case CompareIC::SMIS:
245 return TypeInfo::Smi();
246 case CompareIC::HEAP_NUMBERS:
247 return TypeInfo::Number();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000248 case CompareIC::SYMBOLS:
249 case CompareIC::STRINGS:
250 return TypeInfo::String();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000251 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
vegorov@chromium.org7304bca2011-05-16 12:14:13 +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
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000271TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000272 Handle<Object> object = GetInfo(expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000273 TypeInfo unknown = TypeInfo::Unknown();
274 if (!object->IsCode()) return unknown;
275 Handle<Code> code = Handle<Code>::cast(object);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000276 ASSERT(code->is_unary_op_stub());
277 UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>(
278 code->unary_op_type());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000279 switch (type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000280 case UnaryOpIC::SMI:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000281 return TypeInfo::Smi();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000282 case UnaryOpIC::HEAP_NUMBER:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000283 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);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000295 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());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000300
301 switch (type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000302 case BinaryOpIC::UNINITIALIZED:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000303 // Uninitialized means never executed.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000304 return TypeInfo::Uninitialized();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000305 case BinaryOpIC::SMI:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000306 switch (result_type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000307 case BinaryOpIC::UNINITIALIZED:
308 case BinaryOpIC::SMI:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 return TypeInfo::Smi();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000310 case BinaryOpIC::INT32:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000311 return TypeInfo::Integer32();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000312 case BinaryOpIC::HEAP_NUMBER:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000313 return TypeInfo::Double();
314 default:
315 return unknown;
316 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000317 case BinaryOpIC::INT32:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000318 if (expr->op() == Token::DIV ||
danno@chromium.org40cb8782011-05-25 07:58:50 +0000319 result_type == BinaryOpIC::HEAP_NUMBER) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000320 return TypeInfo::Double();
321 }
322 return TypeInfo::Integer32();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000323 case BinaryOpIC::HEAP_NUMBER:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000324 return TypeInfo::Double();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000325 case BinaryOpIC::BOTH_STRING:
danno@chromium.org160a7b02011-04-18 15:51:38 +0000326 return TypeInfo::String();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000327 case BinaryOpIC::STRING:
328 case BinaryOpIC::GENERIC:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000329 return unknown;
330 default:
331 return unknown;
332 }
333 }
334 return unknown;
335}
336
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000337
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000338TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000339 Handle<Object> object = GetInfo(clause->CompareId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000340 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:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000348 // Uninitialized means never executed.
349 // TODO(fschneider): Introduce a separate value for never-executed ICs.
350 return unknown;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000351 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
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +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);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000370 if (!code->is_binary_op_stub()) return unknown;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000371
danno@chromium.org40cb8782011-05-25 07:58:50 +0000372 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
373 code->binary_op_type());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000374 switch (type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000375 case BinaryOpIC::UNINITIALIZED:
376 case BinaryOpIC::SMI:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000377 return TypeInfo::Smi();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000378 case BinaryOpIC::INT32:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000379 return TypeInfo::Integer32();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000380 case BinaryOpIC::HEAP_NUMBER:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000381 return TypeInfo::Double();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000382 case BinaryOpIC::BOTH_STRING:
383 case BinaryOpIC::STRING:
384 case BinaryOpIC::GENERIC:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000385 return unknown;
386 default:
387 return unknown;
388 }
389 UNREACHABLE();
390 return unknown;
391}
392
393
394ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000395 Handle<String> name,
396 Code::Flags flags) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Isolate* isolate = Isolate::Current();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000398 Handle<Object> object = GetInfo(ast_id);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000399 if (object->IsUndefined() || object->IsSmi()) return NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000400
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000401 if (*object == isolate->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000402 // 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());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000414 return types->length() > 0 ? types : NULL;
415 } else {
416 return NULL;
417 }
418}
419
420
whesse@chromium.org7b260152011-06-20 15:33:18 +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 }
439}
440
441
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000442byte TypeFeedbackOracle::ToBooleanTypes(unsigned ast_id) {
443 Handle<Object> object = GetInfo(ast_id);
444 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0;
445}
446
447
whesse@chromium.org7b260152011-06-20 15:33:18 +0000448// Things are a bit tricky here: The iterator for the RelocInfos and the infos
449// themselves are not GC-safe, so we first get all infos, then we create the
450// dictionary (possibly triggering GC), and finally we relocate the collected
451// infos before we process them.
452void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) {
453 AssertNoAllocation no_allocation;
454 ZoneList<RelocInfo> infos(16);
455 HandleScope scope;
456 GetRelocInfos(code, &infos);
457 CreateDictionary(code, &infos);
458 ProcessRelocInfos(&infos);
459 // Allocate handle in the parent scope.
460 dictionary_ = scope.CloseAndEscape(dictionary_);
461}
462
463
464void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code,
465 ZoneList<RelocInfo>* infos) {
466 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
467 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
468 infos->Add(*it.rinfo());
469 }
470}
471
472
473void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
474 ZoneList<RelocInfo>* infos) {
475 DisableAssertNoAllocation allocation_allowed;
476 byte* old_start = code->instruction_start();
477 dictionary_ = FACTORY->NewNumberDictionary(infos->length());
478 byte* new_start = code->instruction_start();
479 RelocateRelocInfos(infos, old_start, new_start);
480}
481
482
483void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
484 byte* old_start,
485 byte* new_start) {
486 for (int i = 0; i < infos->length(); i++) {
487 RelocInfo* info = &(*infos)[i];
488 info->set_pc(new_start + (info->pc() - old_start));
489 }
490}
491
492
493void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
494 for (int i = 0; i < infos->length(); i++) {
495 unsigned ast_id = static_cast<unsigned>((*infos)[i].data());
496 Code* target = Code::GetCodeFromTargetAddress((*infos)[i].target_address());
497 ProcessTarget(ast_id, target);
498 }
499}
500
501
502void TypeFeedbackOracle::ProcessTarget(unsigned ast_id, Code* target) {
503 switch (target->kind()) {
504 case Code::LOAD_IC:
505 case Code::STORE_IC:
506 case Code::CALL_IC:
507 case Code::KEYED_CALL_IC:
508 if (target->ic_state() == MONOMORPHIC) {
509 if (target->kind() == Code::CALL_IC &&
510 target->check_type() != RECEIVER_MAP_CHECK) {
511 SetInfo(ast_id, Smi::FromInt(target->check_type()));
512 } else {
513 Object* map = target->FindFirstMap();
514 SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
515 }
516 } else if (target->ic_state() == MEGAMORPHIC) {
517 SetInfo(ast_id, target);
518 }
519 break;
520
521 case Code::KEYED_LOAD_IC:
522 case Code::KEYED_STORE_IC:
523 if (target->ic_state() == MONOMORPHIC ||
524 target->ic_state() == MEGAMORPHIC) {
525 SetInfo(ast_id, target);
526 }
527 break;
528
529 case Code::UNARY_OP_IC:
530 case Code::BINARY_OP_IC:
531 case Code::COMPARE_IC:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000532 case Code::TO_BOOLEAN_IC:
whesse@chromium.org7b260152011-06-20 15:33:18 +0000533 SetInfo(ast_id, target);
534 break;
535
536 default:
537 break;
538 }
539}
540
541
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000542void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
543 ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
544 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000545 USE(maybe_result);
546#ifdef DEBUG
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000547 Object* result = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548 // Dictionary has been allocated with sufficient size for all elements.
549 ASSERT(maybe_result->ToObject(&result));
550 ASSERT(*dictionary_ == result);
551#endif
552}
553
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000554} } // namespace v8::internal