blob: bdf7bc3c865338d017b07a6469ebddd18df5c48c [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
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000162void TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
163 Handle<String> name,
164 SmallMapList* types) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000165 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000166 CollectReceiverTypes(expr->id(), name, flags, types);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000167}
168
169
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000170void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
171 Handle<String> name,
172 SmallMapList* types) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000173 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000174 CollectReceiverTypes(expr->id(), name, flags, types);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000175}
176
177
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000178void TypeFeedbackOracle::CallReceiverTypes(Call* expr,
179 Handle<String> name,
180 CallKind call_kind,
181 SmallMapList* types) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000182 int arity = expr->arguments()->length();
danno@chromium.org40cb8782011-05-25 07:58:50 +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
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000189 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
190 NORMAL,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000191 extra_ic_state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000192 OWN_MAP,
193 NOT_IN_LOOP,
194 arity);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000195 CollectReceiverTypes(expr->id(), name, flags, types);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000196}
197
198
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000199CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000200 Handle<Object> value = GetInfo(expr->id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000201 if (!value->IsSmi()) return RECEIVER_MAP_CHECK;
202 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value());
203 ASSERT(check != RECEIVER_MAP_CHECK);
204 return check;
205}
206
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000207Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
208 CheckType check) {
209 JSFunction* function = NULL;
210 switch (check) {
211 case RECEIVER_MAP_CHECK:
212 UNREACHABLE();
213 break;
214 case STRING_CHECK:
215 function = global_context_->string_function();
216 break;
217 case NUMBER_CHECK:
218 function = global_context_->number_function();
219 break;
220 case BOOLEAN_CHECK:
221 function = global_context_->boolean_function();
222 break;
223 }
224 ASSERT(function != NULL);
225 return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
226}
227
228
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000229bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000230 return *GetInfo(expr->id()) ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 Isolate::Current()->builtins()->builtin(id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000232}
233
234
ager@chromium.org378b34e2011-01-28 08:04:38 +0000235TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000236 Handle<Object> object = GetInfo(expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000237 TypeInfo unknown = TypeInfo::Unknown();
238 if (!object->IsCode()) return unknown;
239 Handle<Code> code = Handle<Code>::cast(object);
240 if (!code->is_compare_ic_stub()) return unknown;
241
242 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
243 switch (state) {
244 case CompareIC::UNINITIALIZED:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000245 // Uninitialized means never executed.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000246 return TypeInfo::Uninitialized();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000247 case CompareIC::SMIS:
248 return TypeInfo::Smi();
249 case CompareIC::HEAP_NUMBERS:
250 return TypeInfo::Number();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000251 case CompareIC::SYMBOLS:
252 case CompareIC::STRINGS:
253 return TypeInfo::String();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000254 case CompareIC::OBJECTS:
255 // TODO(kasperl): We really need a type for JS objects here.
256 return TypeInfo::NonPrimitive();
257 case CompareIC::GENERIC:
258 default:
259 return unknown;
260 }
261}
262
263
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000264bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) {
265 Handle<Object> object = GetInfo(expr->id());
266 if (!object->IsCode()) return false;
267 Handle<Code> code = Handle<Code>::cast(object);
268 if (!code->is_compare_ic_stub()) return false;
269 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
270 return state == CompareIC::SYMBOLS;
271}
272
273
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000274TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000275 Handle<Object> object = GetInfo(expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000276 TypeInfo unknown = TypeInfo::Unknown();
277 if (!object->IsCode()) return unknown;
278 Handle<Code> code = Handle<Code>::cast(object);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000279 ASSERT(code->is_unary_op_stub());
280 UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>(
281 code->unary_op_type());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000282 switch (type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000283 case UnaryOpIC::SMI:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000284 return TypeInfo::Smi();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000285 case UnaryOpIC::HEAP_NUMBER:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000286 return TypeInfo::Double();
287 default:
288 return unknown;
289 }
290}
291
292
293TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) {
294 Handle<Object> object = GetInfo(expr->id());
295 TypeInfo unknown = TypeInfo::Unknown();
296 if (!object->IsCode()) return unknown;
297 Handle<Code> code = Handle<Code>::cast(object);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000298 if (code->is_binary_op_stub()) {
299 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
300 code->binary_op_type());
301 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>(
302 code->binary_op_result_type());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000303
304 switch (type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000305 case BinaryOpIC::UNINITIALIZED:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000306 // Uninitialized means never executed.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000307 return TypeInfo::Uninitialized();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000308 case BinaryOpIC::SMI:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 switch (result_type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000310 case BinaryOpIC::UNINITIALIZED:
311 case BinaryOpIC::SMI:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000312 return TypeInfo::Smi();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000313 case BinaryOpIC::INT32:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000314 return TypeInfo::Integer32();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000315 case BinaryOpIC::HEAP_NUMBER:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000316 return TypeInfo::Double();
317 default:
318 return unknown;
319 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000320 case BinaryOpIC::INT32:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000321 if (expr->op() == Token::DIV ||
danno@chromium.org40cb8782011-05-25 07:58:50 +0000322 result_type == BinaryOpIC::HEAP_NUMBER) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000323 return TypeInfo::Double();
324 }
325 return TypeInfo::Integer32();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000326 case BinaryOpIC::HEAP_NUMBER:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000327 return TypeInfo::Double();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000328 case BinaryOpIC::BOTH_STRING:
danno@chromium.org160a7b02011-04-18 15:51:38 +0000329 return TypeInfo::String();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000330 case BinaryOpIC::STRING:
331 case BinaryOpIC::GENERIC:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000332 return unknown;
333 default:
334 return unknown;
335 }
336 }
337 return unknown;
338}
339
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000340
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000341TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000342 Handle<Object> object = GetInfo(clause->CompareId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000343 TypeInfo unknown = TypeInfo::Unknown();
344 if (!object->IsCode()) return unknown;
345 Handle<Code> code = Handle<Code>::cast(object);
346 if (!code->is_compare_ic_stub()) return unknown;
347
348 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
349 switch (state) {
350 case CompareIC::UNINITIALIZED:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000351 // Uninitialized means never executed.
352 // TODO(fschneider): Introduce a separate value for never-executed ICs.
353 return unknown;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000354 case CompareIC::SMIS:
355 return TypeInfo::Smi();
356 case CompareIC::HEAP_NUMBERS:
357 return TypeInfo::Number();
358 case CompareIC::OBJECTS:
359 // TODO(kasperl): We really need a type for JS objects here.
360 return TypeInfo::NonPrimitive();
361 case CompareIC::GENERIC:
362 default:
363 return unknown;
364 }
365}
366
367
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000368TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
369 Handle<Object> object = GetInfo(expr->CountId());
370 TypeInfo unknown = TypeInfo::Unknown();
371 if (!object->IsCode()) return unknown;
372 Handle<Code> code = Handle<Code>::cast(object);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000373 if (!code->is_binary_op_stub()) return unknown;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000374
danno@chromium.org40cb8782011-05-25 07:58:50 +0000375 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>(
376 code->binary_op_type());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000377 switch (type) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000378 case BinaryOpIC::UNINITIALIZED:
379 case BinaryOpIC::SMI:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000380 return TypeInfo::Smi();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000381 case BinaryOpIC::INT32:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000382 return TypeInfo::Integer32();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000383 case BinaryOpIC::HEAP_NUMBER:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000384 return TypeInfo::Double();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000385 case BinaryOpIC::BOTH_STRING:
386 case BinaryOpIC::STRING:
387 case BinaryOpIC::GENERIC:
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000388 return unknown;
389 default:
390 return unknown;
391 }
392 UNREACHABLE();
393 return unknown;
394}
395
396
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000397void TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id,
398 Handle<String> name,
399 Code::Flags flags,
400 SmallMapList* types) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 Isolate* isolate = Isolate::Current();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000402 Handle<Object> object = GetInfo(ast_id);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000403 if (object->IsUndefined() || object->IsSmi()) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000404
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000405 if (*object == isolate->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000406 // TODO(fschneider): We could collect the maps and signal that
407 // we need a generic store (or load) here.
408 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000409 } else if (object->IsMap()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000410 types->Add(Handle<Map>::cast(object));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000411 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000412 types->Reserve(4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000413 ASSERT(object->IsCode());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000415 }
416}
417
418
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000419void TypeFeedbackOracle::CollectKeyedReceiverTypes(unsigned ast_id,
420 SmallMapList* types) {
whesse@chromium.org7b260152011-06-20 15:33:18 +0000421 Handle<Object> object = GetInfo(ast_id);
422 if (!object->IsCode()) return;
423 Handle<Code> code = Handle<Code>::cast(object);
424 if (code->kind() == Code::KEYED_LOAD_IC ||
425 code->kind() == Code::KEYED_STORE_IC) {
426 AssertNoAllocation no_allocation;
427 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
428 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
429 RelocInfo* info = it.rinfo();
430 Object* object = info->target_object();
431 if (object->IsMap()) {
432 types->Add(Handle<Map>(Map::cast(object)));
433 }
434 }
435 }
436}
437
438
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000439byte TypeFeedbackOracle::ToBooleanTypes(unsigned ast_id) {
440 Handle<Object> object = GetInfo(ast_id);
441 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0;
442}
443
444
whesse@chromium.org7b260152011-06-20 15:33:18 +0000445// Things are a bit tricky here: The iterator for the RelocInfos and the infos
446// themselves are not GC-safe, so we first get all infos, then we create the
447// dictionary (possibly triggering GC), and finally we relocate the collected
448// infos before we process them.
449void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) {
450 AssertNoAllocation no_allocation;
451 ZoneList<RelocInfo> infos(16);
452 HandleScope scope;
453 GetRelocInfos(code, &infos);
454 CreateDictionary(code, &infos);
455 ProcessRelocInfos(&infos);
456 // Allocate handle in the parent scope.
457 dictionary_ = scope.CloseAndEscape(dictionary_);
458}
459
460
461void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code,
462 ZoneList<RelocInfo>* infos) {
463 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
464 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
465 infos->Add(*it.rinfo());
466 }
467}
468
469
470void TypeFeedbackOracle::CreateDictionary(Handle<Code> code,
471 ZoneList<RelocInfo>* infos) {
472 DisableAssertNoAllocation allocation_allowed;
473 byte* old_start = code->instruction_start();
474 dictionary_ = FACTORY->NewNumberDictionary(infos->length());
475 byte* new_start = code->instruction_start();
476 RelocateRelocInfos(infos, old_start, new_start);
477}
478
479
480void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos,
481 byte* old_start,
482 byte* new_start) {
483 for (int i = 0; i < infos->length(); i++) {
484 RelocInfo* info = &(*infos)[i];
485 info->set_pc(new_start + (info->pc() - old_start));
486 }
487}
488
489
490void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) {
491 for (int i = 0; i < infos->length(); i++) {
492 unsigned ast_id = static_cast<unsigned>((*infos)[i].data());
493 Code* target = Code::GetCodeFromTargetAddress((*infos)[i].target_address());
494 ProcessTarget(ast_id, target);
495 }
496}
497
498
499void TypeFeedbackOracle::ProcessTarget(unsigned ast_id, Code* target) {
500 switch (target->kind()) {
501 case Code::LOAD_IC:
502 case Code::STORE_IC:
503 case Code::CALL_IC:
504 case Code::KEYED_CALL_IC:
505 if (target->ic_state() == MONOMORPHIC) {
506 if (target->kind() == Code::CALL_IC &&
507 target->check_type() != RECEIVER_MAP_CHECK) {
508 SetInfo(ast_id, Smi::FromInt(target->check_type()));
509 } else {
510 Object* map = target->FindFirstMap();
511 SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map);
512 }
513 } else if (target->ic_state() == MEGAMORPHIC) {
514 SetInfo(ast_id, target);
515 }
516 break;
517
518 case Code::KEYED_LOAD_IC:
519 case Code::KEYED_STORE_IC:
520 if (target->ic_state() == MONOMORPHIC ||
521 target->ic_state() == MEGAMORPHIC) {
522 SetInfo(ast_id, target);
523 }
524 break;
525
526 case Code::UNARY_OP_IC:
527 case Code::BINARY_OP_IC:
528 case Code::COMPARE_IC:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000529 case Code::TO_BOOLEAN_IC:
whesse@chromium.org7b260152011-06-20 15:33:18 +0000530 SetInfo(ast_id, target);
531 break;
532
533 default:
534 break;
535 }
536}
537
538
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000539void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) {
540 ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound);
541 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000542 USE(maybe_result);
543#ifdef DEBUG
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000544 Object* result = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000545 // Dictionary has been allocated with sufficient size for all elements.
546 ASSERT(maybe_result->ToObject(&result));
547 ASSERT(*dictionary_ == result);
548#endif
549}
550
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000551} } // namespace v8::internal