blob: 6b41577ea860cde740974881832d9e82e54ae4d6 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// 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
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "ic-inl.h"
33#include "stub-cache.h"
34
35namespace v8 {
36namespace internal {
37
38// -----------------------------------------------------------------------
39// StubCache implementation.
40
41
42StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
43StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
44
45void StubCache::Initialize(bool create_heap_objects) {
46 ASSERT(IsPowerOf2(kPrimaryTableSize));
47 ASSERT(IsPowerOf2(kSecondaryTableSize));
48 if (create_heap_objects) {
49 HandleScope scope;
50 Clear();
51 }
52}
53
54
55Code* StubCache::Set(String* name, Map* map, Code* code) {
56 // Get the flags from the code.
57 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
58
59 // Validate that the name does not move on scavenge, and that we
60 // can use identity checks instead of string equality checks.
61 ASSERT(!Heap::InNewSpace(name));
62 ASSERT(name->IsSymbol());
63
64 // The state bits are not important to the hash function because
65 // the stub cache only contains monomorphic stubs. Make sure that
66 // the bits are the least significant so they will be the ones
67 // masked out.
68 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
69 ASSERT(Code::kFlagsICStateShift == 0);
70
71 // Make sure that the code type is not included in the hash.
72 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
73
74 // Compute the primary entry.
75 int primary_offset = PrimaryOffset(name, flags, map);
76 Entry* primary = entry(primary_, primary_offset);
77 Code* hit = primary->value;
78
79 // If the primary entry has useful data in it, we retire it to the
80 // secondary cache before overwriting it.
81 if (hit != Builtins::builtin(Builtins::Illegal)) {
82 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
83 int secondary_offset =
84 SecondaryOffset(primary->key, primary_flags, primary_offset);
85 Entry* secondary = entry(secondary_, secondary_offset);
86 *secondary = *primary;
87 }
88
89 // Update primary cache.
90 primary->key = name;
91 primary->value = code;
92 return code;
93}
94
95
Steve Block6ded16b2010-05-10 14:33:55 +010096Object* StubCache::ComputeLoadNonexistent(String* name, JSObject* receiver) {
Steve Block8defd9f2010-07-08 12:39:36 +010097 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
Steve Block6ded16b2010-05-10 14:33:55 +010098 // If no global objects are present in the prototype chain, the load
99 // nonexistent IC stub can be shared for all names for a given map
100 // and we use the empty string for the map cache in that case. If
101 // there are global objects involved, we need to check global
102 // property cells in the stub and therefore the stub will be
103 // specific to the name.
104 String* cache_name = Heap::empty_string();
105 if (receiver->IsGlobalObject()) cache_name = name;
106 JSObject* last = receiver;
107 while (last->GetPrototype() != Heap::null_value()) {
108 last = JSObject::cast(last->GetPrototype());
109 if (last->IsGlobalObject()) cache_name = name;
110 }
111 // Compile the stub that is either shared for all names or
112 // name specific if there are global objects involved.
113 Code::Flags flags =
114 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
115 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
116 if (code->IsUndefined()) {
117 LoadStubCompiler compiler;
118 code = compiler.CompileLoadNonexistent(cache_name, receiver, last);
119 if (code->IsFailure()) return code;
120 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
121 Object* result =
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100122 receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
Steve Block6ded16b2010-05-10 14:33:55 +0100123 if (result->IsFailure()) return result;
124 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100125 return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100126}
127
128
Steve Blocka7e24c12009-10-30 11:49:00 +0000129Object* StubCache::ComputeLoadField(String* name,
130 JSObject* receiver,
131 JSObject* holder,
132 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100133 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000134 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100135 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000136 if (code->IsUndefined()) {
137 LoadStubCompiler compiler;
138 code = compiler.CompileLoadField(receiver, holder, field_index, name);
139 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100140 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100141 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000142 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000143 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100144 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000145}
146
147
148Object* StubCache::ComputeLoadCallback(String* name,
149 JSObject* receiver,
150 JSObject* holder,
151 AccessorInfo* callback) {
152 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Steve Block8defd9f2010-07-08 12:39:36 +0100153 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100155 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 if (code->IsUndefined()) {
157 LoadStubCompiler compiler;
Leon Clarkee46be812010-01-19 14:06:41 +0000158 code = compiler.CompileLoadCallback(name, receiver, holder, callback);
Steve Blocka7e24c12009-10-30 11:49:00 +0000159 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100160 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100161 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000162 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000163 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100164 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000165}
166
167
168Object* StubCache::ComputeLoadConstant(String* name,
169 JSObject* receiver,
170 JSObject* holder,
171 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100172 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 Code::Flags flags =
174 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100175 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000176 if (code->IsUndefined()) {
177 LoadStubCompiler compiler;
178 code = compiler.CompileLoadConstant(receiver, holder, value, name);
179 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100180 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100181 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000182 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100184 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000185}
186
187
188Object* StubCache::ComputeLoadInterceptor(String* name,
189 JSObject* receiver,
190 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100191 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100193 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 if (code->IsUndefined()) {
195 LoadStubCompiler compiler;
196 code = compiler.CompileLoadInterceptor(receiver, holder, name);
197 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100198 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100199 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000200 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100202 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000203}
204
205
Steve Block8defd9f2010-07-08 12:39:36 +0100206Object* StubCache::ComputeLoadNormal() {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100207 return Builtins::builtin(Builtins::LoadIC_Normal);
Steve Blocka7e24c12009-10-30 11:49:00 +0000208}
209
210
211Object* StubCache::ComputeLoadGlobal(String* name,
212 JSObject* receiver,
213 GlobalObject* holder,
214 JSGlobalPropertyCell* cell,
215 bool is_dont_delete) {
Steve Block8defd9f2010-07-08 12:39:36 +0100216 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000217 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100218 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000219 if (code->IsUndefined()) {
220 LoadStubCompiler compiler;
221 code = compiler.CompileLoadGlobal(receiver,
222 holder,
223 cell,
224 name,
225 is_dont_delete);
226 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100227 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100228 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000229 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100231 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000232}
233
234
235Object* StubCache::ComputeKeyedLoadField(String* name,
236 JSObject* receiver,
237 JSObject* holder,
238 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100239 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100241 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 if (code->IsUndefined()) {
243 KeyedLoadStubCompiler compiler;
244 code = compiler.CompileLoadField(name, receiver, holder, field_index);
245 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100246 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100247 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000248 if (result->IsFailure()) return result;
249 }
250 return code;
251}
252
253
254Object* StubCache::ComputeKeyedLoadConstant(String* name,
255 JSObject* receiver,
256 JSObject* holder,
257 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100258 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 Code::Flags flags =
260 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100261 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 if (code->IsUndefined()) {
263 KeyedLoadStubCompiler compiler;
264 code = compiler.CompileLoadConstant(name, receiver, holder, value);
265 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100266 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100267 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000268 if (result->IsFailure()) return result;
269 }
270 return code;
271}
272
273
274Object* StubCache::ComputeKeyedLoadInterceptor(String* name,
275 JSObject* receiver,
276 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100277 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 Code::Flags flags =
279 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100280 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000281 if (code->IsUndefined()) {
282 KeyedLoadStubCompiler compiler;
283 code = compiler.CompileLoadInterceptor(receiver, holder, name);
284 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100285 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100286 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000287 if (result->IsFailure()) return result;
288 }
289 return code;
290}
291
292
293Object* StubCache::ComputeKeyedLoadCallback(String* name,
294 JSObject* receiver,
295 JSObject* holder,
296 AccessorInfo* callback) {
Steve Block8defd9f2010-07-08 12:39:36 +0100297 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 Code::Flags flags =
299 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100300 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000301 if (code->IsUndefined()) {
302 KeyedLoadStubCompiler compiler;
303 code = compiler.CompileLoadCallback(name, receiver, holder, callback);
304 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100305 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100306 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000307 if (result->IsFailure()) return result;
308 }
309 return code;
310}
311
312
313
314Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
315 JSArray* receiver) {
316 Code::Flags flags =
317 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100318 ASSERT(receiver->IsJSObject());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100319 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 if (code->IsUndefined()) {
321 KeyedLoadStubCompiler compiler;
322 code = compiler.CompileLoadArrayLength(name);
323 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100324 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100325 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 if (result->IsFailure()) return result;
327 }
328 return code;
329}
330
331
332Object* StubCache::ComputeKeyedLoadStringLength(String* name,
333 String* receiver) {
334 Code::Flags flags =
335 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100336 Map* map = receiver->map();
337 Object* code = map->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000338 if (code->IsUndefined()) {
339 KeyedLoadStubCompiler compiler;
340 code = compiler.CompileLoadStringLength(name);
341 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100342 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Block8defd9f2010-07-08 12:39:36 +0100343 Object* result = map->UpdateCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000344 if (result->IsFailure()) return result;
345 }
346 return code;
347}
348
349
350Object* StubCache::ComputeKeyedLoadFunctionPrototype(String* name,
351 JSFunction* receiver) {
352 Code::Flags flags =
353 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100354 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000355 if (code->IsUndefined()) {
356 KeyedLoadStubCompiler compiler;
357 code = compiler.CompileLoadFunctionPrototype(name);
358 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100359 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100360 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000361 if (result->IsFailure()) return result;
362 }
363 return code;
364}
365
366
367Object* StubCache::ComputeStoreField(String* name,
368 JSObject* receiver,
369 int field_index,
370 Map* transition) {
371 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
372 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
373 Object* code = receiver->map()->FindInCodeCache(name, flags);
374 if (code->IsUndefined()) {
375 StoreStubCompiler compiler;
376 code = compiler.CompileStoreField(receiver, field_index, transition, name);
377 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100378 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100379 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 if (result->IsFailure()) return result;
381 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100382 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000383}
384
385
Steve Block8defd9f2010-07-08 12:39:36 +0100386Object* StubCache::ComputeStoreNormal() {
387 return Builtins::builtin(Builtins::StoreIC_Normal);
388}
389
390
Steve Blocka7e24c12009-10-30 11:49:00 +0000391Object* StubCache::ComputeStoreGlobal(String* name,
392 GlobalObject* receiver,
393 JSGlobalPropertyCell* cell) {
394 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
395 Object* code = receiver->map()->FindInCodeCache(name, flags);
396 if (code->IsUndefined()) {
397 StoreStubCompiler compiler;
398 code = compiler.CompileStoreGlobal(receiver, cell, name);
399 if (code->IsFailure()) return code;
Steve Block8defd9f2010-07-08 12:39:36 +0100400 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100401 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000402 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000403 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100404 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000405}
406
407
408Object* StubCache::ComputeStoreCallback(String* name,
409 JSObject* receiver,
410 AccessorInfo* callback) {
411 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
412 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
413 Object* code = receiver->map()->FindInCodeCache(name, flags);
414 if (code->IsUndefined()) {
415 StoreStubCompiler compiler;
416 code = compiler.CompileStoreCallback(receiver, callback, name);
417 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100418 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100419 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000420 if (result->IsFailure()) return result;
421 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100422 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000423}
424
425
426Object* StubCache::ComputeStoreInterceptor(String* name,
427 JSObject* receiver) {
428 Code::Flags flags =
429 Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
430 Object* code = receiver->map()->FindInCodeCache(name, flags);
431 if (code->IsUndefined()) {
432 StoreStubCompiler compiler;
433 code = compiler.CompileStoreInterceptor(receiver, name);
434 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100435 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100436 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 if (result->IsFailure()) return result;
438 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100439 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000440}
441
442
443Object* StubCache::ComputeKeyedStoreField(String* name, JSObject* receiver,
444 int field_index, Map* transition) {
445 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
446 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
447 Object* code = receiver->map()->FindInCodeCache(name, flags);
448 if (code->IsUndefined()) {
449 KeyedStoreStubCompiler compiler;
450 code = compiler.CompileStoreField(receiver, field_index, transition, name);
451 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100452 PROFILE(CodeCreateEvent(
453 Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100454 Object* result = receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 if (result->IsFailure()) return result;
456 }
457 return code;
458}
459
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100460#define CALL_LOGGER_TAG(kind, type) \
461 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000462
463Object* StubCache::ComputeCallConstant(int argc,
464 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100465 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000466 String* name,
467 Object* object,
468 JSObject* holder,
469 JSFunction* function) {
470 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100471 InlineCacheHolderFlag cache_holder =
472 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100473 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000474
475 // Compute check type based on receiver/holder.
476 StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK;
477 if (object->IsString()) {
478 check = StubCompiler::STRING_CHECK;
479 } else if (object->IsNumber()) {
480 check = StubCompiler::NUMBER_CHECK;
481 } else if (object->IsBoolean()) {
482 check = StubCompiler::BOOLEAN_CHECK;
483 }
484
485 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100486 Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000487 CONSTANT_FUNCTION,
Steve Block8defd9f2010-07-08 12:39:36 +0100488 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000489 in_loop,
490 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100491 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000492 if (code->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000493 // If the function hasn't been compiled yet, we cannot do it now
494 // because it may cause GC. To avoid this issue, we return an
495 // internal error which will make sure we do not update any
496 // caches.
497 if (!function->is_compiled()) return Failure::InternalError();
498 // Compile the stub - only create stubs for fully compiled functions.
Steve Block8defd9f2010-07-08 12:39:36 +0100499 CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000500 code = compiler.CompileCallConstant(object, holder, function, name, check);
501 if (code->IsFailure()) return code;
502 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100503 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
504 Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100505 Object* result = map_holder->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000506 if (result->IsFailure()) return result;
507 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100508 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000509}
510
511
512Object* StubCache::ComputeCallField(int argc,
513 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100514 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000515 String* name,
516 Object* object,
517 JSObject* holder,
518 int index) {
519 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100520 InlineCacheHolderFlag cache_holder =
521 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100522 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000523
524 // TODO(1233596): We cannot do receiver map check for non-JS objects
525 // because they may be represented as immediates without a
526 // map. Instead, we check against the map in the holder.
527 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
528 object = holder;
529 }
530
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100531 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000532 FIELD,
Steve Block8defd9f2010-07-08 12:39:36 +0100533 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 in_loop,
535 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100536 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000537 if (code->IsUndefined()) {
Steve Block8defd9f2010-07-08 12:39:36 +0100538 CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
Andrei Popescu402d9372010-02-26 13:31:12 +0000539 code = compiler.CompileCallField(JSObject::cast(object),
540 holder,
541 index,
542 name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000543 if (code->IsFailure()) return code;
544 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100545 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
546 Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100547 Object* result = map_holder->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000548 if (result->IsFailure()) return result;
549 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100550 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000551}
552
553
554Object* StubCache::ComputeCallInterceptor(int argc,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100555 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000556 String* name,
557 Object* object,
558 JSObject* holder) {
559 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100560 InlineCacheHolderFlag cache_holder =
561 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100562 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000563
564 // TODO(1233596): We cannot do receiver map check for non-JS objects
565 // because they may be represented as immediates without a
566 // map. Instead, we check against the map in the holder.
567 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
568 object = holder;
569 }
570
571 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100572 Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 INTERCEPTOR,
Steve Block8defd9f2010-07-08 12:39:36 +0100574 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 NOT_IN_LOOP,
576 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100577 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000578 if (code->IsUndefined()) {
Steve Block8defd9f2010-07-08 12:39:36 +0100579 CallStubCompiler compiler(argc, NOT_IN_LOOP, kind, cache_holder);
Andrei Popescu402d9372010-02-26 13:31:12 +0000580 code = compiler.CompileCallInterceptor(JSObject::cast(object),
581 holder,
582 name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 if (code->IsFailure()) return code;
584 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100585 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
586 Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100587 Object* result = map_holder->UpdateMapCodeCache(name, Code::cast(code));
Steve Blocka7e24c12009-10-30 11:49:00 +0000588 if (result->IsFailure()) return result;
589 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100590 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000591}
592
593
594Object* StubCache::ComputeCallNormal(int argc,
595 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100596 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000597 String* name,
598 JSObject* receiver) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100599 Object* code = ComputeCallNormal(argc, in_loop, kind);
Steve Blocka7e24c12009-10-30 11:49:00 +0000600 if (code->IsFailure()) return code;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100601 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000602}
603
604
605Object* StubCache::ComputeCallGlobal(int argc,
606 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100607 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 String* name,
609 JSObject* receiver,
610 GlobalObject* holder,
611 JSGlobalPropertyCell* cell,
612 JSFunction* function) {
Steve Block8defd9f2010-07-08 12:39:36 +0100613 InlineCacheHolderFlag cache_holder =
614 IC::GetCodeCacheForObject(receiver, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100615 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000616 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100617 Code::ComputeMonomorphicFlags(kind,
618 NORMAL,
Steve Block8defd9f2010-07-08 12:39:36 +0100619 cache_holder,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100620 in_loop,
621 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100622 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000623 if (code->IsUndefined()) {
624 // If the function hasn't been compiled yet, we cannot do it now
625 // because it may cause GC. To avoid this issue, we return an
626 // internal error which will make sure we do not update any
627 // caches.
628 if (!function->is_compiled()) return Failure::InternalError();
Steve Block8defd9f2010-07-08 12:39:36 +0100629 CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000630 code = compiler.CompileCallGlobal(receiver, holder, cell, function, name);
631 if (code->IsFailure()) return code;
632 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100633 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
634 Code::cast(code), name));
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100635 Object* result = map_holder->UpdateMapCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000636 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000637 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100638 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000639}
640
641
642static Object* GetProbeValue(Code::Flags flags) {
643 // Use raw_unchecked... so we don't get assert failures during GC.
644 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
645 int entry = dictionary->FindEntry(flags);
646 if (entry != -1) return dictionary->ValueAt(entry);
647 return Heap::raw_unchecked_undefined_value();
648}
649
650
651static Object* ProbeCache(Code::Flags flags) {
652 Object* probe = GetProbeValue(flags);
653 if (probe != Heap::undefined_value()) return probe;
654 // Seed the cache with an undefined value to make sure that any
655 // generated code object can always be inserted into the cache
656 // without causing allocation failures.
657 Object* result =
658 Heap::non_monomorphic_cache()->AtNumberPut(flags,
659 Heap::undefined_value());
660 if (result->IsFailure()) return result;
661 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
662 return probe;
663}
664
665
666static Object* FillCache(Object* code) {
667 if (code->IsCode()) {
668 int entry =
669 Heap::non_monomorphic_cache()->FindEntry(
670 Code::cast(code)->flags());
671 // The entry must be present see comment in ProbeCache.
672 ASSERT(entry != -1);
673 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
674 Heap::undefined_value());
675 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
676 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
677 }
678 return code;
679}
680
681
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100682Code* StubCache::FindCallInitialize(int argc,
683 InLoopFlag in_loop,
684 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000685 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100686 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000687 Object* result = ProbeCache(flags);
688 ASSERT(!result->IsUndefined());
689 // This might be called during the marking phase of the collector
690 // hence the unchecked cast.
691 return reinterpret_cast<Code*>(result);
692}
693
694
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100695Object* StubCache::ComputeCallInitialize(int argc,
696 InLoopFlag in_loop,
697 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000698 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100699 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000700 Object* probe = ProbeCache(flags);
701 if (!probe->IsUndefined()) return probe;
702 StubCompiler compiler;
703 return FillCache(compiler.CompileCallInitialize(flags));
704}
705
706
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100707Object* StubCache::ComputeCallPreMonomorphic(int argc,
708 InLoopFlag in_loop,
709 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000710 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100711 Code::ComputeFlags(kind, in_loop, PREMONOMORPHIC, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000712 Object* probe = ProbeCache(flags);
713 if (!probe->IsUndefined()) return probe;
714 StubCompiler compiler;
715 return FillCache(compiler.CompileCallPreMonomorphic(flags));
716}
717
718
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100719Object* StubCache::ComputeCallNormal(int argc,
720 InLoopFlag in_loop,
721 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100723 Code::ComputeFlags(kind, in_loop, MONOMORPHIC, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000724 Object* probe = ProbeCache(flags);
725 if (!probe->IsUndefined()) return probe;
726 StubCompiler compiler;
727 return FillCache(compiler.CompileCallNormal(flags));
728}
729
730
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100731Object* StubCache::ComputeCallMegamorphic(int argc,
732 InLoopFlag in_loop,
733 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100735 Code::ComputeFlags(kind, in_loop, MEGAMORPHIC, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 Object* probe = ProbeCache(flags);
737 if (!probe->IsUndefined()) return probe;
738 StubCompiler compiler;
739 return FillCache(compiler.CompileCallMegamorphic(flags));
740}
741
742
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100743Object* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
744 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
745 // and monomorphic stubs are not mixed up together in the stub cache.
746 Code::Flags flags = Code::ComputeFlags(
747 kind, NOT_IN_LOOP, MONOMORPHIC_PROTOTYPE_FAILURE, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000748 Object* probe = ProbeCache(flags);
749 if (!probe->IsUndefined()) return probe;
750 StubCompiler compiler;
751 return FillCache(compiler.CompileCallMiss(flags));
752}
753
754
755#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100756Object* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000757 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100758 Code::ComputeFlags(kind, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 Object* probe = ProbeCache(flags);
760 if (!probe->IsUndefined()) return probe;
761 StubCompiler compiler;
762 return FillCache(compiler.CompileCallDebugBreak(flags));
763}
764
765
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100766Object* StubCache::ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000767 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100768 Code::ComputeFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 NOT_IN_LOOP,
770 DEBUG_PREPARE_STEP_IN,
771 NORMAL,
772 argc);
773 Object* probe = ProbeCache(flags);
774 if (!probe->IsUndefined()) return probe;
775 StubCompiler compiler;
776 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
777}
778#endif
779
780
Steve Blocka7e24c12009-10-30 11:49:00 +0000781void StubCache::Clear() {
782 for (int i = 0; i < kPrimaryTableSize; i++) {
783 primary_[i].key = Heap::empty_string();
784 primary_[i].value = Builtins::builtin(Builtins::Illegal);
785 }
786 for (int j = 0; j < kSecondaryTableSize; j++) {
787 secondary_[j].key = Heap::empty_string();
788 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
789 }
790}
791
792
793// ------------------------------------------------------------------------
794// StubCompiler implementation.
795
796
Steve Blocka7e24c12009-10-30 11:49:00 +0000797Object* LoadCallbackProperty(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +0000798 ASSERT(args[0]->IsJSObject());
799 ASSERT(args[1]->IsJSObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000800 AccessorInfo* callback = AccessorInfo::cast(args[2]);
801 Address getter_address = v8::ToCData<Address>(callback->getter());
802 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
803 ASSERT(fun != NULL);
Steve Blockd0582a62009-12-15 09:54:21 +0000804 CustomArguments custom_args(callback->data(),
805 JSObject::cast(args[0]),
806 JSObject::cast(args[1]));
807 v8::AccessorInfo info(custom_args.end());
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 HandleScope scope;
809 v8::Handle<v8::Value> result;
810 {
811 // Leaving JavaScript.
812 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000813#ifdef ENABLE_LOGGING_AND_PROFILING
814 state.set_external_callback(getter_address);
815#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
817 }
818 RETURN_IF_SCHEDULED_EXCEPTION();
819 if (result.IsEmpty()) return Heap::undefined_value();
820 return *v8::Utils::OpenHandle(*result);
821}
822
823
824Object* StoreCallbackProperty(Arguments args) {
825 JSObject* recv = JSObject::cast(args[0]);
826 AccessorInfo* callback = AccessorInfo::cast(args[1]);
827 Address setter_address = v8::ToCData<Address>(callback->setter());
828 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
829 ASSERT(fun != NULL);
830 Handle<String> name = args.at<String>(2);
831 Handle<Object> value = args.at<Object>(3);
832 HandleScope scope;
833 LOG(ApiNamedPropertyAccess("store", recv, *name));
834 CustomArguments custom_args(callback->data(), recv, recv);
835 v8::AccessorInfo info(custom_args.end());
836 {
837 // Leaving JavaScript.
838 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000839#ifdef ENABLE_LOGGING_AND_PROFILING
840 state.set_external_callback(setter_address);
841#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000842 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
843 }
844 RETURN_IF_SCHEDULED_EXCEPTION();
845 return *value;
846}
847
Steve Block6ded16b2010-05-10 14:33:55 +0100848
849static const int kAccessorInfoOffsetInInterceptorArgs = 2;
850
851
Steve Blocka7e24c12009-10-30 11:49:00 +0000852/**
853 * Attempts to load a property with an interceptor (which must be present),
854 * but doesn't search the prototype chain.
855 *
856 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
857 * provide any value for the given name.
858 */
859Object* LoadPropertyWithInterceptorOnly(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +0100860 Handle<String> name_handle = args.at<String>(0);
861 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
862 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
863 ASSERT(args[2]->IsJSObject()); // Receiver.
864 ASSERT(args[3]->IsJSObject()); // Holder.
865 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000866
867 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
868 v8::NamedPropertyGetter getter =
869 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
870 ASSERT(getter != NULL);
871
872 {
873 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +0100874 v8::AccessorInfo info(args.arguments() -
875 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +0000876 HandleScope scope;
877 v8::Handle<v8::Value> r;
878 {
879 // Leaving JavaScript.
880 VMState state(EXTERNAL);
881 r = getter(v8::Utils::ToLocal(name_handle), info);
882 }
883 RETURN_IF_SCHEDULED_EXCEPTION();
884 if (!r.IsEmpty()) {
885 return *v8::Utils::OpenHandle(*r);
886 }
887 }
888
889 return Heap::no_interceptor_result_sentinel();
890}
891
892
893static Object* ThrowReferenceError(String* name) {
894 // If the load is non-contextual, just return the undefined result.
895 // Note that both keyed and non-keyed loads may end up here, so we
896 // can't use either LoadIC or KeyedLoadIC constructors.
897 IC ic(IC::NO_EXTRA_FRAME);
898 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Leon Clarkee46be812010-01-19 14:06:41 +0000899 if (!ic.SlowIsContextual()) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000900
901 // Throw a reference error.
902 HandleScope scope;
903 Handle<String> name_handle(name);
904 Handle<Object> error =
905 Factory::NewReferenceError("not_defined",
906 HandleVector(&name_handle, 1));
907 return Top::Throw(*error);
908}
909
910
911static Object* LoadWithInterceptor(Arguments* args,
912 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +0100913 Handle<String> name_handle = args->at<String>(0);
914 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
915 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
916 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
917 Handle<JSObject> holder_handle = args->at<JSObject>(3);
918 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000919
920 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
921 v8::NamedPropertyGetter getter =
922 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
923 ASSERT(getter != NULL);
924
925 {
926 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +0100927 v8::AccessorInfo info(args->arguments() -
928 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +0000929 HandleScope scope;
930 v8::Handle<v8::Value> r;
931 {
932 // Leaving JavaScript.
933 VMState state(EXTERNAL);
934 r = getter(v8::Utils::ToLocal(name_handle), info);
935 }
936 RETURN_IF_SCHEDULED_EXCEPTION();
937 if (!r.IsEmpty()) {
938 *attrs = NONE;
939 return *v8::Utils::OpenHandle(*r);
940 }
941 }
942
943 Object* result = holder_handle->GetPropertyPostInterceptor(
944 *receiver_handle,
945 *name_handle,
946 attrs);
947 RETURN_IF_SCHEDULED_EXCEPTION();
948 return result;
949}
950
951
952/**
953 * Loads a property with an interceptor performing post interceptor
954 * lookup if interceptor failed.
955 */
956Object* LoadPropertyWithInterceptorForLoad(Arguments args) {
957 PropertyAttributes attr = NONE;
958 Object* result = LoadWithInterceptor(&args, &attr);
959 if (result->IsFailure()) return result;
960
961 // If the property is present, return it.
962 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +0100963 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +0000964}
965
966
967Object* LoadPropertyWithInterceptorForCall(Arguments args) {
968 PropertyAttributes attr;
969 Object* result = LoadWithInterceptor(&args, &attr);
970 RETURN_IF_SCHEDULED_EXCEPTION();
971 // This is call IC. In this case, we simply return the undefined result which
972 // will lead to an exception when trying to invoke the result as a
973 // function.
974 return result;
975}
976
977
978Object* StoreInterceptorProperty(Arguments args) {
979 JSObject* recv = JSObject::cast(args[0]);
980 String* name = String::cast(args[1]);
981 Object* value = args[2];
982 ASSERT(recv->HasNamedInterceptor());
983 PropertyAttributes attr = NONE;
984 Object* result = recv->SetPropertyWithInterceptor(name, value, attr);
985 return result;
986}
987
988
Andrei Popescu402d9372010-02-26 13:31:12 +0000989Object* KeyedLoadPropertyWithInterceptor(Arguments args) {
990 JSObject* receiver = JSObject::cast(args[0]);
991 uint32_t index = Smi::cast(args[1])->value();
992 return receiver->GetElementWithInterceptor(receiver, index);
993}
994
995
Steve Blocka7e24c12009-10-30 11:49:00 +0000996Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
997 HandleScope scope;
998 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100999 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1000 if (kind == Code::CALL_IC) {
1001 CallIC::GenerateInitialize(masm(), argc);
1002 } else {
1003 KeyedCallIC::GenerateInitialize(masm(), argc);
1004 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001005 Object* result = GetCodeWithFlags(flags, "CompileCallInitialize");
1006 if (!result->IsFailure()) {
1007 Counters::call_initialize_stubs.Increment();
1008 Code* code = Code::cast(result);
1009 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001010 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001011 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001012 }
1013 return result;
1014}
1015
1016
1017Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1018 HandleScope scope;
1019 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1020 // The code of the PreMonomorphic stub is the same as the code
1021 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001022 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1023 if (kind == Code::CALL_IC) {
1024 CallIC::GenerateInitialize(masm(), argc);
1025 } else {
1026 KeyedCallIC::GenerateInitialize(masm(), argc);
1027 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001028 Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1029 if (!result->IsFailure()) {
1030 Counters::call_premonomorphic_stubs.Increment();
1031 Code* code = Code::cast(result);
1032 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001033 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001034 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001035 }
1036 return result;
1037}
1038
1039
1040Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
1041 HandleScope scope;
1042 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001043 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1044 if (kind == Code::CALL_IC) {
1045 CallIC::GenerateNormal(masm(), argc);
1046 } else {
1047 KeyedCallIC::GenerateNormal(masm(), argc);
1048 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001049 Object* result = GetCodeWithFlags(flags, "CompileCallNormal");
1050 if (!result->IsFailure()) {
1051 Counters::call_normal_stubs.Increment();
1052 Code* code = Code::cast(result);
1053 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001054 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001055 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001056 }
1057 return result;
1058}
1059
1060
1061Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1062 HandleScope scope;
1063 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001064 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1065 if (kind == Code::CALL_IC) {
1066 CallIC::GenerateMegamorphic(masm(), argc);
1067 } else {
1068 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1069 }
1070
Steve Blocka7e24c12009-10-30 11:49:00 +00001071 Object* result = GetCodeWithFlags(flags, "CompileCallMegamorphic");
1072 if (!result->IsFailure()) {
1073 Counters::call_megamorphic_stubs.Increment();
1074 Code* code = Code::cast(result);
1075 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001076 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001077 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001078 }
1079 return result;
1080}
1081
1082
1083Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
1084 HandleScope scope;
1085 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001086 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1087 if (kind == Code::CALL_IC) {
1088 CallIC::GenerateMiss(masm(), argc);
1089 } else {
1090 KeyedCallIC::GenerateMiss(masm(), argc);
1091 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001092 Object* result = GetCodeWithFlags(flags, "CompileCallMiss");
1093 if (!result->IsFailure()) {
1094 Counters::call_megamorphic_stubs.Increment();
1095 Code* code = Code::cast(result);
1096 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001097 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001098 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001099 }
1100 return result;
1101}
1102
1103
1104#ifdef ENABLE_DEBUGGER_SUPPORT
1105Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1106 HandleScope scope;
1107 Debug::GenerateCallICDebugBreak(masm());
1108 Object* result = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1109 if (!result->IsFailure()) {
1110 Code* code = Code::cast(result);
1111 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001112 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001113 USE(kind);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001114 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001115 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001116 }
1117 return result;
1118}
1119
1120
1121Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1122 HandleScope scope;
1123 // Use the same code for the the step in preparations as we do for
1124 // the miss case.
1125 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001126 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1127 if (kind == Code::CALL_IC) {
1128 CallIC::GenerateMiss(masm(), argc);
1129 } else {
1130 KeyedCallIC::GenerateMiss(masm(), argc);
1131 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001132 Object* result = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1133 if (!result->IsFailure()) {
1134 Code* code = Code::cast(result);
1135 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001136 PROFILE(CodeCreateEvent(
1137 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1138 code,
1139 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001140 }
1141 return result;
1142}
1143#endif
1144
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001145#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001146
1147Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
1148 // Check for allocation failures during stub compilation.
1149 if (failure_->IsFailure()) return failure_;
1150
1151 // Create code object in the heap.
1152 CodeDesc desc;
1153 masm_.GetCode(&desc);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001154 Object* result = Heap::CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001155#ifdef ENABLE_DISASSEMBLER
1156 if (FLAG_print_code_stubs && !result->IsFailure()) {
1157 Code::cast(result)->Disassemble(name);
1158 }
1159#endif
1160 return result;
1161}
1162
1163
1164Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1165 if (FLAG_print_code_stubs && (name != NULL)) {
1166 return GetCodeWithFlags(flags, *name->ToCString());
1167 }
1168 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1169}
1170
Andrei Popescu402d9372010-02-26 13:31:12 +00001171
Leon Clarke4515c472010-02-03 11:58:03 +00001172void StubCompiler::LookupPostInterceptor(JSObject* holder,
1173 String* name,
1174 LookupResult* lookup) {
1175 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001176 if (!lookup->IsProperty()) {
1177 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001178 Object* proto = holder->GetPrototype();
1179 if (proto != Heap::null_value()) {
1180 proto->Lookup(name, lookup);
1181 }
1182 }
1183}
1184
1185
Steve Blocka7e24c12009-10-30 11:49:00 +00001186
1187Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
1188 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001189 Object* result = GetCodeWithFlags(flags, name);
1190 if (!result->IsFailure()) {
1191 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(result), name));
1192 }
1193 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001194}
1195
1196
1197Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
1198 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001199 Object* result = GetCodeWithFlags(flags, name);
1200 if (!result->IsFailure()) {
1201 PROFILE(
1202 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(result), name));
1203 }
1204 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001205}
1206
1207
1208Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
1209 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001210 Object* result = GetCodeWithFlags(flags, name);
1211 if (!result->IsFailure()) {
1212 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(result), name));
1213 }
1214 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001215}
1216
1217
1218Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
1219 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001220 Object* result = GetCodeWithFlags(flags, name);
1221 if (!result->IsFailure()) {
1222 PROFILE(
1223 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(result), name));
1224 }
1225 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001226}
1227
1228
Steve Block8defd9f2010-07-08 12:39:36 +01001229CallStubCompiler::CallStubCompiler(int argc,
1230 InLoopFlag in_loop,
1231 Code::Kind kind,
1232 InlineCacheHolderFlag cache_holder)
1233 : arguments_(argc)
1234 , in_loop_(in_loop)
1235 , kind_(kind)
1236 , cache_holder_(cache_holder) {
1237}
1238
1239
Kristian Monsen25f61362010-05-21 11:50:48 +01001240Object* CallStubCompiler::CompileCustomCall(int generator_id,
1241 Object* object,
1242 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001243 JSGlobalPropertyCell* cell,
Kristian Monsen25f61362010-05-21 11:50:48 +01001244 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001245 String* fname) {
1246 ASSERT(generator_id >= 0 && generator_id < kNumCallGenerators);
1247 switch (generator_id) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001248#define CALL_GENERATOR_CASE(ignored1, ignored2, name) \
Steve Block59151502010-09-22 15:07:15 +01001249 case k##name##CallGenerator: \
1250 return CallStubCompiler::Compile##name##Call(object, \
1251 holder, \
1252 cell, \
1253 function, \
1254 fname);
1255 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Kristian Monsen25f61362010-05-21 11:50:48 +01001256#undef CALL_GENERATOR_CASE
Steve Block59151502010-09-22 15:07:15 +01001257 }
1258 UNREACHABLE();
1259 return Heap::undefined_value();
Kristian Monsen25f61362010-05-21 11:50:48 +01001260}
1261
1262
Steve Blocka7e24c12009-10-30 11:49:00 +00001263Object* CallStubCompiler::GetCode(PropertyType type, String* name) {
1264 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001265 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001266 type,
Steve Block8defd9f2010-07-08 12:39:36 +01001267 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001268 in_loop_,
1269 argc);
1270 return GetCodeWithFlags(flags, name);
1271}
1272
1273
Kristian Monsen25f61362010-05-21 11:50:48 +01001274Object* CallStubCompiler::GetCode(JSFunction* function) {
1275 String* function_name = NULL;
1276 if (function->shared()->name()->IsString()) {
1277 function_name = String::cast(function->shared()->name());
1278 }
1279 return GetCode(CONSTANT_FUNCTION, function_name);
1280}
1281
1282
Steve Blocka7e24c12009-10-30 11:49:00 +00001283Object* ConstructStubCompiler::GetCode() {
1284 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1285 Object* result = GetCodeWithFlags(flags, "ConstructStub");
1286 if (!result->IsFailure()) {
1287 Code* code = Code::cast(result);
1288 USE(code);
Steve Block6ded16b2010-05-10 14:33:55 +01001289 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 }
1291 return result;
1292}
1293
1294
Steve Block6ded16b2010-05-10 14:33:55 +01001295CallOptimization::CallOptimization(LookupResult* lookup) {
1296 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1297 lookup->type() != CONSTANT_FUNCTION) {
1298 Initialize(NULL);
1299 } else {
1300 // We only optimize constant function calls.
1301 Initialize(lookup->GetConstantFunction());
1302 }
1303}
1304
1305CallOptimization::CallOptimization(JSFunction* function) {
1306 Initialize(function);
1307}
1308
1309
1310int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1311 JSObject* holder) const {
1312 ASSERT(is_simple_api_call_);
1313 if (expected_receiver_type_ == NULL) return 0;
1314 int depth = 0;
1315 while (object != holder) {
1316 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1317 object = JSObject::cast(object->GetPrototype());
1318 ++depth;
1319 }
1320 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1321 return kInvalidProtoDepth;
1322}
1323
1324
1325void CallOptimization::Initialize(JSFunction* function) {
1326 constant_function_ = NULL;
1327 is_simple_api_call_ = false;
1328 expected_receiver_type_ = NULL;
1329 api_call_info_ = NULL;
1330
1331 if (function == NULL || !function->is_compiled()) return;
1332
1333 constant_function_ = function;
1334 AnalyzePossibleApiFunction(function);
1335}
1336
1337
1338void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1339 SharedFunctionInfo* sfi = function->shared();
1340 if (!sfi->IsApiFunction()) return;
1341 FunctionTemplateInfo* info = sfi->get_api_func_data();
1342
1343 // Require a C++ callback.
1344 if (info->call_code()->IsUndefined()) return;
1345 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1346
1347 // Accept signatures that either have no restrictions at all or
1348 // only have restrictions on the receiver.
1349 if (!info->signature()->IsUndefined()) {
1350 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1351 if (!signature->args()->IsUndefined()) return;
1352 if (!signature->receiver()->IsUndefined()) {
1353 expected_receiver_type_ =
1354 FunctionTemplateInfo::cast(signature->receiver());
1355 }
1356 }
1357
1358 is_simple_api_call_ = true;
1359}
1360
1361
Steve Blocka7e24c12009-10-30 11:49:00 +00001362} } // namespace v8::internal