blob: 86e72012135fb305bf5f6e3c660b1648e3a9172e [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "ic-inl.h"
33#include "stub-cache.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010034#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035
36namespace v8 {
37namespace internal {
38
39// -----------------------------------------------------------------------
40// StubCache implementation.
41
42
43StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
44StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
45
46void StubCache::Initialize(bool create_heap_objects) {
47 ASSERT(IsPowerOf2(kPrimaryTableSize));
48 ASSERT(IsPowerOf2(kSecondaryTableSize));
49 if (create_heap_objects) {
50 HandleScope scope;
51 Clear();
52 }
53}
54
55
56Code* StubCache::Set(String* name, Map* map, Code* code) {
57 // Get the flags from the code.
58 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
59
60 // Validate that the name does not move on scavenge, and that we
61 // can use identity checks instead of string equality checks.
62 ASSERT(!Heap::InNewSpace(name));
63 ASSERT(name->IsSymbol());
64
65 // The state bits are not important to the hash function because
66 // the stub cache only contains monomorphic stubs. Make sure that
67 // the bits are the least significant so they will be the ones
68 // masked out.
69 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
70 ASSERT(Code::kFlagsICStateShift == 0);
71
72 // Make sure that the code type is not included in the hash.
73 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
74
75 // Compute the primary entry.
76 int primary_offset = PrimaryOffset(name, flags, map);
77 Entry* primary = entry(primary_, primary_offset);
78 Code* hit = primary->value;
79
80 // If the primary entry has useful data in it, we retire it to the
81 // secondary cache before overwriting it.
82 if (hit != Builtins::builtin(Builtins::Illegal)) {
83 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
84 int secondary_offset =
85 SecondaryOffset(primary->key, primary_flags, primary_offset);
86 Entry* secondary = entry(secondary_, secondary_offset);
87 *secondary = *primary;
88 }
89
90 // Update primary cache.
91 primary->key = name;
92 primary->value = code;
93 return code;
94}
95
96
John Reck59135872010-11-02 12:39:01 -070097MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
98 JSObject* receiver) {
Steve Block8defd9f2010-07-08 12:39:36 +010099 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
Steve Block6ded16b2010-05-10 14:33:55 +0100100 // If no global objects are present in the prototype chain, the load
101 // nonexistent IC stub can be shared for all names for a given map
102 // and we use the empty string for the map cache in that case. If
103 // there are global objects involved, we need to check global
104 // property cells in the stub and therefore the stub will be
105 // specific to the name.
106 String* cache_name = Heap::empty_string();
107 if (receiver->IsGlobalObject()) cache_name = name;
108 JSObject* last = receiver;
109 while (last->GetPrototype() != Heap::null_value()) {
110 last = JSObject::cast(last->GetPrototype());
111 if (last->IsGlobalObject()) cache_name = name;
112 }
113 // Compile the stub that is either shared for all names or
114 // name specific if there are global objects involved.
115 Code::Flags flags =
116 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
117 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
118 if (code->IsUndefined()) {
119 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700120 { MaybeObject* maybe_code =
121 compiler.CompileLoadNonexistent(cache_name, receiver, last);
122 if (!maybe_code->ToObject(&code)) return maybe_code;
123 }
Steve Block6ded16b2010-05-10 14:33:55 +0100124 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
John Reck59135872010-11-02 12:39:01 -0700125 Object* result;
126 { MaybeObject* maybe_result =
127 receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
128 if (!maybe_result->ToObject(&result)) return maybe_result;
129 }
Steve Block6ded16b2010-05-10 14:33:55 +0100130 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100131 return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100132}
133
134
John Reck59135872010-11-02 12:39:01 -0700135MaybeObject* StubCache::ComputeLoadField(String* name,
136 JSObject* receiver,
137 JSObject* holder,
138 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100139 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100141 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000142 if (code->IsUndefined()) {
143 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700144 { MaybeObject* maybe_code =
145 compiler.CompileLoadField(receiver, holder, field_index, name);
146 if (!maybe_code->ToObject(&code)) return maybe_code;
147 }
Steve Block6ded16b2010-05-10 14:33:55 +0100148 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700149 Object* result;
150 { MaybeObject* maybe_result =
151 receiver->UpdateMapCodeCache(name, Code::cast(code));
152 if (!maybe_result->ToObject(&result)) return maybe_result;
153 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100155 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000156}
157
158
John Reck59135872010-11-02 12:39:01 -0700159MaybeObject* StubCache::ComputeLoadCallback(String* name,
160 JSObject* receiver,
161 JSObject* holder,
162 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000163 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Steve Block8defd9f2010-07-08 12:39:36 +0100164 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000165 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100166 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000167 if (code->IsUndefined()) {
168 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700169 { MaybeObject* maybe_code =
170 compiler.CompileLoadCallback(name, receiver, holder, callback);
171 if (!maybe_code->ToObject(&code)) return maybe_code;
172 }
Steve Block6ded16b2010-05-10 14:33:55 +0100173 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700174 Object* result;
175 { MaybeObject* maybe_result =
176 receiver->UpdateMapCodeCache(name, Code::cast(code));
177 if (!maybe_result->ToObject(&result)) return maybe_result;
178 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100180 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000181}
182
183
John Reck59135872010-11-02 12:39:01 -0700184MaybeObject* StubCache::ComputeLoadConstant(String* name,
185 JSObject* receiver,
186 JSObject* holder,
187 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100188 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000189 Code::Flags flags =
190 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100191 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 if (code->IsUndefined()) {
193 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700194 { MaybeObject* maybe_code =
195 compiler.CompileLoadConstant(receiver, holder, value, name);
196 if (!maybe_code->ToObject(&code)) return maybe_code;
197 }
Steve Block6ded16b2010-05-10 14:33:55 +0100198 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700199 Object* result;
200 { MaybeObject* maybe_result =
201 receiver->UpdateMapCodeCache(name, Code::cast(code));
202 if (!maybe_result->ToObject(&result)) return maybe_result;
203 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100205 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000206}
207
208
John Reck59135872010-11-02 12:39:01 -0700209MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
210 JSObject* receiver,
211 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100212 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100214 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 if (code->IsUndefined()) {
216 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700217 { MaybeObject* maybe_code =
218 compiler.CompileLoadInterceptor(receiver, holder, name);
219 if (!maybe_code->ToObject(&code)) return maybe_code;
220 }
Steve Block6ded16b2010-05-10 14:33:55 +0100221 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700222 Object* result;
223 { MaybeObject* maybe_result =
224 receiver->UpdateMapCodeCache(name, Code::cast(code));
225 if (!maybe_result->ToObject(&result)) return maybe_result;
226 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000227 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100228 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000229}
230
231
John Reck59135872010-11-02 12:39:01 -0700232MaybeObject* StubCache::ComputeLoadNormal() {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100233 return Builtins::builtin(Builtins::LoadIC_Normal);
Steve Blocka7e24c12009-10-30 11:49:00 +0000234}
235
236
John Reck59135872010-11-02 12:39:01 -0700237MaybeObject* StubCache::ComputeLoadGlobal(String* name,
238 JSObject* receiver,
239 GlobalObject* holder,
240 JSGlobalPropertyCell* cell,
241 bool is_dont_delete) {
Steve Block8defd9f2010-07-08 12:39:36 +0100242 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000243 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100244 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 if (code->IsUndefined()) {
246 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700247 { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
248 holder,
249 cell,
250 name,
251 is_dont_delete);
252 if (!maybe_code->ToObject(&code)) return maybe_code;
253 }
Steve Block6ded16b2010-05-10 14:33:55 +0100254 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700255 Object* result;
256 { MaybeObject* maybe_result =
257 receiver->UpdateMapCodeCache(name, Code::cast(code));
258 if (!maybe_result->ToObject(&result)) return maybe_result;
259 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000260 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100261 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000262}
263
264
John Reck59135872010-11-02 12:39:01 -0700265MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
266 JSObject* receiver,
267 JSObject* holder,
268 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100269 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000270 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100271 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000272 if (code->IsUndefined()) {
273 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700274 { MaybeObject* maybe_code =
275 compiler.CompileLoadField(name, receiver, holder, field_index);
276 if (!maybe_code->ToObject(&code)) return maybe_code;
277 }
Steve Block6ded16b2010-05-10 14:33:55 +0100278 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700279 Object* result;
280 { MaybeObject* maybe_result =
281 receiver->UpdateMapCodeCache(name, Code::cast(code));
282 if (!maybe_result->ToObject(&result)) return maybe_result;
283 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000284 }
285 return code;
286}
287
288
John Reck59135872010-11-02 12:39:01 -0700289MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
290 JSObject* receiver,
291 JSObject* holder,
292 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100293 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000294 Code::Flags flags =
295 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100296 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000297 if (code->IsUndefined()) {
298 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700299 { MaybeObject* maybe_code =
300 compiler.CompileLoadConstant(name, receiver, holder, value);
301 if (!maybe_code->ToObject(&code)) return maybe_code;
302 }
Steve Block6ded16b2010-05-10 14:33:55 +0100303 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700304 Object* result;
305 { MaybeObject* maybe_result =
306 receiver->UpdateMapCodeCache(name, Code::cast(code));
307 if (!maybe_result->ToObject(&result)) return maybe_result;
308 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000309 }
310 return code;
311}
312
313
John Reck59135872010-11-02 12:39:01 -0700314MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
315 JSObject* receiver,
316 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100317 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 Code::Flags flags =
319 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100320 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 if (code->IsUndefined()) {
322 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700323 { MaybeObject* maybe_code =
324 compiler.CompileLoadInterceptor(receiver, holder, name);
325 if (!maybe_code->ToObject(&code)) return maybe_code;
326 }
Steve Block6ded16b2010-05-10 14:33:55 +0100327 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700328 Object* result;
329 { MaybeObject* maybe_result =
330 receiver->UpdateMapCodeCache(name, Code::cast(code));
331 if (!maybe_result->ToObject(&result)) return maybe_result;
332 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000333 }
334 return code;
335}
336
337
John Reck59135872010-11-02 12:39:01 -0700338MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
339 JSObject* receiver,
340 JSObject* holder,
341 AccessorInfo* callback) {
Steve Block8defd9f2010-07-08 12:39:36 +0100342 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 Code::Flags flags =
344 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100345 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 if (code->IsUndefined()) {
347 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700348 { MaybeObject* maybe_code =
349 compiler.CompileLoadCallback(name, receiver, holder, callback);
350 if (!maybe_code->ToObject(&code)) return maybe_code;
351 }
Steve Block6ded16b2010-05-10 14:33:55 +0100352 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700353 Object* result;
354 { MaybeObject* maybe_result =
355 receiver->UpdateMapCodeCache(name, Code::cast(code));
356 if (!maybe_result->ToObject(&result)) return maybe_result;
357 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 }
359 return code;
360}
361
362
363
John Reck59135872010-11-02 12:39:01 -0700364MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
365 JSArray* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000366 Code::Flags flags =
367 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100368 ASSERT(receiver->IsJSObject());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100369 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 if (code->IsUndefined()) {
371 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700372 { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
373 if (!maybe_code->ToObject(&code)) return maybe_code;
374 }
Steve Block6ded16b2010-05-10 14:33:55 +0100375 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700376 Object* result;
377 { MaybeObject* maybe_result =
378 receiver->UpdateMapCodeCache(name, Code::cast(code));
379 if (!maybe_result->ToObject(&result)) return maybe_result;
380 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 }
382 return code;
383}
384
385
John Reck59135872010-11-02 12:39:01 -0700386MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
387 String* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 Code::Flags flags =
389 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100390 Map* map = receiver->map();
391 Object* code = map->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 if (code->IsUndefined()) {
393 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700394 { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
395 if (!maybe_code->ToObject(&code)) return maybe_code;
396 }
Steve Block6ded16b2010-05-10 14:33:55 +0100397 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700398 Object* result;
399 { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
400 if (!maybe_result->ToObject(&result)) return maybe_result;
401 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000402 }
403 return code;
404}
405
406
John Reck59135872010-11-02 12:39:01 -0700407MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
408 String* name,
409 JSFunction* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 Code::Flags flags =
411 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100412 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000413 if (code->IsUndefined()) {
414 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700415 { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
416 if (!maybe_code->ToObject(&code)) return maybe_code;
417 }
Steve Block6ded16b2010-05-10 14:33:55 +0100418 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700419 Object* result;
420 { MaybeObject* maybe_result =
421 receiver->UpdateMapCodeCache(name, Code::cast(code));
422 if (!maybe_result->ToObject(&result)) return maybe_result;
423 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 }
425 return code;
426}
427
428
Ben Murdochb0fe1622011-05-05 13:52:32 +0100429MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
430 Code::Flags flags =
431 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
432 String* name = Heap::KeyedLoadSpecialized_symbol();
433 Object* code = receiver->map()->FindInCodeCache(name, flags);
434 if (code->IsUndefined()) {
435 KeyedLoadStubCompiler compiler;
436 { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
437 if (!maybe_code->ToObject(&code)) return maybe_code;
438 }
439 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
440 Object* result;
441 { MaybeObject* maybe_result =
442 receiver->UpdateMapCodeCache(name, Code::cast(code));
443 if (!maybe_result->ToObject(&result)) return maybe_result;
444 }
445 }
446 return code;
447}
448
449
John Reck59135872010-11-02 12:39:01 -0700450MaybeObject* StubCache::ComputeStoreField(String* name,
451 JSObject* receiver,
452 int field_index,
453 Map* transition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
455 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
456 Object* code = receiver->map()->FindInCodeCache(name, flags);
457 if (code->IsUndefined()) {
458 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700459 { MaybeObject* maybe_code =
460 compiler.CompileStoreField(receiver, field_index, transition, name);
461 if (!maybe_code->ToObject(&code)) return maybe_code;
462 }
Steve Block6ded16b2010-05-10 14:33:55 +0100463 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700464 Object* result;
465 { MaybeObject* maybe_result =
466 receiver->UpdateMapCodeCache(name, Code::cast(code));
467 if (!maybe_result->ToObject(&result)) return maybe_result;
468 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100470 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000471}
472
473
Ben Murdochb0fe1622011-05-05 13:52:32 +0100474MaybeObject* StubCache::ComputeKeyedStoreSpecialized(JSObject* receiver) {
475 Code::Flags flags =
476 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL);
477 String* name = Heap::KeyedStoreSpecialized_symbol();
478 Object* code = receiver->map()->FindInCodeCache(name, flags);
479 if (code->IsUndefined()) {
480 KeyedStoreStubCompiler compiler;
481 { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
482 if (!maybe_code->ToObject(&code)) return maybe_code;
483 }
484 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
485 Object* result;
486 { MaybeObject* maybe_result =
487 receiver->UpdateMapCodeCache(name, Code::cast(code));
488 if (!maybe_result->ToObject(&result)) return maybe_result;
489 }
490 }
491 return code;
492}
493
494
John Reck59135872010-11-02 12:39:01 -0700495MaybeObject* StubCache::ComputeStoreNormal() {
Steve Block8defd9f2010-07-08 12:39:36 +0100496 return Builtins::builtin(Builtins::StoreIC_Normal);
497}
498
499
John Reck59135872010-11-02 12:39:01 -0700500MaybeObject* StubCache::ComputeStoreGlobal(String* name,
501 GlobalObject* receiver,
502 JSGlobalPropertyCell* cell) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000503 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
504 Object* code = receiver->map()->FindInCodeCache(name, flags);
505 if (code->IsUndefined()) {
506 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700507 { MaybeObject* maybe_code =
508 compiler.CompileStoreGlobal(receiver, cell, name);
509 if (!maybe_code->ToObject(&code)) return maybe_code;
510 }
Steve Block8defd9f2010-07-08 12:39:36 +0100511 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700512 Object* result;
513 { MaybeObject* maybe_result =
514 receiver->UpdateMapCodeCache(name, Code::cast(code));
515 if (!maybe_result->ToObject(&result)) return maybe_result;
516 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000517 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100518 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000519}
520
521
John Reck59135872010-11-02 12:39:01 -0700522MaybeObject* StubCache::ComputeStoreCallback(String* name,
523 JSObject* receiver,
524 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000525 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
526 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
527 Object* code = receiver->map()->FindInCodeCache(name, flags);
528 if (code->IsUndefined()) {
529 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700530 { MaybeObject* maybe_code =
531 compiler.CompileStoreCallback(receiver, callback, name);
532 if (!maybe_code->ToObject(&code)) return maybe_code;
533 }
Steve Block6ded16b2010-05-10 14:33:55 +0100534 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700535 Object* result;
536 { MaybeObject* maybe_result =
537 receiver->UpdateMapCodeCache(name, Code::cast(code));
538 if (!maybe_result->ToObject(&result)) return maybe_result;
539 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000540 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100541 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000542}
543
544
John Reck59135872010-11-02 12:39:01 -0700545MaybeObject* StubCache::ComputeStoreInterceptor(String* name,
546 JSObject* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 Code::Flags flags =
548 Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
549 Object* code = receiver->map()->FindInCodeCache(name, flags);
550 if (code->IsUndefined()) {
551 StoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700552 { MaybeObject* maybe_code =
553 compiler.CompileStoreInterceptor(receiver, name);
554 if (!maybe_code->ToObject(&code)) return maybe_code;
555 }
Steve Block6ded16b2010-05-10 14:33:55 +0100556 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700557 Object* result;
558 { MaybeObject* maybe_result =
559 receiver->UpdateMapCodeCache(name, Code::cast(code));
560 if (!maybe_result->ToObject(&result)) return maybe_result;
561 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000562 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100563 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000564}
565
566
John Reck59135872010-11-02 12:39:01 -0700567MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
568 JSObject* receiver,
569 int field_index,
570 Map* transition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000571 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
572 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
573 Object* code = receiver->map()->FindInCodeCache(name, flags);
574 if (code->IsUndefined()) {
575 KeyedStoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700576 { MaybeObject* maybe_code =
577 compiler.CompileStoreField(receiver, field_index, transition, name);
578 if (!maybe_code->ToObject(&code)) return maybe_code;
579 }
Steve Block6ded16b2010-05-10 14:33:55 +0100580 PROFILE(CodeCreateEvent(
581 Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700582 Object* result;
583 { MaybeObject* maybe_result =
584 receiver->UpdateMapCodeCache(name, Code::cast(code));
585 if (!maybe_result->ToObject(&result)) return maybe_result;
586 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000587 }
588 return code;
589}
590
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100591#define CALL_LOGGER_TAG(kind, type) \
592 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000593
John Reck59135872010-11-02 12:39:01 -0700594MaybeObject* StubCache::ComputeCallConstant(int argc,
595 InLoopFlag in_loop,
596 Code::Kind kind,
597 String* name,
598 Object* object,
599 JSObject* holder,
600 JSFunction* function) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100602 InlineCacheHolderFlag cache_holder =
603 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100604 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000605
606 // Compute check type based on receiver/holder.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100607 CheckType check = RECEIVER_MAP_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 if (object->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100609 check = STRING_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 } else if (object->IsNumber()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100611 check = NUMBER_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000612 } else if (object->IsBoolean()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100613 check = BOOLEAN_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000614 }
615
616 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100617 Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000618 CONSTANT_FUNCTION,
Steve Block8defd9f2010-07-08 12:39:36 +0100619 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000620 in_loop,
621 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100622 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000623 if (code->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 // If the function hasn't been compiled yet, we cannot do it now
625 // because it may cause GC. To avoid this issue, we return an
626 // internal error which will make sure we do not update any
627 // caches.
628 if (!function->is_compiled()) return Failure::InternalError();
629 // Compile the stub - only create stubs for fully compiled functions.
Steve Block8defd9f2010-07-08 12:39:36 +0100630 CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700631 { MaybeObject* maybe_code =
632 compiler.CompileCallConstant(object, holder, function, name, check);
633 if (!maybe_code->ToObject(&code)) return maybe_code;
634 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100635 Code::cast(code)->set_check_type(check);
Steve Blocka7e24c12009-10-30 11:49:00 +0000636 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100637 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
638 Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700639 Object* result;
640 { MaybeObject* maybe_result =
641 map_holder->UpdateMapCodeCache(name, Code::cast(code));
642 if (!maybe_result->ToObject(&result)) return maybe_result;
643 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000644 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100645 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000646}
647
648
John Reck59135872010-11-02 12:39:01 -0700649MaybeObject* StubCache::ComputeCallField(int argc,
650 InLoopFlag in_loop,
651 Code::Kind kind,
652 String* name,
653 Object* object,
654 JSObject* holder,
655 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000656 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100657 InlineCacheHolderFlag cache_holder =
658 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100659 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000660
661 // TODO(1233596): We cannot do receiver map check for non-JS objects
662 // because they may be represented as immediates without a
663 // map. Instead, we check against the map in the holder.
664 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
665 object = holder;
666 }
667
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100668 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 FIELD,
Steve Block8defd9f2010-07-08 12:39:36 +0100670 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000671 in_loop,
672 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100673 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000674 if (code->IsUndefined()) {
Steve Block8defd9f2010-07-08 12:39:36 +0100675 CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700676 { MaybeObject* maybe_code =
677 compiler.CompileCallField(JSObject::cast(object),
678 holder,
679 index,
680 name);
681 if (!maybe_code->ToObject(&code)) return maybe_code;
682 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000683 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100684 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
685 Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700686 Object* result;
687 { MaybeObject* maybe_result =
688 map_holder->UpdateMapCodeCache(name, Code::cast(code));
689 if (!maybe_result->ToObject(&result)) return maybe_result;
690 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100692 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000693}
694
695
John Reck59135872010-11-02 12:39:01 -0700696MaybeObject* StubCache::ComputeCallInterceptor(int argc,
697 Code::Kind kind,
698 String* name,
699 Object* object,
700 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000701 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100702 InlineCacheHolderFlag cache_holder =
703 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100704 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000705
706 // TODO(1233596): We cannot do receiver map check for non-JS objects
707 // because they may be represented as immediates without a
708 // map. Instead, we check against the map in the holder.
709 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
710 object = holder;
711 }
712
713 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100714 Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000715 INTERCEPTOR,
Steve Block8defd9f2010-07-08 12:39:36 +0100716 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 NOT_IN_LOOP,
718 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100719 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000720 if (code->IsUndefined()) {
Steve Block8defd9f2010-07-08 12:39:36 +0100721 CallStubCompiler compiler(argc, NOT_IN_LOOP, kind, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700722 { MaybeObject* maybe_code =
723 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
724 if (!maybe_code->ToObject(&code)) return maybe_code;
725 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000726 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100727 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
728 Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700729 Object* result;
730 { MaybeObject* maybe_result =
731 map_holder->UpdateMapCodeCache(name, Code::cast(code));
732 if (!maybe_result->ToObject(&result)) return maybe_result;
733 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100735 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000736}
737
738
John Reck59135872010-11-02 12:39:01 -0700739MaybeObject* StubCache::ComputeCallNormal(int argc,
740 InLoopFlag in_loop,
741 Code::Kind kind,
742 String* name,
743 JSObject* receiver) {
744 Object* code;
745 { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
746 if (!maybe_code->ToObject(&code)) return maybe_code;
747 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100748 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000749}
750
751
John Reck59135872010-11-02 12:39:01 -0700752MaybeObject* StubCache::ComputeCallGlobal(int argc,
753 InLoopFlag in_loop,
754 Code::Kind kind,
755 String* name,
756 JSObject* receiver,
757 GlobalObject* holder,
758 JSGlobalPropertyCell* cell,
759 JSFunction* function) {
Steve Block8defd9f2010-07-08 12:39:36 +0100760 InlineCacheHolderFlag cache_holder =
761 IC::GetCodeCacheForObject(receiver, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100762 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000763 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100764 Code::ComputeMonomorphicFlags(kind,
765 NORMAL,
Steve Block8defd9f2010-07-08 12:39:36 +0100766 cache_holder,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100767 in_loop,
768 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100769 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000770 if (code->IsUndefined()) {
771 // If the function hasn't been compiled yet, we cannot do it now
772 // because it may cause GC. To avoid this issue, we return an
773 // internal error which will make sure we do not update any
774 // caches.
775 if (!function->is_compiled()) return Failure::InternalError();
Steve Block8defd9f2010-07-08 12:39:36 +0100776 CallStubCompiler compiler(argc, in_loop, kind, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700777 { MaybeObject* maybe_code =
778 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
779 if (!maybe_code->ToObject(&code)) return maybe_code;
780 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100782 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
783 Code::cast(code), name));
John Reck59135872010-11-02 12:39:01 -0700784 Object* result;
785 { MaybeObject* maybe_result =
786 map_holder->UpdateMapCodeCache(name, Code::cast(code));
787 if (!maybe_result->ToObject(&result)) return maybe_result;
788 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000789 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100790 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000791}
792
793
794static Object* GetProbeValue(Code::Flags flags) {
795 // Use raw_unchecked... so we don't get assert failures during GC.
796 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
797 int entry = dictionary->FindEntry(flags);
798 if (entry != -1) return dictionary->ValueAt(entry);
799 return Heap::raw_unchecked_undefined_value();
800}
801
802
John Reck59135872010-11-02 12:39:01 -0700803MUST_USE_RESULT static MaybeObject* ProbeCache(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000804 Object* probe = GetProbeValue(flags);
805 if (probe != Heap::undefined_value()) return probe;
806 // Seed the cache with an undefined value to make sure that any
807 // generated code object can always be inserted into the cache
808 // without causing allocation failures.
John Reck59135872010-11-02 12:39:01 -0700809 Object* result;
810 { MaybeObject* maybe_result =
811 Heap::non_monomorphic_cache()->AtNumberPut(flags,
812 Heap::undefined_value());
813 if (!maybe_result->ToObject(&result)) return maybe_result;
814 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000815 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
816 return probe;
817}
818
819
John Reck59135872010-11-02 12:39:01 -0700820static MaybeObject* FillCache(MaybeObject* maybe_code) {
821 Object* code;
822 if (maybe_code->ToObject(&code)) {
823 if (code->IsCode()) {
824 int entry =
825 Heap::non_monomorphic_cache()->FindEntry(
826 Code::cast(code)->flags());
827 // The entry must be present see comment in ProbeCache.
828 ASSERT(entry != -1);
829 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
830 Heap::undefined_value());
831 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
832 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
833 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000834 }
John Reck59135872010-11-02 12:39:01 -0700835 return maybe_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000836}
837
838
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100839Code* StubCache::FindCallInitialize(int argc,
840 InLoopFlag in_loop,
841 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000842 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100843 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
John Reck59135872010-11-02 12:39:01 -0700844 Object* result = ProbeCache(flags)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 ASSERT(!result->IsUndefined());
846 // This might be called during the marking phase of the collector
847 // hence the unchecked cast.
848 return reinterpret_cast<Code*>(result);
849}
850
851
John Reck59135872010-11-02 12:39:01 -0700852MaybeObject* StubCache::ComputeCallInitialize(int argc,
853 InLoopFlag in_loop,
854 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000855 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100856 Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc);
John Reck59135872010-11-02 12:39:01 -0700857 Object* probe;
858 { MaybeObject* maybe_probe = ProbeCache(flags);
859 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
860 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 if (!probe->IsUndefined()) return probe;
862 StubCompiler compiler;
863 return FillCache(compiler.CompileCallInitialize(flags));
864}
865
866
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800867Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
868 if (in_loop == IN_LOOP) {
869 // Force the creation of the corresponding stub outside loops,
870 // because it may be used when clearing the ICs later - it is
871 // possible for a series of IC transitions to lose the in-loop
872 // information, and the IC clearing code can't generate a stub
873 // that it needs so we need to ensure it is generated already.
874 ComputeCallInitialize(argc, NOT_IN_LOOP);
875 }
876 CALL_HEAP_FUNCTION(ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
877}
878
879
880Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
881 InLoopFlag in_loop) {
882 if (in_loop == IN_LOOP) {
883 // Force the creation of the corresponding stub outside loops,
884 // because it may be used when clearing the ICs later - it is
885 // possible for a series of IC transitions to lose the in-loop
886 // information, and the IC clearing code can't generate a stub
887 // that it needs so we need to ensure it is generated already.
888 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
889 }
890 CALL_HEAP_FUNCTION(
891 ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
892}
893
894
John Reck59135872010-11-02 12:39:01 -0700895MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
896 InLoopFlag in_loop,
897 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100899 Code::ComputeFlags(kind, in_loop, PREMONOMORPHIC, NORMAL, argc);
John Reck59135872010-11-02 12:39:01 -0700900 Object* probe;
901 { MaybeObject* maybe_probe = ProbeCache(flags);
902 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
903 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000904 if (!probe->IsUndefined()) return probe;
905 StubCompiler compiler;
906 return FillCache(compiler.CompileCallPreMonomorphic(flags));
907}
908
909
John Reck59135872010-11-02 12:39:01 -0700910MaybeObject* StubCache::ComputeCallNormal(int argc,
911 InLoopFlag in_loop,
912 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000913 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100914 Code::ComputeFlags(kind, in_loop, MONOMORPHIC, NORMAL, argc);
John Reck59135872010-11-02 12:39:01 -0700915 Object* probe;
916 { MaybeObject* maybe_probe = ProbeCache(flags);
917 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
918 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000919 if (!probe->IsUndefined()) return probe;
920 StubCompiler compiler;
921 return FillCache(compiler.CompileCallNormal(flags));
922}
923
924
John Reck59135872010-11-02 12:39:01 -0700925MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
926 InLoopFlag in_loop,
927 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000928 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100929 Code::ComputeFlags(kind, in_loop, MEGAMORPHIC, NORMAL, argc);
John Reck59135872010-11-02 12:39:01 -0700930 Object* probe;
931 { MaybeObject* maybe_probe = ProbeCache(flags);
932 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
933 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000934 if (!probe->IsUndefined()) return probe;
935 StubCompiler compiler;
936 return FillCache(compiler.CompileCallMegamorphic(flags));
937}
938
939
John Reck59135872010-11-02 12:39:01 -0700940MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100941 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
942 // and monomorphic stubs are not mixed up together in the stub cache.
943 Code::Flags flags = Code::ComputeFlags(
944 kind, NOT_IN_LOOP, MONOMORPHIC_PROTOTYPE_FAILURE, NORMAL, argc);
John Reck59135872010-11-02 12:39:01 -0700945 Object* probe;
946 { MaybeObject* maybe_probe = ProbeCache(flags);
947 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
948 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 if (!probe->IsUndefined()) return probe;
950 StubCompiler compiler;
951 return FillCache(compiler.CompileCallMiss(flags));
952}
953
954
955#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -0700956MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000957 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100958 Code::ComputeFlags(kind, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc);
John Reck59135872010-11-02 12:39:01 -0700959 Object* probe;
960 { MaybeObject* maybe_probe = ProbeCache(flags);
961 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
962 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000963 if (!probe->IsUndefined()) return probe;
964 StubCompiler compiler;
965 return FillCache(compiler.CompileCallDebugBreak(flags));
966}
967
968
John Reck59135872010-11-02 12:39:01 -0700969MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
970 Code::Kind kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000971 Code::Flags flags =
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100972 Code::ComputeFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000973 NOT_IN_LOOP,
974 DEBUG_PREPARE_STEP_IN,
975 NORMAL,
976 argc);
John Reck59135872010-11-02 12:39:01 -0700977 Object* probe;
978 { MaybeObject* maybe_probe = ProbeCache(flags);
979 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
980 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 if (!probe->IsUndefined()) return probe;
982 StubCompiler compiler;
983 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
984}
985#endif
986
987
Steve Blocka7e24c12009-10-30 11:49:00 +0000988void StubCache::Clear() {
989 for (int i = 0; i < kPrimaryTableSize; i++) {
990 primary_[i].key = Heap::empty_string();
991 primary_[i].value = Builtins::builtin(Builtins::Illegal);
992 }
993 for (int j = 0; j < kSecondaryTableSize; j++) {
994 secondary_[j].key = Heap::empty_string();
995 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
996 }
997}
998
999
Ben Murdochb0fe1622011-05-05 13:52:32 +01001000void StubCache::CollectMatchingMaps(ZoneMapList* types,
1001 String* name,
1002 Code::Flags flags) {
1003 for (int i = 0; i < kPrimaryTableSize; i++) {
1004 if (primary_[i].key == name) {
1005 Map* map = primary_[i].value->FindFirstMap();
1006 // Map can be NULL, if the stub is constant function call
1007 // with a primitive receiver.
1008 if (map == NULL) continue;
1009
1010 int offset = PrimaryOffset(name, flags, map);
1011 if (entry(primary_, offset) == &primary_[i]) {
1012 types->Add(Handle<Map>(map));
1013 }
1014 }
1015 }
1016
1017 for (int i = 0; i < kSecondaryTableSize; i++) {
1018 if (secondary_[i].key == name) {
1019 Map* map = secondary_[i].value->FindFirstMap();
1020 // Map can be NULL, if the stub is constant function call
1021 // with a primitive receiver.
1022 if (map == NULL) continue;
1023
1024 // Lookup in primary table and skip duplicates.
1025 int primary_offset = PrimaryOffset(name, flags, map);
1026 Entry* primary_entry = entry(primary_, primary_offset);
1027 if (primary_entry->key == name) {
1028 Map* primary_map = primary_entry->value->FindFirstMap();
1029 if (map == primary_map) continue;
1030 }
1031
1032 // Lookup in secondary table and add matches.
1033 int offset = SecondaryOffset(name, flags, primary_offset);
1034 if (entry(secondary_, offset) == &secondary_[i]) {
1035 types->Add(Handle<Map>(map));
1036 }
1037 }
1038 }
1039}
1040
1041
Steve Blocka7e24c12009-10-30 11:49:00 +00001042// ------------------------------------------------------------------------
1043// StubCompiler implementation.
1044
1045
John Reck59135872010-11-02 12:39:01 -07001046MaybeObject* LoadCallbackProperty(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +00001047 ASSERT(args[0]->IsJSObject());
1048 ASSERT(args[1]->IsJSObject());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001049 AccessorInfo* callback = AccessorInfo::cast(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001050 Address getter_address = v8::ToCData<Address>(callback->getter());
1051 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1052 ASSERT(fun != NULL);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001053 v8::AccessorInfo info(&args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001054 HandleScope scope;
1055 v8::Handle<v8::Value> result;
1056 {
1057 // Leaving JavaScript.
1058 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001059 ExternalCallbackScope call_scope(getter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001060 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1061 }
1062 RETURN_IF_SCHEDULED_EXCEPTION();
1063 if (result.IsEmpty()) return Heap::undefined_value();
1064 return *v8::Utils::OpenHandle(*result);
1065}
1066
1067
John Reck59135872010-11-02 12:39:01 -07001068MaybeObject* StoreCallbackProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001069 JSObject* recv = JSObject::cast(args[0]);
1070 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1071 Address setter_address = v8::ToCData<Address>(callback->setter());
1072 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1073 ASSERT(fun != NULL);
1074 Handle<String> name = args.at<String>(2);
1075 Handle<Object> value = args.at<Object>(3);
1076 HandleScope scope;
1077 LOG(ApiNamedPropertyAccess("store", recv, *name));
1078 CustomArguments custom_args(callback->data(), recv, recv);
1079 v8::AccessorInfo info(custom_args.end());
1080 {
1081 // Leaving JavaScript.
1082 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001083 ExternalCallbackScope call_scope(setter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001084 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1085 }
1086 RETURN_IF_SCHEDULED_EXCEPTION();
1087 return *value;
1088}
1089
Steve Block6ded16b2010-05-10 14:33:55 +01001090
1091static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1092
1093
Steve Blocka7e24c12009-10-30 11:49:00 +00001094/**
1095 * Attempts to load a property with an interceptor (which must be present),
1096 * but doesn't search the prototype chain.
1097 *
1098 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1099 * provide any value for the given name.
1100 */
John Reck59135872010-11-02 12:39:01 -07001101MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001102 Handle<String> name_handle = args.at<String>(0);
1103 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1104 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1105 ASSERT(args[2]->IsJSObject()); // Receiver.
1106 ASSERT(args[3]->IsJSObject()); // Holder.
1107 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001108
1109 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1110 v8::NamedPropertyGetter getter =
1111 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1112 ASSERT(getter != NULL);
1113
1114 {
1115 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001116 v8::AccessorInfo info(args.arguments() -
1117 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001118 HandleScope scope;
1119 v8::Handle<v8::Value> r;
1120 {
1121 // Leaving JavaScript.
1122 VMState state(EXTERNAL);
1123 r = getter(v8::Utils::ToLocal(name_handle), info);
1124 }
1125 RETURN_IF_SCHEDULED_EXCEPTION();
1126 if (!r.IsEmpty()) {
1127 return *v8::Utils::OpenHandle(*r);
1128 }
1129 }
1130
1131 return Heap::no_interceptor_result_sentinel();
1132}
1133
1134
John Reck59135872010-11-02 12:39:01 -07001135static MaybeObject* ThrowReferenceError(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001136 // If the load is non-contextual, just return the undefined result.
1137 // Note that both keyed and non-keyed loads may end up here, so we
1138 // can't use either LoadIC or KeyedLoadIC constructors.
1139 IC ic(IC::NO_EXTRA_FRAME);
1140 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Leon Clarkee46be812010-01-19 14:06:41 +00001141 if (!ic.SlowIsContextual()) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001142
1143 // Throw a reference error.
1144 HandleScope scope;
1145 Handle<String> name_handle(name);
1146 Handle<Object> error =
1147 Factory::NewReferenceError("not_defined",
1148 HandleVector(&name_handle, 1));
1149 return Top::Throw(*error);
1150}
1151
1152
John Reck59135872010-11-02 12:39:01 -07001153static MaybeObject* LoadWithInterceptor(Arguments* args,
1154 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +01001155 Handle<String> name_handle = args->at<String>(0);
1156 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1157 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1158 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1159 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1160 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001161
1162 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1163 v8::NamedPropertyGetter getter =
1164 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1165 ASSERT(getter != NULL);
1166
1167 {
1168 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001169 v8::AccessorInfo info(args->arguments() -
1170 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001171 HandleScope scope;
1172 v8::Handle<v8::Value> r;
1173 {
1174 // Leaving JavaScript.
1175 VMState state(EXTERNAL);
1176 r = getter(v8::Utils::ToLocal(name_handle), info);
1177 }
1178 RETURN_IF_SCHEDULED_EXCEPTION();
1179 if (!r.IsEmpty()) {
1180 *attrs = NONE;
1181 return *v8::Utils::OpenHandle(*r);
1182 }
1183 }
1184
John Reck59135872010-11-02 12:39:01 -07001185 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 *receiver_handle,
1187 *name_handle,
1188 attrs);
1189 RETURN_IF_SCHEDULED_EXCEPTION();
1190 return result;
1191}
1192
1193
1194/**
1195 * Loads a property with an interceptor performing post interceptor
1196 * lookup if interceptor failed.
1197 */
John Reck59135872010-11-02 12:39:01 -07001198MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001199 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001200 Object* result;
1201 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1202 if (!maybe_result->ToObject(&result)) return maybe_result;
1203 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001204
1205 // If the property is present, return it.
1206 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +01001207 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001208}
1209
1210
John Reck59135872010-11-02 12:39:01 -07001211MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001212 PropertyAttributes attr;
John Reck59135872010-11-02 12:39:01 -07001213 MaybeObject* result = LoadWithInterceptor(&args, &attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 RETURN_IF_SCHEDULED_EXCEPTION();
1215 // This is call IC. In this case, we simply return the undefined result which
1216 // will lead to an exception when trying to invoke the result as a
1217 // function.
1218 return result;
1219}
1220
1221
John Reck59135872010-11-02 12:39:01 -07001222MaybeObject* StoreInterceptorProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001223 JSObject* recv = JSObject::cast(args[0]);
1224 String* name = String::cast(args[1]);
1225 Object* value = args[2];
1226 ASSERT(recv->HasNamedInterceptor());
1227 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001228 MaybeObject* result = recv->SetPropertyWithInterceptor(name, value, attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001229 return result;
1230}
1231
1232
John Reck59135872010-11-02 12:39:01 -07001233MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001234 JSObject* receiver = JSObject::cast(args[0]);
Ben Murdochf87a2032010-10-22 12:50:53 +01001235 ASSERT(Smi::cast(args[1])->value() >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001236 uint32_t index = Smi::cast(args[1])->value();
1237 return receiver->GetElementWithInterceptor(receiver, index);
1238}
1239
1240
John Reck59135872010-11-02 12:39:01 -07001241MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 HandleScope scope;
1243 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001244 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1245 if (kind == Code::CALL_IC) {
1246 CallIC::GenerateInitialize(masm(), argc);
1247 } else {
1248 KeyedCallIC::GenerateInitialize(masm(), argc);
1249 }
John Reck59135872010-11-02 12:39:01 -07001250 Object* result;
1251 { MaybeObject* maybe_result =
1252 GetCodeWithFlags(flags, "CompileCallInitialize");
1253 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001254 }
John Reck59135872010-11-02 12:39:01 -07001255 Counters::call_initialize_stubs.Increment();
1256 Code* code = Code::cast(result);
1257 USE(code);
1258 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1259 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 return result;
1261}
1262
1263
John Reck59135872010-11-02 12:39:01 -07001264MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 HandleScope scope;
1266 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1267 // The code of the PreMonomorphic stub is the same as the code
1268 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001269 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1270 if (kind == Code::CALL_IC) {
1271 CallIC::GenerateInitialize(masm(), argc);
1272 } else {
1273 KeyedCallIC::GenerateInitialize(masm(), argc);
1274 }
John Reck59135872010-11-02 12:39:01 -07001275 Object* result;
1276 { MaybeObject* maybe_result =
1277 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1278 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001279 }
John Reck59135872010-11-02 12:39:01 -07001280 Counters::call_premonomorphic_stubs.Increment();
1281 Code* code = Code::cast(result);
1282 USE(code);
1283 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1284 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 return result;
1286}
1287
1288
John Reck59135872010-11-02 12:39:01 -07001289MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 HandleScope scope;
1291 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001292 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1293 if (kind == Code::CALL_IC) {
1294 CallIC::GenerateNormal(masm(), argc);
1295 } else {
1296 KeyedCallIC::GenerateNormal(masm(), argc);
1297 }
John Reck59135872010-11-02 12:39:01 -07001298 Object* result;
1299 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1300 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001301 }
John Reck59135872010-11-02 12:39:01 -07001302 Counters::call_normal_stubs.Increment();
1303 Code* code = Code::cast(result);
1304 USE(code);
1305 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1306 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 return result;
1308}
1309
1310
John Reck59135872010-11-02 12:39:01 -07001311MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001312 HandleScope scope;
1313 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001314 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1315 if (kind == Code::CALL_IC) {
1316 CallIC::GenerateMegamorphic(masm(), argc);
1317 } else {
1318 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1319 }
1320
John Reck59135872010-11-02 12:39:01 -07001321 Object* result;
1322 { MaybeObject* maybe_result =
1323 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1324 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 }
John Reck59135872010-11-02 12:39:01 -07001326 Counters::call_megamorphic_stubs.Increment();
1327 Code* code = Code::cast(result);
1328 USE(code);
1329 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1330 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 return result;
1332}
1333
1334
John Reck59135872010-11-02 12:39:01 -07001335MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001336 HandleScope scope;
1337 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001338 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1339 if (kind == Code::CALL_IC) {
1340 CallIC::GenerateMiss(masm(), argc);
1341 } else {
1342 KeyedCallIC::GenerateMiss(masm(), argc);
1343 }
John Reck59135872010-11-02 12:39:01 -07001344 Object* result;
1345 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1346 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001347 }
John Reck59135872010-11-02 12:39:01 -07001348 Counters::call_megamorphic_stubs.Increment();
1349 Code* code = Code::cast(result);
1350 USE(code);
1351 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1352 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001353 return result;
1354}
1355
1356
1357#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001358MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001359 HandleScope scope;
1360 Debug::GenerateCallICDebugBreak(masm());
John Reck59135872010-11-02 12:39:01 -07001361 Object* result;
1362 { MaybeObject* maybe_result =
1363 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1364 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 }
John Reck59135872010-11-02 12:39:01 -07001366 Code* code = Code::cast(result);
1367 USE(code);
1368 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1369 USE(kind);
1370 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
1371 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001372 return result;
1373}
1374
1375
John Reck59135872010-11-02 12:39:01 -07001376MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001377 HandleScope scope;
1378 // Use the same code for the the step in preparations as we do for
1379 // the miss case.
1380 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001381 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1382 if (kind == Code::CALL_IC) {
1383 CallIC::GenerateMiss(masm(), argc);
1384 } else {
1385 KeyedCallIC::GenerateMiss(masm(), argc);
1386 }
John Reck59135872010-11-02 12:39:01 -07001387 Object* result;
1388 { MaybeObject* maybe_result =
1389 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1390 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001391 }
John Reck59135872010-11-02 12:39:01 -07001392 Code* code = Code::cast(result);
1393 USE(code);
1394 PROFILE(CodeCreateEvent(
1395 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1396 code,
1397 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 return result;
1399}
1400#endif
1401
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001402#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001403
John Reck59135872010-11-02 12:39:01 -07001404MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1405 const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001406 // Check for allocation failures during stub compilation.
1407 if (failure_->IsFailure()) return failure_;
1408
1409 // Create code object in the heap.
1410 CodeDesc desc;
1411 masm_.GetCode(&desc);
John Reck59135872010-11-02 12:39:01 -07001412 MaybeObject* result = Heap::CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001413#ifdef ENABLE_DISASSEMBLER
1414 if (FLAG_print_code_stubs && !result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001415 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 }
1417#endif
1418 return result;
1419}
1420
1421
John Reck59135872010-11-02 12:39:01 -07001422MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001423 if (FLAG_print_code_stubs && (name != NULL)) {
1424 return GetCodeWithFlags(flags, *name->ToCString());
1425 }
1426 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1427}
1428
Andrei Popescu402d9372010-02-26 13:31:12 +00001429
Leon Clarke4515c472010-02-03 11:58:03 +00001430void StubCompiler::LookupPostInterceptor(JSObject* holder,
1431 String* name,
1432 LookupResult* lookup) {
1433 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001434 if (!lookup->IsProperty()) {
1435 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001436 Object* proto = holder->GetPrototype();
1437 if (proto != Heap::null_value()) {
1438 proto->Lookup(name, lookup);
1439 }
1440 }
1441}
1442
1443
Steve Blocka7e24c12009-10-30 11:49:00 +00001444
John Reck59135872010-11-02 12:39:01 -07001445MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001446 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001447 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001448 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001449 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG,
1450 Code::cast(result->ToObjectUnchecked()),
1451 name));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001452 }
1453 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001454}
1455
1456
John Reck59135872010-11-02 12:39:01 -07001457MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001458 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001459 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001460 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001461 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
1462 Code::cast(result->ToObjectUnchecked()),
1463 name));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001464 }
1465 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001466}
1467
1468
John Reck59135872010-11-02 12:39:01 -07001469MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
John Reck59135872010-11-02 12:39:01 -07001471 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001472 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001473 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,
1474 Code::cast(result->ToObjectUnchecked()),
1475 name));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001476 }
1477 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001478}
1479
1480
John Reck59135872010-11-02 12:39:01 -07001481MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
John Reck59135872010-11-02 12:39:01 -07001483 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001484 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001485 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
1486 Code::cast(result->ToObjectUnchecked()),
1487 name));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001488 }
1489 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001490}
1491
1492
Steve Block8defd9f2010-07-08 12:39:36 +01001493CallStubCompiler::CallStubCompiler(int argc,
1494 InLoopFlag in_loop,
1495 Code::Kind kind,
1496 InlineCacheHolderFlag cache_holder)
1497 : arguments_(argc)
1498 , in_loop_(in_loop)
1499 , kind_(kind)
1500 , cache_holder_(cache_holder) {
1501}
1502
1503
Ben Murdochb0fe1622011-05-05 13:52:32 +01001504bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) {
1505#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1506 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1507#undef CALL_GENERATOR_CASE
1508 return false;
1509}
1510
1511
1512MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id,
John Reck59135872010-11-02 12:39:01 -07001513 Object* object,
1514 JSObject* holder,
1515 JSGlobalPropertyCell* cell,
1516 JSFunction* function,
1517 String* fname) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001518#define CALL_GENERATOR_CASE(name) \
1519 if (id == k##name) { \
1520 return CallStubCompiler::Compile##name##Call(object, \
1521 holder, \
1522 cell, \
1523 function, \
1524 fname); \
Steve Block59151502010-09-22 15:07:15 +01001525 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001526 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1527#undef CALL_GENERATOR_CASE
1528 ASSERT(!HasCustomCallGenerator(id));
Steve Block59151502010-09-22 15:07:15 +01001529 return Heap::undefined_value();
Kristian Monsen25f61362010-05-21 11:50:48 +01001530}
1531
1532
John Reck59135872010-11-02 12:39:01 -07001533MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001534 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001535 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001536 type,
Steve Block8defd9f2010-07-08 12:39:36 +01001537 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001538 in_loop_,
1539 argc);
1540 return GetCodeWithFlags(flags, name);
1541}
1542
1543
John Reck59135872010-11-02 12:39:01 -07001544MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001545 String* function_name = NULL;
1546 if (function->shared()->name()->IsString()) {
1547 function_name = String::cast(function->shared()->name());
1548 }
1549 return GetCode(CONSTANT_FUNCTION, function_name);
1550}
1551
1552
John Reck59135872010-11-02 12:39:01 -07001553MaybeObject* ConstructStubCompiler::GetCode() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001554 Code::Flags flags = Code::ComputeFlags(Code::STUB);
John Reck59135872010-11-02 12:39:01 -07001555 Object* result;
1556 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1557 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001558 }
John Reck59135872010-11-02 12:39:01 -07001559 Code* code = Code::cast(result);
1560 USE(code);
1561 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Steve Blocka7e24c12009-10-30 11:49:00 +00001562 return result;
1563}
1564
1565
Steve Block6ded16b2010-05-10 14:33:55 +01001566CallOptimization::CallOptimization(LookupResult* lookup) {
1567 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1568 lookup->type() != CONSTANT_FUNCTION) {
1569 Initialize(NULL);
1570 } else {
1571 // We only optimize constant function calls.
1572 Initialize(lookup->GetConstantFunction());
1573 }
1574}
1575
1576CallOptimization::CallOptimization(JSFunction* function) {
1577 Initialize(function);
1578}
1579
1580
1581int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1582 JSObject* holder) const {
1583 ASSERT(is_simple_api_call_);
1584 if (expected_receiver_type_ == NULL) return 0;
1585 int depth = 0;
1586 while (object != holder) {
1587 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1588 object = JSObject::cast(object->GetPrototype());
1589 ++depth;
1590 }
1591 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1592 return kInvalidProtoDepth;
1593}
1594
1595
1596void CallOptimization::Initialize(JSFunction* function) {
1597 constant_function_ = NULL;
1598 is_simple_api_call_ = false;
1599 expected_receiver_type_ = NULL;
1600 api_call_info_ = NULL;
1601
1602 if (function == NULL || !function->is_compiled()) return;
1603
1604 constant_function_ = function;
1605 AnalyzePossibleApiFunction(function);
1606}
1607
1608
1609void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1610 SharedFunctionInfo* sfi = function->shared();
1611 if (!sfi->IsApiFunction()) return;
1612 FunctionTemplateInfo* info = sfi->get_api_func_data();
1613
1614 // Require a C++ callback.
1615 if (info->call_code()->IsUndefined()) return;
1616 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1617
1618 // Accept signatures that either have no restrictions at all or
1619 // only have restrictions on the receiver.
1620 if (!info->signature()->IsUndefined()) {
1621 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1622 if (!signature->args()->IsUndefined()) return;
1623 if (!signature->receiver()->IsUndefined()) {
1624 expected_receiver_type_ =
1625 FunctionTemplateInfo::cast(signature->receiver());
1626 }
1627 }
1628
1629 is_simple_api_call_ = true;
1630}
1631
1632
Steve Blocka7e24c12009-10-30 11:49:00 +00001633} } // namespace v8::internal