blob: f5f00ae0a5dbdbf40dd0264443e753023bb110e3 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
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 { namespace internal {
36
37// -----------------------------------------------------------------------
38// StubCache implementation.
39
40
41StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
42StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
43
44void StubCache::Initialize(bool create_heap_objects) {
45 ASSERT(IsPowerOf2(kPrimaryTableSize));
46 ASSERT(IsPowerOf2(kSecondaryTableSize));
47 if (create_heap_objects) {
48 HandleScope scope;
49 Clear();
50 }
51}
52
53
54Code* StubCache::Set(String* name, Map* map, Code* code) {
55 // Get the flags from the code.
56 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
57
58 // Validate that the name does not move on scavenge, and that we
59 // can use identity checks instead of string equality checks.
60 ASSERT(!Heap::InNewSpace(name));
61 ASSERT(name->IsSymbol());
62
63 // The state bits are not important to the hash function because
64 // the stub cache only contains monomorphic stubs. Make sure that
65 // the bits are the least significant so they will be the ones
66 // masked out.
kasper.lund7276f142008-07-30 08:49:36 +000067 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
68 ASSERT(Code::kFlagsICStateShift == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70 // Make sure that the code type is not included in the hash.
71 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
72
73 // Compute the primary entry.
74 int primary_offset = PrimaryOffset(name, flags, map);
75 Entry* primary = entry(primary_, primary_offset);
76 Code* hit = primary->value;
77
78 // If the primary entry has useful data in it, we retire it to the
79 // secondary cache before overwriting it.
80 if (hit != Builtins::builtin(Builtins::Illegal)) {
81 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
82 int secondary_offset =
83 SecondaryOffset(primary->key, primary_flags, primary_offset);
84 Entry* secondary = entry(secondary_, secondary_offset);
85 *secondary = *primary;
86 }
87
88 // Update primary cache.
89 primary->key = name;
90 primary->value = code;
91 return code;
92}
93
94
95Object* StubCache::ComputeLoadField(String* name,
96 JSObject* receiver,
97 JSObject* holder,
98 int field_index) {
99 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
100 Object* code = receiver->map()->FindInCodeCache(name, flags);
101 if (code->IsUndefined()) {
102 LoadStubCompiler compiler;
103 code = compiler.CompileLoadField(receiver, holder, field_index);
104 if (code->IsFailure()) return code;
105 LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
106 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
107 if (result->IsFailure()) return code;
108 }
109 return Set(name, receiver->map(), Code::cast(code));
110}
111
112
113Object* StubCache::ComputeLoadCallback(String* name,
114 JSObject* receiver,
115 JSObject* holder,
116 AccessorInfo* callback) {
117 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
118 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
119 Object* code = receiver->map()->FindInCodeCache(name, flags);
120 if (code->IsUndefined()) {
121 LoadStubCompiler compiler;
122 code = compiler.CompileLoadCallback(receiver, holder, callback);
123 if (code->IsFailure()) return code;
124 LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
125 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
126 if (result->IsFailure()) return code;
127 }
128 return Set(name, receiver->map(), Code::cast(code));
129}
130
131
132Object* StubCache::ComputeLoadConstant(String* name,
133 JSObject* receiver,
134 JSObject* holder,
135 Object* value) {
136 Code::Flags flags =
137 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
138 Object* code = receiver->map()->FindInCodeCache(name, flags);
139 if (code->IsUndefined()) {
140 LoadStubCompiler compiler;
141 code = compiler.CompileLoadConstant(receiver, holder, value);
142 if (code->IsFailure()) return code;
143 LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
144 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
145 if (result->IsFailure()) return code;
146 }
147 return Set(name, receiver->map(), Code::cast(code));
148}
149
150
151Object* StubCache::ComputeLoadInterceptor(String* name,
152 JSObject* receiver,
153 JSObject* holder) {
154 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
155 Object* code = receiver->map()->FindInCodeCache(name, flags);
156 if (code->IsUndefined()) {
157 LoadStubCompiler compiler;
158 code = compiler.CompileLoadInterceptor(receiver, holder, name);
159 if (code->IsFailure()) return code;
160 LOG(CodeCreateEvent("LoadIC", Code::cast(code), name));
161 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
162 if (result->IsFailure()) return code;
163 }
164 return Set(name, receiver->map(), Code::cast(code));
165}
166
167
168Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
169 Code* code = Builtins::builtin(Builtins::LoadIC_Normal);
170 return Set(name, receiver->map(), code);
171}
172
173
174Object* StubCache::ComputeKeyedLoadField(String* name,
175 JSObject* receiver,
176 JSObject* holder,
177 int field_index) {
178 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
179 Object* code = receiver->map()->FindInCodeCache(name, flags);
180 if (code->IsUndefined()) {
181 KeyedLoadStubCompiler compiler;
182 code = compiler.CompileLoadField(name, receiver, holder, field_index);
183 if (code->IsFailure()) return code;
184 LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
185 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
186 if (result->IsFailure()) return result;
187 }
188 return code;
189}
190
191
192Object* StubCache::ComputeKeyedLoadConstant(String* name,
193 JSObject* receiver,
194 JSObject* holder,
195 Object* value) {
196 Code::Flags flags =
197 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
198 Object* code = receiver->map()->FindInCodeCache(name, flags);
199 if (code->IsUndefined()) {
200 KeyedLoadStubCompiler compiler;
201 code = compiler.CompileLoadConstant(name, receiver, holder, value);
202 if (code->IsFailure()) return code;
203 LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
204 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
205 if (result->IsFailure()) return result;
206 }
207 return code;
208}
209
210
211Object* StubCache::ComputeKeyedLoadInterceptor(String* name,
212 JSObject* receiver,
213 JSObject* holder) {
214 Code::Flags flags =
215 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
216 Object* code = receiver->map()->FindInCodeCache(name, flags);
217 if (code->IsUndefined()) {
218 KeyedLoadStubCompiler compiler;
219 code = compiler.CompileLoadInterceptor(receiver, holder, name);
220 if (code->IsFailure()) return code;
221 LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
222 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
223 if (result->IsFailure()) return result;
224 }
225 return code;
226}
227
228
229Object* StubCache::ComputeKeyedLoadCallback(String* name,
230 JSObject* receiver,
231 JSObject* holder,
232 AccessorInfo* callback) {
233 Code::Flags flags =
234 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
235 Object* code = receiver->map()->FindInCodeCache(name, flags);
236 if (code->IsUndefined()) {
237 KeyedLoadStubCompiler compiler;
238 code = compiler.CompileLoadCallback(name, receiver, holder, callback);
239 if (code->IsFailure()) return code;
240 LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
241 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
242 if (result->IsFailure()) return result;
243 }
244 return code;
245}
246
247
248
249Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
250 JSArray* receiver) {
251 Code::Flags flags =
252 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
253 Object* code = receiver->map()->FindInCodeCache(name, flags);
254 if (code->IsUndefined()) {
255 KeyedLoadStubCompiler compiler;
256 code = compiler.CompileLoadArrayLength(name);
257 if (code->IsFailure()) return code;
258 LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
259 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
260 if (result->IsFailure()) return result;
261 }
262 return code;
263}
264
265
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000266Object* StubCache::ComputeKeyedLoadStringLength(String* name,
267 String* receiver) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 Code::Flags flags =
269 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
270 Object* code = receiver->map()->FindInCodeCache(name, flags);
271 if (code->IsUndefined()) {
272 KeyedLoadStubCompiler compiler;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000273 code = compiler.CompileLoadStringLength(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000274 if (code->IsFailure()) return code;
275 LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
276 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
277 if (result->IsFailure()) return result;
278 }
279 return code;
280}
281
282
283Object* StubCache::ComputeKeyedLoadFunctionPrototype(String* name,
284 JSFunction* receiver) {
285 Code::Flags flags =
286 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
287 Object* code = receiver->map()->FindInCodeCache(name, flags);
288 if (code->IsUndefined()) {
289 KeyedLoadStubCompiler compiler;
290 code = compiler.CompileLoadFunctionPrototype(name);
291 if (code->IsFailure()) return code;
292 LOG(CodeCreateEvent("KeyedLoadIC", Code::cast(code), name));
293 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
294 if (result->IsFailure()) return result;
295 }
296 return code;
297}
298
299
300Object* StubCache::ComputeStoreField(String* name,
301 JSObject* receiver,
302 int field_index,
303 Map* transition) {
304 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
305 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
306 Object* code = receiver->map()->FindInCodeCache(name, flags);
307 if (code->IsUndefined()) {
308 StoreStubCompiler compiler;
309 code = compiler.CompileStoreField(receiver, field_index, transition, name);
310 if (code->IsFailure()) return code;
311 LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
312 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
313 if (result->IsFailure()) return result;
314 }
315 return Set(name, receiver->map(), Code::cast(code));
316}
317
318
319Object* StubCache::ComputeStoreCallback(String* name,
320 JSObject* receiver,
321 AccessorInfo* callback) {
322 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
323 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
324 Object* code = receiver->map()->FindInCodeCache(name, flags);
325 if (code->IsUndefined()) {
326 StoreStubCompiler compiler;
327 code = compiler.CompileStoreCallback(receiver, callback, name);
328 if (code->IsFailure()) return code;
329 LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
330 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
331 if (result->IsFailure()) return result;
332 }
333 return Set(name, receiver->map(), Code::cast(code));
334}
335
336
337Object* StubCache::ComputeStoreInterceptor(String* name,
338 JSObject* receiver) {
339 Code::Flags flags =
340 Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
341 Object* code = receiver->map()->FindInCodeCache(name, flags);
342 if (code->IsUndefined()) {
343 StoreStubCompiler compiler;
344 code = compiler.CompileStoreInterceptor(receiver, name);
345 if (code->IsFailure()) return code;
346 LOG(CodeCreateEvent("StoreIC", Code::cast(code), name));
347 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
348 if (result->IsFailure()) return result;
349 }
350 return Set(name, receiver->map(), Code::cast(code));
351}
352
353
354Object* StubCache::ComputeKeyedStoreField(String* name, JSObject* receiver,
355 int field_index, Map* transition) {
356 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
357 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
358 Object* code = receiver->map()->FindInCodeCache(name, flags);
359 if (code->IsUndefined()) {
360 KeyedStoreStubCompiler compiler;
361 code = compiler.CompileStoreField(receiver, field_index, transition, name);
362 if (code->IsFailure()) return code;
363 LOG(CodeCreateEvent("KeyedStoreIC", Code::cast(code), name));
364 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
365 if (result->IsFailure()) return result;
366 }
367 return code;
368}
369
370
371Object* StubCache::ComputeCallConstant(int argc,
372 String* name,
373 Object* object,
374 JSObject* holder,
375 JSFunction* function) {
376 // Compute the check type and the map.
377 Map* map = IC::GetCodeCacheMapForObject(object);
378
379 // Compute check type based on receiver/holder.
380 StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK;
381 if (object->IsString()) {
382 check = StubCompiler::STRING_CHECK;
383 } else if (object->IsNumber()) {
384 check = StubCompiler::NUMBER_CHECK;
385 } else if (object->IsBoolean()) {
386 check = StubCompiler::BOOLEAN_CHECK;
387 }
388
389 Code::Flags flags =
390 Code::ComputeMonomorphicFlags(Code::CALL_IC, CONSTANT_FUNCTION, argc);
391 Object* code = map->FindInCodeCache(name, flags);
392 if (code->IsUndefined()) {
393 if (object->IsJSObject()) {
394 Object* opt =
395 Top::LookupSpecialFunction(JSObject::cast(object), holder, function);
396 if (opt->IsJSFunction()) {
397 check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK;
398 function = JSFunction::cast(opt);
399 }
400 }
401 // If the function hasn't been compiled yet, we cannot do it now
402 // because it may cause GC. To avoid this issue, we return an
403 // internal error which will make sure we do not update any
404 // caches.
405 if (!function->is_compiled()) return Failure::InternalError();
406 // Compile the stub - only create stubs for fully compiled functions.
407 CallStubCompiler compiler(argc);
408 code = compiler.CompileCallConstant(object, holder, function, check);
409 if (code->IsFailure()) return code;
410 LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
411 Object* result = map->UpdateCodeCache(name, Code::cast(code));
412 if (result->IsFailure()) return result;
413 }
414 return Set(name, map, Code::cast(code));
415}
416
417
418Object* StubCache::ComputeCallField(int argc,
419 String* name,
420 Object* object,
421 JSObject* holder,
422 int index) {
423 // Compute the check type and the map.
424 Map* map = IC::GetCodeCacheMapForObject(object);
425
426 // TODO(1233596): We cannot do receiver map check for non-JS objects
427 // because they may be represented as immediates without a
428 // map. Instead, we check against the map in the holder.
429 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
430 object = holder;
431 }
432
433 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, FIELD, argc);
434 Object* code = map->FindInCodeCache(name, flags);
435 if (code->IsUndefined()) {
436 CallStubCompiler compiler(argc);
437 code = compiler.CompileCallField(object, holder, index);
438 if (code->IsFailure()) return code;
439 LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
440 Object* result = map->UpdateCodeCache(name, Code::cast(code));
441 if (result->IsFailure()) return result;
442 }
443 return Set(name, map, Code::cast(code));
444}
445
446
447Object* StubCache::ComputeCallInterceptor(int argc,
448 String* name,
449 Object* object,
450 JSObject* holder) {
451 // Compute the check type and the map.
452 // If the object is a value, we use the prototype map for the cache.
453 Map* map = IC::GetCodeCacheMapForObject(object);
454
455 // TODO(1233596): We cannot do receiver map check for non-JS objects
456 // because they may be represented as immediates without a
457 // map. Instead, we check against the map in the holder.
458 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
459 object = holder;
460 }
461
462 Code::Flags flags =
463 Code::ComputeMonomorphicFlags(Code::CALL_IC, INTERCEPTOR, argc);
464 Object* code = map->FindInCodeCache(name, flags);
465 if (code->IsUndefined()) {
466 CallStubCompiler compiler(argc);
467 code = compiler.CompileCallInterceptor(object, holder, name);
468 if (code->IsFailure()) return code;
469 LOG(CodeCreateEvent("CallIC", Code::cast(code), name));
470 Object* result = map->UpdateCodeCache(name, Code::cast(code));
471 if (result->IsFailure()) return result;
472 }
473 return Set(name, map, Code::cast(code));
474}
475
476
477Object* StubCache::ComputeCallNormal(int argc,
478 String* name,
479 JSObject* receiver) {
480 Object* code = ComputeCallNormal(argc);
481 if (code->IsFailure()) return code;
482 return Set(name, receiver->map(), Code::cast(code));
483}
484
485
486static Object* GetProbeValue(Code::Flags flags) {
487 Dictionary* dictionary = Heap::non_monomorphic_cache();
488 int entry = dictionary->FindNumberEntry(flags);
489 if (entry != -1) return dictionary->ValueAt(entry);
490 return Heap::undefined_value();
491}
492
493
494static Object* ProbeCache(Code::Flags flags) {
495 Object* probe = GetProbeValue(flags);
496 if (probe != Heap::undefined_value()) return probe;
497 // Seed the cache with an undefined value to make sure that any
498 // generated code object can always be inserted into the cache
499 // without causing allocation failures.
500 Object* result =
501 Heap::non_monomorphic_cache()->AtNumberPut(flags,
502 Heap::undefined_value());
503 if (result->IsFailure()) return result;
504 Heap::set_non_monomorphic_cache(Dictionary::cast(result));
505 return probe;
506}
507
508
509static Object* FillCache(Object* code) {
510 if (code->IsCode()) {
511 int entry =
512 Heap::non_monomorphic_cache()->FindNumberEntry(
513 Code::cast(code)->flags());
514 // The entry must be present see comment in ProbeCache.
515 ASSERT(entry != -1);
516 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
517 Heap::undefined_value());
518 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
519 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
520 }
521 return code;
522}
523
524
525Code* StubCache::FindCallInitialize(int argc) {
526 Code::Flags flags =
527 Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc);
528 Object* result = ProbeCache(flags);
529 ASSERT(!result->IsUndefined());
530 // This might be called during the marking phase of the collector
531 // hence the unchecked cast.
532 return reinterpret_cast<Code*>(result);
533}
534
535
536Object* StubCache::ComputeCallInitialize(int argc) {
537 Code::Flags flags =
538 Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc);
539 Object* probe = ProbeCache(flags);
540 if (!probe->IsUndefined()) return probe;
541 StubCompiler compiler;
542 return FillCache(compiler.CompileCallInitialize(flags));
543}
544
545
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000546Object* StubCache::ComputeCallInitializeInLoop(int argc) {
547 Code::Flags flags =
548 Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED_IN_LOOP, NORMAL, argc);
549 Object* probe = ProbeCache(flags);
550 if (!probe->IsUndefined()) return probe;
551 StubCompiler compiler;
552 return FillCache(compiler.CompileCallInitialize(flags));
553}
554
555
556
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557Object* StubCache::ComputeCallPreMonomorphic(int argc) {
558 Code::Flags flags =
559 Code::ComputeFlags(Code::CALL_IC, PREMONOMORPHIC, NORMAL, argc);
560 Object* probe = ProbeCache(flags);
561 if (!probe->IsUndefined()) return probe;
562 StubCompiler compiler;
563 return FillCache(compiler.CompileCallPreMonomorphic(flags));
564}
565
566
567Object* StubCache::ComputeCallNormal(int argc) {
568 Code::Flags flags =
569 Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc);
570 Object* probe = ProbeCache(flags);
571 if (!probe->IsUndefined()) return probe;
572 StubCompiler compiler;
573 return FillCache(compiler.CompileCallNormal(flags));
574}
575
576
577Object* StubCache::ComputeCallMegamorphic(int argc) {
578 Code::Flags flags =
579 Code::ComputeFlags(Code::CALL_IC, MEGAMORPHIC, NORMAL, argc);
580 Object* probe = ProbeCache(flags);
581 if (!probe->IsUndefined()) return probe;
582 StubCompiler compiler;
583 return FillCache(compiler.CompileCallMegamorphic(flags));
584}
585
586
587Object* StubCache::ComputeCallMiss(int argc) {
588 Code::Flags flags =
589 Code::ComputeFlags(Code::STUB, MEGAMORPHIC, NORMAL, argc);
590 Object* probe = ProbeCache(flags);
591 if (!probe->IsUndefined()) return probe;
592 StubCompiler compiler;
593 return FillCache(compiler.CompileCallMiss(flags));
594}
595
596
597Object* StubCache::ComputeCallDebugBreak(int argc) {
598 Code::Flags flags =
599 Code::ComputeFlags(Code::CALL_IC, DEBUG_BREAK, NORMAL, argc);
600 Object* probe = ProbeCache(flags);
601 if (!probe->IsUndefined()) return probe;
602 StubCompiler compiler;
603 return FillCache(compiler.CompileCallDebugBreak(flags));
604}
605
606
607Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) {
608 Code::Flags flags =
609 Code::ComputeFlags(Code::CALL_IC, DEBUG_PREPARE_STEP_IN, NORMAL, argc);
610 Object* probe = ProbeCache(flags);
611 if (!probe->IsUndefined()) return probe;
612 StubCompiler compiler;
613 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
614}
615
616
617Object* StubCache::ComputeLazyCompile(int argc) {
618 Code::Flags flags =
619 Code::ComputeFlags(Code::STUB, UNINITIALIZED, NORMAL, argc);
620 Object* probe = ProbeCache(flags);
621 if (!probe->IsUndefined()) return probe;
622 StubCompiler compiler;
623 Object* result = FillCache(compiler.CompileLazyCompile(flags));
624 if (result->IsCode()) {
625 Code* code = Code::cast(result);
626 USE(code);
627 LOG(CodeCreateEvent("LazyCompile", code, code->arguments_count()));
628 }
629 return result;
630}
631
632
633void StubCache::Clear() {
634 for (int i = 0; i < kPrimaryTableSize; i++) {
635 primary_[i].key = Heap::empty_string();
636 primary_[i].value = Builtins::builtin(Builtins::Illegal);
637 }
638 for (int j = 0; j < kSecondaryTableSize; j++) {
639 secondary_[j].key = Heap::empty_string();
640 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
641 }
642}
643
644
645// ------------------------------------------------------------------------
646// StubCompiler implementation.
647
648
649// Support function for computing call IC miss stubs.
650Handle<Code> ComputeCallMiss(int argc) {
651 CALL_HEAP_FUNCTION(StubCache::ComputeCallMiss(argc), Code);
652}
653
654
655
656Object* LoadCallbackProperty(Arguments args) {
657 Handle<JSObject> recv = args.at<JSObject>(0);
658 AccessorInfo* callback = AccessorInfo::cast(args[1]);
659 v8::AccessorGetter fun =
660 FUNCTION_CAST<v8::AccessorGetter>(
661 v8::ToCData<Address>(callback->getter()));
662 ASSERT(fun != NULL);
663 Handle<String> name = args.at<String>(2);
664 Handle<JSObject> holder = args.at<JSObject>(3);
665 HandleScope scope;
666 Handle<Object> data(callback->data());
667 LOG(ApiNamedPropertyAccess("load", *recv, *name));
668 // NOTE: If we can align the structure of an AccessorInfo with the
669 // locations of the arguments to this function maybe we don't have
670 // to explicitly create the structure but can just pass a pointer
671 // into the stack.
672 v8::AccessorInfo info(
673 v8::Utils::ToLocal(recv),
674 v8::Utils::ToLocal(data),
675 v8::Utils::ToLocal(holder));
676 v8::Handle<v8::Value> result;
677 {
678 // Leaving JavaScript.
679 VMState state(OTHER);
680 result = fun(v8::Utils::ToLocal(name), info);
681 }
682 RETURN_IF_SCHEDULED_EXCEPTION();
683 if (result.IsEmpty()) {
684 return Heap::undefined_value();
685 } else {
686 return *v8::Utils::OpenHandle(*result);
687 }
688}
689
690
691Object* StoreCallbackProperty(Arguments args) {
692 Handle<JSObject> recv = args.at<JSObject>(0);
693 AccessorInfo* callback = AccessorInfo::cast(args[1]);
694 v8::AccessorSetter fun =
695 FUNCTION_CAST<v8::AccessorSetter>(
696 v8::ToCData<Address>(callback->setter()));
697 ASSERT(fun != NULL);
698 Handle<String> name = args.at<String>(2);
699 Handle<Object> value = args.at<Object>(3);
700 HandleScope scope;
701 Handle<Object> data(callback->data());
702 LOG(ApiNamedPropertyAccess("store", *recv, *name));
703 v8::AccessorInfo info(
704 v8::Utils::ToLocal(recv),
705 v8::Utils::ToLocal(data),
706 v8::Utils::ToLocal(recv));
707 {
708 // Leaving JavaScript.
709 VMState state(OTHER);
710 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
711 }
712 RETURN_IF_SCHEDULED_EXCEPTION();
713 return *value;
714}
715
716
717Object* LoadInterceptorProperty(Arguments args) {
718 HandleScope scope;
719 Handle<JSObject> recv = args.at<JSObject>(0);
720 Handle<JSObject> holder = args.at<JSObject>(1);
721 Handle<String> name = args.at<String>(2);
722 ASSERT(holder->HasNamedInterceptor());
723 PropertyAttributes attr = NONE;
724 Handle<Object> result = GetPropertyWithInterceptor(recv, holder, name, &attr);
725
726 // GetPropertyWithInterceptor already converts a scheduled exception
727 // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION() here.
728
729 // Make sure to propagate exceptions.
730 if (result.is_null()) {
731 // Failure::Exception is converted to a null handle in the
732 // handle-based methods such as SetProperty. We therefore need
733 // to convert null handles back to exceptions.
734 ASSERT(Top::has_pending_exception());
735 return Failure::Exception();
736 }
737
738 // If the property is present, return it.
739 if (attr != ABSENT) return *result;
740
741 // If the top frame is an internal frame, this is really a call
742 // IC. In this case, we simply return the undefined result which
743 // will lead to an exception when trying to invoke the result as a
744 // function.
745 StackFrameIterator it;
746 it.Advance(); // skip exit frame
747 if (it.frame()->is_internal()) return *result;
748
749 // If the load is non-contextual, just return the undefined result.
750 // Note that both keyed and non-keyed loads may end up here, so we
751 // can't use either LoadIC or KeyedLoadIC constructors.
752 IC ic(IC::NO_EXTRA_FRAME);
753 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
754 if (!ic.is_contextual()) return *result;
755
756 // Throw a reference error.
757 Handle<Object> error =
758 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
759 return Top::Throw(*error);
760}
761
762
763Object* StoreInterceptorProperty(Arguments args) {
764 HandleScope scope;
765 Handle<JSObject> recv = args.at<JSObject>(0);
766 Handle<String> name = args.at<String>(1);
767 Handle<Object> value = args.at<Object>(2);
768 ASSERT(recv->HasNamedInterceptor());
769 PropertyAttributes attr = NONE;
770 Handle<Object> result = SetPropertyWithInterceptor(recv, name, value, attr);
771
772 // SetPropertyWithInterceptor already converts a scheduled exception
773 // to a pending one if any. Don't use RETURN_IF_SCHEDULED_EXCEPTION() here.
774
775 // Make sure to propagate exceptions.
776 if (result.is_null()) {
777 // Failure::Exception is converted to a null handle in the
778 // handle-based methods such as SetProperty. We therefore need
779 // to convert null handles back to exceptions.
780 ASSERT(Top::has_pending_exception());
781 return Failure::Exception();
782 }
783 return *result;
784}
785
786
787Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
788 HandleScope scope;
789 int argc = Code::ExtractArgumentsCountFromFlags(flags);
790 CallIC::GenerateInitialize(masm(), argc);
791 Object* result = GetCodeWithFlags(flags);
792 if (!result->IsFailure()) {
793 Counters::call_initialize_stubs.Increment();
794 Code* code = Code::cast(result);
795 USE(code);
796 LOG(CodeCreateEvent("CallInitialize", code, code->arguments_count()));
797 }
798 return result;
799}
800
801
802Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
803 HandleScope scope;
804 int argc = Code::ExtractArgumentsCountFromFlags(flags);
805 CallIC::GenerateInitialize(masm(), argc);
806 Object* result = GetCodeWithFlags(flags);
807 if (!result->IsFailure()) {
808 Counters::call_premonomorphic_stubs.Increment();
809 Code* code = Code::cast(result);
810 USE(code);
811 LOG(CodeCreateEvent("CallPreMonomorphic", code, code->arguments_count()));
812 }
813 return result;
814}
815
816
817Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
818 HandleScope scope;
819 int argc = Code::ExtractArgumentsCountFromFlags(flags);
820 CallIC::GenerateNormal(masm(), argc);
821 Object* result = GetCodeWithFlags(flags);
822 if (!result->IsFailure()) {
823 Counters::call_normal_stubs.Increment();
824 Code* code = Code::cast(result);
825 USE(code);
826 LOG(CodeCreateEvent("CallNormal", code, code->arguments_count()));
827 }
828 return result;
829}
830
831
832Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
833 HandleScope scope;
834 int argc = Code::ExtractArgumentsCountFromFlags(flags);
835 CallIC::GenerateMegamorphic(masm(), argc);
836 Object* result = GetCodeWithFlags(flags);
837 if (!result->IsFailure()) {
838 Counters::call_megamorphic_stubs.Increment();
839 Code* code = Code::cast(result);
840 USE(code);
841 LOG(CodeCreateEvent("CallMegamorphic", code, code->arguments_count()));
842 }
843 return result;
844}
845
846
847Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
848 HandleScope scope;
849 int argc = Code::ExtractArgumentsCountFromFlags(flags);
850 CallIC::GenerateMiss(masm(), argc);
851 Object* result = GetCodeWithFlags(flags);
852 if (!result->IsFailure()) {
853 Counters::call_megamorphic_stubs.Increment();
854 Code* code = Code::cast(result);
855 USE(code);
856 LOG(CodeCreateEvent("CallMiss", code, code->arguments_count()));
857 }
858 return result;
859}
860
861
862Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
863 HandleScope scope;
864 Builtins::Generate_CallIC_DebugBreak(masm());
865 Object* result = GetCodeWithFlags(flags);
866 if (!result->IsFailure()) {
867 Code* code = Code::cast(result);
868 USE(code);
869 LOG(CodeCreateEvent("CallDebugBreak", code, code->arguments_count()));
870 }
871 return result;
872}
873
874
875Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
876 HandleScope scope;
877 // Use the same code for the the step in preparations as we do for
878 // the miss case.
879 int argc = Code::ExtractArgumentsCountFromFlags(flags);
880 CallIC::GenerateMiss(masm(), argc);
881 Object* result = GetCodeWithFlags(flags);
882 if (!result->IsFailure()) {
883 Code* code = Code::cast(result);
884 USE(code);
885 LOG(CodeCreateEvent("CallDebugPrepareStepIn", code,
886 code->arguments_count()));
887 }
888 return result;
889}
890
891
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892Object* StubCompiler::GetCodeWithFlags(Code::Flags flags) {
893 CodeDesc desc;
894 masm_.GetCode(&desc);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000895 Object* result = Heap::CreateCode(desc, NULL, flags, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896#ifdef DEBUG
897 if (FLAG_print_code_stubs && !result->IsFailure()) {
898 Code::cast(result)->Print();
899 }
900#endif
901 return result;
902}
903
904
905Object* LoadStubCompiler::GetCode(PropertyType type) {
906 return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::LOAD_IC, type));
907}
908
909
910Object* KeyedLoadStubCompiler::GetCode(PropertyType type) {
911 return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC,
912 type));
913}
914
915
916Object* StoreStubCompiler::GetCode(PropertyType type) {
917 return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::STORE_IC, type));
918}
919
920
921Object* KeyedStoreStubCompiler::GetCode(PropertyType type) {
922 return GetCodeWithFlags(Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC,
923 type));
924}
925
926
927Object* CallStubCompiler::GetCode(PropertyType type) {
928 int argc = arguments_.immediate();
929 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, type, argc);
930 return GetCodeWithFlags(flags);
931}
932
933
934} } // namespace v8::internal