blob: f87728b7e09653c2b1506454a942c48f7e25d368 [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) {
Steve Block1e0659c2011-05-24 12:43:12 +0100444 // Using NORMAL as the PropertyType for array element loads is a misuse. The
445 // generated stub always accesses fast elements, not slow-mode fields, but
446 // some property type is required for the stub lookup. Note that overloading
447 // the NORMAL PropertyType is only safe as long as no stubs are generated for
448 // other keyed field loads. This is guaranteed to be the case since all field
449 // keyed loads that are not array elements go through a generic builtin stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100450 Code::Flags flags =
451 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
452 String* name = Heap::KeyedLoadSpecialized_symbol();
453 Object* code = receiver->map()->FindInCodeCache(name, flags);
454 if (code->IsUndefined()) {
455 KeyedLoadStubCompiler compiler;
456 { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
457 if (!maybe_code->ToObject(&code)) return maybe_code;
458 }
459 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
460 Object* result;
461 { MaybeObject* maybe_result =
462 receiver->UpdateMapCodeCache(name, Code::cast(code));
463 if (!maybe_result->ToObject(&result)) return maybe_result;
464 }
465 }
466 return code;
467}
468
469
Steve Block1e0659c2011-05-24 12:43:12 +0100470MaybeObject* StubCache::ComputeKeyedLoadPixelArray(JSObject* receiver) {
471 // Using NORMAL as the PropertyType for array element loads is a misuse. The
472 // generated stub always accesses fast elements, not slow-mode fields, but
473 // some property type is required for the stub lookup. Note that overloading
474 // the NORMAL PropertyType is only safe as long as no stubs are generated for
475 // other keyed field loads. This is guaranteed to be the case since all field
476 // keyed loads that are not array elements go through a generic builtin stub.
477 Code::Flags flags =
478 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
479 String* name = Heap::KeyedLoadPixelArray_symbol();
480 Object* code = receiver->map()->FindInCodeCache(name, flags);
481 if (code->IsUndefined()) {
482 KeyedLoadStubCompiler compiler;
483 { MaybeObject* maybe_code = compiler.CompileLoadPixelArray(receiver);
484 if (!maybe_code->ToObject(&code)) return maybe_code;
485 }
486 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
487 Object* result;
488 { MaybeObject* maybe_result =
489 receiver->UpdateMapCodeCache(name, Code::cast(code));
490 if (!maybe_result->ToObject(&result)) return maybe_result;
491 }
492 }
493 return code;
494}
495
496
John Reck59135872010-11-02 12:39:01 -0700497MaybeObject* StubCache::ComputeStoreField(String* name,
498 JSObject* receiver,
499 int field_index,
Steve Block1e0659c2011-05-24 12:43:12 +0100500 Map* transition,
501 Code::ExtraICState extra_ic_state) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000502 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Steve Block1e0659c2011-05-24 12:43:12 +0100503 Code::Flags flags = Code::ComputeMonomorphicFlags(
504 Code::STORE_IC, type, extra_ic_state);
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 Object* code = receiver->map()->FindInCodeCache(name, flags);
506 if (code->IsUndefined()) {
Steve Block1e0659c2011-05-24 12:43:12 +0100507 StoreStubCompiler compiler(extra_ic_state);
John Reck59135872010-11-02 12:39:01 -0700508 { MaybeObject* maybe_code =
509 compiler.CompileStoreField(receiver, field_index, transition, name);
510 if (!maybe_code->ToObject(&code)) return maybe_code;
511 }
Steve Block6ded16b2010-05-10 14:33:55 +0100512 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100513 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700514 Object* result;
515 { MaybeObject* maybe_result =
516 receiver->UpdateMapCodeCache(name, Code::cast(code));
517 if (!maybe_result->ToObject(&result)) return maybe_result;
518 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000519 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100520 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000521}
522
523
Ben Murdochb0fe1622011-05-05 13:52:32 +0100524MaybeObject* StubCache::ComputeKeyedStoreSpecialized(JSObject* receiver) {
525 Code::Flags flags =
526 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL);
527 String* name = Heap::KeyedStoreSpecialized_symbol();
528 Object* code = receiver->map()->FindInCodeCache(name, flags);
529 if (code->IsUndefined()) {
530 KeyedStoreStubCompiler compiler;
531 { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
532 if (!maybe_code->ToObject(&code)) return maybe_code;
533 }
534 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
535 Object* result;
536 { MaybeObject* maybe_result =
537 receiver->UpdateMapCodeCache(name, Code::cast(code));
538 if (!maybe_result->ToObject(&result)) return maybe_result;
539 }
540 }
541 return code;
542}
543
544
Steve Block1e0659c2011-05-24 12:43:12 +0100545namespace {
546
547ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
548 switch (kind) {
549 case JSObject::EXTERNAL_BYTE_ELEMENTS:
550 return kExternalByteArray;
551 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
552 return kExternalUnsignedByteArray;
553 case JSObject::EXTERNAL_SHORT_ELEMENTS:
554 return kExternalShortArray;
555 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
556 return kExternalUnsignedShortArray;
557 case JSObject::EXTERNAL_INT_ELEMENTS:
558 return kExternalIntArray;
559 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
560 return kExternalUnsignedIntArray;
561 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
562 return kExternalFloatArray;
563 default:
564 UNREACHABLE();
565 return static_cast<ExternalArrayType>(0);
566 }
567}
568
569} // anonymous namespace
570
571
572MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
573 JSObject* receiver,
574 bool is_store) {
575 Code::Flags flags =
576 Code::ComputeMonomorphicFlags(
577 is_store ? Code::KEYED_STORE_IC : Code::KEYED_LOAD_IC,
578 NORMAL);
579 ExternalArrayType array_type =
580 ElementsKindToExternalArrayType(receiver->GetElementsKind());
581 String* name =
582 is_store ? Heap::KeyedStoreExternalArray_symbol()
583 : Heap::KeyedLoadExternalArray_symbol();
584 // Use the global maps for the particular external array types,
585 // rather than the receiver's map, when looking up the cached code,
586 // so that we actually canonicalize these stubs.
587 Map* map = Heap::MapForExternalArrayType(array_type);
588 Object* code = map->FindInCodeCache(name, flags);
589 if (code->IsUndefined()) {
590 ExternalArrayStubCompiler compiler;
591 { MaybeObject* maybe_code =
592 is_store ? compiler.CompileKeyedStoreStub(array_type, flags) :
593 compiler.CompileKeyedLoadStub(array_type, flags);
594 if (!maybe_code->ToObject(&code)) return maybe_code;
595 }
596 if (is_store) {
597 PROFILE(
598 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
599 } else {
600 PROFILE(
601 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
602 }
603 Object* result;
604 { MaybeObject* maybe_result =
605 map->UpdateCodeCache(name, Code::cast(code));
606 if (!maybe_result->ToObject(&result)) return maybe_result;
607 }
608 }
609 return code;
610}
611
612
613MaybeObject* StubCache::ComputeStoreNormal(Code::ExtraICState extra_ic_state) {
614 return Builtins::builtin(extra_ic_state == StoreIC::kStoreICStrict
615 ? Builtins::StoreIC_Normal_Strict
616 : Builtins::StoreIC_Normal);
Steve Block8defd9f2010-07-08 12:39:36 +0100617}
618
619
John Reck59135872010-11-02 12:39:01 -0700620MaybeObject* StubCache::ComputeStoreGlobal(String* name,
621 GlobalObject* receiver,
Steve Block1e0659c2011-05-24 12:43:12 +0100622 JSGlobalPropertyCell* cell,
623 Code::ExtraICState extra_ic_state) {
624 Code::Flags flags = Code::ComputeMonomorphicFlags(
625 Code::STORE_IC, NORMAL, extra_ic_state);
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 Object* code = receiver->map()->FindInCodeCache(name, flags);
627 if (code->IsUndefined()) {
Steve Block1e0659c2011-05-24 12:43:12 +0100628 StoreStubCompiler compiler(extra_ic_state);
John Reck59135872010-11-02 12:39:01 -0700629 { MaybeObject* maybe_code =
630 compiler.CompileStoreGlobal(receiver, cell, name);
631 if (!maybe_code->ToObject(&code)) return maybe_code;
632 }
Steve Block8defd9f2010-07-08 12:39:36 +0100633 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100634 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700635 Object* result;
636 { MaybeObject* maybe_result =
637 receiver->UpdateMapCodeCache(name, Code::cast(code));
638 if (!maybe_result->ToObject(&result)) return maybe_result;
639 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000640 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100641 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000642}
643
644
Steve Block1e0659c2011-05-24 12:43:12 +0100645MaybeObject* StubCache::ComputeStoreCallback(
646 String* name,
647 JSObject* receiver,
648 AccessorInfo* callback,
649 Code::ExtraICState extra_ic_state) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000650 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
Steve Block1e0659c2011-05-24 12:43:12 +0100651 Code::Flags flags = Code::ComputeMonomorphicFlags(
652 Code::STORE_IC, CALLBACKS, extra_ic_state);
Steve Blocka7e24c12009-10-30 11:49:00 +0000653 Object* code = receiver->map()->FindInCodeCache(name, flags);
654 if (code->IsUndefined()) {
Steve Block1e0659c2011-05-24 12:43:12 +0100655 StoreStubCompiler compiler(extra_ic_state);
John Reck59135872010-11-02 12:39:01 -0700656 { MaybeObject* maybe_code =
657 compiler.CompileStoreCallback(receiver, callback, name);
658 if (!maybe_code->ToObject(&code)) return maybe_code;
659 }
Steve Block6ded16b2010-05-10 14:33:55 +0100660 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100661 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700662 Object* result;
663 { MaybeObject* maybe_result =
664 receiver->UpdateMapCodeCache(name, Code::cast(code));
665 if (!maybe_result->ToObject(&result)) return maybe_result;
666 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000667 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100668 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000669}
670
671
Steve Block1e0659c2011-05-24 12:43:12 +0100672MaybeObject* StubCache::ComputeStoreInterceptor(
673 String* name,
674 JSObject* receiver,
675 Code::ExtraICState extra_ic_state) {
676 Code::Flags flags = Code::ComputeMonomorphicFlags(
677 Code::STORE_IC, INTERCEPTOR, extra_ic_state);
Steve Blocka7e24c12009-10-30 11:49:00 +0000678 Object* code = receiver->map()->FindInCodeCache(name, flags);
679 if (code->IsUndefined()) {
Steve Block1e0659c2011-05-24 12:43:12 +0100680 StoreStubCompiler compiler(extra_ic_state);
John Reck59135872010-11-02 12:39:01 -0700681 { MaybeObject* maybe_code =
682 compiler.CompileStoreInterceptor(receiver, name);
683 if (!maybe_code->ToObject(&code)) return maybe_code;
684 }
Steve Block6ded16b2010-05-10 14:33:55 +0100685 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100686 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700687 Object* result;
688 { MaybeObject* maybe_result =
689 receiver->UpdateMapCodeCache(name, Code::cast(code));
690 if (!maybe_result->ToObject(&result)) return maybe_result;
691 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000692 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100693 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000694}
695
696
John Reck59135872010-11-02 12:39:01 -0700697MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
698 JSObject* receiver,
699 int field_index,
700 Map* transition) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000701 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
702 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
703 Object* code = receiver->map()->FindInCodeCache(name, flags);
704 if (code->IsUndefined()) {
705 KeyedStoreStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700706 { MaybeObject* maybe_code =
707 compiler.CompileStoreField(receiver, field_index, transition, name);
708 if (!maybe_code->ToObject(&code)) return maybe_code;
709 }
Steve Block6ded16b2010-05-10 14:33:55 +0100710 PROFILE(CodeCreateEvent(
711 Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100712 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700713 Object* result;
714 { MaybeObject* maybe_result =
715 receiver->UpdateMapCodeCache(name, Code::cast(code));
716 if (!maybe_result->ToObject(&result)) return maybe_result;
717 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000718 }
719 return code;
720}
721
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100722#define CALL_LOGGER_TAG(kind, type) \
723 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000724
John Reck59135872010-11-02 12:39:01 -0700725MaybeObject* StubCache::ComputeCallConstant(int argc,
726 InLoopFlag in_loop,
727 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100728 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700729 String* name,
730 Object* object,
731 JSObject* holder,
732 JSFunction* function) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000733 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100734 InlineCacheHolderFlag cache_holder =
735 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100736 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000737
738 // Compute check type based on receiver/holder.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100739 CheckType check = RECEIVER_MAP_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000740 if (object->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100741 check = STRING_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 } else if (object->IsNumber()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100743 check = NUMBER_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000744 } else if (object->IsBoolean()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100745 check = BOOLEAN_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000746 }
747
Ben Murdochb8e0da22011-05-16 14:20:40 +0100748 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
749 CONSTANT_FUNCTION,
750 extra_ic_state,
751 cache_holder,
752 in_loop,
753 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100754 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000755 if (code->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000756 // If the function hasn't been compiled yet, we cannot do it now
757 // because it may cause GC. To avoid this issue, we return an
758 // internal error which will make sure we do not update any
759 // caches.
760 if (!function->is_compiled()) return Failure::InternalError();
761 // Compile the stub - only create stubs for fully compiled functions.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100762 CallStubCompiler compiler(
763 argc, in_loop, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700764 { MaybeObject* maybe_code =
765 compiler.CompileCallConstant(object, holder, function, name, check);
766 if (!maybe_code->ToObject(&code)) return maybe_code;
767 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100768 Code::cast(code)->set_check_type(check);
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100770 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
771 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100772 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700773 Object* result;
774 { MaybeObject* maybe_result =
775 map_holder->UpdateMapCodeCache(name, Code::cast(code));
776 if (!maybe_result->ToObject(&result)) return maybe_result;
777 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000778 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100779 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000780}
781
782
John Reck59135872010-11-02 12:39:01 -0700783MaybeObject* StubCache::ComputeCallField(int argc,
784 InLoopFlag in_loop,
785 Code::Kind kind,
786 String* name,
787 Object* object,
788 JSObject* holder,
789 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000790 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100791 InlineCacheHolderFlag cache_holder =
792 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100793 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000794
795 // TODO(1233596): We cannot do receiver map check for non-JS objects
796 // because they may be represented as immediates without a
797 // map. Instead, we check against the map in the holder.
798 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
799 object = holder;
800 }
801
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100802 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 FIELD,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100804 Code::kNoExtraICState,
Steve Block8defd9f2010-07-08 12:39:36 +0100805 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 in_loop,
807 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100808 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000809 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100810 CallStubCompiler compiler(
811 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700812 { MaybeObject* maybe_code =
813 compiler.CompileCallField(JSObject::cast(object),
814 holder,
815 index,
816 name);
817 if (!maybe_code->ToObject(&code)) return maybe_code;
818 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100820 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
821 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100822 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700823 Object* result;
824 { MaybeObject* maybe_result =
825 map_holder->UpdateMapCodeCache(name, Code::cast(code));
826 if (!maybe_result->ToObject(&result)) return maybe_result;
827 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000828 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100829 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000830}
831
832
John Reck59135872010-11-02 12:39:01 -0700833MaybeObject* StubCache::ComputeCallInterceptor(int argc,
834 Code::Kind kind,
835 String* name,
836 Object* object,
837 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100839 InlineCacheHolderFlag cache_holder =
840 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100841 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000842
843 // TODO(1233596): We cannot do receiver map check for non-JS objects
844 // because they may be represented as immediates without a
845 // map. Instead, we check against the map in the holder.
846 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
847 object = holder;
848 }
849
Ben Murdochb8e0da22011-05-16 14:20:40 +0100850 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
851 INTERCEPTOR,
852 Code::kNoExtraICState,
853 cache_holder,
854 NOT_IN_LOOP,
855 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100856 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000857 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100858 CallStubCompiler compiler(
859 argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700860 { MaybeObject* maybe_code =
861 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
862 if (!maybe_code->ToObject(&code)) return maybe_code;
863 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000864 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100865 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
866 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100867 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700868 Object* result;
869 { MaybeObject* maybe_result =
870 map_holder->UpdateMapCodeCache(name, Code::cast(code));
871 if (!maybe_result->ToObject(&result)) return maybe_result;
872 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000873 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100874 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000875}
876
877
John Reck59135872010-11-02 12:39:01 -0700878MaybeObject* StubCache::ComputeCallNormal(int argc,
879 InLoopFlag in_loop,
880 Code::Kind kind,
881 String* name,
882 JSObject* receiver) {
883 Object* code;
884 { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
885 if (!maybe_code->ToObject(&code)) return maybe_code;
886 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100887 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000888}
889
890
John Reck59135872010-11-02 12:39:01 -0700891MaybeObject* StubCache::ComputeCallGlobal(int argc,
892 InLoopFlag in_loop,
893 Code::Kind kind,
894 String* name,
895 JSObject* receiver,
896 GlobalObject* holder,
897 JSGlobalPropertyCell* cell,
898 JSFunction* function) {
Steve Block8defd9f2010-07-08 12:39:36 +0100899 InlineCacheHolderFlag cache_holder =
900 IC::GetCodeCacheForObject(receiver, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100901 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100902 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
903 NORMAL,
904 Code::kNoExtraICState,
905 cache_holder,
906 in_loop,
907 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100908 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000909 if (code->IsUndefined()) {
910 // If the function hasn't been compiled yet, we cannot do it now
911 // because it may cause GC. To avoid this issue, we return an
912 // internal error which will make sure we do not update any
913 // caches.
914 if (!function->is_compiled()) return Failure::InternalError();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100915 CallStubCompiler compiler(
916 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700917 { MaybeObject* maybe_code =
918 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
919 if (!maybe_code->ToObject(&code)) return maybe_code;
920 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100922 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
923 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100924 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700925 Object* result;
926 { MaybeObject* maybe_result =
927 map_holder->UpdateMapCodeCache(name, Code::cast(code));
928 if (!maybe_result->ToObject(&result)) return maybe_result;
929 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000930 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100931 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000932}
933
934
935static Object* GetProbeValue(Code::Flags flags) {
936 // Use raw_unchecked... so we don't get assert failures during GC.
937 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
938 int entry = dictionary->FindEntry(flags);
939 if (entry != -1) return dictionary->ValueAt(entry);
940 return Heap::raw_unchecked_undefined_value();
941}
942
943
John Reck59135872010-11-02 12:39:01 -0700944MUST_USE_RESULT static MaybeObject* ProbeCache(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000945 Object* probe = GetProbeValue(flags);
946 if (probe != Heap::undefined_value()) return probe;
947 // Seed the cache with an undefined value to make sure that any
948 // generated code object can always be inserted into the cache
949 // without causing allocation failures.
John Reck59135872010-11-02 12:39:01 -0700950 Object* result;
951 { MaybeObject* maybe_result =
952 Heap::non_monomorphic_cache()->AtNumberPut(flags,
953 Heap::undefined_value());
954 if (!maybe_result->ToObject(&result)) return maybe_result;
955 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
957 return probe;
958}
959
960
John Reck59135872010-11-02 12:39:01 -0700961static MaybeObject* FillCache(MaybeObject* maybe_code) {
962 Object* code;
963 if (maybe_code->ToObject(&code)) {
964 if (code->IsCode()) {
965 int entry =
966 Heap::non_monomorphic_cache()->FindEntry(
967 Code::cast(code)->flags());
968 // The entry must be present see comment in ProbeCache.
969 ASSERT(entry != -1);
970 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
971 Heap::undefined_value());
972 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
973 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
974 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000975 }
John Reck59135872010-11-02 12:39:01 -0700976 return maybe_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000977}
978
979
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100980Code* StubCache::FindCallInitialize(int argc,
981 InLoopFlag in_loop,
982 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100983 Code::Flags flags = Code::ComputeFlags(kind,
984 in_loop,
985 UNINITIALIZED,
986 Code::kNoExtraICState,
987 NORMAL,
988 argc);
John Reck59135872010-11-02 12:39:01 -0700989 Object* result = ProbeCache(flags)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000990 ASSERT(!result->IsUndefined());
991 // This might be called during the marking phase of the collector
992 // hence the unchecked cast.
993 return reinterpret_cast<Code*>(result);
994}
995
996
John Reck59135872010-11-02 12:39:01 -0700997MaybeObject* StubCache::ComputeCallInitialize(int argc,
998 InLoopFlag in_loop,
999 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001000 Code::Flags flags = Code::ComputeFlags(kind,
1001 in_loop,
1002 UNINITIALIZED,
1003 Code::kNoExtraICState,
1004 NORMAL,
1005 argc);
John Reck59135872010-11-02 12:39:01 -07001006 Object* probe;
1007 { MaybeObject* maybe_probe = ProbeCache(flags);
1008 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1009 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001010 if (!probe->IsUndefined()) return probe;
1011 StubCompiler compiler;
1012 return FillCache(compiler.CompileCallInitialize(flags));
1013}
1014
1015
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001016Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
1017 if (in_loop == IN_LOOP) {
1018 // Force the creation of the corresponding stub outside loops,
1019 // because it may be used when clearing the ICs later - it is
1020 // possible for a series of IC transitions to lose the in-loop
1021 // information, and the IC clearing code can't generate a stub
1022 // that it needs so we need to ensure it is generated already.
1023 ComputeCallInitialize(argc, NOT_IN_LOOP);
1024 }
1025 CALL_HEAP_FUNCTION(ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
1026}
1027
1028
1029Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
1030 InLoopFlag in_loop) {
1031 if (in_loop == IN_LOOP) {
1032 // Force the creation of the corresponding stub outside loops,
1033 // because it may be used when clearing the ICs later - it is
1034 // possible for a series of IC transitions to lose the in-loop
1035 // information, and the IC clearing code can't generate a stub
1036 // that it needs so we need to ensure it is generated already.
1037 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
1038 }
1039 CALL_HEAP_FUNCTION(
1040 ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
1041}
1042
1043
John Reck59135872010-11-02 12:39:01 -07001044MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
1045 InLoopFlag in_loop,
1046 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001047 Code::Flags flags = Code::ComputeFlags(kind,
1048 in_loop,
1049 PREMONOMORPHIC,
1050 Code::kNoExtraICState,
1051 NORMAL,
1052 argc);
John Reck59135872010-11-02 12:39:01 -07001053 Object* probe;
1054 { MaybeObject* maybe_probe = ProbeCache(flags);
1055 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1056 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001057 if (!probe->IsUndefined()) return probe;
1058 StubCompiler compiler;
1059 return FillCache(compiler.CompileCallPreMonomorphic(flags));
1060}
1061
1062
John Reck59135872010-11-02 12:39:01 -07001063MaybeObject* StubCache::ComputeCallNormal(int argc,
1064 InLoopFlag in_loop,
1065 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001066 Code::Flags flags = Code::ComputeFlags(kind,
1067 in_loop,
1068 MONOMORPHIC,
1069 Code::kNoExtraICState,
1070 NORMAL,
1071 argc);
John Reck59135872010-11-02 12:39:01 -07001072 Object* probe;
1073 { MaybeObject* maybe_probe = ProbeCache(flags);
1074 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1075 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001076 if (!probe->IsUndefined()) return probe;
1077 StubCompiler compiler;
1078 return FillCache(compiler.CompileCallNormal(flags));
1079}
1080
1081
John Reck59135872010-11-02 12:39:01 -07001082MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
1083 InLoopFlag in_loop,
1084 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001085 Code::Flags flags = Code::ComputeFlags(kind,
1086 in_loop,
1087 MEGAMORPHIC,
1088 Code::kNoExtraICState,
1089 NORMAL,
1090 argc);
John Reck59135872010-11-02 12:39:01 -07001091 Object* probe;
1092 { MaybeObject* maybe_probe = ProbeCache(flags);
1093 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1094 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001095 if (!probe->IsUndefined()) return probe;
1096 StubCompiler compiler;
1097 return FillCache(compiler.CompileCallMegamorphic(flags));
1098}
1099
1100
John Reck59135872010-11-02 12:39:01 -07001101MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001102 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
1103 // and monomorphic stubs are not mixed up together in the stub cache.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001104 Code::Flags flags = Code::ComputeFlags(kind,
1105 NOT_IN_LOOP,
1106 MONOMORPHIC_PROTOTYPE_FAILURE,
1107 Code::kNoExtraICState,
1108 NORMAL,
1109 argc,
1110 OWN_MAP);
John Reck59135872010-11-02 12:39:01 -07001111 Object* probe;
1112 { MaybeObject* maybe_probe = ProbeCache(flags);
1113 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1114 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001115 if (!probe->IsUndefined()) return probe;
1116 StubCompiler compiler;
1117 return FillCache(compiler.CompileCallMiss(flags));
1118}
1119
1120
1121#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001122MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001123 Code::Flags flags = Code::ComputeFlags(kind,
1124 NOT_IN_LOOP,
1125 DEBUG_BREAK,
1126 Code::kNoExtraICState,
1127 NORMAL,
1128 argc);
John Reck59135872010-11-02 12:39:01 -07001129 Object* probe;
1130 { MaybeObject* maybe_probe = ProbeCache(flags);
1131 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1132 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001133 if (!probe->IsUndefined()) return probe;
1134 StubCompiler compiler;
1135 return FillCache(compiler.CompileCallDebugBreak(flags));
1136}
1137
1138
John Reck59135872010-11-02 12:39:01 -07001139MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
1140 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001141 Code::Flags flags = Code::ComputeFlags(kind,
1142 NOT_IN_LOOP,
1143 DEBUG_PREPARE_STEP_IN,
1144 Code::kNoExtraICState,
1145 NORMAL,
1146 argc);
John Reck59135872010-11-02 12:39:01 -07001147 Object* probe;
1148 { MaybeObject* maybe_probe = ProbeCache(flags);
1149 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1150 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001151 if (!probe->IsUndefined()) return probe;
1152 StubCompiler compiler;
1153 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
1154}
1155#endif
1156
1157
Steve Blocka7e24c12009-10-30 11:49:00 +00001158void StubCache::Clear() {
1159 for (int i = 0; i < kPrimaryTableSize; i++) {
1160 primary_[i].key = Heap::empty_string();
1161 primary_[i].value = Builtins::builtin(Builtins::Illegal);
1162 }
1163 for (int j = 0; j < kSecondaryTableSize; j++) {
1164 secondary_[j].key = Heap::empty_string();
1165 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
1166 }
1167}
1168
1169
Ben Murdochb0fe1622011-05-05 13:52:32 +01001170void StubCache::CollectMatchingMaps(ZoneMapList* types,
1171 String* name,
1172 Code::Flags flags) {
1173 for (int i = 0; i < kPrimaryTableSize; i++) {
1174 if (primary_[i].key == name) {
1175 Map* map = primary_[i].value->FindFirstMap();
1176 // Map can be NULL, if the stub is constant function call
1177 // with a primitive receiver.
1178 if (map == NULL) continue;
1179
1180 int offset = PrimaryOffset(name, flags, map);
1181 if (entry(primary_, offset) == &primary_[i]) {
1182 types->Add(Handle<Map>(map));
1183 }
1184 }
1185 }
1186
1187 for (int i = 0; i < kSecondaryTableSize; i++) {
1188 if (secondary_[i].key == name) {
1189 Map* map = secondary_[i].value->FindFirstMap();
1190 // Map can be NULL, if the stub is constant function call
1191 // with a primitive receiver.
1192 if (map == NULL) continue;
1193
1194 // Lookup in primary table and skip duplicates.
1195 int primary_offset = PrimaryOffset(name, flags, map);
1196 Entry* primary_entry = entry(primary_, primary_offset);
1197 if (primary_entry->key == name) {
1198 Map* primary_map = primary_entry->value->FindFirstMap();
1199 if (map == primary_map) continue;
1200 }
1201
1202 // Lookup in secondary table and add matches.
1203 int offset = SecondaryOffset(name, flags, primary_offset);
1204 if (entry(secondary_, offset) == &secondary_[i]) {
1205 types->Add(Handle<Map>(map));
1206 }
1207 }
1208 }
1209}
1210
1211
Steve Blocka7e24c12009-10-30 11:49:00 +00001212// ------------------------------------------------------------------------
1213// StubCompiler implementation.
1214
1215
John Reck59135872010-11-02 12:39:01 -07001216MaybeObject* LoadCallbackProperty(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +00001217 ASSERT(args[0]->IsJSObject());
1218 ASSERT(args[1]->IsJSObject());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001219 AccessorInfo* callback = AccessorInfo::cast(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001220 Address getter_address = v8::ToCData<Address>(callback->getter());
1221 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1222 ASSERT(fun != NULL);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001223 v8::AccessorInfo info(&args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001224 HandleScope scope;
1225 v8::Handle<v8::Value> result;
1226 {
1227 // Leaving JavaScript.
1228 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001229 ExternalCallbackScope call_scope(getter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001230 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1231 }
1232 RETURN_IF_SCHEDULED_EXCEPTION();
1233 if (result.IsEmpty()) return Heap::undefined_value();
1234 return *v8::Utils::OpenHandle(*result);
1235}
1236
1237
John Reck59135872010-11-02 12:39:01 -07001238MaybeObject* StoreCallbackProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 JSObject* recv = JSObject::cast(args[0]);
1240 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1241 Address setter_address = v8::ToCData<Address>(callback->setter());
1242 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1243 ASSERT(fun != NULL);
1244 Handle<String> name = args.at<String>(2);
1245 Handle<Object> value = args.at<Object>(3);
1246 HandleScope scope;
1247 LOG(ApiNamedPropertyAccess("store", recv, *name));
1248 CustomArguments custom_args(callback->data(), recv, recv);
1249 v8::AccessorInfo info(custom_args.end());
1250 {
1251 // Leaving JavaScript.
1252 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001253 ExternalCallbackScope call_scope(setter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001254 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1255 }
1256 RETURN_IF_SCHEDULED_EXCEPTION();
1257 return *value;
1258}
1259
Steve Block6ded16b2010-05-10 14:33:55 +01001260
1261static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1262
1263
Steve Blocka7e24c12009-10-30 11:49:00 +00001264/**
1265 * Attempts to load a property with an interceptor (which must be present),
1266 * but doesn't search the prototype chain.
1267 *
1268 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1269 * provide any value for the given name.
1270 */
John Reck59135872010-11-02 12:39:01 -07001271MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001272 Handle<String> name_handle = args.at<String>(0);
1273 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1274 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1275 ASSERT(args[2]->IsJSObject()); // Receiver.
1276 ASSERT(args[3]->IsJSObject()); // Holder.
1277 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001278
1279 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1280 v8::NamedPropertyGetter getter =
1281 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1282 ASSERT(getter != NULL);
1283
1284 {
1285 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001286 v8::AccessorInfo info(args.arguments() -
1287 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001288 HandleScope scope;
1289 v8::Handle<v8::Value> r;
1290 {
1291 // Leaving JavaScript.
1292 VMState state(EXTERNAL);
1293 r = getter(v8::Utils::ToLocal(name_handle), info);
1294 }
1295 RETURN_IF_SCHEDULED_EXCEPTION();
1296 if (!r.IsEmpty()) {
1297 return *v8::Utils::OpenHandle(*r);
1298 }
1299 }
1300
1301 return Heap::no_interceptor_result_sentinel();
1302}
1303
1304
John Reck59135872010-11-02 12:39:01 -07001305static MaybeObject* ThrowReferenceError(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001306 // If the load is non-contextual, just return the undefined result.
1307 // Note that both keyed and non-keyed loads may end up here, so we
1308 // can't use either LoadIC or KeyedLoadIC constructors.
1309 IC ic(IC::NO_EXTRA_FRAME);
1310 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Leon Clarkee46be812010-01-19 14:06:41 +00001311 if (!ic.SlowIsContextual()) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001312
1313 // Throw a reference error.
1314 HandleScope scope;
1315 Handle<String> name_handle(name);
1316 Handle<Object> error =
1317 Factory::NewReferenceError("not_defined",
1318 HandleVector(&name_handle, 1));
1319 return Top::Throw(*error);
1320}
1321
1322
John Reck59135872010-11-02 12:39:01 -07001323static MaybeObject* LoadWithInterceptor(Arguments* args,
1324 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +01001325 Handle<String> name_handle = args->at<String>(0);
1326 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1327 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1328 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1329 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1330 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001331
1332 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1333 v8::NamedPropertyGetter getter =
1334 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1335 ASSERT(getter != NULL);
1336
1337 {
1338 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001339 v8::AccessorInfo info(args->arguments() -
1340 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001341 HandleScope scope;
1342 v8::Handle<v8::Value> r;
1343 {
1344 // Leaving JavaScript.
1345 VMState state(EXTERNAL);
1346 r = getter(v8::Utils::ToLocal(name_handle), info);
1347 }
1348 RETURN_IF_SCHEDULED_EXCEPTION();
1349 if (!r.IsEmpty()) {
1350 *attrs = NONE;
1351 return *v8::Utils::OpenHandle(*r);
1352 }
1353 }
1354
John Reck59135872010-11-02 12:39:01 -07001355 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00001356 *receiver_handle,
1357 *name_handle,
1358 attrs);
1359 RETURN_IF_SCHEDULED_EXCEPTION();
1360 return result;
1361}
1362
1363
1364/**
1365 * Loads a property with an interceptor performing post interceptor
1366 * lookup if interceptor failed.
1367 */
John Reck59135872010-11-02 12:39:01 -07001368MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001370 Object* result;
1371 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1372 if (!maybe_result->ToObject(&result)) return maybe_result;
1373 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001374
1375 // If the property is present, return it.
1376 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +01001377 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001378}
1379
1380
John Reck59135872010-11-02 12:39:01 -07001381MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001382 PropertyAttributes attr;
John Reck59135872010-11-02 12:39:01 -07001383 MaybeObject* result = LoadWithInterceptor(&args, &attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001384 RETURN_IF_SCHEDULED_EXCEPTION();
1385 // This is call IC. In this case, we simply return the undefined result which
1386 // will lead to an exception when trying to invoke the result as a
1387 // function.
1388 return result;
1389}
1390
1391
John Reck59135872010-11-02 12:39:01 -07001392MaybeObject* StoreInterceptorProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001393 JSObject* recv = JSObject::cast(args[0]);
1394 String* name = String::cast(args[1]);
1395 Object* value = args[2];
1396 ASSERT(recv->HasNamedInterceptor());
1397 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001398 MaybeObject* result = recv->SetPropertyWithInterceptor(name, value, attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 return result;
1400}
1401
1402
John Reck59135872010-11-02 12:39:01 -07001403MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001404 JSObject* receiver = JSObject::cast(args[0]);
Ben Murdochf87a2032010-10-22 12:50:53 +01001405 ASSERT(Smi::cast(args[1])->value() >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001406 uint32_t index = Smi::cast(args[1])->value();
1407 return receiver->GetElementWithInterceptor(receiver, index);
1408}
1409
1410
John Reck59135872010-11-02 12:39:01 -07001411MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001412 HandleScope scope;
1413 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001414 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1415 if (kind == Code::CALL_IC) {
1416 CallIC::GenerateInitialize(masm(), argc);
1417 } else {
1418 KeyedCallIC::GenerateInitialize(masm(), argc);
1419 }
John Reck59135872010-11-02 12:39:01 -07001420 Object* result;
1421 { MaybeObject* maybe_result =
1422 GetCodeWithFlags(flags, "CompileCallInitialize");
1423 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001424 }
John Reck59135872010-11-02 12:39:01 -07001425 Counters::call_initialize_stubs.Increment();
1426 Code* code = Code::cast(result);
1427 USE(code);
1428 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1429 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001430 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001431 return result;
1432}
1433
1434
John Reck59135872010-11-02 12:39:01 -07001435MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001436 HandleScope scope;
1437 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1438 // The code of the PreMonomorphic stub is the same as the code
1439 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001440 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1441 if (kind == Code::CALL_IC) {
1442 CallIC::GenerateInitialize(masm(), argc);
1443 } else {
1444 KeyedCallIC::GenerateInitialize(masm(), argc);
1445 }
John Reck59135872010-11-02 12:39:01 -07001446 Object* result;
1447 { MaybeObject* maybe_result =
1448 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1449 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001450 }
John Reck59135872010-11-02 12:39:01 -07001451 Counters::call_premonomorphic_stubs.Increment();
1452 Code* code = Code::cast(result);
1453 USE(code);
1454 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1455 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001456 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001457 return result;
1458}
1459
1460
John Reck59135872010-11-02 12:39:01 -07001461MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001462 HandleScope scope;
1463 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001464 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1465 if (kind == Code::CALL_IC) {
1466 CallIC::GenerateNormal(masm(), argc);
1467 } else {
1468 KeyedCallIC::GenerateNormal(masm(), argc);
1469 }
John Reck59135872010-11-02 12:39:01 -07001470 Object* result;
1471 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1472 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001473 }
John Reck59135872010-11-02 12:39:01 -07001474 Counters::call_normal_stubs.Increment();
1475 Code* code = Code::cast(result);
1476 USE(code);
1477 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1478 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001479 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 return result;
1481}
1482
1483
John Reck59135872010-11-02 12:39:01 -07001484MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001485 HandleScope scope;
1486 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001487 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1488 if (kind == Code::CALL_IC) {
1489 CallIC::GenerateMegamorphic(masm(), argc);
1490 } else {
1491 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1492 }
1493
John Reck59135872010-11-02 12:39:01 -07001494 Object* result;
1495 { MaybeObject* maybe_result =
1496 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1497 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 }
John Reck59135872010-11-02 12:39:01 -07001499 Counters::call_megamorphic_stubs.Increment();
1500 Code* code = Code::cast(result);
1501 USE(code);
1502 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1503 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001504 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001505 return result;
1506}
1507
1508
John Reck59135872010-11-02 12:39:01 -07001509MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 HandleScope scope;
1511 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001512 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1513 if (kind == Code::CALL_IC) {
1514 CallIC::GenerateMiss(masm(), argc);
1515 } else {
1516 KeyedCallIC::GenerateMiss(masm(), argc);
1517 }
John Reck59135872010-11-02 12:39:01 -07001518 Object* result;
1519 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1520 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001521 }
John Reck59135872010-11-02 12:39:01 -07001522 Counters::call_megamorphic_stubs.Increment();
1523 Code* code = Code::cast(result);
1524 USE(code);
1525 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1526 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001527 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001528 return result;
1529}
1530
1531
1532#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001533MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001534 HandleScope scope;
1535 Debug::GenerateCallICDebugBreak(masm());
John Reck59135872010-11-02 12:39:01 -07001536 Object* result;
1537 { MaybeObject* maybe_result =
1538 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1539 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001540 }
John Reck59135872010-11-02 12:39:01 -07001541 Code* code = Code::cast(result);
1542 USE(code);
1543 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1544 USE(kind);
1545 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
1546 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001547 return result;
1548}
1549
1550
John Reck59135872010-11-02 12:39:01 -07001551MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001552 HandleScope scope;
1553 // Use the same code for the the step in preparations as we do for
1554 // the miss case.
1555 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001556 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1557 if (kind == Code::CALL_IC) {
1558 CallIC::GenerateMiss(masm(), argc);
1559 } else {
1560 KeyedCallIC::GenerateMiss(masm(), argc);
1561 }
John Reck59135872010-11-02 12:39:01 -07001562 Object* result;
1563 { MaybeObject* maybe_result =
1564 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1565 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001566 }
John Reck59135872010-11-02 12:39:01 -07001567 Code* code = Code::cast(result);
1568 USE(code);
1569 PROFILE(CodeCreateEvent(
1570 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1571 code,
1572 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001573 return result;
1574}
1575#endif
1576
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001577#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001578
John Reck59135872010-11-02 12:39:01 -07001579MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1580 const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001581 // Check for allocation failures during stub compilation.
1582 if (failure_->IsFailure()) return failure_;
1583
1584 // Create code object in the heap.
1585 CodeDesc desc;
1586 masm_.GetCode(&desc);
John Reck59135872010-11-02 12:39:01 -07001587 MaybeObject* result = Heap::CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001588#ifdef ENABLE_DISASSEMBLER
1589 if (FLAG_print_code_stubs && !result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001590 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001591 }
1592#endif
1593 return result;
1594}
1595
1596
John Reck59135872010-11-02 12:39:01 -07001597MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001598 if (FLAG_print_code_stubs && (name != NULL)) {
1599 return GetCodeWithFlags(flags, *name->ToCString());
1600 }
1601 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1602}
1603
Andrei Popescu402d9372010-02-26 13:31:12 +00001604
Leon Clarke4515c472010-02-03 11:58:03 +00001605void StubCompiler::LookupPostInterceptor(JSObject* holder,
1606 String* name,
1607 LookupResult* lookup) {
1608 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001609 if (!lookup->IsProperty()) {
1610 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001611 Object* proto = holder->GetPrototype();
1612 if (proto != Heap::null_value()) {
1613 proto->Lookup(name, lookup);
1614 }
1615 }
1616}
1617
1618
Steve Blocka7e24c12009-10-30 11:49:00 +00001619
John Reck59135872010-11-02 12:39:01 -07001620MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001622 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001623 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001624 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG,
1625 Code::cast(result->ToObjectUnchecked()),
1626 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001627 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1628 name,
1629 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001630 }
1631 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001632}
1633
1634
John Reck59135872010-11-02 12:39:01 -07001635MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001636 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001637 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001638 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001639 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
1640 Code::cast(result->ToObjectUnchecked()),
1641 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001642 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1643 name,
1644 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001645 }
1646 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001647}
1648
1649
John Reck59135872010-11-02 12:39:01 -07001650MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Steve Block1e0659c2011-05-24 12:43:12 +01001651 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type,
1652 extra_ic_state_);
John Reck59135872010-11-02 12:39:01 -07001653 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001654 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001655 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,
1656 Code::cast(result->ToObjectUnchecked()),
1657 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001658 GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1659 name,
1660 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001661 }
1662 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001663}
1664
1665
John Reck59135872010-11-02 12:39:01 -07001666MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001667 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
John Reck59135872010-11-02 12:39:01 -07001668 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001669 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001670 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
1671 Code::cast(result->ToObjectUnchecked()),
1672 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001673 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1674 name,
1675 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001676 }
1677 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001678}
1679
1680
Steve Block8defd9f2010-07-08 12:39:36 +01001681CallStubCompiler::CallStubCompiler(int argc,
1682 InLoopFlag in_loop,
1683 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001684 Code::ExtraICState extra_ic_state,
Steve Block8defd9f2010-07-08 12:39:36 +01001685 InlineCacheHolderFlag cache_holder)
Ben Murdochb8e0da22011-05-16 14:20:40 +01001686 : arguments_(argc),
1687 in_loop_(in_loop),
1688 kind_(kind),
1689 extra_ic_state_(extra_ic_state),
1690 cache_holder_(cache_holder) {
Steve Block8defd9f2010-07-08 12:39:36 +01001691}
1692
1693
Ben Murdochb0fe1622011-05-05 13:52:32 +01001694bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) {
1695#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1696 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1697#undef CALL_GENERATOR_CASE
1698 return false;
1699}
1700
1701
1702MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id,
John Reck59135872010-11-02 12:39:01 -07001703 Object* object,
1704 JSObject* holder,
1705 JSGlobalPropertyCell* cell,
1706 JSFunction* function,
1707 String* fname) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001708#define CALL_GENERATOR_CASE(name) \
1709 if (id == k##name) { \
1710 return CallStubCompiler::Compile##name##Call(object, \
1711 holder, \
1712 cell, \
1713 function, \
1714 fname); \
Steve Block59151502010-09-22 15:07:15 +01001715 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001716 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1717#undef CALL_GENERATOR_CASE
1718 ASSERT(!HasCustomCallGenerator(id));
Steve Block59151502010-09-22 15:07:15 +01001719 return Heap::undefined_value();
Kristian Monsen25f61362010-05-21 11:50:48 +01001720}
1721
1722
John Reck59135872010-11-02 12:39:01 -07001723MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001724 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001725 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001726 type,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001727 extra_ic_state_,
Steve Block8defd9f2010-07-08 12:39:36 +01001728 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001729 in_loop_,
1730 argc);
1731 return GetCodeWithFlags(flags, name);
1732}
1733
1734
John Reck59135872010-11-02 12:39:01 -07001735MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001736 String* function_name = NULL;
1737 if (function->shared()->name()->IsString()) {
1738 function_name = String::cast(function->shared()->name());
1739 }
1740 return GetCode(CONSTANT_FUNCTION, function_name);
1741}
1742
1743
John Reck59135872010-11-02 12:39:01 -07001744MaybeObject* ConstructStubCompiler::GetCode() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001745 Code::Flags flags = Code::ComputeFlags(Code::STUB);
John Reck59135872010-11-02 12:39:01 -07001746 Object* result;
1747 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1748 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001749 }
John Reck59135872010-11-02 12:39:01 -07001750 Code* code = Code::cast(result);
1751 USE(code);
1752 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001753 GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 return result;
1755}
1756
1757
Steve Block6ded16b2010-05-10 14:33:55 +01001758CallOptimization::CallOptimization(LookupResult* lookup) {
1759 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1760 lookup->type() != CONSTANT_FUNCTION) {
1761 Initialize(NULL);
1762 } else {
1763 // We only optimize constant function calls.
1764 Initialize(lookup->GetConstantFunction());
1765 }
1766}
1767
1768CallOptimization::CallOptimization(JSFunction* function) {
1769 Initialize(function);
1770}
1771
1772
1773int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1774 JSObject* holder) const {
1775 ASSERT(is_simple_api_call_);
1776 if (expected_receiver_type_ == NULL) return 0;
1777 int depth = 0;
1778 while (object != holder) {
1779 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1780 object = JSObject::cast(object->GetPrototype());
1781 ++depth;
1782 }
1783 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1784 return kInvalidProtoDepth;
1785}
1786
1787
1788void CallOptimization::Initialize(JSFunction* function) {
1789 constant_function_ = NULL;
1790 is_simple_api_call_ = false;
1791 expected_receiver_type_ = NULL;
1792 api_call_info_ = NULL;
1793
1794 if (function == NULL || !function->is_compiled()) return;
1795
1796 constant_function_ = function;
1797 AnalyzePossibleApiFunction(function);
1798}
1799
1800
1801void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1802 SharedFunctionInfo* sfi = function->shared();
1803 if (!sfi->IsApiFunction()) return;
1804 FunctionTemplateInfo* info = sfi->get_api_func_data();
1805
1806 // Require a C++ callback.
1807 if (info->call_code()->IsUndefined()) return;
1808 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1809
1810 // Accept signatures that either have no restrictions at all or
1811 // only have restrictions on the receiver.
1812 if (!info->signature()->IsUndefined()) {
1813 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1814 if (!signature->args()->IsUndefined()) return;
1815 if (!signature->receiver()->IsUndefined()) {
1816 expected_receiver_type_ =
1817 FunctionTemplateInfo::cast(signature->receiver());
1818 }
1819 }
1820
1821 is_simple_api_call_ = true;
1822}
1823
1824
Steve Block1e0659c2011-05-24 12:43:12 +01001825MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
1826 Object* result;
1827 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
1828 if (!maybe_result->ToObject(&result)) return maybe_result;
1829 }
1830 Code* code = Code::cast(result);
1831 USE(code);
1832 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
1833 return result;
1834}
1835
1836
Steve Blocka7e24c12009-10-30 11:49:00 +00001837} } // namespace v8::internal