blob: 295cc4a60b3ecc0e2f518796d310f1641ef1133f [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
Ben Murdochb8e0da22011-05-16 14:20:40 +010032#include "gdb-jit.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "ic-inl.h"
34#include "stub-cache.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036
37namespace v8 {
38namespace internal {
39
40// -----------------------------------------------------------------------
41// StubCache implementation.
42
43
44StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
45StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
46
47void StubCache::Initialize(bool create_heap_objects) {
48 ASSERT(IsPowerOf2(kPrimaryTableSize));
49 ASSERT(IsPowerOf2(kSecondaryTableSize));
50 if (create_heap_objects) {
51 HandleScope scope;
52 Clear();
53 }
54}
55
56
57Code* StubCache::Set(String* name, Map* map, Code* code) {
58 // Get the flags from the code.
59 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
60
61 // Validate that the name does not move on scavenge, and that we
62 // can use identity checks instead of string equality checks.
63 ASSERT(!Heap::InNewSpace(name));
64 ASSERT(name->IsSymbol());
65
66 // The state bits are not important to the hash function because
67 // the stub cache only contains monomorphic stubs. Make sure that
68 // the bits are the least significant so they will be the ones
69 // masked out.
70 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
71 ASSERT(Code::kFlagsICStateShift == 0);
72
73 // Make sure that the code type is not included in the hash.
74 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
75
76 // Compute the primary entry.
77 int primary_offset = PrimaryOffset(name, flags, map);
78 Entry* primary = entry(primary_, primary_offset);
79 Code* hit = primary->value;
80
81 // If the primary entry has useful data in it, we retire it to the
82 // secondary cache before overwriting it.
83 if (hit != Builtins::builtin(Builtins::Illegal)) {
84 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
85 int secondary_offset =
86 SecondaryOffset(primary->key, primary_flags, primary_offset);
87 Entry* secondary = entry(secondary_, secondary_offset);
88 *secondary = *primary;
89 }
90
91 // Update primary cache.
92 primary->key = name;
93 primary->value = code;
94 return code;
95}
96
97
John Reck59135872010-11-02 12:39:01 -070098MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
99 JSObject* receiver) {
Steve Block8defd9f2010-07-08 12:39:36 +0100100 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
Steve Block6ded16b2010-05-10 14:33:55 +0100101 // If no global objects are present in the prototype chain, the load
102 // nonexistent IC stub can be shared for all names for a given map
103 // and we use the empty string for the map cache in that case. If
104 // there are global objects involved, we need to check global
105 // property cells in the stub and therefore the stub will be
106 // specific to the name.
107 String* cache_name = Heap::empty_string();
108 if (receiver->IsGlobalObject()) cache_name = name;
109 JSObject* last = receiver;
110 while (last->GetPrototype() != Heap::null_value()) {
111 last = JSObject::cast(last->GetPrototype());
112 if (last->IsGlobalObject()) cache_name = name;
113 }
114 // Compile the stub that is either shared for all names or
115 // name specific if there are global objects involved.
116 Code::Flags flags =
117 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
118 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
119 if (code->IsUndefined()) {
120 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700121 { MaybeObject* maybe_code =
122 compiler.CompileLoadNonexistent(cache_name, receiver, last);
123 if (!maybe_code->ToObject(&code)) return maybe_code;
124 }
Steve Block6ded16b2010-05-10 14:33:55 +0100125 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100126 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700127 Object* result;
128 { MaybeObject* maybe_result =
129 receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
130 if (!maybe_result->ToObject(&result)) return maybe_result;
131 }
Steve Block6ded16b2010-05-10 14:33:55 +0100132 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100133 return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100134}
135
136
John Reck59135872010-11-02 12:39:01 -0700137MaybeObject* StubCache::ComputeLoadField(String* name,
138 JSObject* receiver,
139 JSObject* holder,
140 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100141 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000142 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100143 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000144 if (code->IsUndefined()) {
145 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700146 { MaybeObject* maybe_code =
147 compiler.CompileLoadField(receiver, holder, field_index, name);
148 if (!maybe_code->ToObject(&code)) return maybe_code;
149 }
Steve Block6ded16b2010-05-10 14:33:55 +0100150 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100151 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700152 Object* result;
153 { MaybeObject* maybe_result =
154 receiver->UpdateMapCodeCache(name, Code::cast(code));
155 if (!maybe_result->ToObject(&result)) return maybe_result;
156 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100158 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000159}
160
161
John Reck59135872010-11-02 12:39:01 -0700162MaybeObject* StubCache::ComputeLoadCallback(String* name,
163 JSObject* receiver,
164 JSObject* holder,
165 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Steve Block8defd9f2010-07-08 12:39:36 +0100167 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000168 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100169 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000170 if (code->IsUndefined()) {
171 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700172 { MaybeObject* maybe_code =
173 compiler.CompileLoadCallback(name, receiver, holder, callback);
174 if (!maybe_code->ToObject(&code)) return maybe_code;
175 }
Steve Block6ded16b2010-05-10 14:33:55 +0100176 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100177 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700178 Object* result;
179 { MaybeObject* maybe_result =
180 receiver->UpdateMapCodeCache(name, Code::cast(code));
181 if (!maybe_result->ToObject(&result)) return maybe_result;
182 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100184 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000185}
186
187
John Reck59135872010-11-02 12:39:01 -0700188MaybeObject* StubCache::ComputeLoadConstant(String* name,
189 JSObject* receiver,
190 JSObject* holder,
191 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100192 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 Code::Flags flags =
194 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100195 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000196 if (code->IsUndefined()) {
197 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700198 { MaybeObject* maybe_code =
199 compiler.CompileLoadConstant(receiver, holder, value, name);
200 if (!maybe_code->ToObject(&code)) return maybe_code;
201 }
Steve Block6ded16b2010-05-10 14:33:55 +0100202 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100203 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700204 Object* result;
205 { MaybeObject* maybe_result =
206 receiver->UpdateMapCodeCache(name, Code::cast(code));
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000209 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100210 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000211}
212
213
John Reck59135872010-11-02 12:39:01 -0700214MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
215 JSObject* receiver,
216 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100217 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000218 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100219 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000220 if (code->IsUndefined()) {
221 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700222 { MaybeObject* maybe_code =
223 compiler.CompileLoadInterceptor(receiver, holder, name);
224 if (!maybe_code->ToObject(&code)) return maybe_code;
225 }
Steve Block6ded16b2010-05-10 14:33:55 +0100226 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100227 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700228 Object* result;
229 { MaybeObject* maybe_result =
230 receiver->UpdateMapCodeCache(name, Code::cast(code));
231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100234 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000235}
236
237
John Reck59135872010-11-02 12:39:01 -0700238MaybeObject* StubCache::ComputeLoadNormal() {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100239 return Builtins::builtin(Builtins::LoadIC_Normal);
Steve Blocka7e24c12009-10-30 11:49:00 +0000240}
241
242
John Reck59135872010-11-02 12:39:01 -0700243MaybeObject* StubCache::ComputeLoadGlobal(String* name,
244 JSObject* receiver,
245 GlobalObject* holder,
246 JSGlobalPropertyCell* cell,
247 bool is_dont_delete) {
Steve Block8defd9f2010-07-08 12:39:36 +0100248 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000249 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100250 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000251 if (code->IsUndefined()) {
252 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700253 { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
254 holder,
255 cell,
256 name,
257 is_dont_delete);
258 if (!maybe_code->ToObject(&code)) return maybe_code;
259 }
Steve Block6ded16b2010-05-10 14:33:55 +0100260 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100261 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700262 Object* result;
263 { MaybeObject* maybe_result =
264 receiver->UpdateMapCodeCache(name, Code::cast(code));
265 if (!maybe_result->ToObject(&result)) return maybe_result;
266 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100268 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000269}
270
271
John Reck59135872010-11-02 12:39:01 -0700272MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
273 JSObject* receiver,
274 JSObject* holder,
275 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100276 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100278 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000279 if (code->IsUndefined()) {
280 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700281 { MaybeObject* maybe_code =
282 compiler.CompileLoadField(name, receiver, holder, field_index);
283 if (!maybe_code->ToObject(&code)) return maybe_code;
284 }
Steve Block6ded16b2010-05-10 14:33:55 +0100285 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100286 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700287 Object* result;
288 { MaybeObject* maybe_result =
289 receiver->UpdateMapCodeCache(name, Code::cast(code));
290 if (!maybe_result->ToObject(&result)) return maybe_result;
291 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 }
293 return code;
294}
295
296
John Reck59135872010-11-02 12:39:01 -0700297MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
298 JSObject* receiver,
299 JSObject* holder,
300 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100301 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 Code::Flags flags =
303 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100304 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 if (code->IsUndefined()) {
306 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700307 { MaybeObject* maybe_code =
308 compiler.CompileLoadConstant(name, receiver, holder, value);
309 if (!maybe_code->ToObject(&code)) return maybe_code;
310 }
Steve Block6ded16b2010-05-10 14:33:55 +0100311 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100312 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700313 Object* result;
314 { MaybeObject* maybe_result =
315 receiver->UpdateMapCodeCache(name, Code::cast(code));
316 if (!maybe_result->ToObject(&result)) return maybe_result;
317 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 }
319 return code;
320}
321
322
John Reck59135872010-11-02 12:39:01 -0700323MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
324 JSObject* receiver,
325 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100326 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 Code::Flags flags =
328 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100329 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 if (code->IsUndefined()) {
331 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700332 { MaybeObject* maybe_code =
333 compiler.CompileLoadInterceptor(receiver, holder, name);
334 if (!maybe_code->ToObject(&code)) return maybe_code;
335 }
Steve Block6ded16b2010-05-10 14:33:55 +0100336 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100337 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700338 Object* result;
339 { MaybeObject* maybe_result =
340 receiver->UpdateMapCodeCache(name, Code::cast(code));
341 if (!maybe_result->ToObject(&result)) return maybe_result;
342 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 }
344 return code;
345}
346
347
John Reck59135872010-11-02 12:39:01 -0700348MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
349 JSObject* receiver,
350 JSObject* holder,
351 AccessorInfo* callback) {
Steve Block8defd9f2010-07-08 12:39:36 +0100352 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000353 Code::Flags flags =
354 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100355 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000356 if (code->IsUndefined()) {
357 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700358 { MaybeObject* maybe_code =
359 compiler.CompileLoadCallback(name, receiver, holder, callback);
360 if (!maybe_code->ToObject(&code)) return maybe_code;
361 }
Steve Block6ded16b2010-05-10 14:33:55 +0100362 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100363 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700364 Object* result;
365 { MaybeObject* maybe_result =
366 receiver->UpdateMapCodeCache(name, Code::cast(code));
367 if (!maybe_result->ToObject(&result)) return maybe_result;
368 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 }
370 return code;
371}
372
373
374
John Reck59135872010-11-02 12:39:01 -0700375MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
376 JSArray* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000377 Code::Flags flags =
378 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100379 ASSERT(receiver->IsJSObject());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100380 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 if (code->IsUndefined()) {
382 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700383 { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
384 if (!maybe_code->ToObject(&code)) return maybe_code;
385 }
Steve Block6ded16b2010-05-10 14:33:55 +0100386 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100387 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700388 Object* result;
389 { MaybeObject* maybe_result =
390 receiver->UpdateMapCodeCache(name, Code::cast(code));
391 if (!maybe_result->ToObject(&result)) return maybe_result;
392 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000393 }
394 return code;
395}
396
397
John Reck59135872010-11-02 12:39:01 -0700398MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
399 String* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 Code::Flags flags =
401 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100402 Map* map = receiver->map();
403 Object* code = map->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 if (code->IsUndefined()) {
405 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700406 { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
407 if (!maybe_code->ToObject(&code)) return maybe_code;
408 }
Steve Block6ded16b2010-05-10 14:33:55 +0100409 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100410 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700411 Object* result;
412 { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
413 if (!maybe_result->ToObject(&result)) return maybe_result;
414 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 }
416 return code;
417}
418
419
John Reck59135872010-11-02 12:39:01 -0700420MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
421 String* name,
422 JSFunction* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 Code::Flags flags =
424 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100425 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000426 if (code->IsUndefined()) {
427 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700428 { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
429 if (!maybe_code->ToObject(&code)) return maybe_code;
430 }
Steve Block6ded16b2010-05-10 14:33:55 +0100431 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100432 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700433 Object* result;
434 { MaybeObject* maybe_result =
435 receiver->UpdateMapCodeCache(name, Code::cast(code));
436 if (!maybe_result->ToObject(&result)) return maybe_result;
437 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000438 }
439 return code;
440}
441
442
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
444 Code::Flags flags =
445 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
446 String* name = Heap::KeyedLoadSpecialized_symbol();
447 Object* code = receiver->map()->FindInCodeCache(name, flags);
448 if (code->IsUndefined()) {
449 KeyedLoadStubCompiler compiler;
450 { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
451 if (!maybe_code->ToObject(&code)) return maybe_code;
452 }
453 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
454 Object* result;
455 { MaybeObject* maybe_result =
456 receiver->UpdateMapCodeCache(name, Code::cast(code));
457 if (!maybe_result->ToObject(&result)) return maybe_result;
458 }
459 }
460 return code;
461}
462
463
John Reck59135872010-11-02 12:39:01 -0700464MaybeObject* StubCache::ComputeStoreField(String* name,
465 JSObject* receiver,
466 int field_index,
467 Map* transition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
469 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
470 Object* code = receiver->map()->FindInCodeCache(name, flags);
471 if (code->IsUndefined()) {
472 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700473 { MaybeObject* maybe_code =
474 compiler.CompileStoreField(receiver, field_index, transition, name);
475 if (!maybe_code->ToObject(&code)) return maybe_code;
476 }
Steve Block6ded16b2010-05-10 14:33:55 +0100477 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100478 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700479 Object* result;
480 { MaybeObject* maybe_result =
481 receiver->UpdateMapCodeCache(name, Code::cast(code));
482 if (!maybe_result->ToObject(&result)) return maybe_result;
483 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000484 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100485 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000486}
487
488
Ben Murdochb0fe1622011-05-05 13:52:32 +0100489MaybeObject* StubCache::ComputeKeyedStoreSpecialized(JSObject* receiver) {
490 Code::Flags flags =
491 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL);
492 String* name = Heap::KeyedStoreSpecialized_symbol();
493 Object* code = receiver->map()->FindInCodeCache(name, flags);
494 if (code->IsUndefined()) {
495 KeyedStoreStubCompiler compiler;
496 { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
497 if (!maybe_code->ToObject(&code)) return maybe_code;
498 }
499 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
500 Object* result;
501 { MaybeObject* maybe_result =
502 receiver->UpdateMapCodeCache(name, Code::cast(code));
503 if (!maybe_result->ToObject(&result)) return maybe_result;
504 }
505 }
506 return code;
507}
508
509
John Reck59135872010-11-02 12:39:01 -0700510MaybeObject* StubCache::ComputeStoreNormal() {
Steve Block8defd9f2010-07-08 12:39:36 +0100511 return Builtins::builtin(Builtins::StoreIC_Normal);
512}
513
514
John Reck59135872010-11-02 12:39:01 -0700515MaybeObject* StubCache::ComputeStoreGlobal(String* name,
516 GlobalObject* receiver,
517 JSGlobalPropertyCell* cell) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000518 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
519 Object* code = receiver->map()->FindInCodeCache(name, flags);
520 if (code->IsUndefined()) {
521 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700522 { MaybeObject* maybe_code =
523 compiler.CompileStoreGlobal(receiver, cell, name);
524 if (!maybe_code->ToObject(&code)) return maybe_code;
525 }
Steve Block8defd9f2010-07-08 12:39:36 +0100526 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100527 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700528 Object* result;
529 { MaybeObject* maybe_result =
530 receiver->UpdateMapCodeCache(name, Code::cast(code));
531 if (!maybe_result->ToObject(&result)) return maybe_result;
532 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000533 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100534 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000535}
536
537
John Reck59135872010-11-02 12:39:01 -0700538MaybeObject* StubCache::ComputeStoreCallback(String* name,
539 JSObject* receiver,
540 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000541 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
542 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
543 Object* code = receiver->map()->FindInCodeCache(name, flags);
544 if (code->IsUndefined()) {
545 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700546 { MaybeObject* maybe_code =
547 compiler.CompileStoreCallback(receiver, callback, name);
548 if (!maybe_code->ToObject(&code)) return maybe_code;
549 }
Steve Block6ded16b2010-05-10 14:33:55 +0100550 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100551 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700552 Object* result;
553 { MaybeObject* maybe_result =
554 receiver->UpdateMapCodeCache(name, Code::cast(code));
555 if (!maybe_result->ToObject(&result)) return maybe_result;
556 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000557 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100558 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000559}
560
561
John Reck59135872010-11-02 12:39:01 -0700562MaybeObject* StubCache::ComputeStoreInterceptor(String* name,
563 JSObject* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000564 Code::Flags flags =
565 Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
566 Object* code = receiver->map()->FindInCodeCache(name, flags);
567 if (code->IsUndefined()) {
568 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700569 { MaybeObject* maybe_code =
570 compiler.CompileStoreInterceptor(receiver, name);
571 if (!maybe_code->ToObject(&code)) return maybe_code;
572 }
Steve Block6ded16b2010-05-10 14:33:55 +0100573 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100574 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700575 Object* result;
576 { MaybeObject* maybe_result =
577 receiver->UpdateMapCodeCache(name, Code::cast(code));
578 if (!maybe_result->ToObject(&result)) return maybe_result;
579 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100581 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000582}
583
584
John Reck59135872010-11-02 12:39:01 -0700585MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
586 JSObject* receiver,
587 int field_index,
588 Map* transition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
590 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
591 Object* code = receiver->map()->FindInCodeCache(name, flags);
592 if (code->IsUndefined()) {
593 KeyedStoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700594 { MaybeObject* maybe_code =
595 compiler.CompileStoreField(receiver, field_index, transition, name);
596 if (!maybe_code->ToObject(&code)) return maybe_code;
597 }
Steve Block6ded16b2010-05-10 14:33:55 +0100598 PROFILE(CodeCreateEvent(
599 Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100600 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700601 Object* result;
602 { MaybeObject* maybe_result =
603 receiver->UpdateMapCodeCache(name, Code::cast(code));
604 if (!maybe_result->ToObject(&result)) return maybe_result;
605 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 }
607 return code;
608}
609
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100610#define CALL_LOGGER_TAG(kind, type) \
611 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000612
John Reck59135872010-11-02 12:39:01 -0700613MaybeObject* StubCache::ComputeCallConstant(int argc,
614 InLoopFlag in_loop,
615 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100616 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700617 String* name,
618 Object* object,
619 JSObject* holder,
620 JSFunction* function) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100622 InlineCacheHolderFlag cache_holder =
623 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100624 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000625
626 // Compute check type based on receiver/holder.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100627 CheckType check = RECEIVER_MAP_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 if (object->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100629 check = STRING_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000630 } else if (object->IsNumber()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100631 check = NUMBER_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 } else if (object->IsBoolean()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100633 check = BOOLEAN_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 }
635
Ben Murdochb8e0da22011-05-16 14:20:40 +0100636 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
637 CONSTANT_FUNCTION,
638 extra_ic_state,
639 cache_holder,
640 in_loop,
641 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100642 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000643 if (code->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000644 // If the function hasn't been compiled yet, we cannot do it now
645 // because it may cause GC. To avoid this issue, we return an
646 // internal error which will make sure we do not update any
647 // caches.
648 if (!function->is_compiled()) return Failure::InternalError();
649 // Compile the stub - only create stubs for fully compiled functions.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100650 CallStubCompiler compiler(
651 argc, in_loop, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700652 { MaybeObject* maybe_code =
653 compiler.CompileCallConstant(object, holder, function, name, check);
654 if (!maybe_code->ToObject(&code)) return maybe_code;
655 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100656 Code::cast(code)->set_check_type(check);
Steve Blocka7e24c12009-10-30 11:49:00 +0000657 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100658 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
659 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100660 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700661 Object* result;
662 { MaybeObject* maybe_result =
663 map_holder->UpdateMapCodeCache(name, Code::cast(code));
664 if (!maybe_result->ToObject(&result)) return maybe_result;
665 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000666 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100667 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000668}
669
670
John Reck59135872010-11-02 12:39:01 -0700671MaybeObject* StubCache::ComputeCallField(int argc,
672 InLoopFlag in_loop,
673 Code::Kind kind,
674 String* name,
675 Object* object,
676 JSObject* holder,
677 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000678 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100679 InlineCacheHolderFlag cache_holder =
680 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100681 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000682
683 // TODO(1233596): We cannot do receiver map check for non-JS objects
684 // because they may be represented as immediates without a
685 // map. Instead, we check against the map in the holder.
686 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
687 object = holder;
688 }
689
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100690 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 FIELD,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100692 Code::kNoExtraICState,
Steve Block8defd9f2010-07-08 12:39:36 +0100693 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000694 in_loop,
695 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100696 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000697 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100698 CallStubCompiler compiler(
699 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700700 { MaybeObject* maybe_code =
701 compiler.CompileCallField(JSObject::cast(object),
702 holder,
703 index,
704 name);
705 if (!maybe_code->ToObject(&code)) return maybe_code;
706 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000707 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100708 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
709 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100710 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700711 Object* result;
712 { MaybeObject* maybe_result =
713 map_holder->UpdateMapCodeCache(name, Code::cast(code));
714 if (!maybe_result->ToObject(&result)) return maybe_result;
715 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000716 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100717 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000718}
719
720
John Reck59135872010-11-02 12:39:01 -0700721MaybeObject* StubCache::ComputeCallInterceptor(int argc,
722 Code::Kind kind,
723 String* name,
724 Object* object,
725 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000726 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100727 InlineCacheHolderFlag cache_holder =
728 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100729 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000730
731 // TODO(1233596): We cannot do receiver map check for non-JS objects
732 // because they may be represented as immediates without a
733 // map. Instead, we check against the map in the holder.
734 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
735 object = holder;
736 }
737
Ben Murdochb8e0da22011-05-16 14:20:40 +0100738 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
739 INTERCEPTOR,
740 Code::kNoExtraICState,
741 cache_holder,
742 NOT_IN_LOOP,
743 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100744 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000745 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100746 CallStubCompiler compiler(
747 argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700748 { MaybeObject* maybe_code =
749 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
750 if (!maybe_code->ToObject(&code)) return maybe_code;
751 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100753 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
754 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100755 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700756 Object* result;
757 { MaybeObject* maybe_result =
758 map_holder->UpdateMapCodeCache(name, Code::cast(code));
759 if (!maybe_result->ToObject(&result)) return maybe_result;
760 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000761 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100762 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000763}
764
765
John Reck59135872010-11-02 12:39:01 -0700766MaybeObject* StubCache::ComputeCallNormal(int argc,
767 InLoopFlag in_loop,
768 Code::Kind kind,
769 String* name,
770 JSObject* receiver) {
771 Object* code;
772 { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
773 if (!maybe_code->ToObject(&code)) return maybe_code;
774 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100775 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000776}
777
778
John Reck59135872010-11-02 12:39:01 -0700779MaybeObject* StubCache::ComputeCallGlobal(int argc,
780 InLoopFlag in_loop,
781 Code::Kind kind,
782 String* name,
783 JSObject* receiver,
784 GlobalObject* holder,
785 JSGlobalPropertyCell* cell,
786 JSFunction* function) {
Steve Block8defd9f2010-07-08 12:39:36 +0100787 InlineCacheHolderFlag cache_holder =
788 IC::GetCodeCacheForObject(receiver, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100789 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100790 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
791 NORMAL,
792 Code::kNoExtraICState,
793 cache_holder,
794 in_loop,
795 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100796 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000797 if (code->IsUndefined()) {
798 // If the function hasn't been compiled yet, we cannot do it now
799 // because it may cause GC. To avoid this issue, we return an
800 // internal error which will make sure we do not update any
801 // caches.
802 if (!function->is_compiled()) return Failure::InternalError();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100803 CallStubCompiler compiler(
804 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700805 { MaybeObject* maybe_code =
806 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
807 if (!maybe_code->ToObject(&code)) return maybe_code;
808 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000809 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100810 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
811 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100812 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700813 Object* result;
814 { MaybeObject* maybe_result =
815 map_holder->UpdateMapCodeCache(name, Code::cast(code));
816 if (!maybe_result->ToObject(&result)) return maybe_result;
817 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000818 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100819 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000820}
821
822
823static Object* GetProbeValue(Code::Flags flags) {
824 // Use raw_unchecked... so we don't get assert failures during GC.
825 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
826 int entry = dictionary->FindEntry(flags);
827 if (entry != -1) return dictionary->ValueAt(entry);
828 return Heap::raw_unchecked_undefined_value();
829}
830
831
John Reck59135872010-11-02 12:39:01 -0700832MUST_USE_RESULT static MaybeObject* ProbeCache(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000833 Object* probe = GetProbeValue(flags);
834 if (probe != Heap::undefined_value()) return probe;
835 // Seed the cache with an undefined value to make sure that any
836 // generated code object can always be inserted into the cache
837 // without causing allocation failures.
John Reck59135872010-11-02 12:39:01 -0700838 Object* result;
839 { MaybeObject* maybe_result =
840 Heap::non_monomorphic_cache()->AtNumberPut(flags,
841 Heap::undefined_value());
842 if (!maybe_result->ToObject(&result)) return maybe_result;
843 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
845 return probe;
846}
847
848
John Reck59135872010-11-02 12:39:01 -0700849static MaybeObject* FillCache(MaybeObject* maybe_code) {
850 Object* code;
851 if (maybe_code->ToObject(&code)) {
852 if (code->IsCode()) {
853 int entry =
854 Heap::non_monomorphic_cache()->FindEntry(
855 Code::cast(code)->flags());
856 // The entry must be present see comment in ProbeCache.
857 ASSERT(entry != -1);
858 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
859 Heap::undefined_value());
860 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
861 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
862 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000863 }
John Reck59135872010-11-02 12:39:01 -0700864 return maybe_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000865}
866
867
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100868Code* StubCache::FindCallInitialize(int argc,
869 InLoopFlag in_loop,
870 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100871 Code::Flags flags = Code::ComputeFlags(kind,
872 in_loop,
873 UNINITIALIZED,
874 Code::kNoExtraICState,
875 NORMAL,
876 argc);
John Reck59135872010-11-02 12:39:01 -0700877 Object* result = ProbeCache(flags)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000878 ASSERT(!result->IsUndefined());
879 // This might be called during the marking phase of the collector
880 // hence the unchecked cast.
881 return reinterpret_cast<Code*>(result);
882}
883
884
John Reck59135872010-11-02 12:39:01 -0700885MaybeObject* StubCache::ComputeCallInitialize(int argc,
886 InLoopFlag in_loop,
887 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100888 Code::Flags flags = Code::ComputeFlags(kind,
889 in_loop,
890 UNINITIALIZED,
891 Code::kNoExtraICState,
892 NORMAL,
893 argc);
John Reck59135872010-11-02 12:39:01 -0700894 Object* probe;
895 { MaybeObject* maybe_probe = ProbeCache(flags);
896 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
897 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 if (!probe->IsUndefined()) return probe;
899 StubCompiler compiler;
900 return FillCache(compiler.CompileCallInitialize(flags));
901}
902
903
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800904Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
905 if (in_loop == IN_LOOP) {
906 // Force the creation of the corresponding stub outside loops,
907 // because it may be used when clearing the ICs later - it is
908 // possible for a series of IC transitions to lose the in-loop
909 // information, and the IC clearing code can't generate a stub
910 // that it needs so we need to ensure it is generated already.
911 ComputeCallInitialize(argc, NOT_IN_LOOP);
912 }
913 CALL_HEAP_FUNCTION(ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
914}
915
916
917Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
918 InLoopFlag in_loop) {
919 if (in_loop == IN_LOOP) {
920 // Force the creation of the corresponding stub outside loops,
921 // because it may be used when clearing the ICs later - it is
922 // possible for a series of IC transitions to lose the in-loop
923 // information, and the IC clearing code can't generate a stub
924 // that it needs so we need to ensure it is generated already.
925 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
926 }
927 CALL_HEAP_FUNCTION(
928 ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
929}
930
931
John Reck59135872010-11-02 12:39:01 -0700932MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
933 InLoopFlag in_loop,
934 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100935 Code::Flags flags = Code::ComputeFlags(kind,
936 in_loop,
937 PREMONOMORPHIC,
938 Code::kNoExtraICState,
939 NORMAL,
940 argc);
John Reck59135872010-11-02 12:39:01 -0700941 Object* probe;
942 { MaybeObject* maybe_probe = ProbeCache(flags);
943 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
944 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000945 if (!probe->IsUndefined()) return probe;
946 StubCompiler compiler;
947 return FillCache(compiler.CompileCallPreMonomorphic(flags));
948}
949
950
John Reck59135872010-11-02 12:39:01 -0700951MaybeObject* StubCache::ComputeCallNormal(int argc,
952 InLoopFlag in_loop,
953 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100954 Code::Flags flags = Code::ComputeFlags(kind,
955 in_loop,
956 MONOMORPHIC,
957 Code::kNoExtraICState,
958 NORMAL,
959 argc);
John Reck59135872010-11-02 12:39:01 -0700960 Object* probe;
961 { MaybeObject* maybe_probe = ProbeCache(flags);
962 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
963 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000964 if (!probe->IsUndefined()) return probe;
965 StubCompiler compiler;
966 return FillCache(compiler.CompileCallNormal(flags));
967}
968
969
John Reck59135872010-11-02 12:39:01 -0700970MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
971 InLoopFlag in_loop,
972 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100973 Code::Flags flags = Code::ComputeFlags(kind,
974 in_loop,
975 MEGAMORPHIC,
976 Code::kNoExtraICState,
977 NORMAL,
978 argc);
John Reck59135872010-11-02 12:39:01 -0700979 Object* probe;
980 { MaybeObject* maybe_probe = ProbeCache(flags);
981 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
982 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 if (!probe->IsUndefined()) return probe;
984 StubCompiler compiler;
985 return FillCache(compiler.CompileCallMegamorphic(flags));
986}
987
988
John Reck59135872010-11-02 12:39:01 -0700989MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100990 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
991 // and monomorphic stubs are not mixed up together in the stub cache.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100992 Code::Flags flags = Code::ComputeFlags(kind,
993 NOT_IN_LOOP,
994 MONOMORPHIC_PROTOTYPE_FAILURE,
995 Code::kNoExtraICState,
996 NORMAL,
997 argc,
998 OWN_MAP);
John Reck59135872010-11-02 12:39:01 -0700999 Object* probe;
1000 { MaybeObject* maybe_probe = ProbeCache(flags);
1001 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1002 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 if (!probe->IsUndefined()) return probe;
1004 StubCompiler compiler;
1005 return FillCache(compiler.CompileCallMiss(flags));
1006}
1007
1008
1009#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001010MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001011 Code::Flags flags = Code::ComputeFlags(kind,
1012 NOT_IN_LOOP,
1013 DEBUG_BREAK,
1014 Code::kNoExtraICState,
1015 NORMAL,
1016 argc);
John Reck59135872010-11-02 12:39:01 -07001017 Object* probe;
1018 { MaybeObject* maybe_probe = ProbeCache(flags);
1019 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1020 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001021 if (!probe->IsUndefined()) return probe;
1022 StubCompiler compiler;
1023 return FillCache(compiler.CompileCallDebugBreak(flags));
1024}
1025
1026
John Reck59135872010-11-02 12:39:01 -07001027MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
1028 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001029 Code::Flags flags = Code::ComputeFlags(kind,
1030 NOT_IN_LOOP,
1031 DEBUG_PREPARE_STEP_IN,
1032 Code::kNoExtraICState,
1033 NORMAL,
1034 argc);
John Reck59135872010-11-02 12:39:01 -07001035 Object* probe;
1036 { MaybeObject* maybe_probe = ProbeCache(flags);
1037 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1038 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001039 if (!probe->IsUndefined()) return probe;
1040 StubCompiler compiler;
1041 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
1042}
1043#endif
1044
1045
Steve Blocka7e24c12009-10-30 11:49:00 +00001046void StubCache::Clear() {
1047 for (int i = 0; i < kPrimaryTableSize; i++) {
1048 primary_[i].key = Heap::empty_string();
1049 primary_[i].value = Builtins::builtin(Builtins::Illegal);
1050 }
1051 for (int j = 0; j < kSecondaryTableSize; j++) {
1052 secondary_[j].key = Heap::empty_string();
1053 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
1054 }
1055}
1056
1057
Ben Murdochb0fe1622011-05-05 13:52:32 +01001058void StubCache::CollectMatchingMaps(ZoneMapList* types,
1059 String* name,
1060 Code::Flags flags) {
1061 for (int i = 0; i < kPrimaryTableSize; i++) {
1062 if (primary_[i].key == name) {
1063 Map* map = primary_[i].value->FindFirstMap();
1064 // Map can be NULL, if the stub is constant function call
1065 // with a primitive receiver.
1066 if (map == NULL) continue;
1067
1068 int offset = PrimaryOffset(name, flags, map);
1069 if (entry(primary_, offset) == &primary_[i]) {
1070 types->Add(Handle<Map>(map));
1071 }
1072 }
1073 }
1074
1075 for (int i = 0; i < kSecondaryTableSize; i++) {
1076 if (secondary_[i].key == name) {
1077 Map* map = secondary_[i].value->FindFirstMap();
1078 // Map can be NULL, if the stub is constant function call
1079 // with a primitive receiver.
1080 if (map == NULL) continue;
1081
1082 // Lookup in primary table and skip duplicates.
1083 int primary_offset = PrimaryOffset(name, flags, map);
1084 Entry* primary_entry = entry(primary_, primary_offset);
1085 if (primary_entry->key == name) {
1086 Map* primary_map = primary_entry->value->FindFirstMap();
1087 if (map == primary_map) continue;
1088 }
1089
1090 // Lookup in secondary table and add matches.
1091 int offset = SecondaryOffset(name, flags, primary_offset);
1092 if (entry(secondary_, offset) == &secondary_[i]) {
1093 types->Add(Handle<Map>(map));
1094 }
1095 }
1096 }
1097}
1098
1099
Steve Blocka7e24c12009-10-30 11:49:00 +00001100// ------------------------------------------------------------------------
1101// StubCompiler implementation.
1102
1103
John Reck59135872010-11-02 12:39:01 -07001104MaybeObject* LoadCallbackProperty(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +00001105 ASSERT(args[0]->IsJSObject());
1106 ASSERT(args[1]->IsJSObject());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001107 AccessorInfo* callback = AccessorInfo::cast(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001108 Address getter_address = v8::ToCData<Address>(callback->getter());
1109 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1110 ASSERT(fun != NULL);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001111 v8::AccessorInfo info(&args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001112 HandleScope scope;
1113 v8::Handle<v8::Value> result;
1114 {
1115 // Leaving JavaScript.
1116 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001117 ExternalCallbackScope call_scope(getter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001118 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1119 }
1120 RETURN_IF_SCHEDULED_EXCEPTION();
1121 if (result.IsEmpty()) return Heap::undefined_value();
1122 return *v8::Utils::OpenHandle(*result);
1123}
1124
1125
John Reck59135872010-11-02 12:39:01 -07001126MaybeObject* StoreCallbackProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001127 JSObject* recv = JSObject::cast(args[0]);
1128 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1129 Address setter_address = v8::ToCData<Address>(callback->setter());
1130 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1131 ASSERT(fun != NULL);
1132 Handle<String> name = args.at<String>(2);
1133 Handle<Object> value = args.at<Object>(3);
1134 HandleScope scope;
1135 LOG(ApiNamedPropertyAccess("store", recv, *name));
1136 CustomArguments custom_args(callback->data(), recv, recv);
1137 v8::AccessorInfo info(custom_args.end());
1138 {
1139 // Leaving JavaScript.
1140 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001141 ExternalCallbackScope call_scope(setter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001142 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1143 }
1144 RETURN_IF_SCHEDULED_EXCEPTION();
1145 return *value;
1146}
1147
Steve Block6ded16b2010-05-10 14:33:55 +01001148
1149static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1150
1151
Steve Blocka7e24c12009-10-30 11:49:00 +00001152/**
1153 * Attempts to load a property with an interceptor (which must be present),
1154 * but doesn't search the prototype chain.
1155 *
1156 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1157 * provide any value for the given name.
1158 */
John Reck59135872010-11-02 12:39:01 -07001159MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001160 Handle<String> name_handle = args.at<String>(0);
1161 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1162 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1163 ASSERT(args[2]->IsJSObject()); // Receiver.
1164 ASSERT(args[3]->IsJSObject()); // Holder.
1165 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001166
1167 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1168 v8::NamedPropertyGetter getter =
1169 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1170 ASSERT(getter != NULL);
1171
1172 {
1173 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001174 v8::AccessorInfo info(args.arguments() -
1175 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 HandleScope scope;
1177 v8::Handle<v8::Value> r;
1178 {
1179 // Leaving JavaScript.
1180 VMState state(EXTERNAL);
1181 r = getter(v8::Utils::ToLocal(name_handle), info);
1182 }
1183 RETURN_IF_SCHEDULED_EXCEPTION();
1184 if (!r.IsEmpty()) {
1185 return *v8::Utils::OpenHandle(*r);
1186 }
1187 }
1188
1189 return Heap::no_interceptor_result_sentinel();
1190}
1191
1192
John Reck59135872010-11-02 12:39:01 -07001193static MaybeObject* ThrowReferenceError(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001194 // If the load is non-contextual, just return the undefined result.
1195 // Note that both keyed and non-keyed loads may end up here, so we
1196 // can't use either LoadIC or KeyedLoadIC constructors.
1197 IC ic(IC::NO_EXTRA_FRAME);
1198 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Leon Clarkee46be812010-01-19 14:06:41 +00001199 if (!ic.SlowIsContextual()) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001200
1201 // Throw a reference error.
1202 HandleScope scope;
1203 Handle<String> name_handle(name);
1204 Handle<Object> error =
1205 Factory::NewReferenceError("not_defined",
1206 HandleVector(&name_handle, 1));
1207 return Top::Throw(*error);
1208}
1209
1210
John Reck59135872010-11-02 12:39:01 -07001211static MaybeObject* LoadWithInterceptor(Arguments* args,
1212 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +01001213 Handle<String> name_handle = args->at<String>(0);
1214 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1215 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1216 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1217 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1218 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001219
1220 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1221 v8::NamedPropertyGetter getter =
1222 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1223 ASSERT(getter != NULL);
1224
1225 {
1226 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001227 v8::AccessorInfo info(args->arguments() -
1228 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001229 HandleScope scope;
1230 v8::Handle<v8::Value> r;
1231 {
1232 // Leaving JavaScript.
1233 VMState state(EXTERNAL);
1234 r = getter(v8::Utils::ToLocal(name_handle), info);
1235 }
1236 RETURN_IF_SCHEDULED_EXCEPTION();
1237 if (!r.IsEmpty()) {
1238 *attrs = NONE;
1239 return *v8::Utils::OpenHandle(*r);
1240 }
1241 }
1242
John Reck59135872010-11-02 12:39:01 -07001243 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00001244 *receiver_handle,
1245 *name_handle,
1246 attrs);
1247 RETURN_IF_SCHEDULED_EXCEPTION();
1248 return result;
1249}
1250
1251
1252/**
1253 * Loads a property with an interceptor performing post interceptor
1254 * lookup if interceptor failed.
1255 */
John Reck59135872010-11-02 12:39:01 -07001256MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001257 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001258 Object* result;
1259 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1260 if (!maybe_result->ToObject(&result)) return maybe_result;
1261 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001262
1263 // If the property is present, return it.
1264 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +01001265 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001266}
1267
1268
John Reck59135872010-11-02 12:39:01 -07001269MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001270 PropertyAttributes attr;
John Reck59135872010-11-02 12:39:01 -07001271 MaybeObject* result = LoadWithInterceptor(&args, &attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001272 RETURN_IF_SCHEDULED_EXCEPTION();
1273 // This is call IC. In this case, we simply return the undefined result which
1274 // will lead to an exception when trying to invoke the result as a
1275 // function.
1276 return result;
1277}
1278
1279
John Reck59135872010-11-02 12:39:01 -07001280MaybeObject* StoreInterceptorProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001281 JSObject* recv = JSObject::cast(args[0]);
1282 String* name = String::cast(args[1]);
1283 Object* value = args[2];
1284 ASSERT(recv->HasNamedInterceptor());
1285 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001286 MaybeObject* result = recv->SetPropertyWithInterceptor(name, value, attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001287 return result;
1288}
1289
1290
John Reck59135872010-11-02 12:39:01 -07001291MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001292 JSObject* receiver = JSObject::cast(args[0]);
Ben Murdochf87a2032010-10-22 12:50:53 +01001293 ASSERT(Smi::cast(args[1])->value() >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001294 uint32_t index = Smi::cast(args[1])->value();
1295 return receiver->GetElementWithInterceptor(receiver, index);
1296}
1297
1298
John Reck59135872010-11-02 12:39:01 -07001299MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 HandleScope scope;
1301 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001302 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1303 if (kind == Code::CALL_IC) {
1304 CallIC::GenerateInitialize(masm(), argc);
1305 } else {
1306 KeyedCallIC::GenerateInitialize(masm(), argc);
1307 }
John Reck59135872010-11-02 12:39:01 -07001308 Object* result;
1309 { MaybeObject* maybe_result =
1310 GetCodeWithFlags(flags, "CompileCallInitialize");
1311 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001312 }
John Reck59135872010-11-02 12:39:01 -07001313 Counters::call_initialize_stubs.Increment();
1314 Code* code = Code::cast(result);
1315 USE(code);
1316 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1317 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001318 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001319 return result;
1320}
1321
1322
John Reck59135872010-11-02 12:39:01 -07001323MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001324 HandleScope scope;
1325 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1326 // The code of the PreMonomorphic stub is the same as the code
1327 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001328 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1329 if (kind == Code::CALL_IC) {
1330 CallIC::GenerateInitialize(masm(), argc);
1331 } else {
1332 KeyedCallIC::GenerateInitialize(masm(), argc);
1333 }
John Reck59135872010-11-02 12:39:01 -07001334 Object* result;
1335 { MaybeObject* maybe_result =
1336 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1337 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001338 }
John Reck59135872010-11-02 12:39:01 -07001339 Counters::call_premonomorphic_stubs.Increment();
1340 Code* code = Code::cast(result);
1341 USE(code);
1342 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1343 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001344 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001345 return result;
1346}
1347
1348
John Reck59135872010-11-02 12:39:01 -07001349MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001350 HandleScope scope;
1351 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001352 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1353 if (kind == Code::CALL_IC) {
1354 CallIC::GenerateNormal(masm(), argc);
1355 } else {
1356 KeyedCallIC::GenerateNormal(masm(), argc);
1357 }
John Reck59135872010-11-02 12:39:01 -07001358 Object* result;
1359 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1360 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001361 }
John Reck59135872010-11-02 12:39:01 -07001362 Counters::call_normal_stubs.Increment();
1363 Code* code = Code::cast(result);
1364 USE(code);
1365 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1366 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001367 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001368 return result;
1369}
1370
1371
John Reck59135872010-11-02 12:39:01 -07001372MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001373 HandleScope scope;
1374 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001375 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1376 if (kind == Code::CALL_IC) {
1377 CallIC::GenerateMegamorphic(masm(), argc);
1378 } else {
1379 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1380 }
1381
John Reck59135872010-11-02 12:39:01 -07001382 Object* result;
1383 { MaybeObject* maybe_result =
1384 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1385 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001386 }
John Reck59135872010-11-02 12:39:01 -07001387 Counters::call_megamorphic_stubs.Increment();
1388 Code* code = Code::cast(result);
1389 USE(code);
1390 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1391 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001392 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001393 return result;
1394}
1395
1396
John Reck59135872010-11-02 12:39:01 -07001397MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 HandleScope scope;
1399 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001400 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1401 if (kind == Code::CALL_IC) {
1402 CallIC::GenerateMiss(masm(), argc);
1403 } else {
1404 KeyedCallIC::GenerateMiss(masm(), argc);
1405 }
John Reck59135872010-11-02 12:39:01 -07001406 Object* result;
1407 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1408 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001409 }
John Reck59135872010-11-02 12:39:01 -07001410 Counters::call_megamorphic_stubs.Increment();
1411 Code* code = Code::cast(result);
1412 USE(code);
1413 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1414 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001415 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 return result;
1417}
1418
1419
1420#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001421MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001422 HandleScope scope;
1423 Debug::GenerateCallICDebugBreak(masm());
John Reck59135872010-11-02 12:39:01 -07001424 Object* result;
1425 { MaybeObject* maybe_result =
1426 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1427 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001428 }
John Reck59135872010-11-02 12:39:01 -07001429 Code* code = Code::cast(result);
1430 USE(code);
1431 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1432 USE(kind);
1433 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
1434 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 return result;
1436}
1437
1438
John Reck59135872010-11-02 12:39:01 -07001439MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001440 HandleScope scope;
1441 // Use the same code for the the step in preparations as we do for
1442 // the miss case.
1443 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001444 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1445 if (kind == Code::CALL_IC) {
1446 CallIC::GenerateMiss(masm(), argc);
1447 } else {
1448 KeyedCallIC::GenerateMiss(masm(), argc);
1449 }
John Reck59135872010-11-02 12:39:01 -07001450 Object* result;
1451 { MaybeObject* maybe_result =
1452 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1453 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001454 }
John Reck59135872010-11-02 12:39:01 -07001455 Code* code = Code::cast(result);
1456 USE(code);
1457 PROFILE(CodeCreateEvent(
1458 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1459 code,
1460 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 return result;
1462}
1463#endif
1464
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001465#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001466
John Reck59135872010-11-02 12:39:01 -07001467MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1468 const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001469 // Check for allocation failures during stub compilation.
1470 if (failure_->IsFailure()) return failure_;
1471
1472 // Create code object in the heap.
1473 CodeDesc desc;
1474 masm_.GetCode(&desc);
John Reck59135872010-11-02 12:39:01 -07001475 MaybeObject* result = Heap::CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001476#ifdef ENABLE_DISASSEMBLER
1477 if (FLAG_print_code_stubs && !result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001478 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001479 }
1480#endif
1481 return result;
1482}
1483
1484
John Reck59135872010-11-02 12:39:01 -07001485MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001486 if (FLAG_print_code_stubs && (name != NULL)) {
1487 return GetCodeWithFlags(flags, *name->ToCString());
1488 }
1489 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1490}
1491
Andrei Popescu402d9372010-02-26 13:31:12 +00001492
Leon Clarke4515c472010-02-03 11:58:03 +00001493void StubCompiler::LookupPostInterceptor(JSObject* holder,
1494 String* name,
1495 LookupResult* lookup) {
1496 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001497 if (!lookup->IsProperty()) {
1498 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001499 Object* proto = holder->GetPrototype();
1500 if (proto != Heap::null_value()) {
1501 proto->Lookup(name, lookup);
1502 }
1503 }
1504}
1505
1506
Steve Blocka7e24c12009-10-30 11:49:00 +00001507
John Reck59135872010-11-02 12:39:01 -07001508MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001510 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001511 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001512 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG,
1513 Code::cast(result->ToObjectUnchecked()),
1514 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001515 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1516 name,
1517 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001518 }
1519 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001520}
1521
1522
John Reck59135872010-11-02 12:39:01 -07001523MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001524 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001525 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001526 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001527 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
1528 Code::cast(result->ToObjectUnchecked()),
1529 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001530 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1531 name,
1532 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001533 }
1534 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001535}
1536
1537
John Reck59135872010-11-02 12:39:01 -07001538MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001539 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
John Reck59135872010-11-02 12:39:01 -07001540 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001541 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001542 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,
1543 Code::cast(result->ToObjectUnchecked()),
1544 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001545 GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1546 name,
1547 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001548 }
1549 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001550}
1551
1552
John Reck59135872010-11-02 12:39:01 -07001553MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001554 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
John Reck59135872010-11-02 12:39:01 -07001555 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001556 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001557 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
1558 Code::cast(result->ToObjectUnchecked()),
1559 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001560 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1561 name,
1562 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001563 }
1564 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001565}
1566
1567
Steve Block8defd9f2010-07-08 12:39:36 +01001568CallStubCompiler::CallStubCompiler(int argc,
1569 InLoopFlag in_loop,
1570 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001571 Code::ExtraICState extra_ic_state,
Steve Block8defd9f2010-07-08 12:39:36 +01001572 InlineCacheHolderFlag cache_holder)
Ben Murdochb8e0da22011-05-16 14:20:40 +01001573 : arguments_(argc),
1574 in_loop_(in_loop),
1575 kind_(kind),
1576 extra_ic_state_(extra_ic_state),
1577 cache_holder_(cache_holder) {
Steve Block8defd9f2010-07-08 12:39:36 +01001578}
1579
1580
Ben Murdochb0fe1622011-05-05 13:52:32 +01001581bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) {
1582#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1583 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1584#undef CALL_GENERATOR_CASE
1585 return false;
1586}
1587
1588
1589MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id,
John Reck59135872010-11-02 12:39:01 -07001590 Object* object,
1591 JSObject* holder,
1592 JSGlobalPropertyCell* cell,
1593 JSFunction* function,
1594 String* fname) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001595#define CALL_GENERATOR_CASE(name) \
1596 if (id == k##name) { \
1597 return CallStubCompiler::Compile##name##Call(object, \
1598 holder, \
1599 cell, \
1600 function, \
1601 fname); \
Steve Block59151502010-09-22 15:07:15 +01001602 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001603 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1604#undef CALL_GENERATOR_CASE
1605 ASSERT(!HasCustomCallGenerator(id));
Steve Block59151502010-09-22 15:07:15 +01001606 return Heap::undefined_value();
Kristian Monsen25f61362010-05-21 11:50:48 +01001607}
1608
1609
John Reck59135872010-11-02 12:39:01 -07001610MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001611 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001612 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001613 type,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001614 extra_ic_state_,
Steve Block8defd9f2010-07-08 12:39:36 +01001615 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001616 in_loop_,
1617 argc);
1618 return GetCodeWithFlags(flags, name);
1619}
1620
1621
John Reck59135872010-11-02 12:39:01 -07001622MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001623 String* function_name = NULL;
1624 if (function->shared()->name()->IsString()) {
1625 function_name = String::cast(function->shared()->name());
1626 }
1627 return GetCode(CONSTANT_FUNCTION, function_name);
1628}
1629
1630
John Reck59135872010-11-02 12:39:01 -07001631MaybeObject* ConstructStubCompiler::GetCode() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001632 Code::Flags flags = Code::ComputeFlags(Code::STUB);
John Reck59135872010-11-02 12:39:01 -07001633 Object* result;
1634 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1635 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001636 }
John Reck59135872010-11-02 12:39:01 -07001637 Code* code = Code::cast(result);
1638 USE(code);
1639 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001640 GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001641 return result;
1642}
1643
1644
Steve Block6ded16b2010-05-10 14:33:55 +01001645CallOptimization::CallOptimization(LookupResult* lookup) {
1646 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1647 lookup->type() != CONSTANT_FUNCTION) {
1648 Initialize(NULL);
1649 } else {
1650 // We only optimize constant function calls.
1651 Initialize(lookup->GetConstantFunction());
1652 }
1653}
1654
1655CallOptimization::CallOptimization(JSFunction* function) {
1656 Initialize(function);
1657}
1658
1659
1660int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1661 JSObject* holder) const {
1662 ASSERT(is_simple_api_call_);
1663 if (expected_receiver_type_ == NULL) return 0;
1664 int depth = 0;
1665 while (object != holder) {
1666 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1667 object = JSObject::cast(object->GetPrototype());
1668 ++depth;
1669 }
1670 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1671 return kInvalidProtoDepth;
1672}
1673
1674
1675void CallOptimization::Initialize(JSFunction* function) {
1676 constant_function_ = NULL;
1677 is_simple_api_call_ = false;
1678 expected_receiver_type_ = NULL;
1679 api_call_info_ = NULL;
1680
1681 if (function == NULL || !function->is_compiled()) return;
1682
1683 constant_function_ = function;
1684 AnalyzePossibleApiFunction(function);
1685}
1686
1687
1688void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1689 SharedFunctionInfo* sfi = function->shared();
1690 if (!sfi->IsApiFunction()) return;
1691 FunctionTemplateInfo* info = sfi->get_api_func_data();
1692
1693 // Require a C++ callback.
1694 if (info->call_code()->IsUndefined()) return;
1695 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1696
1697 // Accept signatures that either have no restrictions at all or
1698 // only have restrictions on the receiver.
1699 if (!info->signature()->IsUndefined()) {
1700 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1701 if (!signature->args()->IsUndefined()) return;
1702 if (!signature->receiver()->IsUndefined()) {
1703 expected_receiver_type_ =
1704 FunctionTemplateInfo::cast(signature->receiver());
1705 }
1706 }
1707
1708 is_simple_api_call_ = true;
1709}
1710
1711
Steve Blocka7e24c12009-10-30 11:49:00 +00001712} } // namespace v8::internal