1
// Copyright 2012 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
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.
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.
31
#include "arguments.h"
33
#include "code-stubs.h"
36
#include "stub-cache.h"
37
#include "vm-state-inl.h"
42
// -----------------------------------------------------------------------
43
// StubCache implementation.
46
StubCache::StubCache(Isolate* isolate, Zone* zone)
48
ASSERT(isolate == Isolate::Current());
52
void StubCache::Initialize() {
53
ASSERT(IsPowerOf2(kPrimaryTableSize));
54
ASSERT(IsPowerOf2(kSecondaryTableSize));
59
Code* StubCache::Set(String* name, Map* map, Code* code) {
60
// Get the flags from the code.
61
Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
63
// Validate that the name does not move on scavenge, and that we
64
// can use identity checks instead of string equality checks.
65
ASSERT(!heap()->InNewSpace(name));
66
ASSERT(name->IsSymbol());
68
// The state bits are not important to the hash function because
69
// the stub cache only contains monomorphic stubs. Make sure that
70
// the bits are the least significant so they will be the ones
72
ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
73
STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
75
// Make sure that the code type is not included in the hash.
76
ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
78
// Compute the primary entry.
79
int primary_offset = PrimaryOffset(name, flags, map);
80
Entry* primary = entry(primary_, primary_offset);
81
Code* old_code = primary->value;
83
// If the primary entry has useful data in it, we retire it to the
84
// secondary cache before overwriting it.
85
if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
86
Map* old_map = primary->map;
87
Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
88
int seed = PrimaryOffset(primary->key, old_flags, old_map);
89
int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
90
Entry* secondary = entry(secondary_, secondary_offset);
91
*secondary = *primary;
94
// Update primary cache.
96
primary->value = code;
98
isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
103
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
104
Handle<JSObject> receiver) {
105
ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
106
// If no global objects are present in the prototype chain, the load
107
// nonexistent IC stub can be shared for all names for a given map
108
// and we use the empty string for the map cache in that case. If
109
// there are global objects involved, we need to check global
110
// property cells in the stub and therefore the stub will be
111
// specific to the name.
112
Handle<String> cache_name = factory()->empty_string();
113
if (receiver->IsGlobalObject()) cache_name = name;
114
Handle<JSObject> last = receiver;
115
while (last->GetPrototype() != heap()->null_value()) {
116
last = Handle<JSObject>(JSObject::cast(last->GetPrototype()));
117
if (last->IsGlobalObject()) cache_name = name;
119
// Compile the stub that is either shared for all names or
120
// name specific if there are global objects involved.
122
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::NONEXISTENT);
123
Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags));
124
if (probe->IsCode()) return Handle<Code>::cast(probe);
126
LoadStubCompiler compiler(isolate_);
128
compiler.CompileLoadNonexistent(cache_name, receiver, last);
129
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
130
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
131
JSObject::UpdateMapCodeCache(receiver, cache_name, code);
136
Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
137
Handle<JSObject> receiver,
138
Handle<JSObject> holder,
140
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
141
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::FIELD);
142
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
143
if (probe->IsCode()) return Handle<Code>::cast(probe);
145
LoadStubCompiler compiler(isolate_);
147
compiler.CompileLoadField(receiver, holder, field_index, name);
148
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
149
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
150
JSObject::UpdateMapCodeCache(receiver, name, code);
155
Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name,
156
Handle<JSObject> receiver,
157
Handle<JSObject> holder,
158
Handle<AccessorInfo> callback) {
159
ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
160
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
162
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS);
163
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
164
if (probe->IsCode()) return Handle<Code>::cast(probe);
166
LoadStubCompiler compiler(isolate_);
168
compiler.CompileLoadCallback(name, receiver, holder, callback);
169
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
170
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
171
JSObject::UpdateMapCodeCache(receiver, name, code);
176
Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name,
177
Handle<JSObject> receiver,
178
Handle<JSObject> holder,
179
Handle<JSFunction> getter) {
180
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
182
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS);
183
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
184
if (probe->IsCode()) return Handle<Code>::cast(probe);
186
LoadStubCompiler compiler(isolate_);
188
compiler.CompileLoadViaGetter(name, receiver, holder, getter);
189
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
190
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
191
JSObject::UpdateMapCodeCache(receiver, name, code);
196
Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
197
Handle<JSObject> receiver,
198
Handle<JSObject> holder,
199
Handle<JSFunction> value) {
200
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
202
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CONSTANT_FUNCTION);
203
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
204
if (probe->IsCode()) return Handle<Code>::cast(probe);
206
LoadStubCompiler compiler(isolate_);
208
compiler.CompileLoadConstant(receiver, holder, value, name);
209
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
210
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
211
JSObject::UpdateMapCodeCache(receiver, name, code);
216
Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
217
Handle<JSObject> receiver,
218
Handle<JSObject> holder) {
219
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
221
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::INTERCEPTOR);
222
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
223
if (probe->IsCode()) return Handle<Code>::cast(probe);
225
LoadStubCompiler compiler(isolate_);
227
compiler.CompileLoadInterceptor(receiver, holder, name);
228
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
229
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
230
JSObject::UpdateMapCodeCache(receiver, name, code);
235
Handle<Code> StubCache::ComputeLoadNormal() {
236
return isolate_->builtins()->LoadIC_Normal();
240
Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
241
Handle<JSObject> receiver,
242
Handle<GlobalObject> holder,
243
Handle<JSGlobalPropertyCell> cell,
244
bool is_dont_delete) {
245
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
247
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::NORMAL);
248
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
249
if (probe->IsCode()) return Handle<Code>::cast(probe);
251
LoadStubCompiler compiler(isolate_);
253
compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
254
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
255
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
256
JSObject::UpdateMapCodeCache(receiver, name, code);
261
Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
262
Handle<JSObject> receiver,
263
Handle<JSObject> holder,
265
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
267
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::FIELD);
268
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
269
if (probe->IsCode()) return Handle<Code>::cast(probe);
271
KeyedLoadStubCompiler compiler(isolate_);
273
compiler.CompileLoadField(name, receiver, holder, field_index);
274
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
275
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
276
JSObject::UpdateMapCodeCache(receiver, name, code);
281
Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
282
Handle<JSObject> receiver,
283
Handle<JSObject> holder,
284
Handle<JSFunction> value) {
285
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
286
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC,
287
Code::CONSTANT_FUNCTION);
288
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
289
if (probe->IsCode()) return Handle<Code>::cast(probe);
291
KeyedLoadStubCompiler compiler(isolate_);
293
compiler.CompileLoadConstant(name, receiver, holder, value);
294
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
295
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
296
JSObject::UpdateMapCodeCache(receiver, name, code);
301
Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
302
Handle<JSObject> receiver,
303
Handle<JSObject> holder) {
304
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
306
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
307
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
308
if (probe->IsCode()) return Handle<Code>::cast(probe);
310
KeyedLoadStubCompiler compiler(isolate_);
311
Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
312
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
313
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
314
JSObject::UpdateMapCodeCache(receiver, name, code);
319
Handle<Code> StubCache::ComputeKeyedLoadCallback(
321
Handle<JSObject> receiver,
322
Handle<JSObject> holder,
323
Handle<AccessorInfo> callback) {
324
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
326
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
327
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
328
if (probe->IsCode()) return Handle<Code>::cast(probe);
330
KeyedLoadStubCompiler compiler(isolate_);
332
compiler.CompileLoadCallback(name, receiver, holder, callback);
333
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
334
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
335
JSObject::UpdateMapCodeCache(receiver, name, code);
340
Handle<Code> StubCache::ComputeKeyedLoadArrayLength(Handle<String> name,
341
Handle<JSArray> receiver) {
343
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
344
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
345
if (probe->IsCode()) return Handle<Code>::cast(probe);
347
KeyedLoadStubCompiler compiler(isolate_);
348
Handle<Code> code = compiler.CompileLoadArrayLength(name);
349
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
350
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
351
JSObject::UpdateMapCodeCache(receiver, name, code);
356
Handle<Code> StubCache::ComputeKeyedLoadStringLength(Handle<String> name,
357
Handle<String> receiver) {
359
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
360
Handle<Map> map(receiver->map());
361
Handle<Object> probe(map->FindInCodeCache(*name, flags));
362
if (probe->IsCode()) return Handle<Code>::cast(probe);
364
KeyedLoadStubCompiler compiler(isolate_);
365
Handle<Code> code = compiler.CompileLoadStringLength(name);
366
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
367
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
368
Map::UpdateCodeCache(map, name, code);
373
Handle<Code> StubCache::ComputeKeyedLoadFunctionPrototype(
375
Handle<JSFunction> receiver) {
377
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
378
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
379
if (probe->IsCode()) return Handle<Code>::cast(probe);
381
KeyedLoadStubCompiler compiler(isolate_);
382
Handle<Code> code = compiler.CompileLoadFunctionPrototype(name);
383
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
384
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
385
JSObject::UpdateMapCodeCache(receiver, name, code);
390
Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
391
Handle<JSObject> receiver,
393
Handle<Map> transition,
394
StrictModeFlag strict_mode) {
395
Code::StubType type =
396
(transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION;
397
Code::Flags flags = Code::ComputeMonomorphicFlags(
398
Code::STORE_IC, type, strict_mode);
399
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
400
if (probe->IsCode()) return Handle<Code>::cast(probe);
402
StoreStubCompiler compiler(isolate_, strict_mode);
404
compiler.CompileStoreField(receiver, field_index, transition, name);
405
PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
406
GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
407
JSObject::UpdateMapCodeCache(receiver, name, code);
412
Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement(
413
Handle<Map> receiver_map,
414
KeyedIC::StubKind stub_kind,
415
StrictModeFlag strict_mode) {
416
KeyedAccessGrowMode grow_mode =
417
KeyedIC::GetGrowModeFromStubKind(stub_kind);
418
Code::ExtraICState extra_state =
419
Code::ComputeExtraICState(grow_mode, strict_mode);
421
Code::ComputeMonomorphicFlags(
422
stub_kind == KeyedIC::LOAD ? Code::KEYED_LOAD_IC
423
: Code::KEYED_STORE_IC,
429
name = isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
431
case KeyedIC::STORE_NO_TRANSITION:
432
name = isolate()->factory()->KeyedStoreElementMonomorphic_symbol();
434
case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
435
name = isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
441
Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags));
442
if (probe->IsCode()) return Handle<Code>::cast(probe);
446
case KeyedIC::LOAD: {
447
KeyedLoadStubCompiler compiler(isolate_);
448
code = compiler.CompileLoadElement(receiver_map);
451
case KeyedIC::STORE_AND_GROW_NO_TRANSITION: {
452
KeyedStoreStubCompiler compiler(isolate_, strict_mode,
453
ALLOW_JSARRAY_GROWTH);
454
code = compiler.CompileStoreElement(receiver_map);
457
case KeyedIC::STORE_NO_TRANSITION: {
458
KeyedStoreStubCompiler compiler(isolate_, strict_mode,
459
DO_NOT_ALLOW_JSARRAY_GROWTH);
460
code = compiler.CompileStoreElement(receiver_map);
468
ASSERT(!code.is_null());
470
if (stub_kind == KeyedIC::LOAD) {
471
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
473
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
475
Map::UpdateCodeCache(receiver_map, name, code);
480
Handle<Code> StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
481
return (strict_mode == kStrictMode)
482
? isolate_->builtins()->Builtins::StoreIC_Normal_Strict()
483
: isolate_->builtins()->Builtins::StoreIC_Normal();
487
Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
488
Handle<GlobalObject> receiver,
489
Handle<JSGlobalPropertyCell> cell,
490
StrictModeFlag strict_mode) {
491
Code::Flags flags = Code::ComputeMonomorphicFlags(
492
Code::STORE_IC, Code::NORMAL, strict_mode);
493
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
494
if (probe->IsCode()) return Handle<Code>::cast(probe);
496
StoreStubCompiler compiler(isolate_, strict_mode);
497
Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
498
PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
499
GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
500
JSObject::UpdateMapCodeCache(receiver, name, code);
505
Handle<Code> StubCache::ComputeStoreCallback(Handle<String> name,
506
Handle<JSObject> receiver,
507
Handle<AccessorInfo> callback,
508
StrictModeFlag strict_mode) {
509
ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
510
Code::Flags flags = Code::ComputeMonomorphicFlags(
511
Code::STORE_IC, Code::CALLBACKS, strict_mode);
512
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
513
if (probe->IsCode()) return Handle<Code>::cast(probe);
515
StoreStubCompiler compiler(isolate_, strict_mode);
516
Handle<Code> code = compiler.CompileStoreCallback(receiver, callback, name);
517
PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
518
GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
519
JSObject::UpdateMapCodeCache(receiver, name, code);
524
Handle<Code> StubCache::ComputeStoreViaSetter(Handle<String> name,
525
Handle<JSObject> receiver,
526
Handle<JSObject> holder,
527
Handle<JSFunction> setter,
528
StrictModeFlag strict_mode) {
529
Code::Flags flags = Code::ComputeMonomorphicFlags(
530
Code::STORE_IC, Code::CALLBACKS, strict_mode);
531
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
532
if (probe->IsCode()) return Handle<Code>::cast(probe);
534
StoreStubCompiler compiler(isolate_, strict_mode);
536
compiler.CompileStoreViaSetter(name, receiver, holder, setter);
537
PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
538
GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
539
JSObject::UpdateMapCodeCache(receiver, name, code);
544
Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
545
Handle<JSObject> receiver,
546
StrictModeFlag strict_mode) {
547
Code::Flags flags = Code::ComputeMonomorphicFlags(
548
Code::STORE_IC, Code::INTERCEPTOR, strict_mode);
549
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
550
if (probe->IsCode()) return Handle<Code>::cast(probe);
552
StoreStubCompiler compiler(isolate_, strict_mode);
553
Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
554
PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
555
GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
556
JSObject::UpdateMapCodeCache(receiver, name, code);
560
Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
561
Handle<JSObject> receiver,
563
Handle<Map> transition,
564
StrictModeFlag strict_mode) {
565
Code::StubType type =
566
(transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION;
567
Code::Flags flags = Code::ComputeMonomorphicFlags(
568
Code::KEYED_STORE_IC, type, strict_mode);
569
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
570
if (probe->IsCode()) return Handle<Code>::cast(probe);
572
KeyedStoreStubCompiler compiler(isolate(), strict_mode,
573
DO_NOT_ALLOW_JSARRAY_GROWTH);
575
compiler.CompileStoreField(receiver, field_index, transition, name);
576
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
577
GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
578
JSObject::UpdateMapCodeCache(receiver, name, code);
583
#define CALL_LOGGER_TAG(kind, type) \
584
(kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
586
Handle<Code> StubCache::ComputeCallConstant(int argc,
588
Code::ExtraICState extra_state,
590
Handle<Object> object,
591
Handle<JSObject> holder,
592
Handle<JSFunction> function) {
593
// Compute the check type and the map.
594
InlineCacheHolderFlag cache_holder =
595
IC::GetCodeCacheForObject(*object, *holder);
596
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
598
// Compute check type based on receiver/holder.
599
CheckType check = RECEIVER_MAP_CHECK;
600
if (object->IsString()) {
601
check = STRING_CHECK;
602
} else if (object->IsNumber()) {
603
check = NUMBER_CHECK;
604
} else if (object->IsBoolean()) {
605
check = BOOLEAN_CHECK;
609
Code::ComputeMonomorphicFlags(kind, Code::CONSTANT_FUNCTION, extra_state,
611
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
612
if (probe->IsCode()) return Handle<Code>::cast(probe);
614
CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
616
compiler.CompileCallConstant(object, holder, function, name, check);
617
code->set_check_type(check);
618
ASSERT_EQ(flags, code->flags());
620
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
621
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
622
JSObject::UpdateMapCodeCache(map_holder, name, code);
627
Handle<Code> StubCache::ComputeCallField(int argc,
629
Code::ExtraICState extra_state,
631
Handle<Object> object,
632
Handle<JSObject> holder,
634
// Compute the check type and the map.
635
InlineCacheHolderFlag cache_holder =
636
IC::GetCodeCacheForObject(*object, *holder);
637
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
639
// TODO(1233596): We cannot do receiver map check for non-JS objects
640
// because they may be represented as immediates without a
641
// map. Instead, we check against the map in the holder.
642
if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
647
Code::ComputeMonomorphicFlags(kind, Code::FIELD, extra_state,
649
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
650
if (probe->IsCode()) return Handle<Code>::cast(probe);
652
CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
654
compiler.CompileCallField(Handle<JSObject>::cast(object),
655
holder, index, name);
656
ASSERT_EQ(flags, code->flags());
658
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
659
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
660
JSObject::UpdateMapCodeCache(map_holder, name, code);
665
Handle<Code> StubCache::ComputeCallInterceptor(int argc,
667
Code::ExtraICState extra_state,
669
Handle<Object> object,
670
Handle<JSObject> holder) {
671
// Compute the check type and the map.
672
InlineCacheHolderFlag cache_holder =
673
IC::GetCodeCacheForObject(*object, *holder);
674
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
676
// TODO(1233596): We cannot do receiver map check for non-JS objects
677
// because they may be represented as immediates without a
678
// map. Instead, we check against the map in the holder.
679
if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
684
Code::ComputeMonomorphicFlags(kind, Code::INTERCEPTOR, extra_state,
686
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
687
if (probe->IsCode()) return Handle<Code>::cast(probe);
689
CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
691
compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
693
ASSERT_EQ(flags, code->flags());
695
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
696
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
697
JSObject::UpdateMapCodeCache(map_holder, name, code);
702
Handle<Code> StubCache::ComputeCallGlobal(int argc,
704
Code::ExtraICState extra_state,
706
Handle<JSObject> receiver,
707
Handle<GlobalObject> holder,
708
Handle<JSGlobalPropertyCell> cell,
709
Handle<JSFunction> function) {
710
InlineCacheHolderFlag cache_holder =
711
IC::GetCodeCacheForObject(*receiver, *holder);
712
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
714
Code::ComputeMonomorphicFlags(kind, Code::NORMAL, extra_state,
716
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
717
if (probe->IsCode()) return Handle<Code>::cast(probe);
719
CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
721
compiler.CompileCallGlobal(receiver, holder, cell, function, name);
722
ASSERT_EQ(flags, code->flags());
724
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
725
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
726
JSObject::UpdateMapCodeCache(map_holder, name, code);
731
static void FillCache(Isolate* isolate, Handle<Code> code) {
732
Handle<UnseededNumberDictionary> dictionary =
733
UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
736
isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
740
Code* StubCache::FindCallInitialize(int argc,
741
RelocInfo::Mode mode,
743
Code::ExtraICState extra_state =
744
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
745
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
747
Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
749
// Use raw_unchecked... so we don't get assert failures during GC.
750
UnseededNumberDictionary* dictionary =
751
isolate()->heap()->raw_unchecked_non_monomorphic_cache();
752
int entry = dictionary->FindEntry(isolate(), flags);
754
Object* code = dictionary->ValueAt(entry);
755
// This might be called during the marking phase of the collector
756
// hence the unchecked cast.
757
return reinterpret_cast<Code*>(code);
761
Handle<Code> StubCache::ComputeCallInitialize(int argc,
762
RelocInfo::Mode mode,
764
Code::ExtraICState extra_state =
765
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
766
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
768
Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
769
Handle<UnseededNumberDictionary> cache =
770
isolate_->factory()->non_monomorphic_cache();
771
int entry = cache->FindEntry(isolate_, flags);
772
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
774
StubCompiler compiler(isolate_);
775
Handle<Code> code = compiler.CompileCallInitialize(flags);
776
FillCache(isolate_, code);
781
Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
782
return ComputeCallInitialize(argc, mode, Code::CALL_IC);
786
Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
787
return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
788
Code::KEYED_CALL_IC);
792
Handle<Code> StubCache::ComputeCallPreMonomorphic(
795
Code::ExtraICState extra_state) {
797
Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc);
798
Handle<UnseededNumberDictionary> cache =
799
isolate_->factory()->non_monomorphic_cache();
800
int entry = cache->FindEntry(isolate_, flags);
801
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
803
StubCompiler compiler(isolate_);
804
Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
805
FillCache(isolate_, code);
810
Handle<Code> StubCache::ComputeCallNormal(int argc,
812
Code::ExtraICState extra_state) {
814
Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc);
815
Handle<UnseededNumberDictionary> cache =
816
isolate_->factory()->non_monomorphic_cache();
817
int entry = cache->FindEntry(isolate_, flags);
818
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
820
StubCompiler compiler(isolate_);
821
Handle<Code> code = compiler.CompileCallNormal(flags);
822
FillCache(isolate_, code);
827
Handle<Code> StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
828
ASSERT(kind == Code::KEYED_CALL_IC);
830
Code::ComputeFlags(kind, MEGAMORPHIC, Code::kNoExtraICState,
832
Handle<UnseededNumberDictionary> cache =
833
isolate_->factory()->non_monomorphic_cache();
834
int entry = cache->FindEntry(isolate_, flags);
835
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
837
StubCompiler compiler(isolate_);
838
Handle<Code> code = compiler.CompileCallArguments(flags);
839
FillCache(isolate_, code);
844
Handle<Code> StubCache::ComputeCallMegamorphic(
847
Code::ExtraICState extra_state) {
849
Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
851
Handle<UnseededNumberDictionary> cache =
852
isolate_->factory()->non_monomorphic_cache();
853
int entry = cache->FindEntry(isolate_, flags);
854
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
856
StubCompiler compiler(isolate_);
857
Handle<Code> code = compiler.CompileCallMegamorphic(flags);
858
FillCache(isolate_, code);
863
Handle<Code> StubCache::ComputeCallMiss(int argc,
865
Code::ExtraICState extra_state) {
866
// MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
867
// and monomorphic stubs are not mixed up together in the stub cache.
869
Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
870
Code::NORMAL, argc, OWN_MAP);
871
Handle<UnseededNumberDictionary> cache =
872
isolate_->factory()->non_monomorphic_cache();
873
int entry = cache->FindEntry(isolate_, flags);
874
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
876
StubCompiler compiler(isolate_);
877
Handle<Code> code = compiler.CompileCallMiss(flags);
878
FillCache(isolate_, code);
883
#ifdef ENABLE_DEBUGGER_SUPPORT
884
Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
886
// Extra IC state is irrelevant for debug break ICs. They jump to
887
// the actual call ic to carry out the work.
889
Code::ComputeFlags(kind, DEBUG_BREAK, Code::kNoExtraICState,
891
Handle<UnseededNumberDictionary> cache =
892
isolate_->factory()->non_monomorphic_cache();
893
int entry = cache->FindEntry(isolate_, flags);
894
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
896
StubCompiler compiler(isolate_);
897
Handle<Code> code = compiler.CompileCallDebugBreak(flags);
898
FillCache(isolate_, code);
903
Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
905
// Extra IC state is irrelevant for debug break ICs. They jump to
906
// the actual call ic to carry out the work.
908
Code::ComputeFlags(kind, DEBUG_PREPARE_STEP_IN, Code::kNoExtraICState,
910
Handle<UnseededNumberDictionary> cache =
911
isolate_->factory()->non_monomorphic_cache();
912
int entry = cache->FindEntry(isolate_, flags);
913
if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
915
StubCompiler compiler(isolate_);
916
Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
917
FillCache(isolate_, code);
923
void StubCache::Clear() {
924
Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
925
for (int i = 0; i < kPrimaryTableSize; i++) {
926
primary_[i].key = heap()->empty_string();
927
primary_[i].value = empty;
929
for (int j = 0; j < kSecondaryTableSize; j++) {
930
secondary_[j].key = heap()->empty_string();
931
secondary_[j].value = empty;
936
void StubCache::CollectMatchingMaps(SmallMapList* types,
939
Handle<Context> global_context,
941
for (int i = 0; i < kPrimaryTableSize; i++) {
942
if (primary_[i].key == name) {
943
Map* map = primary_[i].value->FindFirstMap();
944
// Map can be NULL, if the stub is constant function call
945
// with a primitive receiver.
946
if (map == NULL) continue;
948
int offset = PrimaryOffset(name, flags, map);
949
if (entry(primary_, offset) == &primary_[i] &&
950
!TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
951
types->Add(Handle<Map>(map), zone);
956
for (int i = 0; i < kSecondaryTableSize; i++) {
957
if (secondary_[i].key == name) {
958
Map* map = secondary_[i].value->FindFirstMap();
959
// Map can be NULL, if the stub is constant function call
960
// with a primitive receiver.
961
if (map == NULL) continue;
963
// Lookup in primary table and skip duplicates.
964
int primary_offset = PrimaryOffset(name, flags, map);
965
Entry* primary_entry = entry(primary_, primary_offset);
966
if (primary_entry->key == name) {
967
Map* primary_map = primary_entry->value->FindFirstMap();
968
if (map == primary_map) continue;
971
// Lookup in secondary table and add matches.
972
int offset = SecondaryOffset(name, flags, primary_offset);
973
if (entry(secondary_, offset) == &secondary_[i] &&
974
!TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
975
types->Add(Handle<Map>(map), zone);
982
// ------------------------------------------------------------------------
983
// StubCompiler implementation.
986
RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
987
ASSERT(args[0]->IsJSObject());
988
ASSERT(args[1]->IsJSObject());
989
ASSERT(args[3]->IsSmi());
990
AccessorInfo* callback = AccessorInfo::cast(args[4]);
991
Address getter_address = v8::ToCData<Address>(callback->getter());
992
v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
994
ASSERT(callback->IsCompatibleReceiver(args[0]));
995
v8::AccessorInfo info(&args[0]);
996
HandleScope scope(isolate);
997
v8::Handle<v8::Value> result;
999
// Leaving JavaScript.
1000
VMState state(isolate, EXTERNAL);
1001
ExternalCallbackScope call_scope(isolate, getter_address);
1002
result = fun(v8::Utils::ToLocal(args.at<String>(5)), info);
1004
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1005
if (result.IsEmpty()) return HEAP->undefined_value();
1006
return *v8::Utils::OpenHandle(*result);
1010
RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
1011
JSObject* recv = JSObject::cast(args[0]);
1012
AccessorInfo* callback = AccessorInfo::cast(args[1]);
1013
Address setter_address = v8::ToCData<Address>(callback->setter());
1014
v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1015
ASSERT(fun != NULL);
1016
ASSERT(callback->IsCompatibleReceiver(recv));
1017
Handle<String> name = args.at<String>(2);
1018
Handle<Object> value = args.at<Object>(3);
1019
HandleScope scope(isolate);
1020
LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
1021
CustomArguments custom_args(isolate, callback->data(), recv, recv);
1022
v8::AccessorInfo info(custom_args.end());
1024
// Leaving JavaScript.
1025
VMState state(isolate, EXTERNAL);
1026
ExternalCallbackScope call_scope(isolate, setter_address);
1027
fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1029
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1034
static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1038
* Attempts to load a property with an interceptor (which must be present),
1039
* but doesn't search the prototype chain.
1041
* Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1042
* provide any value for the given name.
1044
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
1045
Handle<String> name_handle = args.at<String>(0);
1046
Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1047
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1048
ASSERT(args[2]->IsJSObject()); // Receiver.
1049
ASSERT(args[3]->IsJSObject()); // Holder.
1050
ASSERT(args[5]->IsSmi()); // Isolate.
1051
ASSERT(args.length() == 6);
1053
Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1054
v8::NamedPropertyGetter getter =
1055
FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1056
ASSERT(getter != NULL);
1059
// Use the interceptor getter.
1060
v8::AccessorInfo info(args.arguments() -
1061
kAccessorInfoOffsetInInterceptorArgs);
1062
HandleScope scope(isolate);
1063
v8::Handle<v8::Value> r;
1065
// Leaving JavaScript.
1066
VMState state(isolate, EXTERNAL);
1067
r = getter(v8::Utils::ToLocal(name_handle), info);
1069
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1071
return *v8::Utils::OpenHandle(*r);
1075
return isolate->heap()->no_interceptor_result_sentinel();
1079
static MaybeObject* ThrowReferenceError(String* name) {
1080
// If the load is non-contextual, just return the undefined result.
1081
// Note that both keyed and non-keyed loads may end up here, so we
1082
// can't use either LoadIC or KeyedLoadIC constructors.
1083
IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
1084
ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
1085
if (!ic.SlowIsContextual()) return HEAP->undefined_value();
1087
// Throw a reference error.
1089
Handle<String> name_handle(name);
1090
Handle<Object> error =
1091
FACTORY->NewReferenceError("not_defined",
1092
HandleVector(&name_handle, 1));
1093
return Isolate::Current()->Throw(*error);
1097
static MaybeObject* LoadWithInterceptor(Arguments* args,
1098
PropertyAttributes* attrs) {
1099
Handle<String> name_handle = args->at<String>(0);
1100
Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1101
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1102
Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1103
Handle<JSObject> holder_handle = args->at<JSObject>(3);
1104
ASSERT(args->length() == 6);
1106
Isolate* isolate = receiver_handle->GetIsolate();
1108
Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1109
v8::NamedPropertyGetter getter =
1110
FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1111
ASSERT(getter != NULL);
1114
// Use the interceptor getter.
1115
v8::AccessorInfo info(args->arguments() -
1116
kAccessorInfoOffsetInInterceptorArgs);
1117
HandleScope scope(isolate);
1118
v8::Handle<v8::Value> r;
1120
// Leaving JavaScript.
1121
VMState state(isolate, EXTERNAL);
1122
r = getter(v8::Utils::ToLocal(name_handle), info);
1124
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1127
return *v8::Utils::OpenHandle(*r);
1131
MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
1135
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1141
* Loads a property with an interceptor performing post interceptor
1142
* lookup if interceptor failed.
1144
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
1145
PropertyAttributes attr = NONE;
1147
{ MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1148
if (!maybe_result->ToObject(&result)) return maybe_result;
1151
// If the property is present, return it.
1152
if (attr != ABSENT) return result;
1153
return ThrowReferenceError(String::cast(args[0]));
1157
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
1158
PropertyAttributes attr;
1159
MaybeObject* result = LoadWithInterceptor(&args, &attr);
1160
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1161
// This is call IC. In this case, we simply return the undefined result which
1162
// will lead to an exception when trying to invoke the result as a
1168
RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
1169
ASSERT(args.length() == 4);
1170
JSObject* recv = JSObject::cast(args[0]);
1171
String* name = String::cast(args[1]);
1172
Object* value = args[2];
1173
ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode);
1174
StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
1175
ASSERT(recv->HasNamedInterceptor());
1176
PropertyAttributes attr = NONE;
1177
MaybeObject* result = recv->SetPropertyWithInterceptor(
1178
name, value, attr, strict_mode);
1183
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
1184
JSObject* receiver = JSObject::cast(args[0]);
1185
ASSERT(args.smi_at(1) >= 0);
1186
uint32_t index = args.smi_at(1);
1187
return receiver->GetElementWithInterceptor(receiver, index);
1191
Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
1192
int argc = Code::ExtractArgumentsCountFromFlags(flags);
1193
Code::Kind kind = Code::ExtractKindFromFlags(flags);
1194
Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1195
if (kind == Code::CALL_IC) {
1196
CallIC::GenerateInitialize(masm(), argc, extra_state);
1198
KeyedCallIC::GenerateInitialize(masm(), argc);
1200
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
1201
isolate()->counters()->call_initialize_stubs()->Increment();
1203
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1204
*code, code->arguments_count()));
1205
GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
1210
Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1211
int argc = Code::ExtractArgumentsCountFromFlags(flags);
1212
// The code of the PreMonomorphic stub is the same as the code
1213
// of the Initialized stub. They just differ on the code object flags.
1214
Code::Kind kind = Code::ExtractKindFromFlags(flags);
1215
Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1216
if (kind == Code::CALL_IC) {
1217
CallIC::GenerateInitialize(masm(), argc, extra_state);
1219
KeyedCallIC::GenerateInitialize(masm(), argc);
1221
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1222
isolate()->counters()->call_premonomorphic_stubs()->Increment();
1224
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1225
*code, code->arguments_count()));
1226
GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
1231
Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
1232
int argc = Code::ExtractArgumentsCountFromFlags(flags);
1233
Code::Kind kind = Code::ExtractKindFromFlags(flags);
1234
if (kind == Code::CALL_IC) {
1235
// Call normal is always with a explict receiver.
1236
ASSERT(!CallIC::Contextual::decode(
1237
Code::ExtractExtraICStateFromFlags(flags)));
1238
CallIC::GenerateNormal(masm(), argc);
1240
KeyedCallIC::GenerateNormal(masm(), argc);
1242
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
1243
isolate()->counters()->call_normal_stubs()->Increment();
1245
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1246
*code, code->arguments_count()));
1247
GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
1252
Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1253
int argc = Code::ExtractArgumentsCountFromFlags(flags);
1254
Code::Kind kind = Code::ExtractKindFromFlags(flags);
1255
Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1256
if (kind == Code::CALL_IC) {
1257
CallIC::GenerateMegamorphic(masm(), argc, extra_state);
1259
KeyedCallIC::GenerateMegamorphic(masm(), argc);
1261
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
1262
isolate()->counters()->call_megamorphic_stubs()->Increment();
1264
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1265
*code, code->arguments_count()));
1266
GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1271
Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
1272
int argc = Code::ExtractArgumentsCountFromFlags(flags);
1273
KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
1274
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
1276
CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1277
CALL_MEGAMORPHIC_TAG),
1278
*code, code->arguments_count()));
1279
GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1284
Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
1285
int argc = Code::ExtractArgumentsCountFromFlags(flags);
1286
Code::Kind kind = Code::ExtractKindFromFlags(flags);
1287
Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1288
if (kind == Code::CALL_IC) {
1289
CallIC::GenerateMiss(masm(), argc, extra_state);
1291
KeyedCallIC::GenerateMiss(masm(), argc);
1293
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
1294
isolate()->counters()->call_megamorphic_stubs()->Increment();
1296
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1297
*code, code->arguments_count()));
1298
GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
1303
#ifdef ENABLE_DEBUGGER_SUPPORT
1304
Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1305
Debug::GenerateCallICDebugBreak(masm());
1306
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1308
CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1309
CALL_DEBUG_BREAK_TAG),
1310
*code, code->arguments_count()));
1315
Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1316
// Use the same code for the the step in preparations as we do for the
1318
int argc = Code::ExtractArgumentsCountFromFlags(flags);
1319
Code::Kind kind = Code::ExtractKindFromFlags(flags);
1320
if (kind == Code::CALL_IC) {
1321
// For the debugger extra ic state is irrelevant.
1322
CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
1324
KeyedCallIC::GenerateMiss(masm(), argc);
1326
Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1329
CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1331
code->arguments_count()));
1334
#endif // ENABLE_DEBUGGER_SUPPORT
1336
#undef CALL_LOGGER_TAG
1339
Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1341
// Create code object in the heap.
1343
masm_.GetCode(&desc);
1344
Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
1345
#ifdef ENABLE_DISASSEMBLER
1346
if (FLAG_print_code_stubs) code->Disassemble(name);
1352
Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1353
Handle<String> name) {
1354
return (FLAG_print_code_stubs && !name.is_null())
1355
? GetCodeWithFlags(flags, *name->ToCString())
1356
: GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1360
void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
1361
Handle<String> name,
1362
LookupResult* lookup) {
1363
holder->LocalLookupRealNamedProperty(*name, lookup);
1364
if (lookup->IsFound()) return;
1365
if (holder->GetPrototype()->IsNull()) return;
1366
holder->GetPrototype()->Lookup(*name, lookup);
1370
Handle<Code> LoadStubCompiler::GetCode(Code::StubType type,
1371
Handle<String> name) {
1372
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
1373
Handle<Code> code = GetCodeWithFlags(flags, name);
1374
PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
1375
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
1380
Handle<Code> KeyedLoadStubCompiler::GetCode(Code::StubType type,
1381
Handle<String> name,
1382
InlineCacheState state) {
1383
Code::Flags flags = Code::ComputeFlags(
1384
Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
1385
Handle<Code> code = GetCodeWithFlags(flags, name);
1386
PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
1387
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
1392
Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
1393
Handle<String> name) {
1395
Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
1396
Handle<Code> code = GetCodeWithFlags(flags, name);
1397
PROFILE(isolate(), CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
1398
GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
1403
Handle<Code> KeyedStoreStubCompiler::GetCode(Code::StubType type,
1404
Handle<String> name,
1405
InlineCacheState state) {
1406
Code::ExtraICState extra_state =
1407
Code::ComputeExtraICState(grow_mode_, strict_mode_);
1409
Code::ComputeFlags(Code::KEYED_STORE_IC, state, extra_state, type);
1410
Handle<Code> code = GetCodeWithFlags(flags, name);
1411
PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
1412
GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
1417
void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1418
MacroAssembler* masm) {
1419
KeyedStoreIC::GenerateSlow(masm);
1423
CallStubCompiler::CallStubCompiler(Isolate* isolate,
1426
Code::ExtraICState extra_state,
1427
InlineCacheHolderFlag cache_holder)
1428
: StubCompiler(isolate),
1431
extra_state_(extra_state),
1432
cache_holder_(cache_holder) {
1436
bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
1437
if (function->shared()->HasBuiltinFunctionId()) {
1438
BuiltinFunctionId id = function->shared()->builtin_function_id();
1439
#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1440
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1441
#undef CALL_GENERATOR_CASE
1444
CallOptimization optimization(function);
1445
return optimization.is_simple_api_call();
1449
Handle<Code> CallStubCompiler::CompileCustomCall(
1450
Handle<Object> object,
1451
Handle<JSObject> holder,
1452
Handle<JSGlobalPropertyCell> cell,
1453
Handle<JSFunction> function,
1454
Handle<String> fname) {
1455
ASSERT(HasCustomCallGenerator(function));
1457
if (function->shared()->HasBuiltinFunctionId()) {
1458
BuiltinFunctionId id = function->shared()->builtin_function_id();
1459
#define CALL_GENERATOR_CASE(name) \
1460
if (id == k##name) { \
1461
return CallStubCompiler::Compile##name##Call(object, \
1467
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1468
#undef CALL_GENERATOR_CASE
1470
CallOptimization optimization(function);
1471
ASSERT(optimization.is_simple_api_call());
1472
return CompileFastApiCall(optimization,
1481
Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
1482
Handle<String> name) {
1483
int argc = arguments_.immediate();
1484
Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
1489
return GetCodeWithFlags(flags, name);
1493
Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
1494
Handle<String> function_name;
1495
if (function->shared()->name()->IsString()) {
1496
function_name = Handle<String>(String::cast(function->shared()->name()));
1498
return GetCode(Code::CONSTANT_FUNCTION, function_name);
1502
Handle<Code> ConstructStubCompiler::GetCode() {
1503
Code::Flags flags = Code::ComputeFlags(Code::STUB);
1504
Handle<Code> code = GetCodeWithFlags(flags, "ConstructStub");
1505
PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, "ConstructStub"));
1506
GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", *code));
1511
CallOptimization::CallOptimization(LookupResult* lookup) {
1512
if (lookup->IsFound() &&
1513
lookup->IsCacheable() &&
1514
lookup->type() == CONSTANT_FUNCTION) {
1515
// We only optimize constant function calls.
1516
Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1518
Initialize(Handle<JSFunction>::null());
1522
CallOptimization::CallOptimization(Handle<JSFunction> function) {
1523
Initialize(function);
1527
int CallOptimization::GetPrototypeDepthOfExpectedType(
1528
Handle<JSObject> object,
1529
Handle<JSObject> holder) const {
1530
ASSERT(is_simple_api_call());
1531
if (expected_receiver_type_.is_null()) return 0;
1533
while (!object.is_identical_to(holder)) {
1534
if (object->IsInstanceOf(*expected_receiver_type_)) return depth;
1535
object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
1538
if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
1539
return kInvalidProtoDepth;
1543
void CallOptimization::Initialize(Handle<JSFunction> function) {
1544
constant_function_ = Handle<JSFunction>::null();
1545
is_simple_api_call_ = false;
1546
expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1547
api_call_info_ = Handle<CallHandlerInfo>::null();
1549
if (function.is_null() || !function->is_compiled()) return;
1551
constant_function_ = function;
1552
AnalyzePossibleApiFunction(function);
1556
void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1557
if (!function->shared()->IsApiFunction()) return;
1558
Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1560
// Require a C++ callback.
1561
if (info->call_code()->IsUndefined()) return;
1563
Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1565
// Accept signatures that either have no restrictions at all or
1566
// only have restrictions on the receiver.
1567
if (!info->signature()->IsUndefined()) {
1568
Handle<SignatureInfo> signature =
1569
Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1570
if (!signature->args()->IsUndefined()) return;
1571
if (!signature->receiver()->IsUndefined()) {
1572
expected_receiver_type_ =
1573
Handle<FunctionTemplateInfo>(
1574
FunctionTemplateInfo::cast(signature->receiver()));
1578
is_simple_api_call_ = true;
1582
} } // namespace v8::internal