blob: ffa92dd3661a47964de25a255d4db472e990f022 [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) {
97 // If no global objects are present in the prototype chain, the load
98 // nonexistent IC stub can be shared for all names for a given map
99 // and we use the empty string for the map cache in that case. If
100 // there are global objects involved, we need to check global
101 // property cells in the stub and therefore the stub will be
102 // specific to the name.
103 String* cache_name = Heap::empty_string();
104 if (receiver->IsGlobalObject()) cache_name = name;
105 JSObject* last = receiver;
106 while (last->GetPrototype() != Heap::null_value()) {
107 last = JSObject::cast(last->GetPrototype());
108 if (last->IsGlobalObject()) cache_name = name;
109 }
110 // Compile the stub that is either shared for all names or
111 // name specific if there are global objects involved.
112 Code::Flags flags =
113 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
114 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
115 if (code->IsUndefined()) {
116 LoadStubCompiler compiler;
117 code = compiler.CompileLoadNonexistent(cache_name, receiver, last);
118 if (code->IsFailure()) return code;
119 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
120 Object* result =
121 receiver->map()->UpdateCodeCache(cache_name, Code::cast(code));
122 if (result->IsFailure()) return result;
123 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100124 return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100125}
126
127
Steve Blocka7e24c12009-10-30 11:49:00 +0000128Object* StubCache::ComputeLoadField(String* name,
129 JSObject* receiver,
130 JSObject* holder,
131 int field_index) {
132 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
133 Object* code = receiver->map()->FindInCodeCache(name, flags);
134 if (code->IsUndefined()) {
135 LoadStubCompiler compiler;
136 code = compiler.CompileLoadField(receiver, holder, field_index, name);
137 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100138 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000139 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000140 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000141 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100142 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000143}
144
145
146Object* StubCache::ComputeLoadCallback(String* name,
147 JSObject* receiver,
148 JSObject* holder,
149 AccessorInfo* callback) {
150 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
151 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
152 Object* code = receiver->map()->FindInCodeCache(name, flags);
153 if (code->IsUndefined()) {
154 LoadStubCompiler compiler;
Leon Clarkee46be812010-01-19 14:06:41 +0000155 code = compiler.CompileLoadCallback(name, receiver, holder, callback);
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100157 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000159 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000160 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100161 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000162}
163
164
165Object* StubCache::ComputeLoadConstant(String* name,
166 JSObject* receiver,
167 JSObject* holder,
168 Object* value) {
169 Code::Flags flags =
170 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
171 Object* code = receiver->map()->FindInCodeCache(name, flags);
172 if (code->IsUndefined()) {
173 LoadStubCompiler compiler;
174 code = compiler.CompileLoadConstant(receiver, holder, value, name);
175 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100176 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000178 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100180 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000181}
182
183
184Object* StubCache::ComputeLoadInterceptor(String* name,
185 JSObject* receiver,
186 JSObject* holder) {
187 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
188 Object* code = receiver->map()->FindInCodeCache(name, flags);
189 if (code->IsUndefined()) {
190 LoadStubCompiler compiler;
191 code = compiler.CompileLoadInterceptor(receiver, holder, name);
192 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100193 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000195 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000196 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100197 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000198}
199
200
201Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100202 return Builtins::builtin(Builtins::LoadIC_Normal);
Steve Blocka7e24c12009-10-30 11:49:00 +0000203}
204
205
206Object* StubCache::ComputeLoadGlobal(String* name,
207 JSObject* receiver,
208 GlobalObject* holder,
209 JSGlobalPropertyCell* cell,
210 bool is_dont_delete) {
211 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
212 Object* code = receiver->map()->FindInCodeCache(name, flags);
213 if (code->IsUndefined()) {
214 LoadStubCompiler compiler;
215 code = compiler.CompileLoadGlobal(receiver,
216 holder,
217 cell,
218 name,
219 is_dont_delete);
220 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100221 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000223 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100225 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000226}
227
228
229Object* StubCache::ComputeKeyedLoadField(String* name,
230 JSObject* receiver,
231 JSObject* holder,
232 int field_index) {
233 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
234 Object* code = receiver->map()->FindInCodeCache(name, flags);
235 if (code->IsUndefined()) {
236 KeyedLoadStubCompiler compiler;
237 code = compiler.CompileLoadField(name, receiver, holder, field_index);
238 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100239 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
241 if (result->IsFailure()) return result;
242 }
243 return code;
244}
245
246
247Object* StubCache::ComputeKeyedLoadConstant(String* name,
248 JSObject* receiver,
249 JSObject* holder,
250 Object* value) {
251 Code::Flags flags =
252 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
253 Object* code = receiver->map()->FindInCodeCache(name, flags);
254 if (code->IsUndefined()) {
255 KeyedLoadStubCompiler compiler;
256 code = compiler.CompileLoadConstant(name, receiver, holder, value);
257 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100258 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
260 if (result->IsFailure()) return result;
261 }
262 return code;
263}
264
265
266Object* StubCache::ComputeKeyedLoadInterceptor(String* name,
267 JSObject* receiver,
268 JSObject* holder) {
269 Code::Flags flags =
270 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
271 Object* code = receiver->map()->FindInCodeCache(name, flags);
272 if (code->IsUndefined()) {
273 KeyedLoadStubCompiler compiler;
274 code = compiler.CompileLoadInterceptor(receiver, holder, name);
275 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100276 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
278 if (result->IsFailure()) return result;
279 }
280 return code;
281}
282
283
284Object* StubCache::ComputeKeyedLoadCallback(String* name,
285 JSObject* receiver,
286 JSObject* holder,
287 AccessorInfo* callback) {
288 Code::Flags flags =
289 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
290 Object* code = receiver->map()->FindInCodeCache(name, flags);
291 if (code->IsUndefined()) {
292 KeyedLoadStubCompiler compiler;
293 code = compiler.CompileLoadCallback(name, receiver, holder, callback);
294 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100295 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000296 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
297 if (result->IsFailure()) return result;
298 }
299 return code;
300}
301
302
303
304Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
305 JSArray* receiver) {
306 Code::Flags flags =
307 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
308 Object* code = receiver->map()->FindInCodeCache(name, flags);
309 if (code->IsUndefined()) {
310 KeyedLoadStubCompiler compiler;
311 code = compiler.CompileLoadArrayLength(name);
312 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100313 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
315 if (result->IsFailure()) return result;
316 }
317 return code;
318}
319
320
321Object* StubCache::ComputeKeyedLoadStringLength(String* name,
322 String* receiver) {
323 Code::Flags flags =
324 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
325 Object* code = receiver->map()->FindInCodeCache(name, flags);
326 if (code->IsUndefined()) {
327 KeyedLoadStubCompiler compiler;
328 code = compiler.CompileLoadStringLength(name);
329 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100330 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000331 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
332 if (result->IsFailure()) return result;
333 }
334 return code;
335}
336
337
338Object* StubCache::ComputeKeyedLoadFunctionPrototype(String* name,
339 JSFunction* receiver) {
340 Code::Flags flags =
341 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
342 Object* code = receiver->map()->FindInCodeCache(name, flags);
343 if (code->IsUndefined()) {
344 KeyedLoadStubCompiler compiler;
345 code = compiler.CompileLoadFunctionPrototype(name);
346 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100347 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000348 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
349 if (result->IsFailure()) return result;
350 }
351 return code;
352}
353
354
355Object* StubCache::ComputeStoreField(String* name,
356 JSObject* receiver,
357 int field_index,
358 Map* transition) {
359 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
360 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
361 Object* code = receiver->map()->FindInCodeCache(name, flags);
362 if (code->IsUndefined()) {
363 StoreStubCompiler compiler;
364 code = compiler.CompileStoreField(receiver, field_index, transition, name);
365 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100366 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000367 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
368 if (result->IsFailure()) return result;
369 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100370 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000371}
372
373
374Object* StubCache::ComputeStoreGlobal(String* name,
375 GlobalObject* receiver,
376 JSGlobalPropertyCell* cell) {
377 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
378 Object* code = receiver->map()->FindInCodeCache(name, flags);
379 if (code->IsUndefined()) {
380 StoreStubCompiler compiler;
381 code = compiler.CompileStoreGlobal(receiver, cell, name);
382 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100383 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000384 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000385 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100387 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000388}
389
390
391Object* StubCache::ComputeStoreCallback(String* name,
392 JSObject* receiver,
393 AccessorInfo* callback) {
394 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
395 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
396 Object* code = receiver->map()->FindInCodeCache(name, flags);
397 if (code->IsUndefined()) {
398 StoreStubCompiler compiler;
399 code = compiler.CompileStoreCallback(receiver, callback, name);
400 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100401 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000402 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
403 if (result->IsFailure()) return result;
404 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100405 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000406}
407
408
409Object* StubCache::ComputeStoreInterceptor(String* name,
410 JSObject* receiver) {
411 Code::Flags flags =
412 Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
413 Object* code = receiver->map()->FindInCodeCache(name, flags);
414 if (code->IsUndefined()) {
415 StoreStubCompiler compiler;
416 code = compiler.CompileStoreInterceptor(receiver, 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));
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
420 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::ComputeKeyedStoreField(String* name, JSObject* receiver,
427 int field_index, Map* transition) {
428 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
429 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
430 Object* code = receiver->map()->FindInCodeCache(name, flags);
431 if (code->IsUndefined()) {
432 KeyedStoreStubCompiler compiler;
433 code = compiler.CompileStoreField(receiver, field_index, transition, name);
434 if (code->IsFailure()) return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100435 PROFILE(CodeCreateEvent(
436 Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
438 if (result->IsFailure()) return result;
439 }
440 return code;
441}
442
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100443#define CALL_LOGGER_TAG(kind, type) \
444 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000445
446Object* StubCache::ComputeCallConstant(int argc,
447 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100448 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000449 String* name,
450 Object* object,
451 JSObject* holder,
452 JSFunction* function) {
453 // Compute the check type and the map.
454 Map* map = IC::GetCodeCacheMapForObject(object);
455
456 // Compute check type based on receiver/holder.
457 StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK;
458 if (object->IsString()) {
459 check = StubCompiler::STRING_CHECK;
460 } else if (object->IsNumber()) {
461 check = StubCompiler::NUMBER_CHECK;
462 } else if (object->IsBoolean()) {
463 check = StubCompiler::BOOLEAN_CHECK;
464 }
465
466 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100467 Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 CONSTANT_FUNCTION,
469 in_loop,
470 argc);
471 Object* code = map->FindInCodeCache(name, flags);
472 if (code->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 // If the function hasn't been compiled yet, we cannot do it now
474 // because it may cause GC. To avoid this issue, we return an
475 // internal error which will make sure we do not update any
476 // caches.
477 if (!function->is_compiled()) return Failure::InternalError();
478 // Compile the stub - only create stubs for fully compiled functions.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100479 CallStubCompiler compiler(argc, in_loop, kind);
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 code = compiler.CompileCallConstant(object, holder, function, name, check);
481 if (code->IsFailure()) return code;
482 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100483 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
484 Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 Object* result = map->UpdateCodeCache(name, Code::cast(code));
486 if (result->IsFailure()) return result;
487 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100488 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000489}
490
491
492Object* StubCache::ComputeCallField(int argc,
493 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100494 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000495 String* name,
496 Object* object,
497 JSObject* holder,
498 int index) {
499 // Compute the check type and the map.
500 Map* map = IC::GetCodeCacheMapForObject(object);
501
502 // TODO(1233596): We cannot do receiver map check for non-JS objects
503 // because they may be represented as immediates without a
504 // map. Instead, we check against the map in the holder.
505 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
506 object = holder;
507 }
508
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100509 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000510 FIELD,
511 in_loop,
512 argc);
513 Object* code = map->FindInCodeCache(name, flags);
514 if (code->IsUndefined()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100515 CallStubCompiler compiler(argc, in_loop, kind);
Andrei Popescu402d9372010-02-26 13:31:12 +0000516 code = compiler.CompileCallField(JSObject::cast(object),
517 holder,
518 index,
519 name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000520 if (code->IsFailure()) return code;
521 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100522 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
523 Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000524 Object* result = map->UpdateCodeCache(name, Code::cast(code));
525 if (result->IsFailure()) return result;
526 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100527 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000528}
529
530
531Object* StubCache::ComputeCallInterceptor(int argc,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100532 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000533 String* name,
534 Object* object,
535 JSObject* holder) {
536 // Compute the check type and the map.
537 // If the object is a value, we use the prototype map for the cache.
538 Map* map = IC::GetCodeCacheMapForObject(object);
539
540 // TODO(1233596): We cannot do receiver map check for non-JS objects
541 // because they may be represented as immediates without a
542 // map. Instead, we check against the map in the holder.
543 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
544 object = holder;
545 }
546
547 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100548 Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000549 INTERCEPTOR,
550 NOT_IN_LOOP,
551 argc);
552 Object* code = map->FindInCodeCache(name, flags);
553 if (code->IsUndefined()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100554 CallStubCompiler compiler(argc, NOT_IN_LOOP, kind);
Andrei Popescu402d9372010-02-26 13:31:12 +0000555 code = compiler.CompileCallInterceptor(JSObject::cast(object),
556 holder,
557 name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000558 if (code->IsFailure()) return code;
559 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100560 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
561 Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000562 Object* result = map->UpdateCodeCache(name, Code::cast(code));
563 if (result->IsFailure()) return result;
564 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100565 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000566}
567
568
569Object* StubCache::ComputeCallNormal(int argc,
570 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100571 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000572 String* name,
573 JSObject* receiver) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100574 Object* code = ComputeCallNormal(argc, in_loop, kind);
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 if (code->IsFailure()) return code;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100576 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000577}
578
579
580Object* StubCache::ComputeCallGlobal(int argc,
581 InLoopFlag in_loop,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100582 Code::Kind kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 String* name,
584 JSObject* receiver,
585 GlobalObject* holder,
586 JSGlobalPropertyCell* cell,
587 JSFunction* function) {
588 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100589 Code::ComputeMonomorphicFlags(kind,
590 NORMAL,
591 in_loop,
592 argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 Object* code = receiver->map()->FindInCodeCache(name, flags);
594 if (code->IsUndefined()) {
595 // If the function hasn't been compiled yet, we cannot do it now
596 // because it may cause GC. To avoid this issue, we return an
597 // internal error which will make sure we do not update any
598 // caches.
599 if (!function->is_compiled()) return Failure::InternalError();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100600 CallStubCompiler compiler(argc, in_loop, kind);
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 code = compiler.CompileCallGlobal(receiver, holder, cell, function, name);
602 if (code->IsFailure()) return code;
603 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100604 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
605 Code::cast(code), name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
Andrei Popescu402d9372010-02-26 13:31:12 +0000607 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100609 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000610}
611
612
613static Object* GetProbeValue(Code::Flags flags) {
614 // Use raw_unchecked... so we don't get assert failures during GC.
615 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
616 int entry = dictionary->FindEntry(flags);
617 if (entry != -1) return dictionary->ValueAt(entry);
618 return Heap::raw_unchecked_undefined_value();
619}
620
621
622static Object* ProbeCache(Code::Flags flags) {
623 Object* probe = GetProbeValue(flags);
624 if (probe != Heap::undefined_value()) return probe;
625 // Seed the cache with an undefined value to make sure that any
626 // generated code object can always be inserted into the cache
627 // without causing allocation failures.
628 Object* result =
629 Heap::non_monomorphic_cache()->AtNumberPut(flags,
630 Heap::undefined_value());
631 if (result->IsFailure()) return result;
632 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
633 return probe;
634}
635
636
637static Object* FillCache(Object* code) {
638 if (code->IsCode()) {
639 int entry =
640 Heap::non_monomorphic_cache()->FindEntry(
641 Code::cast(code)->flags());
642 // The entry must be present see comment in ProbeCache.
643 ASSERT(entry != -1);
644 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
645 Heap::undefined_value());
646 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
647 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
648 }
649 return code;
650}
651
652
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100653Code* StubCache::FindCallInitialize(int argc,
654 InLoopFlag in_loop,
655 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000656 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100657 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000658 Object* result = ProbeCache(flags);
659 ASSERT(!result->IsUndefined());
660 // This might be called during the marking phase of the collector
661 // hence the unchecked cast.
662 return reinterpret_cast<Code*>(result);
663}
664
665
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100666Object* StubCache::ComputeCallInitialize(int argc,
667 InLoopFlag in_loop,
668 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100670 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000671 Object* probe = ProbeCache(flags);
672 if (!probe->IsUndefined()) return probe;
673 StubCompiler compiler;
674 return FillCache(compiler.CompileCallInitialize(flags));
675}
676
677
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100678Object* StubCache::ComputeCallPreMonomorphic(int argc,
679 InLoopFlag in_loop,
680 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000681 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100682 Code::ComputeFlags(kind, in_loop, PREMONOMORPHIC, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000683 Object* probe = ProbeCache(flags);
684 if (!probe->IsUndefined()) return probe;
685 StubCompiler compiler;
686 return FillCache(compiler.CompileCallPreMonomorphic(flags));
687}
688
689
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100690Object* StubCache::ComputeCallNormal(int argc,
691 InLoopFlag in_loop,
692 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100694 Code::ComputeFlags(kind, in_loop, MONOMORPHIC, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000695 Object* probe = ProbeCache(flags);
696 if (!probe->IsUndefined()) return probe;
697 StubCompiler compiler;
698 return FillCache(compiler.CompileCallNormal(flags));
699}
700
701
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100702Object* StubCache::ComputeCallMegamorphic(int argc,
703 InLoopFlag in_loop,
704 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000705 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100706 Code::ComputeFlags(kind, in_loop, MEGAMORPHIC, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000707 Object* probe = ProbeCache(flags);
708 if (!probe->IsUndefined()) return probe;
709 StubCompiler compiler;
710 return FillCache(compiler.CompileCallMegamorphic(flags));
711}
712
713
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100714Object* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
715 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
716 // and monomorphic stubs are not mixed up together in the stub cache.
717 Code::Flags flags = Code::ComputeFlags(
718 kind, NOT_IN_LOOP, MONOMORPHIC_PROTOTYPE_FAILURE, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000719 Object* probe = ProbeCache(flags);
720 if (!probe->IsUndefined()) return probe;
721 StubCompiler compiler;
722 return FillCache(compiler.CompileCallMiss(flags));
723}
724
725
726#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100727Object* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100729 Code::ComputeFlags(kind, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000730 Object* probe = ProbeCache(flags);
731 if (!probe->IsUndefined()) return probe;
732 StubCompiler compiler;
733 return FillCache(compiler.CompileCallDebugBreak(flags));
734}
735
736
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100737Object* StubCache::ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000738 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100739 Code::ComputeFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000740 NOT_IN_LOOP,
741 DEBUG_PREPARE_STEP_IN,
742 NORMAL,
743 argc);
744 Object* probe = ProbeCache(flags);
745 if (!probe->IsUndefined()) return probe;
746 StubCompiler compiler;
747 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
748}
749#endif
750
751
752Object* StubCache::ComputeLazyCompile(int argc) {
753 Code::Flags flags =
754 Code::ComputeFlags(Code::STUB, NOT_IN_LOOP, UNINITIALIZED, NORMAL, argc);
755 Object* probe = ProbeCache(flags);
756 if (!probe->IsUndefined()) return probe;
757 StubCompiler compiler;
758 Object* result = FillCache(compiler.CompileLazyCompile(flags));
759 if (result->IsCode()) {
760 Code* code = Code::cast(result);
761 USE(code);
Steve Block6ded16b2010-05-10 14:33:55 +0100762 PROFILE(CodeCreateEvent(Logger::LAZY_COMPILE_TAG,
763 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 }
765 return result;
766}
767
768
769void StubCache::Clear() {
770 for (int i = 0; i < kPrimaryTableSize; i++) {
771 primary_[i].key = Heap::empty_string();
772 primary_[i].value = Builtins::builtin(Builtins::Illegal);
773 }
774 for (int j = 0; j < kSecondaryTableSize; j++) {
775 secondary_[j].key = Heap::empty_string();
776 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
777 }
778}
779
780
781// ------------------------------------------------------------------------
782// StubCompiler implementation.
783
784
785// Support function for computing call IC miss stubs.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100786Handle<Code> ComputeCallMiss(int argc, Code::Kind kind) {
787 CALL_HEAP_FUNCTION(StubCache::ComputeCallMiss(argc, kind), Code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000788}
789
790
791
792Object* LoadCallbackProperty(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +0000793 ASSERT(args[0]->IsJSObject());
794 ASSERT(args[1]->IsJSObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000795 AccessorInfo* callback = AccessorInfo::cast(args[2]);
796 Address getter_address = v8::ToCData<Address>(callback->getter());
797 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
798 ASSERT(fun != NULL);
Steve Blockd0582a62009-12-15 09:54:21 +0000799 CustomArguments custom_args(callback->data(),
800 JSObject::cast(args[0]),
801 JSObject::cast(args[1]));
802 v8::AccessorInfo info(custom_args.end());
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 HandleScope scope;
804 v8::Handle<v8::Value> result;
805 {
806 // Leaving JavaScript.
807 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000808#ifdef ENABLE_LOGGING_AND_PROFILING
809 state.set_external_callback(getter_address);
810#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
812 }
813 RETURN_IF_SCHEDULED_EXCEPTION();
814 if (result.IsEmpty()) return Heap::undefined_value();
815 return *v8::Utils::OpenHandle(*result);
816}
817
818
819Object* StoreCallbackProperty(Arguments args) {
820 JSObject* recv = JSObject::cast(args[0]);
821 AccessorInfo* callback = AccessorInfo::cast(args[1]);
822 Address setter_address = v8::ToCData<Address>(callback->setter());
823 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
824 ASSERT(fun != NULL);
825 Handle<String> name = args.at<String>(2);
826 Handle<Object> value = args.at<Object>(3);
827 HandleScope scope;
828 LOG(ApiNamedPropertyAccess("store", recv, *name));
829 CustomArguments custom_args(callback->data(), recv, recv);
830 v8::AccessorInfo info(custom_args.end());
831 {
832 // Leaving JavaScript.
833 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000834#ifdef ENABLE_LOGGING_AND_PROFILING
835 state.set_external_callback(setter_address);
836#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
838 }
839 RETURN_IF_SCHEDULED_EXCEPTION();
840 return *value;
841}
842
Steve Block6ded16b2010-05-10 14:33:55 +0100843
844static const int kAccessorInfoOffsetInInterceptorArgs = 2;
845
846
Steve Blocka7e24c12009-10-30 11:49:00 +0000847/**
848 * Attempts to load a property with an interceptor (which must be present),
849 * but doesn't search the prototype chain.
850 *
851 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
852 * provide any value for the given name.
853 */
854Object* LoadPropertyWithInterceptorOnly(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +0100855 Handle<String> name_handle = args.at<String>(0);
856 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
857 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
858 ASSERT(args[2]->IsJSObject()); // Receiver.
859 ASSERT(args[3]->IsJSObject()); // Holder.
860 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000861
862 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
863 v8::NamedPropertyGetter getter =
864 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
865 ASSERT(getter != NULL);
866
867 {
868 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +0100869 v8::AccessorInfo info(args.arguments() -
870 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +0000871 HandleScope scope;
872 v8::Handle<v8::Value> r;
873 {
874 // Leaving JavaScript.
875 VMState state(EXTERNAL);
876 r = getter(v8::Utils::ToLocal(name_handle), info);
877 }
878 RETURN_IF_SCHEDULED_EXCEPTION();
879 if (!r.IsEmpty()) {
880 return *v8::Utils::OpenHandle(*r);
881 }
882 }
883
884 return Heap::no_interceptor_result_sentinel();
885}
886
887
888static Object* ThrowReferenceError(String* name) {
889 // If the load is non-contextual, just return the undefined result.
890 // Note that both keyed and non-keyed loads may end up here, so we
891 // can't use either LoadIC or KeyedLoadIC constructors.
892 IC ic(IC::NO_EXTRA_FRAME);
893 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Leon Clarkee46be812010-01-19 14:06:41 +0000894 if (!ic.SlowIsContextual()) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000895
896 // Throw a reference error.
897 HandleScope scope;
898 Handle<String> name_handle(name);
899 Handle<Object> error =
900 Factory::NewReferenceError("not_defined",
901 HandleVector(&name_handle, 1));
902 return Top::Throw(*error);
903}
904
905
906static Object* LoadWithInterceptor(Arguments* args,
907 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +0100908 Handle<String> name_handle = args->at<String>(0);
909 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
910 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
911 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
912 Handle<JSObject> holder_handle = args->at<JSObject>(3);
913 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000914
915 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
916 v8::NamedPropertyGetter getter =
917 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
918 ASSERT(getter != NULL);
919
920 {
921 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +0100922 v8::AccessorInfo info(args->arguments() -
923 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +0000924 HandleScope scope;
925 v8::Handle<v8::Value> r;
926 {
927 // Leaving JavaScript.
928 VMState state(EXTERNAL);
929 r = getter(v8::Utils::ToLocal(name_handle), info);
930 }
931 RETURN_IF_SCHEDULED_EXCEPTION();
932 if (!r.IsEmpty()) {
933 *attrs = NONE;
934 return *v8::Utils::OpenHandle(*r);
935 }
936 }
937
938 Object* result = holder_handle->GetPropertyPostInterceptor(
939 *receiver_handle,
940 *name_handle,
941 attrs);
942 RETURN_IF_SCHEDULED_EXCEPTION();
943 return result;
944}
945
946
947/**
948 * Loads a property with an interceptor performing post interceptor
949 * lookup if interceptor failed.
950 */
951Object* LoadPropertyWithInterceptorForLoad(Arguments args) {
952 PropertyAttributes attr = NONE;
953 Object* result = LoadWithInterceptor(&args, &attr);
954 if (result->IsFailure()) return result;
955
956 // If the property is present, return it.
957 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +0100958 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +0000959}
960
961
962Object* LoadPropertyWithInterceptorForCall(Arguments args) {
963 PropertyAttributes attr;
964 Object* result = LoadWithInterceptor(&args, &attr);
965 RETURN_IF_SCHEDULED_EXCEPTION();
966 // This is call IC. In this case, we simply return the undefined result which
967 // will lead to an exception when trying to invoke the result as a
968 // function.
969 return result;
970}
971
972
973Object* StoreInterceptorProperty(Arguments args) {
974 JSObject* recv = JSObject::cast(args[0]);
975 String* name = String::cast(args[1]);
976 Object* value = args[2];
977 ASSERT(recv->HasNamedInterceptor());
978 PropertyAttributes attr = NONE;
979 Object* result = recv->SetPropertyWithInterceptor(name, value, attr);
980 return result;
981}
982
983
Andrei Popescu402d9372010-02-26 13:31:12 +0000984Object* KeyedLoadPropertyWithInterceptor(Arguments args) {
985 JSObject* receiver = JSObject::cast(args[0]);
986 uint32_t index = Smi::cast(args[1])->value();
987 return receiver->GetElementWithInterceptor(receiver, index);
988}
989
990
Steve Blocka7e24c12009-10-30 11:49:00 +0000991Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
992 HandleScope scope;
993 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100994 Code::Kind kind = Code::ExtractKindFromFlags(flags);
995 if (kind == Code::CALL_IC) {
996 CallIC::GenerateInitialize(masm(), argc);
997 } else {
998 KeyedCallIC::GenerateInitialize(masm(), argc);
999 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001000 Object* result = GetCodeWithFlags(flags, "CompileCallInitialize");
1001 if (!result->IsFailure()) {
1002 Counters::call_initialize_stubs.Increment();
1003 Code* code = Code::cast(result);
1004 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001005 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001006 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 }
1008 return result;
1009}
1010
1011
1012Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1013 HandleScope scope;
1014 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1015 // The code of the PreMonomorphic stub is the same as the code
1016 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001017 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1018 if (kind == Code::CALL_IC) {
1019 CallIC::GenerateInitialize(masm(), argc);
1020 } else {
1021 KeyedCallIC::GenerateInitialize(masm(), argc);
1022 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001023 Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1024 if (!result->IsFailure()) {
1025 Counters::call_premonomorphic_stubs.Increment();
1026 Code* code = Code::cast(result);
1027 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001028 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001029 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001030 }
1031 return result;
1032}
1033
1034
1035Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
1036 HandleScope scope;
1037 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001038 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1039 if (kind == Code::CALL_IC) {
1040 CallIC::GenerateNormal(masm(), argc);
1041 } else {
1042 KeyedCallIC::GenerateNormal(masm(), argc);
1043 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001044 Object* result = GetCodeWithFlags(flags, "CompileCallNormal");
1045 if (!result->IsFailure()) {
1046 Counters::call_normal_stubs.Increment();
1047 Code* code = Code::cast(result);
1048 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001049 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001050 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 }
1052 return result;
1053}
1054
1055
1056Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1057 HandleScope scope;
1058 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001059 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1060 if (kind == Code::CALL_IC) {
1061 CallIC::GenerateMegamorphic(masm(), argc);
1062 } else {
1063 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1064 }
1065
Steve Blocka7e24c12009-10-30 11:49:00 +00001066 Object* result = GetCodeWithFlags(flags, "CompileCallMegamorphic");
1067 if (!result->IsFailure()) {
1068 Counters::call_megamorphic_stubs.Increment();
1069 Code* code = Code::cast(result);
1070 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001071 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001072 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001073 }
1074 return result;
1075}
1076
1077
1078Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
1079 HandleScope scope;
1080 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001081 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1082 if (kind == Code::CALL_IC) {
1083 CallIC::GenerateMiss(masm(), argc);
1084 } else {
1085 KeyedCallIC::GenerateMiss(masm(), argc);
1086 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001087 Object* result = GetCodeWithFlags(flags, "CompileCallMiss");
1088 if (!result->IsFailure()) {
1089 Counters::call_megamorphic_stubs.Increment();
1090 Code* code = Code::cast(result);
1091 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001092 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001093 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001094 }
1095 return result;
1096}
1097
1098
1099#ifdef ENABLE_DEBUGGER_SUPPORT
1100Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1101 HandleScope scope;
1102 Debug::GenerateCallICDebugBreak(masm());
1103 Object* result = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1104 if (!result->IsFailure()) {
1105 Code* code = Code::cast(result);
1106 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001107 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001108 USE(kind);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001109 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
Steve Block6ded16b2010-05-10 14:33:55 +01001110 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001111 }
1112 return result;
1113}
1114
1115
1116Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1117 HandleScope scope;
1118 // Use the same code for the the step in preparations as we do for
1119 // the miss case.
1120 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001121 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1122 if (kind == Code::CALL_IC) {
1123 CallIC::GenerateMiss(masm(), argc);
1124 } else {
1125 KeyedCallIC::GenerateMiss(masm(), argc);
1126 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001127 Object* result = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1128 if (!result->IsFailure()) {
1129 Code* code = Code::cast(result);
1130 USE(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001131 PROFILE(CodeCreateEvent(
1132 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1133 code,
1134 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001135 }
1136 return result;
1137}
1138#endif
1139
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001140#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001141
1142Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
1143 // Check for allocation failures during stub compilation.
1144 if (failure_->IsFailure()) return failure_;
1145
1146 // Create code object in the heap.
1147 CodeDesc desc;
1148 masm_.GetCode(&desc);
1149 Object* result = Heap::CreateCode(desc, NULL, flags, masm_.CodeObject());
1150#ifdef ENABLE_DISASSEMBLER
1151 if (FLAG_print_code_stubs && !result->IsFailure()) {
1152 Code::cast(result)->Disassemble(name);
1153 }
1154#endif
1155 return result;
1156}
1157
1158
1159Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1160 if (FLAG_print_code_stubs && (name != NULL)) {
1161 return GetCodeWithFlags(flags, *name->ToCString());
1162 }
1163 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1164}
1165
Andrei Popescu402d9372010-02-26 13:31:12 +00001166
Leon Clarke4515c472010-02-03 11:58:03 +00001167void StubCompiler::LookupPostInterceptor(JSObject* holder,
1168 String* name,
1169 LookupResult* lookup) {
1170 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001171 if (!lookup->IsProperty()) {
1172 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001173 Object* proto = holder->GetPrototype();
1174 if (proto != Heap::null_value()) {
1175 proto->Lookup(name, lookup);
1176 }
1177 }
1178}
1179
1180
Steve Blocka7e24c12009-10-30 11:49:00 +00001181
1182Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
1183 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
1184 return GetCodeWithFlags(flags, name);
1185}
1186
1187
1188Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
1189 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
1190 return GetCodeWithFlags(flags, name);
1191}
1192
1193
1194Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
1195 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
1196 return GetCodeWithFlags(flags, name);
1197}
1198
1199
1200Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
1201 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
1202 return GetCodeWithFlags(flags, name);
1203}
1204
1205
Kristian Monsen25f61362010-05-21 11:50:48 +01001206Object* CallStubCompiler::CompileCustomCall(int generator_id,
1207 Object* object,
1208 JSObject* holder,
1209 JSFunction* function,
1210 String* fname,
1211 CheckType check) {
1212 ASSERT(generator_id >= 0 && generator_id < kNumCallGenerators);
1213 switch (generator_id) {
1214#define CALL_GENERATOR_CASE(ignored1, ignored2, name) \
1215 case k##name##CallGenerator: \
1216 return CallStubCompiler::Compile##name##Call(object, \
1217 holder, \
1218 function, \
1219 fname, \
1220 check);
1221 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1222#undef CALL_GENERATOR_CASE
1223 }
1224 UNREACHABLE();
1225 return Heap::undefined_value();
1226}
1227
1228
Steve Blocka7e24c12009-10-30 11:49:00 +00001229Object* CallStubCompiler::GetCode(PropertyType type, String* name) {
1230 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001231 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001232 type,
1233 in_loop_,
1234 argc);
1235 return GetCodeWithFlags(flags, name);
1236}
1237
1238
Kristian Monsen25f61362010-05-21 11:50:48 +01001239Object* CallStubCompiler::GetCode(JSFunction* function) {
1240 String* function_name = NULL;
1241 if (function->shared()->name()->IsString()) {
1242 function_name = String::cast(function->shared()->name());
1243 }
1244 return GetCode(CONSTANT_FUNCTION, function_name);
1245}
1246
1247
Steve Blocka7e24c12009-10-30 11:49:00 +00001248Object* ConstructStubCompiler::GetCode() {
1249 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1250 Object* result = GetCodeWithFlags(flags, "ConstructStub");
1251 if (!result->IsFailure()) {
1252 Code* code = Code::cast(result);
1253 USE(code);
Steve Block6ded16b2010-05-10 14:33:55 +01001254 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Steve Blocka7e24c12009-10-30 11:49:00 +00001255 }
1256 return result;
1257}
1258
1259
Steve Block6ded16b2010-05-10 14:33:55 +01001260CallOptimization::CallOptimization(LookupResult* lookup) {
1261 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1262 lookup->type() != CONSTANT_FUNCTION) {
1263 Initialize(NULL);
1264 } else {
1265 // We only optimize constant function calls.
1266 Initialize(lookup->GetConstantFunction());
1267 }
1268}
1269
1270CallOptimization::CallOptimization(JSFunction* function) {
1271 Initialize(function);
1272}
1273
1274
1275int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1276 JSObject* holder) const {
1277 ASSERT(is_simple_api_call_);
1278 if (expected_receiver_type_ == NULL) return 0;
1279 int depth = 0;
1280 while (object != holder) {
1281 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1282 object = JSObject::cast(object->GetPrototype());
1283 ++depth;
1284 }
1285 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1286 return kInvalidProtoDepth;
1287}
1288
1289
1290void CallOptimization::Initialize(JSFunction* function) {
1291 constant_function_ = NULL;
1292 is_simple_api_call_ = false;
1293 expected_receiver_type_ = NULL;
1294 api_call_info_ = NULL;
1295
1296 if (function == NULL || !function->is_compiled()) return;
1297
1298 constant_function_ = function;
1299 AnalyzePossibleApiFunction(function);
1300}
1301
1302
1303void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1304 SharedFunctionInfo* sfi = function->shared();
1305 if (!sfi->IsApiFunction()) return;
1306 FunctionTemplateInfo* info = sfi->get_api_func_data();
1307
1308 // Require a C++ callback.
1309 if (info->call_code()->IsUndefined()) return;
1310 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1311
1312 // Accept signatures that either have no restrictions at all or
1313 // only have restrictions on the receiver.
1314 if (!info->signature()->IsUndefined()) {
1315 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1316 if (!signature->args()->IsUndefined()) return;
1317 if (!signature->receiver()->IsUndefined()) {
1318 expected_receiver_type_ =
1319 FunctionTemplateInfo::cast(signature->receiver());
1320 }
1321 }
1322
1323 is_simple_api_call_ = true;
1324}
1325
1326
Steve Blocka7e24c12009-10-30 11:49:00 +00001327} } // namespace v8::internal