blob: e6df1b49e31c9b4fda64dff511608bb7bc1e6a50 [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]);
Ben Murdochf87a2032010-10-22 12:50:53 +0100991 ASSERT(Smi::cast(args[1])->value() >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +0000992 uint32_t index = Smi::cast(args[1])->value();
993 return receiver->GetElementWithInterceptor(receiver, index);
994}
995
996
Steve Blocka7e24c12009-10-30 11:49:00 +0000997Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
998 HandleScope scope;
999 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001000 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1001 if (kind == Code::CALL_IC) {
1002 CallIC::GenerateInitialize(masm(), argc);
1003 } else {
1004 KeyedCallIC::GenerateInitialize(masm(), argc);
1005 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001006 Object* result = GetCodeWithFlags(flags, "CompileCallInitialize");
1007 if (!result->IsFailure()) {
1008 Counters::call_initialize_stubs.Increment();
1009 Code* code = Code::cast(result);
1010 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001011 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001012 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001013 }
1014 return result;
1015}
1016
1017
1018Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1019 HandleScope scope;
1020 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1021 // The code of the PreMonomorphic stub is the same as the code
1022 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001023 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1024 if (kind == Code::CALL_IC) {
1025 CallIC::GenerateInitialize(masm(), argc);
1026 } else {
1027 KeyedCallIC::GenerateInitialize(masm(), argc);
1028 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001029 Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1030 if (!result->IsFailure()) {
1031 Counters::call_premonomorphic_stubs.Increment();
1032 Code* code = Code::cast(result);
1033 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001034 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001035 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001036 }
1037 return result;
1038}
1039
1040
1041Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
1042 HandleScope scope;
1043 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001044 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1045 if (kind == Code::CALL_IC) {
1046 CallIC::GenerateNormal(masm(), argc);
1047 } else {
1048 KeyedCallIC::GenerateNormal(masm(), argc);
1049 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001050 Object* result = GetCodeWithFlags(flags, "CompileCallNormal");
1051 if (!result->IsFailure()) {
1052 Counters::call_normal_stubs.Increment();
1053 Code* code = Code::cast(result);
1054 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001055 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001056 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001057 }
1058 return result;
1059}
1060
1061
1062Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1063 HandleScope scope;
1064 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001065 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1066 if (kind == Code::CALL_IC) {
1067 CallIC::GenerateMegamorphic(masm(), argc);
1068 } else {
1069 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1070 }
1071
Steve Blocka7e24c12009-10-30 11:49:00 +00001072 Object* result = GetCodeWithFlags(flags, "CompileCallMegamorphic");
1073 if (!result->IsFailure()) {
1074 Counters::call_megamorphic_stubs.Increment();
1075 Code* code = Code::cast(result);
1076 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001077 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001078 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001079 }
1080 return result;
1081}
1082
1083
1084Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
1085 HandleScope scope;
1086 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001087 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1088 if (kind == Code::CALL_IC) {
1089 CallIC::GenerateMiss(masm(), argc);
1090 } else {
1091 KeyedCallIC::GenerateMiss(masm(), argc);
1092 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001093 Object* result = GetCodeWithFlags(flags, "CompileCallMiss");
1094 if (!result->IsFailure()) {
1095 Counters::call_megamorphic_stubs.Increment();
1096 Code* code = Code::cast(result);
1097 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001098 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001099 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001100 }
1101 return result;
1102}
1103
1104
1105#ifdef ENABLE_DEBUGGER_SUPPORT
1106Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1107 HandleScope scope;
1108 Debug::GenerateCallICDebugBreak(masm());
1109 Object* result = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1110 if (!result->IsFailure()) {
1111 Code* code = Code::cast(result);
1112 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001113 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001114 USE(kind);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001115 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001116 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001117 }
1118 return result;
1119}
1120
1121
1122Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1123 HandleScope scope;
1124 // Use the same code for the the step in preparations as we do for
1125 // the miss case.
1126 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001127 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1128 if (kind == Code::CALL_IC) {
1129 CallIC::GenerateMiss(masm(), argc);
1130 } else {
1131 KeyedCallIC::GenerateMiss(masm(), argc);
1132 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001133 Object* result = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1134 if (!result->IsFailure()) {
1135 Code* code = Code::cast(result);
1136 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001137 PROFILE(CodeCreateEvent(
1138 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1139 code,
1140 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001141 }
1142 return result;
1143}
1144#endif
1145
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001146#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001147
1148Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
1149 // Check for allocation failures during stub compilation.
1150 if (failure_->IsFailure()) return failure_;
1151
1152 // Create code object in the heap.
1153 CodeDesc desc;
1154 masm_.GetCode(&desc);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001155 Object* result = Heap::CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001156#ifdef ENABLE_DISASSEMBLER
1157 if (FLAG_print_code_stubs && !result->IsFailure()) {
1158 Code::cast(result)->Disassemble(name);
1159 }
1160#endif
1161 return result;
1162}
1163
1164
1165Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1166 if (FLAG_print_code_stubs && (name != NULL)) {
1167 return GetCodeWithFlags(flags, *name->ToCString());
1168 }
1169 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1170}
1171
Andrei Popescu402d9372010-02-26 13:31:12 +00001172
Leon Clarke4515c472010-02-03 11:58:03 +00001173void StubCompiler::LookupPostInterceptor(JSObject* holder,
1174 String* name,
1175 LookupResult* lookup) {
1176 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001177 if (!lookup->IsProperty()) {
1178 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001179 Object* proto = holder->GetPrototype();
1180 if (proto != Heap::null_value()) {
1181 proto->Lookup(name, lookup);
1182 }
1183 }
1184}
1185
1186
Steve Blocka7e24c12009-10-30 11:49:00 +00001187
1188Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
1189 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001190 Object* result = GetCodeWithFlags(flags, name);
1191 if (!result->IsFailure()) {
1192 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(result), name));
1193 }
1194 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001195}
1196
1197
1198Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
1199 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001200 Object* result = GetCodeWithFlags(flags, name);
1201 if (!result->IsFailure()) {
1202 PROFILE(
1203 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(result), name));
1204 }
1205 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001206}
1207
1208
1209Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
1210 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001211 Object* result = GetCodeWithFlags(flags, name);
1212 if (!result->IsFailure()) {
1213 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(result), name));
1214 }
1215 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001216}
1217
1218
1219Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
1220 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001221 Object* result = GetCodeWithFlags(flags, name);
1222 if (!result->IsFailure()) {
1223 PROFILE(
1224 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(result), name));
1225 }
1226 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001227}
1228
1229
Steve Block8defd9f2010-07-08 12:39:36 +01001230CallStubCompiler::CallStubCompiler(int argc,
1231 InLoopFlag in_loop,
1232 Code::Kind kind,
1233 InlineCacheHolderFlag cache_holder)
1234 : arguments_(argc)
1235 , in_loop_(in_loop)
1236 , kind_(kind)
1237 , cache_holder_(cache_holder) {
1238}
1239
1240
Kristian Monsen25f61362010-05-21 11:50:48 +01001241Object* CallStubCompiler::CompileCustomCall(int generator_id,
1242 Object* object,
1243 JSObject* holder,
Steve Block59151502010-09-22 15:07:15 +01001244 JSGlobalPropertyCell* cell,
Kristian Monsen25f61362010-05-21 11:50:48 +01001245 JSFunction* function,
Steve Block59151502010-09-22 15:07:15 +01001246 String* fname) {
1247 ASSERT(generator_id >= 0 && generator_id < kNumCallGenerators);
1248 switch (generator_id) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001249#define CALL_GENERATOR_CASE(ignored1, ignored2, name) \
Steve Block59151502010-09-22 15:07:15 +01001250 case k##name##CallGenerator: \
1251 return CallStubCompiler::Compile##name##Call(object, \
1252 holder, \
1253 cell, \
1254 function, \
1255 fname);
1256 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Kristian Monsen25f61362010-05-21 11:50:48 +01001257#undef CALL_GENERATOR_CASE
Steve Block59151502010-09-22 15:07:15 +01001258 }
1259 UNREACHABLE();
1260 return Heap::undefined_value();
Kristian Monsen25f61362010-05-21 11:50:48 +01001261}
1262
1263
Steve Blocka7e24c12009-10-30 11:49:00 +00001264Object* CallStubCompiler::GetCode(PropertyType type, String* name) {
1265 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001266 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001267 type,
Steve Block8defd9f2010-07-08 12:39:36 +01001268 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001269 in_loop_,
1270 argc);
1271 return GetCodeWithFlags(flags, name);
1272}
1273
1274
Kristian Monsen25f61362010-05-21 11:50:48 +01001275Object* CallStubCompiler::GetCode(JSFunction* function) {
1276 String* function_name = NULL;
1277 if (function->shared()->name()->IsString()) {
1278 function_name = String::cast(function->shared()->name());
1279 }
1280 return GetCode(CONSTANT_FUNCTION, function_name);
1281}
1282
1283
Steve Blocka7e24c12009-10-30 11:49:00 +00001284Object* ConstructStubCompiler::GetCode() {
1285 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1286 Object* result = GetCodeWithFlags(flags, "ConstructStub");
1287 if (!result->IsFailure()) {
1288 Code* code = Code::cast(result);
1289 USE(code);
Steve Block6ded16b2010-05-10 14:33:55 +01001290 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Steve Blocka7e24c12009-10-30 11:49:00 +00001291 }
1292 return result;
1293}
1294
1295
Steve Block6ded16b2010-05-10 14:33:55 +01001296CallOptimization::CallOptimization(LookupResult* lookup) {
1297 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1298 lookup->type() != CONSTANT_FUNCTION) {
1299 Initialize(NULL);
1300 } else {
1301 // We only optimize constant function calls.
1302 Initialize(lookup->GetConstantFunction());
1303 }
1304}
1305
1306CallOptimization::CallOptimization(JSFunction* function) {
1307 Initialize(function);
1308}
1309
1310
1311int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1312 JSObject* holder) const {
1313 ASSERT(is_simple_api_call_);
1314 if (expected_receiver_type_ == NULL) return 0;
1315 int depth = 0;
1316 while (object != holder) {
1317 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1318 object = JSObject::cast(object->GetPrototype());
1319 ++depth;
1320 }
1321 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1322 return kInvalidProtoDepth;
1323}
1324
1325
1326void CallOptimization::Initialize(JSFunction* function) {
1327 constant_function_ = NULL;
1328 is_simple_api_call_ = false;
1329 expected_receiver_type_ = NULL;
1330 api_call_info_ = NULL;
1331
1332 if (function == NULL || !function->is_compiled()) return;
1333
1334 constant_function_ = function;
1335 AnalyzePossibleApiFunction(function);
1336}
1337
1338
1339void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1340 SharedFunctionInfo* sfi = function->shared();
1341 if (!sfi->IsApiFunction()) return;
1342 FunctionTemplateInfo* info = sfi->get_api_func_data();
1343
1344 // Require a C++ callback.
1345 if (info->call_code()->IsUndefined()) return;
1346 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1347
1348 // Accept signatures that either have no restrictions at all or
1349 // only have restrictions on the receiver.
1350 if (!info->signature()->IsUndefined()) {
1351 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1352 if (!signature->args()->IsUndefined()) return;
1353 if (!signature->receiver()->IsUndefined()) {
1354 expected_receiver_type_ =
1355 FunctionTemplateInfo::cast(signature->receiver());
1356 }
1357 }
1358
1359 is_simple_api_call_ = true;
1360}
1361
1362
Steve Blocka7e24c12009-10-30 11:49:00 +00001363} } // namespace v8::internal