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
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 "ast.h"
33#include "code-stubs.h"
34#include "gdb-jit.h"
35#include "ic-inl.h"
36#include "stub-cache.h"
37#include "vm-state-inl.h"
38
39namespace v8 {
40namespace internal {
41
42// -----------------------------------------------------------------------
43// StubCache implementation.
44
45
46StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
47  ASSERT(isolate == Isolate::Current());
48}
49
50
51void StubCache::Initialize() {
52  ASSERT(IsPowerOf2(kPrimaryTableSize));
53  ASSERT(IsPowerOf2(kSecondaryTableSize));
54  Clear();
55}
56
57
58Code* StubCache::Set(String* name, Map* map, Code* code) {
59  // Get the flags from the code.
60  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
61
62  // Validate that the name does not move on scavenge, and that we
63  // can use identity checks instead of string equality checks.
64  ASSERT(!heap()->InNewSpace(name));
65  ASSERT(name->IsSymbol());
66
67  // The state bits are not important to the hash function because
68  // the stub cache only contains monomorphic stubs. Make sure that
69  // the bits are the least significant so they will be the ones
70  // masked out.
71  ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
72  STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
73
74  // Make sure that the code type is not included in the hash.
75  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
76
77  // Compute the primary entry.
78  int primary_offset = PrimaryOffset(name, flags, map);
79  Entry* primary = entry(primary_, primary_offset);
80  Code* old_code = primary->value;
81
82  // If the primary entry has useful data in it, we retire it to the
83  // secondary cache before overwriting it.
84  if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
85    Map* old_map = primary->map;
86    Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
87    int seed = PrimaryOffset(primary->key, old_flags, old_map);
88    int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
89    Entry* secondary = entry(secondary_, secondary_offset);
90    *secondary = *primary;
91  }
92
93  // Update primary cache.
94  primary->key = name;
95  primary->value = code;
96  primary->map = map;
97  isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
98  return code;
99}
100
101
102Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
103                                               Handle<JSObject> receiver) {
104  ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
105  // If no global objects are present in the prototype chain, the load
106  // nonexistent IC stub can be shared for all names for a given map
107  // and we use the empty string for the map cache in that case.  If
108  // there are global objects involved, we need to check global
109  // property cells in the stub and therefore the stub will be
110  // specific to the name.
111  Handle<String> cache_name = factory()->empty_string();
112  if (receiver->IsGlobalObject()) cache_name = name;
113  Handle<JSObject> last = receiver;
114  while (last->GetPrototype() != heap()->null_value()) {
115    last = Handle<JSObject>(JSObject::cast(last->GetPrototype()));
116    if (last->IsGlobalObject()) cache_name = name;
117  }
118  // Compile the stub that is either shared for all names or
119  // name specific if there are global objects involved.
120  Code::Flags flags =
121      Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
122  Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags));
123  if (probe->IsCode()) return Handle<Code>::cast(probe);
124
125  LoadStubCompiler compiler(isolate_);
126  Handle<Code> code =
127      compiler.CompileLoadNonexistent(cache_name, receiver, last);
128  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
129  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
130  JSObject::UpdateMapCodeCache(receiver, cache_name, code);
131  return code;
132}
133
134
135Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
136                                         Handle<JSObject> receiver,
137                                         Handle<JSObject> holder,
138                                         int field_index) {
139  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
140  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
141  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
142  if (probe->IsCode()) return Handle<Code>::cast(probe);
143
144  LoadStubCompiler compiler(isolate_);
145  Handle<Code> code =
146      compiler.CompileLoadField(receiver, holder, field_index, name);
147  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
148  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
149  JSObject::UpdateMapCodeCache(receiver, name, code);
150  return code;
151}
152
153
154Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name,
155                                            Handle<JSObject> receiver,
156                                            Handle<JSObject> holder,
157                                            Handle<AccessorInfo> callback) {
158  ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
159  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
160  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
161  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
162  if (probe->IsCode()) return Handle<Code>::cast(probe);
163
164  LoadStubCompiler compiler(isolate_);
165  Handle<Code> code =
166      compiler.CompileLoadCallback(name, receiver, holder, callback);
167  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
168  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
169  JSObject::UpdateMapCodeCache(receiver, name, code);
170  return code;
171}
172
173
174Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
175                                            Handle<JSObject> receiver,
176                                            Handle<JSObject> holder,
177                                            Handle<JSFunction> value) {
178  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
179  Code::Flags flags =
180      Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
181  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
182  if (probe->IsCode()) return Handle<Code>::cast(probe);
183
184  LoadStubCompiler compiler(isolate_);
185  Handle<Code> code =
186        compiler.CompileLoadConstant(receiver, holder, value, name);
187  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
188  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
189  JSObject::UpdateMapCodeCache(receiver, name, code);
190  return code;
191}
192
193
194Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
195                                               Handle<JSObject> receiver,
196                                               Handle<JSObject> holder) {
197  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
198  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
199  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
200  if (probe->IsCode()) return Handle<Code>::cast(probe);
201
202  LoadStubCompiler compiler(isolate_);
203  Handle<Code> code =
204        compiler.CompileLoadInterceptor(receiver, holder, name);
205  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
206  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
207  JSObject::UpdateMapCodeCache(receiver, name, code);
208  return code;
209}
210
211
212Handle<Code> StubCache::ComputeLoadNormal() {
213  return isolate_->builtins()->LoadIC_Normal();
214}
215
216
217Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
218                                          Handle<JSObject> receiver,
219                                          Handle<GlobalObject> holder,
220                                          Handle<JSGlobalPropertyCell> cell,
221                                          bool is_dont_delete) {
222  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
223  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
224  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
225  if (probe->IsCode()) return Handle<Code>::cast(probe);
226
227  LoadStubCompiler compiler(isolate_);
228  Handle<Code> code =
229      compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
230  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
231  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
232  JSObject::UpdateMapCodeCache(receiver, name, code);
233  return code;
234}
235
236
237Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
238                                              Handle<JSObject> receiver,
239                                              Handle<JSObject> holder,
240                                              int field_index) {
241  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
242  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
243  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
244  if (probe->IsCode()) return Handle<Code>::cast(probe);
245
246  KeyedLoadStubCompiler compiler(isolate_);
247  Handle<Code> code =
248      compiler.CompileLoadField(name, receiver, holder, field_index);
249  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
250  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
251  JSObject::UpdateMapCodeCache(receiver, name, code);
252  return code;
253}
254
255
256Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
257                                                 Handle<JSObject> receiver,
258                                                 Handle<JSObject> holder,
259                                                 Handle<JSFunction> value) {
260  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
261  Code::Flags flags =
262      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
263  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
264  if (probe->IsCode()) return Handle<Code>::cast(probe);
265
266  KeyedLoadStubCompiler compiler(isolate_);
267  Handle<Code> code =
268      compiler.CompileLoadConstant(name, receiver, holder, value);
269  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
270  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
271  JSObject::UpdateMapCodeCache(receiver, name, code);
272  return code;
273}
274
275
276Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
277                                                    Handle<JSObject> receiver,
278                                                    Handle<JSObject> holder) {
279  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
280  Code::Flags flags =
281      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
282  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
283  if (probe->IsCode()) return Handle<Code>::cast(probe);
284
285  KeyedLoadStubCompiler compiler(isolate_);
286  Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
287  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
288  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
289  JSObject::UpdateMapCodeCache(receiver, name, code);
290  return code;
291}
292
293
294Handle<Code> StubCache::ComputeKeyedLoadCallback(
295    Handle<String> name,
296    Handle<JSObject> receiver,
297    Handle<JSObject> holder,
298    Handle<AccessorInfo> callback) {
299  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
300  Code::Flags flags =
301      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
302  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
303  if (probe->IsCode()) return Handle<Code>::cast(probe);
304
305  KeyedLoadStubCompiler compiler(isolate_);
306  Handle<Code> code =
307      compiler.CompileLoadCallback(name, receiver, holder, callback);
308  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
309  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
310  JSObject::UpdateMapCodeCache(receiver, name, code);
311  return code;
312}
313
314
315Handle<Code> StubCache::ComputeKeyedLoadArrayLength(Handle<String> name,
316                                                    Handle<JSArray> receiver) {
317  Code::Flags flags =
318      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
319  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
320  if (probe->IsCode()) return Handle<Code>::cast(probe);
321
322  KeyedLoadStubCompiler compiler(isolate_);
323  Handle<Code> code = compiler.CompileLoadArrayLength(name);
324  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
325  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
326  JSObject::UpdateMapCodeCache(receiver, name, code);
327  return code;
328}
329
330
331Handle<Code> StubCache::ComputeKeyedLoadStringLength(Handle<String> name,
332                                                     Handle<String> receiver) {
333  Code::Flags flags =
334      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
335  Handle<Map> map(receiver->map());
336  Handle<Object> probe(map->FindInCodeCache(*name, flags));
337  if (probe->IsCode()) return Handle<Code>::cast(probe);
338
339  KeyedLoadStubCompiler compiler(isolate_);
340  Handle<Code> code = compiler.CompileLoadStringLength(name);
341  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
342  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
343  Map::UpdateCodeCache(map, name, code);
344  return code;
345}
346
347
348Handle<Code> StubCache::ComputeKeyedLoadFunctionPrototype(
349    Handle<String> name,
350    Handle<JSFunction> receiver) {
351  Code::Flags flags =
352      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
353  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
354  if (probe->IsCode()) return Handle<Code>::cast(probe);
355
356  KeyedLoadStubCompiler compiler(isolate_);
357  Handle<Code> code = compiler.CompileLoadFunctionPrototype(name);
358  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
359  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
360  JSObject::UpdateMapCodeCache(receiver, name, code);
361  return code;
362}
363
364
365Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
366                                          Handle<JSObject> receiver,
367                                          int field_index,
368                                          Handle<Map> transition,
369                                          StrictModeFlag strict_mode) {
370  PropertyType type = (transition.is_null()) ? FIELD : MAP_TRANSITION;
371  Code::Flags flags = Code::ComputeMonomorphicFlags(
372      Code::STORE_IC, type, strict_mode);
373  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
374  if (probe->IsCode()) return Handle<Code>::cast(probe);
375
376  StoreStubCompiler compiler(isolate_, strict_mode);
377  Handle<Code> code =
378      compiler.CompileStoreField(receiver, field_index, transition, name);
379  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
380  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
381  JSObject::UpdateMapCodeCache(receiver, name, code);
382  return code;
383}
384
385
386Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement(
387    Handle<JSObject> receiver,
388    KeyedIC::StubKind stub_kind,
389    StrictModeFlag strict_mode) {
390  KeyedAccessGrowMode grow_mode =
391      KeyedIC::GetGrowModeFromStubKind(stub_kind);
392  Code::ExtraICState extra_state =
393      Code::ComputeExtraICState(grow_mode, strict_mode);
394  Code::Flags flags =
395      Code::ComputeMonomorphicFlags(
396          stub_kind == KeyedIC::LOAD ? Code::KEYED_LOAD_IC
397                                     : Code::KEYED_STORE_IC,
398          NORMAL,
399          extra_state);
400  Handle<String> name;
401  switch (stub_kind) {
402    case KeyedIC::LOAD:
403      name = isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
404      break;
405    case KeyedIC::STORE_NO_TRANSITION:
406      name = isolate()->factory()->KeyedStoreElementMonomorphic_symbol();
407      break;
408    case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
409      name = isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
410      break;
411    default:
412      UNREACHABLE();
413      break;
414  }
415  Handle<Map> receiver_map(receiver->map());
416  Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags));
417  if (probe->IsCode()) return Handle<Code>::cast(probe);
418
419  Handle<Code> code;
420  switch (stub_kind) {
421    case KeyedIC::LOAD: {
422      KeyedLoadStubCompiler compiler(isolate_);
423      code = compiler.CompileLoadElement(receiver_map);
424      break;
425    }
426    case KeyedIC::STORE_AND_GROW_NO_TRANSITION: {
427      KeyedStoreStubCompiler compiler(isolate_, strict_mode,
428                                      ALLOW_JSARRAY_GROWTH);
429      code = compiler.CompileStoreElement(receiver_map);
430      break;
431    }
432    case KeyedIC::STORE_NO_TRANSITION: {
433      KeyedStoreStubCompiler compiler(isolate_, strict_mode,
434                                      DO_NOT_ALLOW_JSARRAY_GROWTH);
435      code = compiler.CompileStoreElement(receiver_map);
436      break;
437    }
438    default:
439      UNREACHABLE();
440      break;
441  }
442
443  ASSERT(!code.is_null());
444
445  if (stub_kind == KeyedIC::LOAD) {
446    PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
447  } else {
448    PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
449  }
450  JSObject::UpdateMapCodeCache(receiver, name, code);
451  return code;
452}
453
454
455Handle<Code> StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
456  return (strict_mode == kStrictMode)
457      ? isolate_->builtins()->Builtins::StoreIC_Normal_Strict()
458      : isolate_->builtins()->Builtins::StoreIC_Normal();
459}
460
461
462Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
463                                           Handle<GlobalObject> receiver,
464                                           Handle<JSGlobalPropertyCell> cell,
465                                           StrictModeFlag strict_mode) {
466  Code::Flags flags = Code::ComputeMonomorphicFlags(
467      Code::STORE_IC, NORMAL, strict_mode);
468  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
469  if (probe->IsCode()) return Handle<Code>::cast(probe);
470
471  StoreStubCompiler compiler(isolate_, strict_mode);
472  Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
473  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
474  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
475  JSObject::UpdateMapCodeCache(receiver, name, code);
476  return code;
477}
478
479
480Handle<Code> StubCache::ComputeStoreCallback(Handle<String> name,
481                                             Handle<JSObject> receiver,
482                                             Handle<AccessorInfo> callback,
483                                             StrictModeFlag strict_mode) {
484  ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
485  Code::Flags flags = Code::ComputeMonomorphicFlags(
486      Code::STORE_IC, CALLBACKS, strict_mode);
487  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
488  if (probe->IsCode()) return Handle<Code>::cast(probe);
489
490  StoreStubCompiler compiler(isolate_, strict_mode);
491  Handle<Code> code = compiler.CompileStoreCallback(receiver, callback, name);
492  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
493  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
494  JSObject::UpdateMapCodeCache(receiver, name, code);
495  return code;
496}
497
498
499Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
500                                                Handle<JSObject> receiver,
501                                                StrictModeFlag strict_mode) {
502  Code::Flags flags = Code::ComputeMonomorphicFlags(
503      Code::STORE_IC, INTERCEPTOR, strict_mode);
504  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
505  if (probe->IsCode()) return Handle<Code>::cast(probe);
506
507  StoreStubCompiler compiler(isolate_, strict_mode);
508  Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
509  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
510  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
511  JSObject::UpdateMapCodeCache(receiver, name, code);
512  return code;
513}
514
515Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
516                                               Handle<JSObject> receiver,
517                                               int field_index,
518                                               Handle<Map> transition,
519                                               StrictModeFlag strict_mode) {
520  PropertyType type = (transition.is_null()) ? FIELD : MAP_TRANSITION;
521  Code::Flags flags = Code::ComputeMonomorphicFlags(
522      Code::KEYED_STORE_IC, type, strict_mode);
523  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
524  if (probe->IsCode()) return Handle<Code>::cast(probe);
525
526  KeyedStoreStubCompiler compiler(isolate(), strict_mode,
527                                  DO_NOT_ALLOW_JSARRAY_GROWTH);
528  Handle<Code> code =
529      compiler.CompileStoreField(receiver, field_index, transition, name);
530  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
531  GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
532  JSObject::UpdateMapCodeCache(receiver, name, code);
533  return code;
534}
535
536
537#define CALL_LOGGER_TAG(kind, type) \
538    (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
539
540Handle<Code> StubCache::ComputeCallConstant(int argc,
541                                            Code::Kind kind,
542                                            Code::ExtraICState extra_state,
543                                            Handle<String> name,
544                                            Handle<Object> object,
545                                            Handle<JSObject> holder,
546                                            Handle<JSFunction> function) {
547  // Compute the check type and the map.
548  InlineCacheHolderFlag cache_holder =
549      IC::GetCodeCacheForObject(*object, *holder);
550  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
551
552  // Compute check type based on receiver/holder.
553  CheckType check = RECEIVER_MAP_CHECK;
554  if (object->IsString()) {
555    check = STRING_CHECK;
556  } else if (object->IsNumber()) {
557    check = NUMBER_CHECK;
558  } else if (object->IsBoolean()) {
559    check = BOOLEAN_CHECK;
560  }
561
562  Code::Flags flags =
563      Code::ComputeMonomorphicFlags(kind, CONSTANT_FUNCTION, extra_state,
564                                    cache_holder, argc);
565  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
566  if (probe->IsCode()) return Handle<Code>::cast(probe);
567
568  CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
569  Handle<Code> code =
570      compiler.CompileCallConstant(object, holder, function, name, check);
571  code->set_check_type(check);
572  ASSERT_EQ(flags, code->flags());
573  PROFILE(isolate_,
574          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
575  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
576  JSObject::UpdateMapCodeCache(map_holder, name, code);
577  return code;
578}
579
580
581Handle<Code> StubCache::ComputeCallField(int argc,
582                                         Code::Kind kind,
583                                         Code::ExtraICState extra_state,
584                                         Handle<String> name,
585                                         Handle<Object> object,
586                                         Handle<JSObject> holder,
587                                         int index) {
588  // Compute the check type and the map.
589  InlineCacheHolderFlag cache_holder =
590      IC::GetCodeCacheForObject(*object, *holder);
591  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
592
593  // TODO(1233596): We cannot do receiver map check for non-JS objects
594  // because they may be represented as immediates without a
595  // map. Instead, we check against the map in the holder.
596  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
597    object = holder;
598  }
599
600  Code::Flags flags =
601      Code::ComputeMonomorphicFlags(kind, FIELD, extra_state,
602                                    cache_holder, argc);
603  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
604  if (probe->IsCode()) return Handle<Code>::cast(probe);
605
606  CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
607  Handle<Code> code =
608      compiler.CompileCallField(Handle<JSObject>::cast(object),
609                                holder, index, name);
610  ASSERT_EQ(flags, code->flags());
611  PROFILE(isolate_,
612          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
613  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
614  JSObject::UpdateMapCodeCache(map_holder, name, code);
615  return code;
616}
617
618
619Handle<Code> StubCache::ComputeCallInterceptor(int argc,
620                                               Code::Kind kind,
621                                               Code::ExtraICState extra_state,
622                                               Handle<String> name,
623                                               Handle<Object> object,
624                                               Handle<JSObject> holder) {
625  // Compute the check type and the map.
626  InlineCacheHolderFlag cache_holder =
627      IC::GetCodeCacheForObject(*object, *holder);
628  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
629
630  // TODO(1233596): We cannot do receiver map check for non-JS objects
631  // because they may be represented as immediates without a
632  // map. Instead, we check against the map in the holder.
633  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
634    object = holder;
635  }
636
637  Code::Flags flags =
638      Code::ComputeMonomorphicFlags(kind, INTERCEPTOR, extra_state,
639                                    cache_holder, argc);
640  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
641  if (probe->IsCode()) return Handle<Code>::cast(probe);
642
643  CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
644  Handle<Code> code =
645      compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
646                                      holder, name);
647  ASSERT_EQ(flags, code->flags());
648  PROFILE(isolate(),
649          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
650  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
651  JSObject::UpdateMapCodeCache(map_holder, name, code);
652  return code;
653}
654
655
656Handle<Code> StubCache::ComputeCallGlobal(int argc,
657                                          Code::Kind kind,
658                                          Code::ExtraICState extra_state,
659                                          Handle<String> name,
660                                          Handle<JSObject> receiver,
661                                          Handle<GlobalObject> holder,
662                                          Handle<JSGlobalPropertyCell> cell,
663                                          Handle<JSFunction> function) {
664  InlineCacheHolderFlag cache_holder =
665      IC::GetCodeCacheForObject(*receiver, *holder);
666  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
667  Code::Flags flags =
668      Code::ComputeMonomorphicFlags(kind, NORMAL, extra_state,
669                                    cache_holder, argc);
670  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
671  if (probe->IsCode()) return Handle<Code>::cast(probe);
672
673  CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
674  Handle<Code> code =
675      compiler.CompileCallGlobal(receiver, holder, cell, function, name);
676  ASSERT_EQ(flags, code->flags());
677  PROFILE(isolate(),
678          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
679  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
680  JSObject::UpdateMapCodeCache(map_holder, name, code);
681  return code;
682}
683
684
685static void FillCache(Isolate* isolate, Handle<Code> code) {
686  Handle<UnseededNumberDictionary> dictionary =
687      UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
688                                    code->flags(),
689                                    code);
690  isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
691}
692
693
694Code* StubCache::FindCallInitialize(int argc,
695                                    RelocInfo::Mode mode,
696                                    Code::Kind kind) {
697  Code::ExtraICState extra_state =
698      CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
699      CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
700  Code::Flags flags =
701      Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc);
702
703  // Use raw_unchecked... so we don't get assert failures during GC.
704  UnseededNumberDictionary* dictionary =
705      isolate()->heap()->raw_unchecked_non_monomorphic_cache();
706  int entry = dictionary->FindEntry(isolate(), flags);
707  ASSERT(entry != -1);
708  Object* code = dictionary->ValueAt(entry);
709  // This might be called during the marking phase of the collector
710  // hence the unchecked cast.
711  return reinterpret_cast<Code*>(code);
712}
713
714
715Handle<Code> StubCache::ComputeCallInitialize(int argc,
716                                              RelocInfo::Mode mode,
717                                              Code::Kind kind) {
718  Code::ExtraICState extra_state =
719      CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
720      CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
721  Code::Flags flags =
722      Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc);
723  Handle<UnseededNumberDictionary> cache =
724      isolate_->factory()->non_monomorphic_cache();
725  int entry = cache->FindEntry(isolate_, flags);
726  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
727
728  StubCompiler compiler(isolate_);
729  Handle<Code> code = compiler.CompileCallInitialize(flags);
730  FillCache(isolate_, code);
731  return code;
732}
733
734
735Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
736  return ComputeCallInitialize(argc, mode, Code::CALL_IC);
737}
738
739
740Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
741  return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
742                               Code::KEYED_CALL_IC);
743}
744
745
746Handle<Code> StubCache::ComputeCallPreMonomorphic(
747    int argc,
748    Code::Kind kind,
749    Code::ExtraICState extra_state) {
750  Code::Flags flags =
751      Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, NORMAL, argc);
752  Handle<UnseededNumberDictionary> cache =
753      isolate_->factory()->non_monomorphic_cache();
754  int entry = cache->FindEntry(isolate_, flags);
755  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
756
757  StubCompiler compiler(isolate_);
758  Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
759  FillCache(isolate_, code);
760  return code;
761}
762
763
764Handle<Code> StubCache::ComputeCallNormal(int argc,
765                                          Code::Kind kind,
766                                          Code::ExtraICState extra_state) {
767  Code::Flags flags =
768      Code::ComputeFlags(kind, MONOMORPHIC, extra_state, 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)));
773
774  StubCompiler compiler(isolate_);
775  Handle<Code> code = compiler.CompileCallNormal(flags);
776  FillCache(isolate_, code);
777  return code;
778}
779
780
781Handle<Code> StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
782  ASSERT(kind == Code::KEYED_CALL_IC);
783  Code::Flags flags =
784      Code::ComputeFlags(kind, MEGAMORPHIC, Code::kNoExtraICState,
785                         NORMAL, argc);
786  Handle<UnseededNumberDictionary> cache =
787      isolate_->factory()->non_monomorphic_cache();
788  int entry = cache->FindEntry(isolate_, flags);
789  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
790
791  StubCompiler compiler(isolate_);
792  Handle<Code> code = compiler.CompileCallArguments(flags);
793  FillCache(isolate_, code);
794  return code;
795}
796
797
798Handle<Code> StubCache::ComputeCallMegamorphic(
799    int argc,
800    Code::Kind kind,
801    Code::ExtraICState extra_state) {
802  Code::Flags flags =
803      Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
804                         NORMAL, argc);
805  Handle<UnseededNumberDictionary> cache =
806      isolate_->factory()->non_monomorphic_cache();
807  int entry = cache->FindEntry(isolate_, flags);
808  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
809
810  StubCompiler compiler(isolate_);
811  Handle<Code> code = compiler.CompileCallMegamorphic(flags);
812  FillCache(isolate_, code);
813  return code;
814}
815
816
817Handle<Code> StubCache::ComputeCallMiss(int argc,
818                                        Code::Kind kind,
819                                        Code::ExtraICState extra_state) {
820  // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
821  // and monomorphic stubs are not mixed up together in the stub cache.
822  Code::Flags flags =
823      Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
824                         NORMAL, argc, OWN_MAP);
825  Handle<UnseededNumberDictionary> cache =
826      isolate_->factory()->non_monomorphic_cache();
827  int entry = cache->FindEntry(isolate_, flags);
828  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
829
830  StubCompiler compiler(isolate_);
831  Handle<Code> code = compiler.CompileCallMiss(flags);
832  FillCache(isolate_, code);
833  return code;
834}
835
836
837#ifdef ENABLE_DEBUGGER_SUPPORT
838Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
839                                              Code::Kind kind) {
840  // Extra IC state is irrelevant for debug break ICs. They jump to
841  // the actual call ic to carry out the work.
842  Code::Flags flags =
843      Code::ComputeFlags(kind, DEBUG_BREAK, Code::kNoExtraICState,
844                         NORMAL, argc);
845  Handle<UnseededNumberDictionary> cache =
846      isolate_->factory()->non_monomorphic_cache();
847  int entry = cache->FindEntry(isolate_, flags);
848  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
849
850  StubCompiler compiler(isolate_);
851  Handle<Code> code = compiler.CompileCallDebugBreak(flags);
852  FillCache(isolate_, code);
853  return code;
854}
855
856
857Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
858                                                      Code::Kind kind) {
859  // Extra IC state is irrelevant for debug break ICs. They jump to
860  // the actual call ic to carry out the work.
861  Code::Flags flags =
862      Code::ComputeFlags(kind, DEBUG_PREPARE_STEP_IN, Code::kNoExtraICState,
863                         NORMAL, argc);
864  Handle<UnseededNumberDictionary> cache =
865      isolate_->factory()->non_monomorphic_cache();
866  int entry = cache->FindEntry(isolate_, flags);
867  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
868
869  StubCompiler compiler(isolate_);
870  Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
871  FillCache(isolate_, code);
872  return code;
873}
874#endif
875
876
877void StubCache::Clear() {
878  Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
879  for (int i = 0; i < kPrimaryTableSize; i++) {
880    primary_[i].key = heap()->empty_string();
881    primary_[i].value = empty;
882  }
883  for (int j = 0; j < kSecondaryTableSize; j++) {
884    secondary_[j].key = heap()->empty_string();
885    secondary_[j].value = empty;
886  }
887}
888
889
890void StubCache::CollectMatchingMaps(SmallMapList* types,
891                                    String* name,
892                                    Code::Flags flags,
893                                    Handle<Context> global_context) {
894  for (int i = 0; i < kPrimaryTableSize; i++) {
895    if (primary_[i].key == name) {
896      Map* map = primary_[i].value->FindFirstMap();
897      // Map can be NULL, if the stub is constant function call
898      // with a primitive receiver.
899      if (map == NULL) continue;
900
901      int offset = PrimaryOffset(name, flags, map);
902      if (entry(primary_, offset) == &primary_[i] &&
903          !TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
904        types->Add(Handle<Map>(map));
905      }
906    }
907  }
908
909  for (int i = 0; i < kSecondaryTableSize; i++) {
910    if (secondary_[i].key == name) {
911      Map* map = secondary_[i].value->FindFirstMap();
912      // Map can be NULL, if the stub is constant function call
913      // with a primitive receiver.
914      if (map == NULL) continue;
915
916      // Lookup in primary table and skip duplicates.
917      int primary_offset = PrimaryOffset(name, flags, map);
918      Entry* primary_entry = entry(primary_, primary_offset);
919      if (primary_entry->key == name) {
920        Map* primary_map = primary_entry->value->FindFirstMap();
921        if (map == primary_map) continue;
922      }
923
924      // Lookup in secondary table and add matches.
925      int offset = SecondaryOffset(name, flags, primary_offset);
926      if (entry(secondary_, offset) == &secondary_[i] &&
927          !TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
928        types->Add(Handle<Map>(map));
929      }
930    }
931  }
932}
933
934
935// ------------------------------------------------------------------------
936// StubCompiler implementation.
937
938
939RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
940  ASSERT(args[0]->IsJSObject());
941  ASSERT(args[1]->IsJSObject());
942  AccessorInfo* callback = AccessorInfo::cast(args[3]);
943  Address getter_address = v8::ToCData<Address>(callback->getter());
944  v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
945  ASSERT(fun != NULL);
946  v8::AccessorInfo info(&args[0]);
947  HandleScope scope(isolate);
948  v8::Handle<v8::Value> result;
949  {
950    // Leaving JavaScript.
951    VMState state(isolate, EXTERNAL);
952    ExternalCallbackScope call_scope(isolate, getter_address);
953    result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
954  }
955  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
956  if (result.IsEmpty()) return HEAP->undefined_value();
957  return *v8::Utils::OpenHandle(*result);
958}
959
960
961RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
962  JSObject* recv = JSObject::cast(args[0]);
963  AccessorInfo* callback = AccessorInfo::cast(args[1]);
964  Address setter_address = v8::ToCData<Address>(callback->setter());
965  v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
966  ASSERT(fun != NULL);
967  Handle<String> name = args.at<String>(2);
968  Handle<Object> value = args.at<Object>(3);
969  HandleScope scope(isolate);
970  LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
971  CustomArguments custom_args(isolate, callback->data(), recv, recv);
972  v8::AccessorInfo info(custom_args.end());
973  {
974    // Leaving JavaScript.
975    VMState state(isolate, EXTERNAL);
976    ExternalCallbackScope call_scope(isolate, setter_address);
977    fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
978  }
979  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
980  return *value;
981}
982
983
984static const int kAccessorInfoOffsetInInterceptorArgs = 2;
985
986
987/**
988 * Attempts to load a property with an interceptor (which must be present),
989 * but doesn't search the prototype chain.
990 *
991 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
992 * provide any value for the given name.
993 */
994RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
995  Handle<String> name_handle = args.at<String>(0);
996  Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
997  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
998  ASSERT(args[2]->IsJSObject());  // Receiver.
999  ASSERT(args[3]->IsJSObject());  // Holder.
1000  ASSERT(args.length() == 5);  // Last arg is data object.
1001
1002  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1003  v8::NamedPropertyGetter getter =
1004      FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1005  ASSERT(getter != NULL);
1006
1007  {
1008    // Use the interceptor getter.
1009    v8::AccessorInfo info(args.arguments() -
1010                          kAccessorInfoOffsetInInterceptorArgs);
1011    HandleScope scope(isolate);
1012    v8::Handle<v8::Value> r;
1013    {
1014      // Leaving JavaScript.
1015      VMState state(isolate, EXTERNAL);
1016      r = getter(v8::Utils::ToLocal(name_handle), info);
1017    }
1018    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1019    if (!r.IsEmpty()) {
1020      return *v8::Utils::OpenHandle(*r);
1021    }
1022  }
1023
1024  return isolate->heap()->no_interceptor_result_sentinel();
1025}
1026
1027
1028static MaybeObject* ThrowReferenceError(String* name) {
1029  // If the load is non-contextual, just return the undefined result.
1030  // Note that both keyed and non-keyed loads may end up here, so we
1031  // can't use either LoadIC or KeyedLoadIC constructors.
1032  IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
1033  ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
1034  if (!ic.SlowIsContextual()) return HEAP->undefined_value();
1035
1036  // Throw a reference error.
1037  HandleScope scope;
1038  Handle<String> name_handle(name);
1039  Handle<Object> error =
1040      FACTORY->NewReferenceError("not_defined",
1041                                  HandleVector(&name_handle, 1));
1042  return Isolate::Current()->Throw(*error);
1043}
1044
1045
1046static MaybeObject* LoadWithInterceptor(Arguments* args,
1047                                        PropertyAttributes* attrs) {
1048  Handle<String> name_handle = args->at<String>(0);
1049  Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1050  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1051  Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1052  Handle<JSObject> holder_handle = args->at<JSObject>(3);
1053  ASSERT(args->length() == 5);  // Last arg is data object.
1054
1055  Isolate* isolate = receiver_handle->GetIsolate();
1056
1057  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1058  v8::NamedPropertyGetter getter =
1059      FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1060  ASSERT(getter != NULL);
1061
1062  {
1063    // Use the interceptor getter.
1064    v8::AccessorInfo info(args->arguments() -
1065                          kAccessorInfoOffsetInInterceptorArgs);
1066    HandleScope scope(isolate);
1067    v8::Handle<v8::Value> r;
1068    {
1069      // Leaving JavaScript.
1070      VMState state(isolate, EXTERNAL);
1071      r = getter(v8::Utils::ToLocal(name_handle), info);
1072    }
1073    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1074    if (!r.IsEmpty()) {
1075      *attrs = NONE;
1076      return *v8::Utils::OpenHandle(*r);
1077    }
1078  }
1079
1080  MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
1081      *receiver_handle,
1082      *name_handle,
1083      attrs);
1084  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1085  return result;
1086}
1087
1088
1089/**
1090 * Loads a property with an interceptor performing post interceptor
1091 * lookup if interceptor failed.
1092 */
1093RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
1094  PropertyAttributes attr = NONE;
1095  Object* result;
1096  { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1097    if (!maybe_result->ToObject(&result)) return maybe_result;
1098  }
1099
1100  // If the property is present, return it.
1101  if (attr != ABSENT) return result;
1102  return ThrowReferenceError(String::cast(args[0]));
1103}
1104
1105
1106RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
1107  PropertyAttributes attr;
1108  MaybeObject* result = LoadWithInterceptor(&args, &attr);
1109  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1110  // This is call IC. In this case, we simply return the undefined result which
1111  // will lead to an exception when trying to invoke the result as a
1112  // function.
1113  return result;
1114}
1115
1116
1117RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
1118  ASSERT(args.length() == 4);
1119  JSObject* recv = JSObject::cast(args[0]);
1120  String* name = String::cast(args[1]);
1121  Object* value = args[2];
1122  ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode);
1123  StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
1124  ASSERT(recv->HasNamedInterceptor());
1125  PropertyAttributes attr = NONE;
1126  MaybeObject* result = recv->SetPropertyWithInterceptor(
1127      name, value, attr, strict_mode);
1128  return result;
1129}
1130
1131
1132RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
1133  JSObject* receiver = JSObject::cast(args[0]);
1134  ASSERT(args.smi_at(1) >= 0);
1135  uint32_t index = args.smi_at(1);
1136  return receiver->GetElementWithInterceptor(receiver, index);
1137}
1138
1139
1140Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
1141  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1142  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1143  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1144  if (kind == Code::CALL_IC) {
1145    CallIC::GenerateInitialize(masm(), argc, extra_state);
1146  } else {
1147    KeyedCallIC::GenerateInitialize(masm(), argc);
1148  }
1149  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
1150  isolate()->counters()->call_initialize_stubs()->Increment();
1151  PROFILE(isolate(),
1152          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1153                          *code, code->arguments_count()));
1154  GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
1155  return code;
1156}
1157
1158
1159Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1160  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1161  // The code of the PreMonomorphic stub is the same as the code
1162  // of the Initialized stub.  They just differ on the code object flags.
1163  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1164  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1165  if (kind == Code::CALL_IC) {
1166    CallIC::GenerateInitialize(masm(), argc, extra_state);
1167  } else {
1168    KeyedCallIC::GenerateInitialize(masm(), argc);
1169  }
1170  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1171  isolate()->counters()->call_premonomorphic_stubs()->Increment();
1172  PROFILE(isolate(),
1173          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1174                          *code, code->arguments_count()));
1175  GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
1176  return code;
1177}
1178
1179
1180Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
1181  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1182  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1183  if (kind == Code::CALL_IC) {
1184    // Call normal is always with a explict receiver.
1185    ASSERT(!CallIC::Contextual::decode(
1186        Code::ExtractExtraICStateFromFlags(flags)));
1187    CallIC::GenerateNormal(masm(), argc);
1188  } else {
1189    KeyedCallIC::GenerateNormal(masm(), argc);
1190  }
1191  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
1192  isolate()->counters()->call_normal_stubs()->Increment();
1193  PROFILE(isolate(),
1194          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1195                          *code, code->arguments_count()));
1196  GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
1197  return code;
1198}
1199
1200
1201Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1202  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1203  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1204  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1205  if (kind == Code::CALL_IC) {
1206    CallIC::GenerateMegamorphic(masm(), argc, extra_state);
1207  } else {
1208    KeyedCallIC::GenerateMegamorphic(masm(), argc);
1209  }
1210  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
1211  isolate()->counters()->call_megamorphic_stubs()->Increment();
1212  PROFILE(isolate(),
1213          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1214                          *code, code->arguments_count()));
1215  GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1216  return code;
1217}
1218
1219
1220Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
1221  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1222  KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
1223  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
1224  PROFILE(isolate(),
1225          CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1226                                          CALL_MEGAMORPHIC_TAG),
1227                          *code, code->arguments_count()));
1228  GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1229  return code;
1230}
1231
1232
1233Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
1234  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1235  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1236  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1237  if (kind == Code::CALL_IC) {
1238    CallIC::GenerateMiss(masm(), argc, extra_state);
1239  } else {
1240    KeyedCallIC::GenerateMiss(masm(), argc);
1241  }
1242  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
1243  isolate()->counters()->call_megamorphic_stubs()->Increment();
1244  PROFILE(isolate(),
1245          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1246                          *code, code->arguments_count()));
1247  GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
1248  return code;
1249}
1250
1251
1252#ifdef ENABLE_DEBUGGER_SUPPORT
1253Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1254  Debug::GenerateCallICDebugBreak(masm());
1255  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1256  PROFILE(isolate(),
1257          CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1258                                          CALL_DEBUG_BREAK_TAG),
1259                          *code, code->arguments_count()));
1260  return code;
1261}
1262
1263
1264Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1265  // Use the same code for the the step in preparations as we do for the
1266  // miss case.
1267  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1268  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1269  if (kind == Code::CALL_IC) {
1270    // For the debugger extra ic state is irrelevant.
1271    CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
1272  } else {
1273    KeyedCallIC::GenerateMiss(masm(), argc);
1274  }
1275  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1276  PROFILE(isolate(),
1277          CodeCreateEvent(
1278              CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1279              *code,
1280              code->arguments_count()));
1281  return code;
1282}
1283#endif  // ENABLE_DEBUGGER_SUPPORT
1284
1285#undef CALL_LOGGER_TAG
1286
1287
1288Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1289                                            const char* name) {
1290  // Create code object in the heap.
1291  CodeDesc desc;
1292  masm_.GetCode(&desc);
1293  Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
1294#ifdef ENABLE_DISASSEMBLER
1295  if (FLAG_print_code_stubs) code->Disassemble(name);
1296#endif
1297  return code;
1298}
1299
1300
1301Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1302                                            Handle<String> name) {
1303  return (FLAG_print_code_stubs && !name.is_null())
1304      ? GetCodeWithFlags(flags, *name->ToCString())
1305      : GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1306}
1307
1308
1309void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
1310                                         Handle<String> name,
1311                                         LookupResult* lookup) {
1312  holder->LocalLookupRealNamedProperty(*name, lookup);
1313  if (lookup->IsProperty()) return;
1314
1315  lookup->NotFound();
1316  if (holder->GetPrototype()->IsNull()) return;
1317
1318  holder->GetPrototype()->Lookup(*name, lookup);
1319}
1320
1321
1322Handle<Code> LoadStubCompiler::GetCode(PropertyType type, Handle<String> name) {
1323  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
1324  Handle<Code> code = GetCodeWithFlags(flags, name);
1325  PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
1326  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
1327  return code;
1328}
1329
1330
1331Handle<Code> KeyedLoadStubCompiler::GetCode(PropertyType type,
1332                                            Handle<String> name,
1333                                            InlineCacheState state) {
1334  Code::Flags flags = Code::ComputeFlags(
1335      Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
1336  Handle<Code> code = GetCodeWithFlags(flags, name);
1337  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
1338  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
1339  return code;
1340}
1341
1342
1343Handle<Code> StoreStubCompiler::GetCode(PropertyType type,
1344                                        Handle<String> name) {
1345  Code::Flags flags =
1346      Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
1347  Handle<Code> code = GetCodeWithFlags(flags, name);
1348  PROFILE(isolate(), CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
1349  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
1350  return code;
1351}
1352
1353
1354Handle<Code> KeyedStoreStubCompiler::GetCode(PropertyType type,
1355                                             Handle<String> name,
1356                                             InlineCacheState state) {
1357  Code::ExtraICState extra_state =
1358      Code::ComputeExtraICState(grow_mode_, strict_mode_);
1359  Code::Flags flags =
1360      Code::ComputeFlags(Code::KEYED_STORE_IC, state, extra_state, type);
1361  Handle<Code> code = GetCodeWithFlags(flags, name);
1362  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
1363  GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
1364  return code;
1365}
1366
1367
1368void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1369    MacroAssembler* masm) {
1370  KeyedStoreIC::GenerateSlow(masm);
1371}
1372
1373
1374CallStubCompiler::CallStubCompiler(Isolate* isolate,
1375                                   int argc,
1376                                   Code::Kind kind,
1377                                   Code::ExtraICState extra_state,
1378                                   InlineCacheHolderFlag cache_holder)
1379    : StubCompiler(isolate),
1380      arguments_(argc),
1381      kind_(kind),
1382      extra_state_(extra_state),
1383      cache_holder_(cache_holder) {
1384}
1385
1386
1387bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
1388  if (function->shared()->HasBuiltinFunctionId()) {
1389    BuiltinFunctionId id = function->shared()->builtin_function_id();
1390#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1391    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1392#undef CALL_GENERATOR_CASE
1393  }
1394
1395  CallOptimization optimization(function);
1396  return optimization.is_simple_api_call();
1397}
1398
1399
1400Handle<Code> CallStubCompiler::CompileCustomCall(
1401    Handle<Object> object,
1402    Handle<JSObject> holder,
1403    Handle<JSGlobalPropertyCell> cell,
1404    Handle<JSFunction> function,
1405    Handle<String> fname) {
1406  ASSERT(HasCustomCallGenerator(function));
1407
1408  if (function->shared()->HasBuiltinFunctionId()) {
1409    BuiltinFunctionId id = function->shared()->builtin_function_id();
1410#define CALL_GENERATOR_CASE(name)                               \
1411    if (id == k##name) {                                        \
1412      return CallStubCompiler::Compile##name##Call(object,      \
1413                                                   holder,      \
1414                                                   cell,        \
1415                                                   function,    \
1416                                                   fname);      \
1417    }
1418    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1419#undef CALL_GENERATOR_CASE
1420  }
1421  CallOptimization optimization(function);
1422  ASSERT(optimization.is_simple_api_call());
1423  return CompileFastApiCall(optimization,
1424                            object,
1425                            holder,
1426                            cell,
1427                            function,
1428                            fname);
1429}
1430
1431
1432Handle<Code> CallStubCompiler::GetCode(PropertyType type, Handle<String> name) {
1433  int argc = arguments_.immediate();
1434  Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
1435                                                    type,
1436                                                    extra_state_,
1437                                                    cache_holder_,
1438                                                    argc);
1439  return GetCodeWithFlags(flags, name);
1440}
1441
1442
1443Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
1444  Handle<String> function_name;
1445  if (function->shared()->name()->IsString()) {
1446    function_name = Handle<String>(String::cast(function->shared()->name()));
1447  }
1448  return GetCode(CONSTANT_FUNCTION, function_name);
1449}
1450
1451
1452Handle<Code> ConstructStubCompiler::GetCode() {
1453  Code::Flags flags = Code::ComputeFlags(Code::STUB);
1454  Handle<Code> code = GetCodeWithFlags(flags, "ConstructStub");
1455  PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, "ConstructStub"));
1456  GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", *code));
1457  return code;
1458}
1459
1460
1461CallOptimization::CallOptimization(LookupResult* lookup) {
1462  if (lookup->IsFound() &&
1463      lookup->IsCacheable() &&
1464      lookup->type() == CONSTANT_FUNCTION) {
1465    // We only optimize constant function calls.
1466    Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1467  } else {
1468    Initialize(Handle<JSFunction>::null());
1469  }
1470}
1471
1472CallOptimization::CallOptimization(Handle<JSFunction> function) {
1473  Initialize(function);
1474}
1475
1476
1477int CallOptimization::GetPrototypeDepthOfExpectedType(
1478    Handle<JSObject> object,
1479    Handle<JSObject> holder) const {
1480  ASSERT(is_simple_api_call());
1481  if (expected_receiver_type_.is_null()) return 0;
1482  int depth = 0;
1483  while (!object.is_identical_to(holder)) {
1484    if (object->IsInstanceOf(*expected_receiver_type_)) return depth;
1485    object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
1486    ++depth;
1487  }
1488  if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
1489  return kInvalidProtoDepth;
1490}
1491
1492
1493void CallOptimization::Initialize(Handle<JSFunction> function) {
1494  constant_function_ = Handle<JSFunction>::null();
1495  is_simple_api_call_ = false;
1496  expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1497  api_call_info_ = Handle<CallHandlerInfo>::null();
1498
1499  if (function.is_null() || !function->is_compiled()) return;
1500
1501  constant_function_ = function;
1502  AnalyzePossibleApiFunction(function);
1503}
1504
1505
1506void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1507  if (!function->shared()->IsApiFunction()) return;
1508  Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1509
1510  // Require a C++ callback.
1511  if (info->call_code()->IsUndefined()) return;
1512  api_call_info_ =
1513      Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1514
1515  // Accept signatures that either have no restrictions at all or
1516  // only have restrictions on the receiver.
1517  if (!info->signature()->IsUndefined()) {
1518    Handle<SignatureInfo> signature =
1519        Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1520    if (!signature->args()->IsUndefined()) return;
1521    if (!signature->receiver()->IsUndefined()) {
1522      expected_receiver_type_ =
1523          Handle<FunctionTemplateInfo>(
1524              FunctionTemplateInfo::cast(signature->receiver()));
1525    }
1526  }
1527
1528  is_simple_api_call_ = true;
1529}
1530
1531
1532} }  // namespace v8::internal
1533